Newer
Older
const {
BaseKonnector,
log,
errors,
addData,
hydrateAndFilter,
cozyClient
} = require('cozy-konnector-libs')
const rp = require('request-promise')
require('moment-timezone')
moment.locale('fr') // set the language
moment.tz.setDefault('Europe/Paris') // set the timezone
const startDate = moment()
.startOf('year')
.subtract(3, 'year')
.subtract(1, 'day')
.format('MM/DD/YYYY')
const endDate = moment().format('MM/DD/YYYY')
const timeRange = ['day', 'month', 'year']
const rangeDate = {
day: {
doctype: 'io.egl.day',
keys: ['year', 'month', 'day']
},
month: {
doctype: 'io.egl.month',
keys: ['year', 'month']
},
year: {
doctype: 'io.egl.year',
keys: ['year']
}
}
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
async function start(fields, cozyParameters) {
try {
// resetting data for demo only
// await resetData()
const baseUrl = cozyParameters.secret.eglBaseURL
const apiAuthKey = cozyParameters.secret.eglAPIAuthKey
const response = await authenticate(
fields.login,
fields.password,
baseUrl,
apiAuthKey
)
Promise.all(
timeRange.map(timeStep =>
processData(timeStep, response, baseUrl, apiAuthKey)
)
)
} catch (error) {
throw new Error(error.message)
}
}
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
async function processData(timeStep, response, baseUrl, apiAuthKey) {
const doctype = rangeDate[timeStep].doctype
log('info', 'Getting data')
const loadProfile = await getData(response, baseUrl, apiAuthKey)
log('info', 'Saving data to Cozy')
if (doctype === rangeDate.day.doctype) {
log('info', 'Saving daily data')
await storeData(loadProfile, rangeDate.day.doctype, rangeDate.day.keys)
} else if (doctype === rangeDate.month.doctype) {
log('info', 'Saving monthly data')
await resetInProgressAggregatedData(rangeDate.month.doctype)
const monthlyData = processMonthlyAggregation(loadProfile, rangeDate.month)
await storeData(monthlyData, rangeDate.month.doctype, rangeDate.month.keys)
} else if (doctype === rangeDate.year.doctype) {
log('info', 'Saving yearly data')
await resetInProgressAggregatedData(rangeDate.year.doctype)
const yearlyData = processYearAggregation(
loadProfile,
rangeDate.year.doctype
)
await storeData(yearlyData, rangeDate.year.doctype, rangeDate.year.keys)
} else {
throw new Error('Unkonw range type: ' + doctype)
}
// .then(
// () => {
// processMonthlyAggregation(loadProfile, rangeDate.month)
// }
// )
// const yearlyData = await processYearAggregation(
// loadProfile,
// rangeDate.year.doctype
// )
// storeData(yearlyData, rangeDate.year.doctype, rangeDate.year.key)
// await processMonthlyAggregation(loadProfile, rangeDate.month)
}
async function authenticate(login, password, baseUrl, apiAuthKey) {
const authRequest = {
method: 'POST',
uri: baseUrl + '/connect.aspx',
headers: {
AuthKey: apiAuthKey,
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
login: login,
pass: password
},
json: true
}
try {
const response = await rp(authRequest)
if (response.codeRetour === 100) {
return response
} else {
throw new Error(errors.LOGIN_FAILED)
}
} catch (error) {
throw error
}
}
async function getData(response, baseUrl, apiAuthKey) {
log('debug', startDate, 'Start date')
log('debug', endDate, 'End date')
const dataRequest = {
method: 'POST',
uri: baseUrl + '/getAllAgregatsByAbonnement.aspx',
headers: {
AuthKey: apiAuthKey,
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
token: response.resultatRetour.token,
num_abt: response.resultatRetour.num_abt,
},
json: true
}
try {
const response = await rp(dataRequest)
switch (response.codeRetour) {
case 100:
return format(response)
case -2:
throw new Error(errors.LOGIN_FAILED)
case -1:
throw new Error(errors.VENDOR_DOWN)
default:
throw new Error(errors.UNKNOWN_ERROR)
}
} catch (error) {
throw new Error(errors.VENDOR_DOWN)
}
}
const data = response.resultatRetour.slice(1).map((value, index) => {
const time = moment(value.DateReleve, moment.ISO_8601)
load: value.ValeurIndex - response.resultatRetour[index].ValeurIndex,
year: parseInt(time.format('YYYY')),
month: parseInt(time.format('M')),
day: parseInt(time.format('D')),
hour: 0,
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
function processYearAggregation(data, doctype) {
log('info', 'Start aggregation for : ' + doctype)
const grouped = data.reduce(reduceYearFunction, {})
return Object.values(grouped)
}
function processMonthlyAggregation(data, range) {
log('info', 'Start aggregation for : ' + range.doctype)
// Filter by year
const tmpData = groupBy(data, 'year')
const keys = Object.keys(tmpData)
var dataToStore = []
// Monthly aggregation
for (const index in keys) {
// Get daily data of a year
var monthlyData = tmpData[keys[index]]
// Monthly aggregation
var aggregatedData = monthlyData.reduce(reduceMonthFunction, {})
// Store it
dataToStore = dataToStore.concat(Object.values(aggregatedData))
}
return dataToStore
}
function groupBy(xs, key) {
return xs.reduce(function(rv, x) {
;(rv[x[key]] = rv[x[key]] || []).push(x)
return rv
}, {})
}
function reduceYearFunction(acc, x) {
var id = acc[x.year]
if (id) {
id.load += x.load
} else {
acc[x.year] = x
}
return acc
}
function reduceMonthFunction(acc, x) {
var id = acc[x.month]
if (id) {
id.load += x.load
} else {
acc[x.month] = x
}
return acc
}
async function storeData(data, doctype, keys) {
log('debug', 'Store into ' + doctype)
log('debug', keys, 'Store into keys ')
return hydrateAndFilter(data, doctype, {
keys: keys
/**
* Function handling special case.
* The temporary aggregated data need to be remove in order for the most recent one te be saved.
* ex for io.egl.month :
* { load: 76.712, month: 2020, ... } need to be replace by
* { load: 82.212, month: 2020, ... } after grdf data reprocess
*/
async function resetInProgressAggregatedData(doctype) {
// /!\ Warning: cannot use mongo queries because not supported for dev by cozy-konnectors-libs
log('debug', doctype, 'Remove aggregated data for')
const result = await cozyClient.data.findAll(doctype)
if (result.error || result.length <= 0) {
console.warn('Error while fetching loads, doctype not found ')
} else {
const currentDate = moment()
// Filter data to remove
var filtered = []
if (doctype === rangeDate.year.doctype) {
// Yearly case
filtered = result.filter(function(el) {
return el.year == currentDate.year()
})
} else {
// Monthly case
filtered = result.filter(function(el) {
return (
el.year == currentDate.year() &&
el.month == parseInt(moment().format('M'))
)
})
}
// Remove data
for (const doc of filtered) {
log('debug', doc, 'Removing this entry for ' + doctype)
await cozyClient.data.delete(doctype, doc)
}