// @ts-check const { BaseKonnector, log, hydrateAndFilter, addData, } = require('cozy-konnector-libs') const soapRequest = require('easy-soap-request') const moment = require('moment') require('moment-timezone') const xml2js = require('xml2js') moment.locale('fr') // set the language moment.tz.setDefault('Europe/Paris') // set the timezone /*** Connector Constants ***/ const manualExecution = process.env.COZY_JOB_MANUAL_EXECUTION === 'true' ? true : false const startDailyDate = manualExecution ? moment().subtract(12, 'month') : moment().subtract(6, 'month') const startDailyDateString = startDailyDate.format('YYYY-MM-DD') // const startLoadDate = moment().subtract(7, 'day') // const startLoadDateString = startLoadDate.format('YYYY-MM-DD') const endDate = moment() const endDateString = endDate.format('YYYY-MM-DD') module.exports = new BaseKonnector(start) // The start function is run by the BaseKonnector instance only when it got all the account // information (fields). When you run this connector yourself in "standalone" mode or "dev" mode, // the account information come from ./konnector-dev-config.json file // cozyParameters are static parameters, independents from the account. Most often, it can be a // secret api key. async function start(fields, cozyParameters) { log('info', 'Gathering data ...') console.log(fields.wso2BaseUrl) console.log(cozyParameters) let baseUrl = fields.wso2BaseUrl let apiAuthKey = fields.apiToken let loginUtilisateur = fields.loginUtilisateur log('info', 'Authenticating ...') if (cozyParameters && Object.keys(cozyParameters).length !== 0) { log('debug', 'Found COZY_PARAMETERS') baseUrl = cozyParameters.secret.wso2BaseUrl apiAuthKey = cozyParameters.secret.apiToken loginUtilisateur = cozyParameters.secret.loginUtilisateur } //TODO: authentification ? log('info', 'Successfully logged in') //TODO: get compteur start data await getData( `${baseUrl}/enedis_SGE_ConsultationMesuresDetaillees/1.0`, apiAuthKey, loginUtilisateur, fields.pointId ) log('info', 'Konnector process end') } /** * * @param {string} url * @param {string} apiAuthKey * @param {string} userLogin * @param {number} pointId */ async function getData(url, apiAuthKey, userLogin, pointId) { log('info', 'Fetching data') const sampleHeaders = { 'Content-Type': 'text/xml;charset=UTF-8', apikey: apiAuthKey, } const { response } = await soapRequest({ url: url, headers: sampleHeaders, xml: userMesureDetailles( pointId, userLogin, startDailyDateString, endDateString ), }).catch(err => { log('error', err) return err }) xml2js.parseString( response.body, { tagNameProcessors: [parseTags], valueProcessors: [parseValue], explicitArray: false, }, processData() ) } /** * Format tag in order to be manipulated easly * @param {string} name * @returns {string} name */ function parseTags(name) { if (name.split(':')[1] !== undefined) { return name.split(':')[1] } return name } /** * * @param {string} value * @param {string} name * @returns {string|number} value */ function parseValue(value, name) { // Wh => KWh if (name === 'v') { return parseFloat((parseInt(value) / 1000).toFixed(2)) } return value } /** * Parse data */ function processData() { return async (err, result) => { if (err) { log('error', err) throw err } // Return only needed part of info const data = parseSgeXmlData(result) return storeData( await formateDataForDoctype(data), 'com.grandlyon.enedis.day', ['year', 'month', 'day'] ) } } /** * * @param {*} result * @returns {SGEData[]} */ function parseSgeXmlData(result) { log('info', 'Parsing list of documents') let json = JSON.stringify(result) return JSON.parse(json)['Envelope']['Body'][ 'consulterMesuresDetailleesResponse' ]['grandeur']['mesure'] } /** * Save data in the right doctype db and prevent duplicated keys * @param {EnedisKonnectorData[]} data * @param {string} doctype * @param {string[]} filterKeys * @returns */ async function storeData(data, doctype, filterKeys) { log('debug', doctype, 'Store into') const filteredDocuments = await hydrateAndFilter(data, doctype, { keys: filterKeys, }) return await addData(filteredDocuments, doctype) } /** * Query SGE in order to get info * @param {number} pointId * @param {string} userLogin * @param {string} startDt * @param {string} endDt * @returns {string} */ function userMesureDetailles(pointId, userLogin, startDt, endDt) { log('info', `Query data between ${startDt} and ${endDt}`) return `<?xml version='1.0' encoding='utf-8'?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v2="http://www.enedis.fr/sge/b2b/services/consultationmesuresdetaillees/v2.0" xmlns:v1="http://www.enedis.fr/sge/b2b/technique/v1.0"> <soapenv:Header/> <soapenv:Body> <v2:consulterMesuresDetaillees> <demande> <initiateurLogin>${userLogin}</initiateurLogin> <pointId>${pointId}</pointId> <mesuresTypeCode>ENERGIE</mesuresTypeCode> <grandeurPhysique>EA</grandeurPhysique> <soutirage>true</soutirage> <injection>false</injection> <dateDebut>${startDt}</dateDebut> <dateFin>${endDt}</dateFin> <mesuresCorrigees>false</mesuresCorrigees> <accordClient>true</accordClient> </demande> </v2:consulterMesuresDetaillees> </soapenv:Body> </soapenv:Envelope> ` } /** * Format data for DB storage * @param {SGEData[]} data * @returns {Promise<EnedisKonnectorData[]>} Parsed timestamp array */ async function formateDataForDoctype(data) { log('info', 'Formating data') console.log(data) // record return data.map(record => { let date = moment(record.d, 'YYYY/MM/DD h:mm:ss') return { load: record.v, year: parseInt(date.format('YYYY')), month: parseInt(date.format('M')), day: parseInt(date.format('D')), hour: parseInt(date.format('H')), minute: parseInt(date.format('m')), } }) }