iobroker.senec 1.6.11 → 1.6.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/main.js CHANGED
@@ -1,41 +1,74 @@
1
- 'use strict';
1
+ "use strict";
2
2
  //process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; // not cool, not nice - but well ... just a last option if everything else fails
3
3
 
4
- const https = require('https');
5
- const agent = new https.Agent({
4
+ const https = require("https");
5
+ const agent = new https.Agent({
6
6
  requestCert: true,
7
- rejectUnauthorized: false
7
+ rejectUnauthorized: false,
8
8
  });
9
9
 
10
- const utils = require('@iobroker/adapter-core');
10
+ const utils = require("@iobroker/adapter-core");
11
11
 
12
- const axios = require('axios').default;
13
- axios.defaults.headers.post['Content-Type'] = "application/json";
12
+ const axios = require("axios").default;
13
+ axios.defaults.headers.post["Content-Type"] = "application/json";
14
14
 
15
- const state_attr = require(__dirname + '/lib/state_attr.js');
16
- const state_trans = require(__dirname + '/lib/state_trans.js');
17
- const api_trans = require(__dirname + '/lib/api_trans.js');
15
+ const state_attr = require(__dirname + "/lib/state_attr.js");
16
+ const state_trans = require(__dirname + "/lib/state_trans.js");
17
+ const api_trans = require(__dirname + "/lib/api_trans.js");
18
18
  const kiloList = ["W", "Wh"];
19
19
 
20
20
  const apiUrl = "https://app-gateway.prod.senec.dev/v1/senec";
21
21
  const apiLoginUrl = apiUrl + "/login";
22
22
  const apiSystemsUrl = apiUrl + "/systems";
23
23
  const apiMonitorUrl = apiUrl + "/monitor";
24
- const apiKnownSystems = []
24
+ const apiKnownSystems = [];
25
25
 
26
- const batteryOn = '{"ENERGY":{"SAFE_CHARGE_FORCE":"u8_01","SAFE_CHARGE_PROHIBIT":"","SAFE_CHARGE_RUNNING":"","LI_STORAGE_MODE_START":"","LI_STORAGE_MODE_STOP":"","LI_STORAGE_MODE_RUNNING":"","STAT_STATE":""}}';
27
- const batteryOff = '{"ENERGY":{"SAFE_CHARGE_FORCE":"","SAFE_CHARGE_PROHIBIT":"u8_01","SAFE_CHARGE_RUNNING":"","LI_STORAGE_MODE_START":"","LI_STORAGE_MODE_STOP":"","LI_STORAGE_MODE_RUNNING":"","STAT_STATE":""}}';
26
+ const batteryOn =
27
+ '{"ENERGY":{"SAFE_CHARGE_FORCE":"u8_01","SAFE_CHARGE_PROHIBIT":"","SAFE_CHARGE_RUNNING":"","LI_STORAGE_MODE_START":"","LI_STORAGE_MODE_STOP":"","LI_STORAGE_MODE_RUNNING":"","STAT_STATE":""}}';
28
+ const batteryOff =
29
+ '{"ENERGY":{"SAFE_CHARGE_FORCE":"","SAFE_CHARGE_PROHIBIT":"u8_01","SAFE_CHARGE_RUNNING":"","LI_STORAGE_MODE_START":"","LI_STORAGE_MODE_STOP":"","LI_STORAGE_MODE_RUNNING":"","STAT_STATE":""}}';
28
30
 
29
31
  let apiConnected = false;
30
32
  let lalaConnected = false;
31
33
  let apiLoginToken = "";
32
- let retry = 0; // retry-counter
33
- let retryLowPrio = 0; // retry-counter
34
34
  let connectVia = "http://";
35
35
 
36
- const allKnownObjects = new Set(["BAT1","BAT1OBJ1","BMS","BMS_PARA","BMZ_CURRENT_LIMITS","CASC","CELL_DEVIATION_ROC","CURRENT_IMBALANCE_CONTROL","DEBUG","ENERGY","FACTORY","FEATURES","GRIDCONFIG","ISKRA","LOG","PM1","PM1OBJ1","PM1OBJ2","PV1","PWR_UNIT","RTC","SENEC_IO_INPUT","SENEC_IO_OUTPUT","SELFTEST_RESULTS","SOCKETS","STECA","SYS_UPDATE","TEMPMEASURE","TEST","UPDATE","WALLBOX","WIZARD"]);
36
+ const allKnownObjects = new Set([
37
+ "BAT1",
38
+ "BAT1OBJ1",
39
+ "BMS",
40
+ "BMS_PARA",
41
+ "BMZ_CURRENT_LIMITS",
42
+ "CASC",
43
+ "CELL_DEVIATION_ROC",
44
+ "CURRENT_IMBALANCE_CONTROL",
45
+ "DEBUG",
46
+ "ENERGY",
47
+ "FACTORY",
48
+ "FEATURES",
49
+ "GRIDCONFIG",
50
+ "ISKRA",
51
+ "LOG",
52
+ "PM1",
53
+ "PM1OBJ1",
54
+ "PM1OBJ2",
55
+ "PV1",
56
+ "PWR_UNIT",
57
+ "RTC",
58
+ "SENEC_IO_INPUT",
59
+ "SENEC_IO_OUTPUT",
60
+ "SELFTEST_RESULTS",
61
+ "SOCKETS",
62
+ "STECA",
63
+ "SYS_UPDATE",
64
+ "TEMPMEASURE",
65
+ "TEST",
66
+ "UPDATE",
67
+ "WALLBOX",
68
+ "WIZARD",
69
+ ]);
37
70
 
38
- const highPrioObjects = new Map;
71
+ const highPrioObjects = new Map();
39
72
  let lowPrioForm = "";
40
73
  let highPrioForm = "";
41
74
 
@@ -44,30 +77,29 @@ let unloaded = false;
44
77
  const knownObjects = {};
45
78
 
46
79
  class Senec extends utils.Adapter {
80
+ /**
81
+ * @param {Partial<ioBroker.AdapterOptions>} [options={}]
82
+ */
83
+ constructor(options) {
84
+ super({
85
+ ...options,
86
+ name: "senec",
87
+ });
88
+ this.on("ready", this.onReady.bind(this));
89
+ this.on("stateChange", this.onStateChange.bind(this));
90
+ this.on("unload", this.onUnload.bind(this));
91
+ }
47
92
 
48
- /**
49
- * @param {Partial<ioBroker.AdapterOptions>} [options={}]
50
- */
51
- constructor(options) {
52
- super({
53
- ...options,
54
- name: 'senec',
55
- });
56
- this.on('ready', this.onReady.bind(this));
57
- this.on('stateChange', this.onStateChange.bind(this));
58
- this.on('unload', this.onUnload.bind(this));
59
- }
60
-
61
- /**
62
- * Is called when databases are connected and adapter received configuration.
63
- */
64
- async onReady() {
65
- // Initialize your adapter here
66
-
67
- // Reset the connection indicator during startup
68
- this.setState('info.connection', false, true);
69
- try {
70
- await this.checkConfig();
93
+ /**
94
+ * Is called when databases are connected and adapter received configuration.
95
+ */
96
+ async onReady() {
97
+ // Initialize your adapter here
98
+
99
+ // Reset the connection indicator during startup
100
+ this.setState("info.connection", false, true);
101
+ try {
102
+ await this.checkConfig();
71
103
  if (this.config.lala_use) {
72
104
  this.log.info("Usage of lala.cgi configured.");
73
105
  await this.initPollSettings();
@@ -87,43 +119,54 @@ class Senec extends utils.Adapter {
87
119
  await this.pollSenecAppApi(0); // App API
88
120
  }
89
121
  } else {
90
- this.log.warn("Usage of SENEC App API not configured. Only polling appliance via local network if configured.");
122
+ this.log.warn(
123
+ "Usage of SENEC App API not configured. Only polling appliance via local network if configured.",
124
+ );
91
125
  }
92
-
93
126
  if (lalaConnected || apiConnected) {
94
- this.setState('info.connection', true, true);
127
+ this.setState("info.connection", true, true);
95
128
  } else {
96
129
  this.log.error("Neither local connection nor API connection configured. Please check config!");
97
130
  }
98
131
  if (this.config.control_active) {
99
132
  this.log.info("Active appliance control activated!");
100
133
  await this.subscribeStatesAsync("control.*"); // subscribe on all state changes in control.
101
- await this.subscribeStatesAsync("ENERGY.STAT_STATE");
134
+ await this.subscribeStatesAsync("ENERGY.STAT_STATE");
102
135
  }
103
- } catch (error) {
104
- this.log.error(error);
105
- this.setState('info.connection', false, true);
106
- }
107
- }
108
-
136
+ } catch (error) {
137
+ this.log.error(error);
138
+ this.setState("info.connection", false, true);
139
+ }
140
+ }
141
+
109
142
  /**
110
- * @param {string} id
111
- * @param {ioBroker.State | null | undefined} state
112
- */
113
- async onStateChange(id, state) {
114
- if (state && !state.ack) {
143
+ * @param {string} id
144
+ * @param {ioBroker.State | null | undefined} state
145
+ */
146
+ async onStateChange(id, state) {
147
+ if (state && !state.ack) {
115
148
  this.log.debug("State changed: " + id + " ( " + JSON.stringify(state) + " )");
116
-
117
- if (this.config.control_active) { // All state-changes for .control.* need active config value
149
+ if (this.config.control_active) {
150
+ // All state-changes for .control.* need active config value
118
151
  if (id === this.namespace + ".control.ForceLoadBattery" && lalaConnected) {
119
152
  const url = connectVia + this.config.senecip + "/lala.cgi";
120
153
  try {
121
154
  if (state.val) {
122
- this.log.info("Enable force battery charging ...");
123
- this.evalPoll(JSON.parse(await this.doGet(url, batteryOn, this, this.config.pollingTimeout, true), reviverNumParse));
155
+ this.log.info("Enable force battery charging ...");
156
+ this.evalPoll(
157
+ JSON.parse(
158
+ await this.doGet(url, batteryOn, this, this.config.pollingTimeout, true),
159
+ reviverNumParse,
160
+ ),
161
+ );
124
162
  } else {
125
163
  this.log.info("Disable force battery charging ...");
126
- this.evalPoll(JSON.parse(await this.doGet(url, batteryOff, this, this.config.pollingTimeout, true), reviverNumParse));
164
+ this.evalPoll(
165
+ JSON.parse(
166
+ await this.doGet(url, batteryOff, this, this.config.pollingTimeout, true),
167
+ reviverNumParse,
168
+ ),
169
+ );
127
170
  }
128
171
  } catch (error) {
129
172
  this.log.error(error);
@@ -132,266 +175,353 @@ class Senec extends utils.Adapter {
132
175
  }
133
176
  }
134
177
  }
135
-
136
- this.setStateAsync(id, { val: state.val, ack: true }); // Verarbeitung bestätigen
137
-
138
- } else if (state && id === this.namespace + ".ENERGY.STAT_STATE") { // states that do have state.ack already
178
+ this.setStateAsync(id, { val: state.val, ack: true }); // Verarbeitung bestätigen
179
+ } else if (state && id === this.namespace + ".ENERGY.STAT_STATE") {
180
+ // states that do have state.ack already
139
181
  this.log.debug("State changed: " + id + " ( " + JSON.stringify(state) + " )");
140
182
  const forceLoad = await this.getStateAsync(this.namespace + ".control.ForceLoadBattery");
141
183
  if (state.val == 8 || state.val == 9) {
142
184
  if (state.val == 9) this.log.info("Battery forced loading completed (battery full).");
143
185
  if (!forceLoad.val) {
144
- this.log.info("Battery forced loading activated (from outside or just lag). Syncing control-state.");
186
+ this.log.info(
187
+ "Battery forced loading activated (from outside or just lag). Syncing control-state.",
188
+ );
145
189
  this.setStateChangedAsync(this.namespace + ".control.ForceLoadBattery", { val: true, ack: true });
146
190
  }
147
191
  } else {
148
192
  if (forceLoad.val) {
149
- this.log.info("Battery forced loading deactivated (from outside or just lag). Syncing control-state.");
193
+ this.log.info(
194
+ "Battery forced loading deactivated (from outside or just lag). Syncing control-state.",
195
+ );
150
196
  this.setStateChangedAsync(this.namespace + ".control.ForceLoadBattery", { val: false, ack: true });
151
197
  }
152
198
  }
153
199
  }
154
- }
200
+ }
155
201
 
156
- /**
157
- * Is called when adapter shuts down - callback has to be called under any circumstances!
158
- * @param {() => void} callback
159
- */
160
- onUnload(callback) {
161
- try {
202
+ /**
203
+ * Is called when adapter shuts down - callback has to be called under any circumstances!
204
+ * @param {() => void} callback
205
+ */
206
+ onUnload(callback) {
207
+ try {
162
208
  unloaded = true;
163
- if (this.timer) {
164
- clearTimeout(this.timer);
165
- }
166
- if (this.timerAPI) {
167
- clearTimeout(this.timerAPI);
168
- }
169
- this.log.info('cleaned everything up...');
170
- this.setState('info.connection', false, true);
171
- callback();
172
- } catch (e) {
173
- callback();
174
- }
175
- }
176
-
209
+ if (this.timer) {
210
+ clearTimeout(this.timer);
211
+ }
212
+ if (this.timerAPI) {
213
+ clearTimeout(this.timerAPI);
214
+ }
215
+ this.log.info("cleaned everything up...");
216
+ this.setState("info.connection", false, true);
217
+ callback();
218
+ } catch (e) {
219
+ callback(e);
220
+ }
221
+ }
222
+
177
223
  async initPollSettings() {
178
224
  // creating form for low priority pulling (which means pulling everything we know)
179
225
  // we can do this while preparing values for high prio
180
- lowPrioForm = '{';
226
+ lowPrioForm = "{";
181
227
  for (const value of allKnownObjects) {
182
228
  lowPrioForm += '"' + value + '":{},';
183
229
  const objectsSet = new Set();
184
230
  switch (value) {
185
231
  case "BMS":
186
- ["CELL_TEMPERATURES_MODULE_A","CELL_TEMPERATURES_MODULE_B","CELL_TEMPERATURES_MODULE_C","CELL_TEMPERATURES_MODULE_D","CELL_VOLTAGES_MODULE_A","CELL_VOLTAGES_MODULE_B","CELL_VOLTAGES_MODULE_C","CELL_VOLTAGES_MODULE_D","CURRENT","SOC","SYSTEM_SOC","TEMP_MAX","TEMP_MIN","VOLTAGE"].forEach(item => objectsSet.add(item));
187
- if (this.config.disclaimer && this.config.highPrio_BMS_active) this.addUserDps(value, objectsSet, this.config.highPrio_BMS);
188
- break;
232
+ [
233
+ "CELL_TEMPERATURES_MODULE_A",
234
+ "CELL_TEMPERATURES_MODULE_B",
235
+ "CELL_TEMPERATURES_MODULE_C",
236
+ "CELL_TEMPERATURES_MODULE_D",
237
+ "CELL_VOLTAGES_MODULE_A",
238
+ "CELL_VOLTAGES_MODULE_B",
239
+ "CELL_VOLTAGES_MODULE_C",
240
+ "CELL_VOLTAGES_MODULE_D",
241
+ "CURRENT",
242
+ "SOC",
243
+ "SYSTEM_SOC",
244
+ "TEMP_MAX",
245
+ "TEMP_MIN",
246
+ "VOLTAGE",
247
+ ].forEach((item) => objectsSet.add(item));
248
+ if (this.config.disclaimer && this.config.highPrio_BMS_active)
249
+ this.addUserDps(value, objectsSet, this.config.highPrio_BMS);
250
+ break;
189
251
  case "ENERGY":
190
- ["STAT_STATE","GUI_BAT_DATA_POWER","GUI_INVERTER_POWER","GUI_HOUSE_POW","GUI_GRID_POW","GUI_BAT_DATA_FUEL_CHARGE","GUI_CHARGING_INFO","GUI_BOOSTING_INFO","GUI_BAT_DATA_POWER","GUI_BAT_DATA_VOLTAGE","GUI_BAT_DATA_CURRENT","GUI_BAT_DATA_FUEL_CHARGE","GUI_BAT_DATA_OA_CHARGING","STAT_LIMITED_NET_SKEW","SAFE_CHARGE_FORCE","SAFE_CHARGE_PROHIBIT","SAFE_CHARGE_RUNNING"].forEach(item => objectsSet.add(item));
191
- if (this.config.disclaimer && this.config.highPrio_ENERGY_active) this.addUserDps(value, objectsSet, this.config.highPrio_ENERGY);
192
- break;
252
+ [
253
+ "STAT_STATE",
254
+ "GUI_BAT_DATA_POWER",
255
+ "GUI_INVERTER_POWER",
256
+ "GUI_HOUSE_POW",
257
+ "GUI_GRID_POW",
258
+ "GUI_BAT_DATA_FUEL_CHARGE",
259
+ "GUI_CHARGING_INFO",
260
+ "GUI_BOOSTING_INFO",
261
+ "GUI_BAT_DATA_POWER",
262
+ "GUI_BAT_DATA_VOLTAGE",
263
+ "GUI_BAT_DATA_CURRENT",
264
+ "GUI_BAT_DATA_FUEL_CHARGE",
265
+ "GUI_BAT_DATA_OA_CHARGING",
266
+ "STAT_LIMITED_NET_SKEW",
267
+ "SAFE_CHARGE_FORCE",
268
+ "SAFE_CHARGE_PROHIBIT",
269
+ "SAFE_CHARGE_RUNNING",
270
+ ].forEach((item) => objectsSet.add(item));
271
+ if (this.config.disclaimer && this.config.highPrio_ENERGY_active)
272
+ this.addUserDps(value, objectsSet, this.config.highPrio_ENERGY);
273
+ break;
193
274
  case "PV1":
194
- ["POWER_RATIO","MPP_POWER"].forEach(item => objectsSet.add(item));
195
- if (this.config.disclaimer && this.config.highPrio_PV1_active) this.addUserDps(value, objectsSet, this.config.highPrio_PV1);
196
- break;
275
+ ["POWER_RATIO", "MPP_POWER"].forEach((item) => objectsSet.add(item));
276
+ if (this.config.disclaimer && this.config.highPrio_PV1_active)
277
+ this.addUserDps(value, objectsSet, this.config.highPrio_PV1);
278
+ break;
197
279
  case "PWR_UNIT":
198
- ["POWER_L1","POWER_L2","POWER_L3"].forEach(item => objectsSet.add(item));
199
- if (this.config.disclaimer && this.config.highPrio_PWR_UNIT_active) this.addUserDps(value, objectsSet, this.config.highPrio_PWR_UNIT);
200
- break;
280
+ ["POWER_L1", "POWER_L2", "POWER_L3"].forEach((item) => objectsSet.add(item));
281
+ if (this.config.disclaimer && this.config.highPrio_PWR_UNIT_active)
282
+ this.addUserDps(value, objectsSet, this.config.highPrio_PWR_UNIT);
283
+ break;
201
284
  case "PM1OBJ1":
202
- ["FREQ","U_AC","I_AC","P_AC","P_TOTAL"].forEach(item => objectsSet.add(item));
203
- if (this.config.disclaimer && this.config.highPrio_PM1OBJ1_active) this.addUserDps(value, objectsSet, this.config.highPrio_PM1OBJ1);
204
- break;
285
+ ["FREQ", "U_AC", "I_AC", "P_AC", "P_TOTAL"].forEach((item) => objectsSet.add(item));
286
+ if (this.config.disclaimer && this.config.highPrio_PM1OBJ1_active)
287
+ this.addUserDps(value, objectsSet, this.config.highPrio_PM1OBJ1);
288
+ break;
205
289
  case "PM1OBJ2":
206
- ["FREQ","U_AC","I_AC","P_AC","P_TOTAL"].forEach(item => objectsSet.add(item));
207
- if (this.config.disclaimer && this.config.highPrio_PM1OBJ2_active) this.addUserDps(value, objectsSet, this.config.highPrio_PM1OBJ2);
208
- break;
290
+ ["FREQ", "U_AC", "I_AC", "P_AC", "P_TOTAL"].forEach((item) => objectsSet.add(item));
291
+ if (this.config.disclaimer && this.config.highPrio_PM1OBJ2_active)
292
+ this.addUserDps(value, objectsSet, this.config.highPrio_PM1OBJ2);
293
+ break;
209
294
  case "WALLBOX":
210
- if (this.config.disclaimer && this.config.highPrio_WALLBOX_active) this.addUserDps(value, objectsSet, this.config.highPrio_WALLBOX);
211
- break;
295
+ if (this.config.disclaimer && this.config.highPrio_WALLBOX_active)
296
+ this.addUserDps(value, objectsSet, this.config.highPrio_WALLBOX);
297
+ break;
212
298
  case "BAT1":
213
- if (this.config.disclaimer && this.config.highPrio_BAT1_active) this.addUserDps(value, objectsSet, this.config.highPrio_BAT1);
214
- break;
299
+ if (this.config.disclaimer && this.config.highPrio_BAT1_active)
300
+ this.addUserDps(value, objectsSet, this.config.highPrio_BAT1);
301
+ break;
215
302
  case "BAT1OBJ1":
216
- if (this.config.disclaimer && this.config.highPrio_BAT1OBJ1_active) this.addUserDps(value, objectsSet, this.config.highPrio_BAT1OBJ1);
217
- break;
303
+ if (this.config.disclaimer && this.config.highPrio_BAT1OBJ1_active)
304
+ this.addUserDps(value, objectsSet, this.config.highPrio_BAT1OBJ1);
305
+ break;
218
306
  case "TEMPMEASURE":
219
- if (this.config.disclaimer && this.config.highPrio_TEMPMEASURE_active) this.addUserDps(value, objectsSet, this.config.highPrio_TEMPMEASURE);
220
- break;
307
+ if (this.config.disclaimer && this.config.highPrio_TEMPMEASURE_active)
308
+ this.addUserDps(value, objectsSet, this.config.highPrio_TEMPMEASURE);
309
+ break;
221
310
  default:
222
311
  // nothing to do here
223
- break;
312
+ break;
224
313
  }
225
314
  if (objectsSet.size > 0) {
226
315
  highPrioObjects.set(value, objectsSet);
227
316
  }
228
317
  }
229
-
230
- lowPrioForm = lowPrioForm.slice(0, -1) + '}';
318
+
319
+ lowPrioForm = lowPrioForm.slice(0, -1) + "}";
231
320
  this.log.info("(initPollSettings) lowPrio: " + lowPrioForm);
232
-
321
+
233
322
  // creating form for high priority pulling
234
- highPrioForm = '{';
235
- highPrioObjects.forEach( function (mapValue, key, map) {
323
+ highPrioForm = "{";
324
+ //highPrioObjects.forEach(function (mapValue, key, map) {
325
+ highPrioObjects.forEach(function (mapValue, key) {
236
326
  highPrioForm += '"' + key + '":{';
237
- mapValue.forEach (function (setValue) {
327
+ mapValue.forEach(function (setValue) {
238
328
  highPrioForm += '"' + setValue + '":"",';
239
- })
240
- highPrioForm = highPrioForm.slice(0, -1) + '},';
241
- })
242
- highPrioForm = highPrioForm.slice(0, -1) + '}';
329
+ });
330
+ highPrioForm = highPrioForm.slice(0, -1) + "},";
331
+ });
332
+ highPrioForm = highPrioForm.slice(0, -1) + "}";
243
333
  this.log.info("(initPollSettings) highPrio: " + highPrioForm);
244
334
  }
245
-
335
+
246
336
  addUserDps(value, objectsSet, dpToAdd) {
247
- if (dpToAdd.trim().length < 1 || !/^[A-Z0-9_,]*$/.test(dpToAdd.toUpperCase().trim())) { // don't accept anything but entries like DP_1,DP2,dp3
248
- this.log.warn("(addUserDps) Datapoints config for " + value + " doesn't follow [A-Z0-9_,] (no blanks allowed!) - Ignoring: " + dpToAdd.toUpperCase().trim());
249
- return;
337
+ if (dpToAdd.trim().length < 1 || !/^[A-Z0-9_,]*$/.test(dpToAdd.toUpperCase().trim())) {
338
+ // don't accept anything but entries like DP_1,DP2,dp3
339
+ this.log.warn(
340
+ "(addUserDps) Datapoints config for " +
341
+ value +
342
+ " doesn't follow [A-Z0-9_,] (no blanks allowed!) - Ignoring: " +
343
+ dpToAdd.toUpperCase().trim(),
344
+ );
345
+ return;
250
346
  }
251
- dpToAdd.toUpperCase().trim().split(",").forEach(item => objectsSet.add(item));
347
+ dpToAdd
348
+ .toUpperCase()
349
+ .trim()
350
+ .split(",")
351
+ .forEach((item) => objectsSet.add(item));
252
352
  this.log.info("(addUserDps) Datapoints config changed for " + value + ": " + dpToAdd.toUpperCase().trim());
253
353
  }
254
354
 
255
- /**
256
- * checks config paramaters
257
- * Fallback to default values in case they are out of scope
258
- */
259
- async checkConfig() {
260
- this.log.debug("(checkConf) Configured polling interval high priority: " + this.config.interval);
261
- if (this.config.interval < 1 || this.config.interval > 3600) {
262
- this.log.warn("(checkConf) Config interval high priority " + this.config.interval + " not [1..3600] seconds. Using default: 10");
263
- this.config.interval = 10;
264
- }
265
- this.log.debug("(checkConf) Configured polling interval low priority: " + this.config.intervalLow);
266
- if (this.config.intervalLow < 10 || this.config.intervalLow > 3600) {
267
- this.log.warn("(checkConf) Config interval low priority " + this.config.intervalLow + " not [10..3600] minutes. Using default: 60");
268
- this.config.intervalLow = 60;
269
- }
270
- this.log.debug("(checkConf) Configured polling timeout: " + this.config.pollingTimeout);
271
- if (this.config.pollingTimeout < 1000 || this.config.pollingTimeout > 10000) {
272
- this.log.warn("(checkConf) Config timeout " + this.config.pollingTimeout + " not [1000..10000] ms. Using default: 5000");
273
- this.config.pollingTimeout = 5000;
274
- }
275
- this.log.debug("(checkConf) Configured num of retries: " + this.config.retries);
276
- if (this.config.retries < 0 || this.config.retries > 999) {
277
- this.log.warn("(checkConf) Config num of retries " + this.config.retries + " not [0..999] seconds. Using default: 10");
278
- this.config.retries = 10;
279
- }
280
- this.log.debug("(checkConf) Configured retry multiplier: " + this.config.retrymultiplier);
281
- if (this.config.retrymultiplier < 1 || this.config.retrymultiplier > 10) {
282
- this.log.warn("(checkConf) Config retry multiplier " + this.config.retrymultiplier + " not [1..10] seconds. Using default: 2");
283
- this.config.retrymultiplier = 2;
284
- }
355
+ /**
356
+ * checks config paramaters
357
+ * Fallback to default values in case they are out of scope
358
+ */
359
+ async checkConfig() {
360
+ this.log.debug("(checkConf) Configured polling interval high priority: " + this.config.interval);
361
+ if (this.config.interval < 1 || this.config.interval > 3600) {
362
+ this.log.warn(
363
+ "(checkConf) Config interval high priority " +
364
+ this.config.interval +
365
+ " not [1..3600] seconds. Using default: 10",
366
+ );
367
+ this.config.interval = 10;
368
+ }
369
+ this.log.debug("(checkConf) Configured polling interval low priority: " + this.config.intervalLow);
370
+ if (this.config.intervalLow < 10 || this.config.intervalLow > 3600) {
371
+ this.log.warn(
372
+ "(checkConf) Config interval low priority " +
373
+ this.config.intervalLow +
374
+ " not [10..3600] minutes. Using default: 60",
375
+ );
376
+ this.config.intervalLow = 60;
377
+ }
378
+ this.log.debug("(checkConf) Configured polling timeout: " + this.config.pollingTimeout);
379
+ if (this.config.pollingTimeout < 1000 || this.config.pollingTimeout > 10000) {
380
+ this.log.warn(
381
+ "(checkConf) Config timeout " +
382
+ this.config.pollingTimeout +
383
+ " not [1000..10000] ms. Using default: 5000",
384
+ );
385
+ this.config.pollingTimeout = 5000;
386
+ }
387
+ this.log.debug("(checkConf) Configured num of retries: " + this.config.retries);
388
+ if (this.config.retries < 0 || this.config.retries > 999) {
389
+ this.log.warn(
390
+ "(checkConf) Config num of retries " + this.config.retries + " not [0..999] seconds. Using default: 10",
391
+ );
392
+ this.config.retries = 10;
393
+ }
394
+ this.log.debug("(checkConf) Configured retry multiplier: " + this.config.retrymultiplier);
395
+ if (this.config.retrymultiplier < 1 || this.config.retrymultiplier > 10) {
396
+ this.log.warn(
397
+ "(checkConf) Config retry multiplier " +
398
+ this.config.retrymultiplier +
399
+ " not [1..10] seconds. Using default: 2",
400
+ );
401
+ this.config.retrymultiplier = 2;
402
+ }
285
403
  this.log.debug("(checkConf) Configured https-usage: " + this.config.useHttps);
286
404
  if (this.config.useHttps) {
287
405
  connectVia = "https://";
288
406
  this.log.debug("(checkConf) Switching to https ... " + this.config.useHttps);
289
407
  }
290
408
  this.log.debug("(checkConf) Configured api polling interval: " + this.config.api_interval);
291
- if (this.config.api_interval < 3 || this.config.api_interval > 1440) {
292
- this.log.warn("(checkConf) Config api polling interval " + this.config.api_interval + " not [3..1440] seconds. Using default: 5");
293
- this.config.api_interval = 5;
294
- }
295
- }
296
-
297
- /**
298
- * checks connection to senec service
299
- */
300
- async checkConnection() {
301
- const url = connectVia + this.config.senecip + '/lala.cgi';
302
- const form = '{"ENERGY":{"STAT_STATE":""}}';
303
- try {
304
- this.log.info('connecting to Senec: ' + url);
305
- const body = await this.doGet(url, form, this, this.config.pollingTimeout, true);
306
- this.log.info('connected to Senec: ' + url);
409
+ if (this.config.api_interval < 3 || this.config.api_interval > 1440) {
410
+ this.log.warn(
411
+ "(checkConf) Config api polling interval " +
412
+ this.config.api_interval +
413
+ " not [3..1440] seconds. Using default: 5",
414
+ );
415
+ this.config.api_interval = 5;
416
+ }
417
+ }
418
+
419
+ /**
420
+ * checks connection to senec service
421
+ */
422
+ async checkConnection() {
423
+ const url = connectVia + this.config.senecip + "/lala.cgi";
424
+ const form = '{"ENERGY":{"STAT_STATE":""}}';
425
+ try {
426
+ this.log.info("connecting to Senec: " + url);
427
+ await this.doGet(url, form, this, this.config.pollingTimeout, true);
428
+ this.log.info("connected to Senec: " + url);
307
429
  lalaConnected = true;
308
- } catch (error) {
309
- throw new Error("Error connecting to Senec (IP: " + connectVia + this.config.senecip + "). Exiting! (" + error + "). Try to toggle https-mode in settings and check FQDN of SENEC appliance.");
310
- }
311
- }
312
-
430
+ } catch (error) {
431
+ throw new Error(
432
+ "Error connecting to Senec (IP: " +
433
+ connectVia +
434
+ this.config.senecip +
435
+ "). Exiting! (" +
436
+ error +
437
+ "). Try to toggle https-mode in settings and check FQDN of SENEC appliance.",
438
+ );
439
+ }
440
+ }
441
+
313
442
  /**
314
- * Inits connection to senec app api
315
- */
316
- async initSenecAppApi() {
443
+ * Inits connection to senec app api
444
+ */
445
+ async initSenecAppApi() {
317
446
  if (!this.config.api_use) {
318
- this.log.info('Usage of SENEC App API not configured. Not using it');
447
+ this.log.info("Usage of SENEC App API not configured. Not using it");
319
448
  return;
320
449
  }
321
- this.log.info('connecting to Senec App API: ' + apiLoginUrl);
450
+ this.log.info("connecting to Senec App API: " + apiLoginUrl);
322
451
  const loginData = JSON.stringify({
323
452
  password: this.config.api_pwd,
324
- username: this.config.api_mail
453
+ username: this.config.api_mail,
325
454
  });
326
455
  try {
327
- const body = await this.doGet(apiLoginUrl, loginData, this, this.config.pollingTimeout, true);
328
- this.log.info('connected to Senec AppAPI.');
456
+ const body = await this.doGet(apiLoginUrl, loginData, this, this.config.pollingTimeout, true);
457
+ this.log.info("connected to Senec AppAPI.");
329
458
  apiLoginToken = JSON.parse(body).token;
330
459
  apiConnected = true;
331
- axios.defaults.headers.get['authorization'] = apiLoginToken;
332
- } catch (error) {
460
+ axios.defaults.headers.get["authorization"] = apiLoginToken;
461
+ } catch (error) {
333
462
  apiConnected = false;
334
- throw new Error("Error connecting to Senec AppAPI. Exiting! (" + error + ").");
335
- }
336
- }
337
-
463
+ throw new Error("Error connecting to Senec AppAPI. Exiting! (" + error + ").");
464
+ }
465
+ }
466
+
338
467
  /**
339
- * Reads system data from senec app api
340
- */
341
- async getApiSystems() {
468
+ * Reads system data from senec app api
469
+ */
470
+ async getApiSystems() {
342
471
  const pfx = "_api.Anlagen.";
343
472
  if (!this.config.api_use || !apiConnected) {
344
- this.log.info('Usage of SENEC App API not configured or not connected.');
473
+ this.log.info("Usage of SENEC App API not configured or not connected.");
345
474
  return;
346
475
  }
347
- this.log.info('Reading Systems Information from Senec App API ' + apiSystemsUrl);
476
+ this.log.info("Reading Systems Information from Senec App API " + apiSystemsUrl);
348
477
  try {
349
- const body = await this.doGet(apiSystemsUrl, "", this, this.config.pollingTimeout, false);
350
- this.log.info('Read Systems Information from Senec AppAPI.');
351
- var obj = JSON.parse(body);
352
- const systems = [];
353
- for (const[key, value] of Object.entries(obj)) {
478
+ const body = await this.doGet(apiSystemsUrl, "", this, this.config.pollingTimeout, false);
479
+ this.log.info("Read Systems Information from Senec AppAPI.");
480
+ const obj = JSON.parse(body);
481
+ for (const [key, value] of Object.entries(obj)) {
482
+ this.log.debug("ApiPull: " + key + ":" + JSON.stringify(value));
354
483
  const systemId = value.id;
355
484
  apiKnownSystems.push(systemId);
356
- for (const[key2, value2] of Object.entries(value)) {
357
- if (typeof value2 === "object")
485
+ for (const [key2, value2] of Object.entries(value)) {
486
+ if (typeof value2 === "object")
358
487
  await this.doState(pfx + systemId + "." + key2, JSON.stringify(value2), "", "", false);
359
- else
360
- await this.doState(pfx + systemId + "." + key2, value2, "", "", false);
488
+ else await this.doState(pfx + systemId + "." + key2, value2, "", "", false);
361
489
  }
362
490
  }
363
- await this.doState(pfx + 'IDs', JSON.stringify(apiKnownSystems), "Anlagen IDs", "", false);
364
- } catch (error) {
365
- throw new Error("Error reading Systems Information from Senec AppAPI. (" + error + ").");
366
- }
367
- }
368
-
369
- /**
370
- * Read from url via axios
371
- * @param url to read from
372
- * @param form to post
373
- */
491
+ await this.doState(pfx + "IDs", JSON.stringify(apiKnownSystems), "Anlagen IDs", "", false);
492
+ } catch (error) {
493
+ throw new Error("Error reading Systems Information from Senec AppAPI. (" + error + ").");
494
+ }
495
+ }
496
+
497
+ /**
498
+ * Read from url via axios
499
+ * @param url to read from
500
+ * @param form to post
501
+ */
374
502
  doGet(pUrl, pForm, caller, pollingTimeout, isPost) {
375
503
  return new Promise(function (resolve, reject) {
376
504
  axios({
377
- method: isPost ? 'post' : 'get',
505
+ method: isPost ? "post" : "get",
378
506
  httpsAgent: agent,
379
507
  url: pUrl,
380
508
  data: pForm,
381
- timeout: pollingTimeout
509
+ timeout: pollingTimeout,
382
510
  })
383
- .then(
384
- async (response) => {
385
- const content = response.data;
386
- caller.log.debug('(Poll) received data (' + response.status + '): ' + JSON.stringify(content));
387
- resolve(JSON.stringify(content));
388
- }
389
- )
390
- .catch(
391
- (error) => {
511
+ .then(async (response) => {
512
+ const content = response.data;
513
+ caller.log.debug("(Poll) received data (" + response.status + "): " + JSON.stringify(content));
514
+ resolve(JSON.stringify(content));
515
+ })
516
+ .catch((error) => {
392
517
  if (error.response) {
393
518
  // The request was made and the server responded with a status code
394
- caller.log.warn('(Poll) received error ' + error.response.status + ' response from SENEC with content: ' + JSON.stringify(error.response.data));
519
+ caller.log.warn(
520
+ "(Poll) received error " +
521
+ error.response.status +
522
+ " response from SENEC with content: " +
523
+ JSON.stringify(error.response.data),
524
+ );
395
525
  if (error.response.status == 403 && apiConnected) {
396
526
  apiConnected = false; // apparently the api is inaccessible
397
527
  this.initSenecAppApi();
@@ -407,162 +537,252 @@ class Senec extends utils.Adapter {
407
537
  caller.log.info(error.message);
408
538
  reject(error.status);
409
539
  }
410
- }
411
- );
540
+ });
412
541
  });
413
542
  }
414
543
 
415
-
416
544
  /**
417
- * Read values from Senec Home V2.1
545
+ * Read values from Senec Home V2.1
418
546
  * Careful with the amount and interval of HighPrio values polled because this causes high demand on the SENEC machine so it shouldn't run too often. Adverse effects: No sync with Senec possible if called too often.
419
- */
547
+ */
420
548
  async pollSenec(isHighPrio, retry) {
421
- const url = connectVia + this.config.senecip + '/lala.cgi';
422
- var interval = this.config.interval * 1000;
423
- if (!isHighPrio) {
424
- this.log.info('LowPrio polling ...');
425
- interval = this.config.intervalLow * 1000 * 60
549
+ const url = connectVia + this.config.senecip + "/lala.cgi";
550
+ let interval = this.config.interval * 1000;
551
+ if (!isHighPrio) {
552
+ this.log.info("LowPrio polling ...");
553
+ interval = this.config.intervalLow * 1000 * 60;
426
554
  }
427
-
555
+
428
556
  try {
429
- var body = await this.doGet(url, (isHighPrio ? highPrioForm : lowPrioForm), this, this.config.pollingTimeout, true);
430
- if (body.includes('\\"')) {
557
+ let body = await this.doGet(
558
+ url,
559
+ isHighPrio ? highPrioForm : lowPrioForm,
560
+ this,
561
+ this.config.pollingTimeout,
562
+ true,
563
+ );
564
+ if (body.includes('\\"')) {
431
565
  // in rare cases senec reports back extra escape sequences on some machines ...
432
566
  this.log.info("(Poll) Double escapes detected! Body inc: " + body);
433
567
  body = body.replace(/\\"/g, '"');
434
568
  this.log.info("(Poll) Double escapes autofixed! Body out: " + body);
435
569
  }
436
- var obj = JSON.parse(body, reviverNumParse);
437
- await this.evalPoll(obj);
570
+ const obj = JSON.parse(body, reviverNumParse);
571
+ await this.evalPoll(obj);
438
572
 
439
- retry = 0;
573
+ retry = 0;
440
574
  if (unloaded) return;
441
- this.timer = setTimeout(() => this.pollSenec(isHighPrio, retry), interval);
442
- } catch (error) {
443
- if ((retry == this.config.retries) && this.config.retries < 999) {
444
- this.log.error("Error reading from Senec " + (isHighPrio ? "high" : "low") + "Prio (" + this.config.senecip + "). Retried " + retry + " times. Giving up now. Check config and restart adapter. (" + error + ")");
445
- this.setState('info.connection', false, true);
446
- } else {
447
- retry += 1;
448
- this.log.warn("Error reading from Senec " + (isHighPrio ? "high" : "low") + "Prio (" + this.config.senecip + "). Retry " + retry + "/" + this.config.retries + " in " + (interval * this.config.retrymultiplier * retry) / 1000 + " seconds! (" + error + ")");
449
- this.timer = setTimeout(() => this.pollSenec(isHighPrio, retry), interval * this.config.retrymultiplier * retry);
450
- }
451
- }
575
+ this.timer = setTimeout(() => this.pollSenec(isHighPrio, retry), interval);
576
+ } catch (error) {
577
+ if (retry == this.config.retries && this.config.retries < 999) {
578
+ this.log.error(
579
+ "Error reading from Senec " +
580
+ (isHighPrio ? "high" : "low") +
581
+ "Prio (" +
582
+ this.config.senecip +
583
+ "). Retried " +
584
+ retry +
585
+ " times. Giving up now. Check config and restart adapter. (" +
586
+ error +
587
+ ")",
588
+ );
589
+ this.setState("info.connection", false, true);
590
+ } else {
591
+ retry += 1;
592
+ this.log.warn(
593
+ "Error reading from Senec " +
594
+ (isHighPrio ? "high" : "low") +
595
+ "Prio (" +
596
+ this.config.senecip +
597
+ "). Retry " +
598
+ retry +
599
+ "/" +
600
+ this.config.retries +
601
+ " in " +
602
+ (interval * this.config.retrymultiplier * retry) / 1000 +
603
+ " seconds! (" +
604
+ error +
605
+ ")",
606
+ );
607
+ this.timer = setTimeout(
608
+ () => this.pollSenec(isHighPrio, retry),
609
+ interval * this.config.retrymultiplier * retry,
610
+ );
611
+ }
612
+ }
452
613
  }
453
-
614
+
454
615
  /**
455
- * Read values from Senec App API
456
- */
616
+ * Read values from Senec App API
617
+ */
457
618
  async pollSenecAppApi(retry) {
458
619
  if (!this.config.api_use || !apiConnected) {
459
- this.log.info('Usage of SENEC App API not configured or not connected.');
620
+ this.log.info("Usage of SENEC App API not configured or not connected.");
460
621
  return;
461
622
  }
462
623
  const interval = this.config.api_interval * 60000;
463
624
  const dates = new Map([
464
- ["THIS_DAY", new Date().toISOString().split('T')[0]],
465
- ["LAST_DAY", new Date(new Date().setDate(new Date().getDate()-1)).toISOString().split('T')[0]],
466
- ["THIS_MONTH", new Date().toISOString().split('T')[0]],
467
- ["LAST_MONTH", new Date(new Date().setDate(0)).toISOString().split('T')[0]],
468
- ["THIS_YEAR", new Date().toISOString().split('T')[0]],
469
- ["LAST_YEAR", new Date(new Date().getFullYear() - 1, 1, 1).toISOString().split('T')[0]]
625
+ ["THIS_DAY", new Date().toISOString().split("T")[0]],
626
+ ["LAST_DAY", new Date(new Date().setDate(new Date().getDate() - 1)).toISOString().split("T")[0]],
627
+ ["THIS_MONTH", new Date().toISOString().split("T")[0]],
628
+ ["LAST_MONTH", new Date(new Date().setDate(0)).toISOString().split("T")[0]],
629
+ ["THIS_YEAR", new Date().toISOString().split("T")[0]],
630
+ ["LAST_YEAR", new Date(new Date().getFullYear() - 1, 1, 1).toISOString().split("T")[0]],
470
631
  ]);
471
-
632
+
472
633
  this.log.debug("Polling API ...");
473
- var body = "";
634
+ let body = "";
474
635
  try {
475
636
  for (let i = 0; i < apiKnownSystems.length; i++) {
476
637
  const baseUrl = apiSystemsUrl + "/" + apiKnownSystems[i];
477
638
  const baseUrlMonitor = apiMonitorUrl + "/" + apiKnownSystems[i];
478
- var url = "";
639
+ let url = "";
479
640
  const tzObj = await this.getStateAsync("_api.Anlagen." + apiKnownSystems[i] + ".zeitzone");
480
641
  const tz = tzObj ? encodeURIComponent(tzObj.val) : encodeURIComponent("Europe/Berlin");
481
-
642
+
482
643
  // dashboard
483
644
  url = baseUrl + "/dashboard";
484
645
  body = await this.doGet(url, "", this, this.config.pollingTimeout, false);
485
646
  await this.decodeDashboard(apiKnownSystems[i], JSON.parse(body));
486
-
487
- for (let[key, value] of dates.entries()) {
647
+
648
+ for (const [key, value] of dates.entries()) {
488
649
  // statistik for period
489
- url = baseUrlMonitor + "/data?period=" + api_trans[key].api + "&date=" + value + "&locale=de_DE&timezone=" + tz;
650
+ url =
651
+ baseUrlMonitor +
652
+ "/data?period=" +
653
+ api_trans[key].api +
654
+ "&date=" +
655
+ value +
656
+ "&locale=de_DE&timezone=" +
657
+ tz;
490
658
  this.log.debug("Calling: " + url);
491
659
  body = await this.doGet(url, "", this, this.config.pollingTimeout, false);
492
660
  await this.decodeStatistik(apiKnownSystems[i], JSON.parse(body), api_trans[key].dp);
493
661
  }
494
-
495
662
  if (this.config.api_alltimeRebuild) await this.rebuildAllTimeHistory(apiKnownSystems[i]);
496
-
497
663
  }
498
664
  retry = 0;
499
665
  if (unloaded) return;
500
666
  this.timerAPI = setTimeout(() => this.pollSenecAppApi(retry), interval);
501
667
  } catch (error) {
502
- if ((retry == this.config.retries) && this.config.retries < 999) {
503
- this.log.error("Error reading from Senec AppAPI. Retried " + retry + " times. Giving up now. Check config and restart adapter. (" + error + ")");
504
- this.setState('info.connection', false, true);
505
- } else {
506
- retry += 1;
507
- this.log.warn("Error reading from Senec AppAPI. Retry " + retry + "/" + this.config.retries + " in " + (interval * this.config.retrymultiplier * retry) / 1000 + " seconds! (" + error + ")");
508
- this.timerAPI = setTimeout(() => this.pollSenecAppApi(retry), interval * this.config.retrymultiplier * retry);
509
- }
510
- }
668
+ if (retry == this.config.retries && this.config.retries < 999) {
669
+ this.log.error(
670
+ "Error reading from Senec AppAPI. Retried " +
671
+ retry +
672
+ " times. Giving up now. Check config and restart adapter. (" +
673
+ error +
674
+ ")",
675
+ );
676
+ this.setState("info.connection", false, true);
677
+ } else {
678
+ retry += 1;
679
+ this.log.warn(
680
+ "Error reading from Senec AppAPI. Retry " +
681
+ retry +
682
+ "/" +
683
+ this.config.retries +
684
+ " in " +
685
+ (interval * this.config.retrymultiplier * retry) / 1000 +
686
+ " seconds! (" +
687
+ error +
688
+ ")",
689
+ );
690
+ this.timerAPI = setTimeout(
691
+ () => this.pollSenecAppApi(retry),
692
+ interval * this.config.retrymultiplier * retry,
693
+ );
694
+ }
695
+ }
511
696
  }
512
-
697
+
513
698
  /**
514
699
  * Decodes Dashboard information from SENEC App API
515
700
  */
516
701
  async decodeDashboard(system, obj) {
517
702
  const pfx = "_api.Anlagen." + system + ".Dashboard.";
518
- for (const[key, value] of Object.entries(obj)) {
703
+ for (const [key, value] of Object.entries(obj)) {
519
704
  if (key == "zeitstempel" || key == "electricVehicleConnected") {
520
705
  await this.doState(pfx + key, value, "", "", false);
521
706
  } else {
522
- for (const[key2, value2] of Object.entries(value)) {
523
- await this.doState(pfx + key + "." + key2, Number((value2.wert).toFixed(2)), "", value2.einheit, false);
707
+ for (const [key2, value2] of Object.entries(value)) {
708
+ await this.doState(
709
+ pfx + key + "." + key2,
710
+ Number(value2.wert.toFixed(2)),
711
+ "",
712
+ value2.einheit,
713
+ false,
714
+ );
524
715
  if (kiloList.includes(value2.einheit)) {
525
- await this.doState(pfx + key + "." + key2 + " (k" + value2.einheit + ")", Number((value2.wert / 1000).toFixed(2)), "", "k" + value2.einheit, false);
716
+ await this.doState(
717
+ pfx + key + "." + key2 + " (k" + value2.einheit + ")",
718
+ Number((value2.wert / 1000).toFixed(2)),
719
+ "",
720
+ "k" + value2.einheit,
721
+ false,
722
+ );
526
723
  }
527
724
  }
528
725
  }
529
726
  }
530
-
531
727
  }
532
-
728
+
533
729
  /**
534
730
  * Decodes Statistik information from SENEC App API
535
731
  */
536
732
  async decodeStatistik(system, obj, period) {
537
733
  if (obj == null || obj == undefined || obj.aggregation == null || obj.aggregation == undefined) return; // could happen (e.g.) if we pull information for "last year" when the appliance isn't that old yet
538
734
  const pfx = "_api.Anlagen." + system + ".Statistik." + period + ".";
539
- for (const[key, value] of Object.entries(obj.aggregation)) {
735
+ for (const [key, value] of Object.entries(obj.aggregation)) {
736
+ this.log.debug("decodeStatistic: " + pfx + key + ":" + value);
540
737
  // only reading 'aggregation' - no interest in fine granular information
541
738
  if (key == "startDate") {
542
739
  await this.doState(pfx + key, value, "", "", false);
543
740
  } else {
544
- if (!this.config.api_alltimeRebuild) { // don't update DPs if we are AllTime-Rebuild-Process
545
- await this.doState(pfx + key, Number((value.value).toFixed(2)), "", value.unit, false);
741
+ if (!this.config.api_alltimeRebuild) {
742
+ // don't update DPs if we are AllTime-Rebuild-Process
743
+ await this.doState(pfx + key, Number(value.value.toFixed(2)), "", value.unit, false);
546
744
  if (kiloList.includes(value.unit)) {
547
- await this.doState(pfx + key + " (k"+ value.unit + ")", Number((value.value / 1000).toFixed(2)), "", "k" + value.unit, false);
745
+ await this.doState(
746
+ pfx + key + " (k" + value.unit + ")",
747
+ Number((value.value / 1000).toFixed(2)),
748
+ "",
749
+ "k" + value.unit,
750
+ false,
751
+ );
548
752
  }
549
753
  }
550
- if (period == api_trans["THIS_YEAR"].dp) await this.insertAllTimeHistory(system, key, new Date(obj.aggregation.startDate).getFullYear(), Number((value.value).toFixed(0)), value.unit);
754
+ if (period == api_trans["THIS_YEAR"].dp)
755
+ await this.insertAllTimeHistory(
756
+ system,
757
+ key,
758
+ new Date(obj.aggregation.startDate).getFullYear(),
759
+ Number(value.value.toFixed(0)),
760
+ value.unit,
761
+ );
551
762
  }
552
763
  }
553
764
  if (obj.aggregation.totalUsage.value != 0) {
554
- const autarky = Number((((obj.aggregation.generation.value - obj.aggregation.gridFeedIn.value - obj.aggregation.storageLoad.value + obj.aggregation.storageConsumption.value) / obj.aggregation.totalUsage.value) * 100).toFixed(2));
765
+ const autarky = Number(
766
+ (
767
+ ((obj.aggregation.generation.value -
768
+ obj.aggregation.gridFeedIn.value -
769
+ obj.aggregation.storageLoad.value +
770
+ obj.aggregation.storageConsumption.value) /
771
+ obj.aggregation.totalUsage.value) *
772
+ 100
773
+ ).toFixed(2),
774
+ );
555
775
  await this.doState(pfx + "Autarkie", autarky, "", "%", false);
556
776
  }
557
777
  await this.updateAllTimeHistory(system);
558
778
  }
559
-
779
+
560
780
  /**
561
781
  * inserts a value for a given key and year into AllTimeValueStore
562
782
  */
563
783
  async insertAllTimeHistory(system, key, year, value, einheit) {
564
- this.log.debug("Insert AllTimeHistory: " + system + "/" + "key" + "/" + year + "/" + value + "/" + einheit);
565
- if (key === '__proto__' || key === 'constructor' || key === 'prototype') return; // Security fix
784
+ this.log.debug("Insert AllTimeHistory: " + system + "/" + key + "/" + year + "/" + value + "/" + einheit);
785
+ if (key === "__proto__" || key === "constructor" || key === "prototype") return; // Security fix
566
786
  if (isNaN(year) || isNaN(value)) return; // Security fix
567
787
  const pfx = "_api.Anlagen." + system + ".Statistik.AllTime.";
568
788
  const valueStore = pfx + "valueStore";
@@ -574,7 +794,7 @@ class Senec extends utils.Adapter {
574
794
  stats[key]["einheit"] = einheit;
575
795
  await this.doState(valueStore, JSON.stringify(stats), "", "", false);
576
796
  }
577
-
797
+
578
798
  /**
579
799
  * Updated AllTimeHistory based on what we have in our AllTimeValueStore
580
800
  */
@@ -584,10 +804,10 @@ class Senec extends utils.Adapter {
584
804
  const statsObj = await this.getStateAsync(valueStore);
585
805
  const stats = statsObj ? JSON.parse(statsObj.val) : {};
586
806
  const sums = {};
587
- for (const[key, value] of Object.entries(stats)) {
588
- var einheit = "";
589
- var sum = 0.0;
590
- for (const[key2, value2] of Object.entries(value)) {
807
+ for (const [key, value] of Object.entries(stats)) {
808
+ let einheit = "";
809
+ let sum = 0.0;
810
+ for (const [key2, value2] of Object.entries(value)) {
591
811
  if (key2 == "einheit") {
592
812
  einheit = value2;
593
813
  } else {
@@ -602,67 +822,78 @@ class Senec extends utils.Adapter {
602
822
  }
603
823
  }
604
824
  if (sums.totalUsage != 0) {
605
- const autarky = Number((((sums.generation - sums.gridFeedIn - sums.storageLoad + sums.storageConsumption) / sums.totalUsage) * 100).toFixed(0));
825
+ const autarky = Number(
826
+ (
827
+ ((sums.generation - sums.gridFeedIn - sums.storageLoad + sums.storageConsumption) /
828
+ sums.totalUsage) *
829
+ 100
830
+ ).toFixed(0),
831
+ );
606
832
  await this.doState(pfx + "Autarkie", autarky, "", "%", false);
607
833
  }
608
834
  }
609
-
835
+
610
836
  /**
611
837
  * Rebuilds AllTimeHistory from SENEC App API
612
838
  */
613
839
  async rebuildAllTimeHistory(system) {
614
840
  if (!this.config.api_use || !apiConnected) {
615
- this.log.info('Usage of SENEC App API not configured or not connected.');
841
+ this.log.info("Usage of SENEC App API not configured or not connected.");
616
842
  return;
617
843
  }
618
-
844
+
619
845
  this.log.info("Rebuilding AllTime History ...");
620
- var year = new Date(new Date().getFullYear() - 1, 1, 1).toISOString().split('T')[0]; // starting last year, because we already got current year covered
621
- var body = "";
846
+ let year = new Date(new Date().getFullYear() - 1, 1, 1).toISOString().split("T")[0]; // starting last year, because we already got current year covered
847
+ let body = "";
622
848
  try {
623
- while (new Date(year).getFullYear() > 2008) { // senec was founded in 2009 by Mathias Hammer as Deutsche Energieversorgung GmbH (DEV) - so no way we have older data :)
849
+ while (new Date(year).getFullYear() > 2008) {
850
+ // senec was founded in 2009 by Mathias Hammer as Deutsche Energieversorgung GmbH (DEV) - so no way we have older data :)
624
851
  this.log.info("Rebuilding AllTime History - Year: " + new Date(year).getFullYear());
625
852
  const baseUrl = apiMonitorUrl + "/" + system;
626
- var url = "";
853
+ let url = "";
627
854
  const tzObj = await this.getStateAsync("_api.Anlagen." + system + ".zeitzone");
628
855
  const tz = tzObj ? encodeURIComponent(tzObj.val) : encodeURIComponent("Europe/Berlin");
629
856
  url = baseUrl + "/data?period=YEAR&date=" + year + "&locale=de_DE&timezone=" + tz;
630
857
  this.log.debug("Polling: " + url);
631
858
  body = await this.doGet(url, "", this, this.config.pollingTimeout, false);
632
859
  await this.decodeStatistik(system, JSON.parse(body), api_trans["THIS_YEAR"].dp);
633
- year = new Date(new Date(year).getFullYear() - 1, 1, 1).toISOString().split('T')[0];
860
+ year = new Date(new Date(year).getFullYear() - 1, 1, 1).toISOString().split("T")[0];
634
861
  if (unloaded) return;
635
862
  }
636
863
  } catch (error) {
637
- this.log.info("Rebuild ended.");
638
- }
864
+ this.log.info("Rebuild ended: " + error);
865
+ }
639
866
  this.log.info("Restarting ...");
640
- this.extendForeignObject(`system.adapter.${this.namespace}`, {native: {api_alltimeRebuild: false}});
867
+ this.extendForeignObject(`system.adapter.${this.namespace}`, { native: { api_alltimeRebuild: false } });
641
868
  }
642
869
 
643
- /**
644
- * sets a state's value and creates the state if it doesn't exist yet
645
- */
646
- async doState(name, value, description, unit, write) {
870
+ /**
871
+ * sets a state's value and creates the state if it doesn't exist yet
872
+ */
873
+ async doState(name, value, description, unit, write) {
647
874
  if (!isNaN(name.substring(0, 1))) {
648
875
  // keys cannot start with digits! Possibly SENEC delivering erraneous data
649
- this.log.debug('(doState) Invalid datapoint: ' + name + ': ' + value);
876
+ this.log.debug("(doState) Invalid datapoint: " + name + ": " + value);
650
877
  return;
651
878
  }
652
- this.log.silly('(doState) Update: ' + name + ': ' + value);
653
-
879
+ this.log.silly("(doState) Update: " + name + ": " + value);
880
+
654
881
  const valueType = value !== null && value !== undefined ? typeof value : "mixed";
655
-
882
+
656
883
  // Check object for changes:
657
884
  const obj = knownObjects[name] ? knownObjects[name] : await this.getObjectAsync(name);
658
885
  if (obj) {
659
886
  const newCommon = {};
660
887
  if (obj.common.name !== description) {
661
- this.log.debug("(doState) Updating object: " + name + " (desc): " + obj.common.name + " -> " + description);
888
+ this.log.debug(
889
+ "(doState) Updating object: " + name + " (desc): " + obj.common.name + " -> " + description,
890
+ );
662
891
  newCommon.name = description;
663
892
  }
664
893
  if (obj.common.type !== valueType) {
665
- this.log.debug("(doState) Updating object: " + name + " (type): " + obj.common.type + " -> " + typeof value);
894
+ this.log.debug(
895
+ "(doState) Updating object: " + name + " (type): " + obj.common.type + " -> " + typeof value,
896
+ );
666
897
  newCommon.type = valueType;
667
898
  }
668
899
  if (obj.common.unit !== unit) {
@@ -685,70 +916,76 @@ class Senec extends utils.Adapter {
685
916
  role: "value",
686
917
  unit: unit,
687
918
  read: true,
688
- write: write
919
+ write: write,
689
920
  },
690
- native: {}
921
+ native: {},
691
922
  };
692
923
  await this.setObjectNotExistsAsync(name, knownObjects[name]);
693
924
  }
694
925
  await this.setStateChangedAsync(name, {
695
926
  val: value,
696
- ack: true
927
+ ack: true,
697
928
  });
698
929
  await this.doDecode(name, value);
699
930
  }
700
-
931
+
701
932
  /**
702
933
  * Checks if there is decoding possible for a given value and creates/updates a decoded state
703
934
  * Language used for translations is the language of the SENEC appliance
704
935
  */
705
936
  async doDecode(name, value) {
706
937
  // Lang: WIZARD.GUI_LANG 0=German, 1=English, 2=Italian
707
- var lang = 1; // fallback to english
708
- var langState = await this.getStateAsync('WIZARD.GUI_LANG');
938
+ let lang = 1; // fallback to english
939
+ const langState = await this.getStateAsync("WIZARD.GUI_LANG");
709
940
  if (langState) lang = langState.val;
710
941
  this.log.silly("(Decode) Senec language: " + lang);
711
- var key = name;
712
- if (!isNaN(name.substring(name.lastIndexOf('.')) + 1)) key = name.substring(0, name.lastIndexOf('.'));
942
+ let key = name;
943
+ if (!isNaN(name.substring(name.lastIndexOf(".")) + 1)) key = name.substring(0, name.lastIndexOf("."));
713
944
  this.log.silly("(Decode) Checking: " + name + " -> " + key);
714
-
945
+
715
946
  if (state_trans[key + "." + lang] !== undefined) {
716
947
  this.log.silly("(Decode) Trans found for: " + key + "." + lang);
717
- const trans = (state_trans[key + "." + lang] !== undefined ? (state_trans[key + "." + lang][value] !== undefined ? state_trans[key + "." + lang][value] : "(unknown)") : "(unknown)");
948
+ const trans =
949
+ state_trans[key + "." + lang] !== undefined
950
+ ? state_trans[key + "." + lang][value] !== undefined
951
+ ? state_trans[key + "." + lang][value]
952
+ : "(unknown)"
953
+ : "(unknown)";
718
954
  this.log.silly("(Decode) Trans " + key + ":" + value + " = " + trans);
719
- const desc = (state_attr[key + "_Text"] !== undefined) ? state_attr[key + "_Text"].name : key;
955
+ const desc = state_attr[key + "_Text"] !== undefined ? state_attr[key + "_Text"].name : key;
720
956
  await this.doState(name + "_Text", trans, desc, "", true);
721
957
  }
722
958
  }
723
-
959
+
724
960
  /**
725
961
  * evaluates data polled from SENEC system.
726
962
  * creates / updates the state.
727
963
  */
728
- async evalPoll(obj) {
964
+ async evalPoll(obj) {
729
965
  if (unloaded) return;
730
- for (const[key1, value1] of Object.entries(obj)) {
731
- for (const[key2, value2] of Object.entries(value1)) {
732
- if (value2 !== "VARIABLE_NOT_FOUND" && key2 !== "OBJECT_NOT_FOUND") {
733
- const key = key1 + '.' + key2;
734
- if (state_attr[key] === undefined) {
735
- this.log.debug('REPORT_TO_DEV: State attribute definition missing for: ' + key + ', Val: ' + value2);
736
- }
737
- const desc = (state_attr[key] !== undefined) ? state_attr[key].name : key2;
738
- const unit = (state_attr[key] !== undefined) ? state_attr[key].unit : "";
739
-
740
- if (Array.isArray(value2)) {
741
- for (var i = 0; i < value2.length; i++) {
742
- this.doState(key + '.' + i, ValueTyping(key, value2[i]), desc + '[' + i + ']', unit, false);
743
- }
744
- } else {
745
- this.doState(key, ValueTyping(key, value2), desc, unit, false);
746
- }
747
- }
748
- }
749
- }
750
- }
966
+ for (const [key1, value1] of Object.entries(obj)) {
967
+ for (const [key2, value2] of Object.entries(value1)) {
968
+ if (value2 !== "VARIABLE_NOT_FOUND" && key2 !== "OBJECT_NOT_FOUND") {
969
+ const key = key1 + "." + key2;
970
+ if (state_attr[key] === undefined) {
971
+ this.log.debug(
972
+ "REPORT_TO_DEV: State attribute definition missing for: " + key + ", Val: " + value2,
973
+ );
974
+ }
975
+ const desc = state_attr[key] !== undefined ? state_attr[key].name : key2;
976
+ const unit = state_attr[key] !== undefined ? state_attr[key].unit : "";
751
977
 
978
+ if (Array.isArray(value2)) {
979
+ for (let i = 0; i < value2.length; i++) {
980
+ this.doState(key + "." + i, ValueTyping(key, value2[i]), desc + "[" + i + "]", unit, false);
981
+ }
982
+ } else {
983
+ this.doState(key, ValueTyping(key, value2), desc, unit, false);
984
+ }
985
+ }
986
+ }
987
+ }
988
+ }
752
989
  }
753
990
 
754
991
  /**
@@ -757,25 +994,25 @@ class Senec extends utils.Adapter {
757
994
  */
758
995
  const ValueTyping = (key, value) => {
759
996
  if (!isNaN(value)) value = Number(value); // otherwise iobroker will note it as string
760
- if (state_attr[key] === undefined) {
761
- return value;
762
- }
763
- const isBool = (state_attr[key] !== undefined && state_attr[key].booltype) ? state_attr[key].booltype : false;
764
- const isDate = (state_attr[key] !== undefined && state_attr[key].datetype) ? state_attr[key].datetype : false;
765
- const isIP = (state_attr[key] !== undefined && state_attr[key].iptype) ? state_attr[key].iptype : false;
766
- const multiply = (state_attr[key] !== undefined && state_attr[key].multiply) ? state_attr[key].multiply : 1;
767
- if (isBool) {
768
- return (value === 0) ? false : true;
769
- } else if (isDate) {
770
- return new Date(value * 1000).toString();
771
- } else if (isIP) {
772
- return DecToIP(value);
773
- } else if (multiply !== 1) {
774
- return parseFloat((value * multiply).toFixed(2));
775
- } else {
776
- return value;
777
- }
778
- }
997
+ if (state_attr[key] === undefined) {
998
+ return value;
999
+ }
1000
+ const isBool = state_attr[key] !== undefined && state_attr[key].booltype ? state_attr[key].booltype : false;
1001
+ const isDate = state_attr[key] !== undefined && state_attr[key].datetype ? state_attr[key].datetype : false;
1002
+ const isIP = state_attr[key] !== undefined && state_attr[key].iptype ? state_attr[key].iptype : false;
1003
+ const multiply = state_attr[key] !== undefined && state_attr[key].multiply ? state_attr[key].multiply : 1;
1004
+ if (isBool) {
1005
+ return value === 0 ? false : true;
1006
+ } else if (isDate) {
1007
+ return new Date(value * 1000).toString();
1008
+ } else if (isIP) {
1009
+ return DecToIP(value);
1010
+ } else if (multiply !== 1) {
1011
+ return parseFloat((value * multiply).toFixed(2));
1012
+ } else {
1013
+ return value;
1014
+ }
1015
+ };
779
1016
 
780
1017
  /**
781
1018
  * Converts float value in hex format to js float32.
@@ -783,22 +1020,22 @@ const ValueTyping = (key, value) => {
783
1020
  * @param string with hex value
784
1021
  */
785
1022
  const HexToFloat32 = (str) => {
786
- var int = parseInt(str, 16);
787
- if (int > 0 || int < 0) {
788
- // var sign = (int >>> 31) ? -1 : 1;
789
- var sign = (int & 0x80000000) ? -1 : 1;
790
- var exp = (int >>> 23 & 0xff) - 127;
791
- var mantissa = ((int & 0x7fffff) + 0x800000).toString(2);
792
- var float32 = 0;
793
- for (var i = 0; i < mantissa.length; i++) {
794
- float32 += parseInt(mantissa[i]) ? Math.pow(2, exp) : 0;
795
- exp--;
796
- }
797
- return (float32 * sign).toFixed(2);
798
- } else {
799
- return 0;
800
- }
801
- }
1023
+ const int = parseInt(str, 16);
1024
+ if (int > 0 || int < 0) {
1025
+ // var sign = (int >>> 31) ? -1 : 1;
1026
+ const sign = int & 0x80000000 ? -1 : 1;
1027
+ let exp = ((int >>> 23) & 0xff) - 127;
1028
+ const mantissa = (int & (0x7fffff + 0x800000)).toString(2);
1029
+ let float32 = 0;
1030
+ for (let i = 0; i < mantissa.length; i++) {
1031
+ float32 += parseInt(mantissa[i]) ? Math.pow(2, exp) : 0;
1032
+ exp--;
1033
+ }
1034
+ return (float32 * sign).toFixed(2);
1035
+ } else {
1036
+ return 0;
1037
+ }
1038
+ };
802
1039
 
803
1040
  /**
804
1041
  * Converts a given decimal to a properly formatted IP address.
@@ -807,16 +1044,16 @@ const HexToFloat32 = (str) => {
807
1044
  * for proper human reading.
808
1045
  */
809
1046
  const DecToIP = (str) => {
810
- var ipHex = str.toString(16);
811
- while (ipHex.length < 8) {
812
- ipHex = '0' + ipHex;
813
- }
814
- const fourth = ipHex.substring(0, 2);
815
- const third = ipHex.substring(2, 4);
816
- const second = ipHex.substring(4, 6);
817
- const first = ipHex.substring(6);
818
- return (parseInt(first, 16) + '.' + parseInt(second, 16) + '.' + parseInt(third, 16) + '.' + parseInt(fourth, 16));
819
- }
1047
+ let ipHex = str.toString(16);
1048
+ while (ipHex.length < 8) {
1049
+ ipHex = "0" + ipHex;
1050
+ }
1051
+ const fourth = ipHex.substring(0, 2);
1052
+ const third = ipHex.substring(2, 4);
1053
+ const second = ipHex.substring(4, 6);
1054
+ const first = ipHex.substring(6);
1055
+ return parseInt(first, 16) + "." + parseInt(second, 16) + "." + parseInt(third, 16) + "." + parseInt(fourth, 16);
1056
+ };
820
1057
 
821
1058
  /**
822
1059
  * Reviver function to convert numeric values to float or int.
@@ -824,100 +1061,101 @@ const DecToIP = (str) => {
824
1061
  * @param key value pair as defined in reviver option
825
1062
  */
826
1063
  const reviverNumParse = (key, value) => {
827
- // prepare values for output using reviver function
828
- if (typeof value === "string") {
829
- if (value.startsWith("fl_")) { // float in hex IEEE754
830
- return HexToFloat32(value.substring(3));
831
- } else if (value.startsWith("u")) { // unsigned int in hex
832
- return parseInt(value.substring(3), 16);
833
- } else if (value.startsWith("st_")) { // string?
834
- return value.substring(3);
835
- } else if (value.startsWith("i1")) { // int
836
- var val = parseInt(value.substring(3), 16);
837
- if (!isNaN(val)) {
838
- if ((val & 0x8000) > 0) {
839
- val = val - 0x10000;
840
- }
841
- return val;
842
- } else
843
- return 0;
844
-
845
- } else if (value.startsWith("i3")) { // int
846
- var val = parseInt(value.substring(3), 16);
847
- if (!isNaN(val)) {
848
- if ((Math.abs(value & 0x80000000)) > 0) {
849
- val = val - 0x100000000;
850
- }
851
- return val;
852
- } else
853
- return 0;
854
-
855
- } else if (value.startsWith("i8")) { // int
856
- var val = parseInt(value.substring(3), 16);
857
- if (!isNaN(val)) {
858
- if ((value & 0x80) > 0) {
859
- val = val - 0x100;
860
- }
861
- return val;
862
- } else
863
- return 0;
864
- } else if (value.startsWith("VARIABLE_NOT_FOUND")) {
865
- return "VARIABLE_NOT_FOUND";
1064
+ // prepare values for output using reviver function
1065
+ if (typeof value === "string") {
1066
+ if (value.startsWith("fl_")) {
1067
+ // float in hex IEEE754
1068
+ return HexToFloat32(value.substring(3));
1069
+ } else if (value.startsWith("u")) {
1070
+ // unsigned int in hex
1071
+ return parseInt(value.substring(3), 16);
1072
+ } else if (value.startsWith("st_")) {
1073
+ // string?
1074
+ return value.substring(3);
1075
+ } else if (value.startsWith("i1")) {
1076
+ // int
1077
+ let val = parseInt(value.substring(3), 16);
1078
+ if (!isNaN(val)) {
1079
+ if ((val & 0x8000) > 0) {
1080
+ val = val - 0x10000;
1081
+ }
1082
+ return val;
1083
+ } else return 0;
1084
+ } else if (value.startsWith("i3")) {
1085
+ // int
1086
+ let val = parseInt(value.substring(3), 16);
1087
+ if (!isNaN(val)) {
1088
+ if (Math.abs(value & 0x80000000) > 0) {
1089
+ val = val - 0x100000000;
1090
+ }
1091
+ return val;
1092
+ } else return 0;
1093
+ } else if (value.startsWith("i8")) {
1094
+ // int
1095
+ let val = parseInt(value.substring(3), 16);
1096
+ if (!isNaN(val)) {
1097
+ if ((value & 0x80) > 0) {
1098
+ val = val - 0x100;
1099
+ }
1100
+ return val;
1101
+ } else return 0;
1102
+ } else if (value.startsWith("VARIABLE_NOT_FOUND")) {
1103
+ return "VARIABLE_NOT_FOUND";
866
1104
  } else if (value.startsWith("FILE_VARIABLE_NOT_READABLE")) {
867
- return "";
868
- } else {
869
- return "REPORT TO DEV: " + key + ":" + value;
870
- //throw new Error("Unknown value in JSON: " + key + ":" + value);
871
- }
872
- } else {
873
- return value;
874
- }
875
- }
1105
+ return "";
1106
+ } else {
1107
+ return "REPORT TO DEV: " + key + ":" + value;
1108
+ //throw new Error("Unknown value in JSON: " + key + ":" + value);
1109
+ }
1110
+ } else {
1111
+ return value;
1112
+ }
1113
+ };
876
1114
 
877
1115
  /**
878
1116
  * Returns the current day of the year
879
1117
  */
880
- const getCurDay = () => {
881
- return (Math.round((new Date().setHours(23) - new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0))/1000/60/60/24));
882
- }
1118
+ //const getCurDay = () => {
1119
+ // return (Math.round((new Date().setHours(23) - new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0))/1000/60/60/24));
1120
+ //}
883
1121
 
884
1122
  /**
885
1123
  * Returns the current month of the year
886
1124
  */
887
- const getCurMonth = () => {
888
- return (new Date().getMonth());
889
- }
1125
+ //const getCurMonth = () => {
1126
+ // return (new Date().getMonth());
1127
+ //}
890
1128
 
891
1129
  /**
892
1130
  * Returns the current year
893
1131
  */
894
- const getCurYear = () => {
895
- return (new Date().getFullYear());
896
- }
1132
+ //const getCurYear = () => {
1133
+ // return (new Date().getFullYear());
1134
+ //}
897
1135
 
898
1136
  /**
899
1137
  * Returns the current week of the year
900
1138
  * Using Standard ISO8601
901
1139
  */
902
- const getCurWeek = () => {
903
- var tdt = new Date();
904
- var dayn = (tdt.getDay() + 6) % 7;
905
- tdt.setDate(tdt.getDate() - dayn + 3);
906
- var firstThursday = tdt.valueOf();
907
- tdt.setMonth(0, 1);
908
- if (tdt.getDay() !== 4) {
909
- tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7);
910
- }
911
- return 1 + Math.ceil((firstThursday - tdt) / 604800000);
912
- }
1140
+ //const getCurWeek = () => {
1141
+ // var tdt = new Date();
1142
+ // var dayn = (tdt.getDay() + 6) % 7;
1143
+ // tdt.setDate(tdt.getDate() - dayn + 3);
1144
+ // var firstThursday = tdt.valueOf();
1145
+ // tdt.setMonth(0, 1);
1146
+ // if (tdt.getDay() !== 4) {
1147
+ // tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7);
1148
+ // }
1149
+ // return 1 + Math.ceil((firstThursday - tdt) / 604800000);
1150
+ //};
913
1151
 
914
1152
  if (require.main !== module) {
915
- // Export the constructor in compact mode
916
- /**
917
- * @param {Partial<ioBroker.AdapterOptions>} [options={}]
918
- */
919
- module.exports = (options) => new Senec(options);
1153
+ // Export the constructor in compact mode
1154
+ /**
1155
+ * @param {Partial<ioBroker.AdapterOptions>} [options={}]
1156
+ */
1157
+ module.exports = (options) => new Senec(options);
920
1158
  } else {
921
- // otherwise start the instance directly
922
- new Senec();
1159
+ // otherwise start the instance directly
1160
+ new Senec();
923
1161
  }