iobroker.senec 1.3.0 → 1.3.4

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,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const utils = require('@iobroker/adapter-core');
4
- const request = require('request');
4
+ const axios = require('axios');
5
5
  const state_attr = require(__dirname + '/lib/state_attr.js');
6
6
  const state_trans = require(__dirname + '/lib/state_trans.js');
7
7
 
@@ -110,30 +110,43 @@ class Senec extends utils.Adapter {
110
110
  }
111
111
 
112
112
  /**
113
- * Read from url via request
113
+ * Read from url via axios
114
114
  * @param url to read from
115
115
  * @param form to post
116
116
  */
117
- async doGet(pUrl, pForm, caller, pollingTimeout) {
118
- return new Promise(function (resolve, reject) {
119
- const options = {
120
- url: pUrl,
121
- method: 'POST',
122
- form: pForm,
123
- timeout: pollingTimeout
124
- };
125
- request(options, function (error, response, body) {
126
- if (error)
127
- return reject(error);
128
- caller.log.debug('Status: ' + response.statusCode);
129
- if (!response || response.statusCode !== 200)
130
- return reject('Cannot read from SENEC: ' + response.statusCode);
131
- caller.log.debug('Response: ' + JSON.stringify(response));
132
- caller.log.debug('Body: ' + body);
133
- resolve(body);
134
- });
135
- });
136
- }
117
+ async doGet(pUrl, pForm, caller, pollingTimeout) {
118
+ return new Promise(function (resolve, reject) {
119
+ axios({
120
+ method: 'post',
121
+ url: pUrl,
122
+ data: pForm,
123
+ timeout: pollingTimeout
124
+ }).then(
125
+ async (response) => {
126
+ const content = response.data;
127
+ caller.log.debug('received data (' + response.status + '): ' + JSON.stringify(content));
128
+ resolve(JSON.stringify(content));
129
+ }
130
+ ).catch(
131
+ (error) => {
132
+ if (error.response) {
133
+ // The request was made and the server responded with a status code
134
+ caller.log.warn('received error ' + error.response.status + ' response from SENEC with content: ' + JSON.stringify(error.response.data));
135
+ reject(error.response.status);
136
+ } else if (error.request) {
137
+ // The request was made but no response was received
138
+ // `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js<div></div>
139
+ caller.log.info(error.message);
140
+ reject(error.message);
141
+ } else {
142
+ // Something happened in setting up the request that triggered an Error
143
+ caller.log.info(error.message);
144
+ reject(error.status);
145
+ }
146
+ }
147
+ );
148
+ });
149
+ }
137
150
 
138
151
  /**
139
152
  * Read values from Senec Home V2.1
@@ -213,6 +226,7 @@ class Senec extends utils.Adapter {
213
226
  * sets a state's value and creates the state if it doesn't exist yet
214
227
  */
215
228
  async doState(name, value, description, unit, write) {
229
+ this.log.silly('Update: ' + name + ': ' + value);
216
230
  await this.setObjectNotExistsAsync(name, {
217
231
  type: 'state',
218
232
  common: {
@@ -240,6 +254,10 @@ class Senec extends utils.Adapter {
240
254
  this.log.debug("Updating object: " + name + " (unit): " + obj.common.unit + " -> " + unit);
241
255
  await this.extendObject(name, {common: {unit: unit}});
242
256
  }
257
+ if (obj.common.write != write) {
258
+ this.log.debug("Updating object: " + name + " (write): " + obj.common.write + " -> " + write);
259
+ await this.extendObject(name, {common: {write: write}});
260
+ }
243
261
 
244
262
  var oldState = await this.getStateAsync(name);
245
263
  if (oldState) {
@@ -266,7 +284,7 @@ class Senec extends utils.Adapter {
266
284
  var lang = 1; // fallback to english
267
285
  var langState = await this.getStateAsync('WIZARD.GUI_LANG');
268
286
  if (langState) lang = langState.val;
269
- this.log.debug("Senec language: " + lang);
287
+ this.log.silly("Senec language: " + lang);
270
288
  var key = name;
271
289
  if (!isNaN(name.substring(name.lastIndexOf('.')) + 1)) key = name.substring(0, name.lastIndexOf('.'));
272
290
  this.log.silly("Checking: " + name + " -> " + key);
@@ -284,7 +302,7 @@ class Senec extends utils.Adapter {
284
302
  * Helper routine
285
303
  */
286
304
  async checkUpdateSelfStat(name) {
287
- if (name == "STATISTIC.LIVE_GRID_EXPORT" || name == "STATISTIC.LIVE_GRID_IMPORT" || name == "STATISTIC.LIVE_HOUSE_CONS" || name == "STATISTIC.LIVE_PV_GEN" || name == "STATISTIC.LIVE_BAT_CHARGE_MASTER" || name == "STATISTIC.LIVE_BAT_DISCHARGE_MASTER") {
305
+ if (name === "STATISTIC.LIVE_GRID_EXPORT" || name === "STATISTIC.LIVE_GRID_IMPORT" || name === "STATISTIC.LIVE_HOUSE_CONS" || name === "STATISTIC.LIVE_PV_GEN" || name === "STATISTIC.LIVE_BAT_CHARGE_MASTER" || name === "STATISTIC.LIVE_BAT_DISCHARGE_MASTER") {
288
306
  await this.updateSelfStat(name);
289
307
  }
290
308
  }
@@ -328,17 +346,15 @@ class Senec extends utils.Adapter {
328
346
  const key = "_calc." + name.substring(10);
329
347
 
330
348
  const refDayObj = await this.getStateAsync(key + ".ref" + day);
331
- var refDay = refDayObj ? refDayObj.val : -1;
349
+ const refDay = refDayObj ? refDayObj.val : -1;
332
350
 
333
351
  const valCurObj = await this.getStateAsync(name);
334
- var valCur = valCurObj ? valCurObj.val : 0;
352
+ const valCur = valCurObj ? valCurObj.val : 0;
335
353
 
336
354
  const valRefObj = await this.getStateAsync(key + refValue);
337
- var valRef = valRefObj ? valRefObj.val : 0;
355
+ const valRef = valRefObj ? valRefObj.val : 0;
338
356
  const valTodayObj = await this.getStateAsync(key + today);
339
- var valToday = valTodayObj ? valTodayObj.val : 0;
340
- const valYesterdayObj = await this.getStateAsync(key + yesterday);
341
- var valYesterday = valYesterdayObj ? valYesterdayObj.val : 0;
357
+ const valToday = valTodayObj ? valTodayObj.val : 0;
342
358
 
343
359
  const descToday = (state_attr[key + today] !== undefined) ? state_attr[key + today].name : key;
344
360
  const unitToday = (state_attr[key + today] !== undefined) ? state_attr[key + today].unit : "";
@@ -352,17 +368,69 @@ class Senec extends utils.Adapter {
352
368
  if (refDay != curDay) {
353
369
  this.log.debug("New " + day + " (or first value seen). Updating stat data for: " + name.substring(10));
354
370
  // Change of day
355
- await this.doState(key + ".ref" + day, curDay, descRefDay, unitRefDay, true);
356
- await this.doState(key + yesterday, valToday, descYesterday, unitYesterday, true);
357
- await this.doState(key + today, 0, descToday, unitToday, true);
358
- await this.doState(key + refValue, valCur, descRef, unitRef, true);
371
+ await this.doState(key + ".ref" + day, curDay, descRefDay, unitRefDay, false);
372
+ await this.doState(key + yesterday, valToday, descYesterday, unitYesterday, false);
373
+ await this.doState(key + today, 0, descToday, unitToday, false);
374
+ if (valRef < valCur) {
375
+ await this.doState(key + refValue, valCur, descRef, unitRef, true);
376
+ } else {
377
+ this.log.warning("Not updating reference value for: " + name.substring(10) + "! Old RefValue (" + valRef + ") >= new RefValue (" + valCur + "). Impossible situation. If this is intentional, please update via admin!");
378
+ }
359
379
  } else {
360
- this.log.debug("Updating " + day +" value for: " + name.substring(10));
380
+ this.log.debug("Updating " + day +" value for: " + name.substring(10) + ": " + Number((valCur - valRef).toFixed(2)));
361
381
  // update today's value
362
- await this.doState(key + today, Number((valCur - valRef).toFixed(2)), descToday, unitToday, true);
382
+ await this.doState(key + today, Number((valCur - valRef).toFixed(2)), descToday, unitToday, false);
363
383
  }
384
+
385
+ if (name === "STATISTIC.LIVE_HOUSE_CONS") await this.updateAutarkyHelper(today, yesterday, day, curDay); // otherwise we get way too many updates
364
386
 
365
387
  }
388
+
389
+ async updateAutarkyHelper(today, yesterday, day, curDay) {
390
+ const key = "_calc.Autarky";
391
+
392
+ // reference object to decide on change of day
393
+ const refDayObj = await this.getStateAsync(key + ".ref" + day);
394
+ const refDay = refDayObj ? refDayObj.val : -1;
395
+ // current day's value (needed in case of day-change)
396
+ const valTodayObj = await this.getStateAsync(key + today);
397
+ const valToday = valTodayObj ? valTodayObj.val : 0;
398
+
399
+ // reading values required for calc
400
+ const valBatChargeObj = await this.getStateAsync("_calc.LIVE_BAT_CHARGE_MASTER" + today);
401
+ const valBatCharge = valBatChargeObj ? valBatChargeObj.val : 0;
402
+ const valBatDischargeObj = await this.getStateAsync("_calc.LIVE_BAT_DISCHARGE_MASTER" + today);
403
+ const valBatDischarge = valBatDischargeObj ? valBatDischargeObj.val : 0;
404
+ const valGridExpObj = await this.getStateAsync("_calc.LIVE_GRID_EXPORT" + today);
405
+ const valGridExp = valGridExpObj ? valGridExpObj.val : 0;
406
+ const valGridImpObj = await this.getStateAsync("_calc.LIVE_GRID_IMPORT" + today);
407
+ const valGridImp = valGridImpObj ? valGridImpObj.val : 0;
408
+ const valHouseConsObj = await this.getStateAsync("_calc.LIVE_HOUSE_CONS" + today);
409
+ const valHouseCons = valHouseConsObj ? valHouseConsObj.val : 1;
410
+ const valPVGenObj = await this.getStateAsync("_calc.LIVE_PV_GEN" + today);
411
+ const valPVGen = valPVGenObj ? valPVGenObj.val : 0;
412
+
413
+ const descToday = (state_attr[key + today] !== undefined) ? state_attr[key + today].name : key;
414
+ const unitToday = (state_attr[key + today] !== undefined) ? state_attr[key + today].unit : "%";
415
+ const descYesterday = (state_attr[key + yesterday] !== undefined) ? state_attr[key + yesterday].name : key;
416
+ const unitYesterday = (state_attr[key + yesterday] !== undefined) ? state_attr[key + yesterday].unit : "%";
417
+ const descRefDay = (state_attr[key + ".ref" + day] !== undefined) ? state_attr[key + ".ref" + day].name : key;
418
+ const unitRefDay = (state_attr[key + ".ref" + day] !== undefined) ? state_attr[key + ".ref" + day].unit : "";
419
+
420
+ if (refDay != curDay) {
421
+ this.log.debug("New " + day + " (or first value seen). Updating Autarky data for: " + key + " " + day);
422
+ // Change of day
423
+ await this.doState(key + ".ref" + day, curDay, descRefDay, unitRefDay, false);
424
+ await this.doState(key + yesterday, valToday, descYesterday, unitYesterday, false);
425
+ // await this.doState(key + today, 0, descToday, unitToday, false); // we don't need to reset autarky to 0 because it is calculated by reference values.
426
+ // instead do the regular calc right after the change of day
427
+ }
428
+ // update today's value - but beware of div/0
429
+ var newVal = 0;
430
+ if (valHouseCons > 0) newVal = Number((((valPVGen - valGridExp - valBatCharge + valBatDischarge) / valHouseCons) * 100).toFixed(0));
431
+ this.log.debug("Updating Autarky " + day +" value for: " + key + today + ": " + newVal);
432
+ if (valHouseCons > 0) await this.doState(key + today, newVal, descToday, unitToday, false);
433
+ }
366
434
 
367
435
  }
368
436
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.senec",
3
- "version": "1.3.0",
3
+ "version": "1.3.4",
4
4
  "description": "Senec Home",
5
5
  "author": {
6
6
  "name": "NoBl",
@@ -24,39 +24,49 @@
24
24
  "url": "https://github.com/nobl/ioBroker.senec.git"
25
25
  },
26
26
  "dependencies": {
27
- "request": "^2.88.2",
28
- "@iobroker/adapter-core": "^2.4.0"
27
+ "axios": "^0.25.0",
28
+ "@iobroker/adapter-core": "^2.5.1"
29
29
  },
30
30
  "devDependencies": {
31
- "@iobroker/testing": "^2.4.4",
32
- "@types/chai": "^4.2.16",
33
- "@types/chai-as-promised": "^7.1.3",
34
- "@types/gulp": "^4.0.8",
35
- "@types/mocha": "^8.2.2",
36
- "@types/node": "^14.14.37",
31
+ "@alcalzone/release-script": "^3.5.2",
32
+ "@iobroker/testing": "^2.5.2",
33
+ "@types/chai": "^4.3.0",
34
+ "@types/chai-as-promised": "^7.1.4",
35
+ "@types/gulp": "^4.0.9",
36
+ "@types/mocha": "^9.0.0",
37
+ "@types/node": "^17.0.17",
37
38
  "@types/proxyquire": "^1.3.28",
38
- "@types/sinon": "^9.0.11",
39
- "@types/sinon-chai": "^3.2.5",
40
- "axios": "^0.21.1",
41
- "chai": "^4.3.4",
39
+ "@types/sinon": "^10.0.6",
40
+ "@types/sinon-chai": "^3.2.8",
41
+ "chai": "^4.3.6",
42
42
  "chai-as-promised": "^7.1.1",
43
- "eslint": "^7.23.0",
43
+ "eslint": "^8.8.0",
44
44
  "gulp": "^4.0.2",
45
- "mocha": "^8.3.2",
45
+ "mocha": "^9.1.3",
46
46
  "proxyquire": "^2.1.3",
47
- "sinon": "^10.0.0",
48
- "sinon-chai": "^3.6.0",
49
- "typescript": "^4.2.3"
47
+ "sinon": "^12.0.1",
48
+ "sinon-chai": "^3.7.0",
49
+ "typescript": "~4.5.5"
50
50
  },
51
51
  "main": "main.js",
52
+ "files": [
53
+ "admin{,/!(src)/**}/!(tsconfig|tsconfig.*).json",
54
+ "admin{,/!(src)/**}/*.{html,css,png,svg,jpg,js}",
55
+ "lib/",
56
+ "www/",
57
+ "io-package.json",
58
+ "LICENSE",
59
+ "main.js"
60
+ ],
52
61
  "scripts": {
53
62
  "test:js": "mocha --config test/mocharc.custom.json \"{!(node_modules|test)/**/*.test.js,*.test.js,test/**/test!(PackageFiles|Startup).js}\"",
54
- "test:package": "mocha test/package --exit",
55
- "test:unit": "mocha test/unit --exit",
56
- "test:integration": "mocha test/integration --exit",
57
- "test": "npm run test:js && npm run test:package",
58
- "check": "tsc --noEmit -p tsconfig.check.json",
59
- "lint": "eslint"
63
+ "test:package": "mocha test/package --exit",
64
+ "test:unit": "mocha test/unit --exit",
65
+ "test:integration": "mocha test/integration --exit",
66
+ "test": "npm run test:js && npm run test:package",
67
+ "check": "tsc --noEmit -p tsconfig.check.json",
68
+ "lint": "eslint",
69
+ "release": "release-script"
60
70
  },
61
71
  "bugs": {
62
72
  "url": "https://github.com/nobl/ioBroker.senec/issues"
package/CHANGELOG_old.md DELETED
@@ -1,68 +0,0 @@
1
- The newest change log is [README.md](README.md)
2
-
3
- ### 1.0.13 (NoBl)
4
- * Added System Description 19 for Senec.Home V3 Hybrid (Credits to noffycws)
5
- * Added Mode Descriptions for 86-91. (Credits to noffycws)
6
-
7
- ### 1.0.12 (NoBl)
8
- * Just set 'supportCustoms' to false so it won't show up in admin custom config.
9
-
10
- ### 1.0.11 (NoBl)
11
- * Update to current adapter template
12
- * Added Datapoints: PV1.MPP_CUR, MPP_VOL, MPP_POWER (former: MPP_INT which is unused at this moment but does still exist)
13
- * Added Datapoints (please feedback any improvements for their descriptions, ...): FEATURES.SGREADY, WIZARD.SETUP_WALLBOX_MAX_TOTAL_CURRENT_BY_GRID, WIZARD.SG_READY_CURR_MODE, BMS.ERROR, BMS.RECOVERLOCKED, BMS.SERIAL, BMS.START_SELFTEST, BAT1.RESET, BAT1.SELFTEST_ACT, BAT1.SELFTEST_LIMIT, BAT1.SELFTEST_OFF, BAT1.SELFTEST_OVERALL_STATE, BAT1.SELFTEST_STATE, BAT1.SELFTEST_STEP, BAT1.SELFTEST_TIME, BAT1.SERIAL, BAT1.TRIG_ITALY_SELF, BAT1OBJ1.COMM, GRIDCONFIG.AU_SOFT_RAMP_EN, GRIDCONFIG.AU_VRR_MAX, GRIDCONFIG.AU_VRR_MIN, GRIDCONFIG.AU_VVAR_PERCENTAGE, GRIDCONFIG.AU_VVAR_P_MAX, GRIDCONFIG.AU_VVAR_P_MIN, GRIDCONFIG.AU_VVAR_VOLTAGE, GRIDCONFIG.AU_VWC_VOLTAGE, GRIDCONFIG.AU_VWD_VOLTAGE, GRIDCONFIG.CEI_SEGNALE_ESTERNO, GRIDCONFIG.VDELVFRTDISABLE, GRIDCONFIG.VDEURMSMAX10
14
-
15
- ### 1.0.10 (NoBl, smartpran)
16
- * DateType objects are stored as date again
17
- * changed WIZARD.SETUP_POWER_RULE unit to '%'
18
- * changed name of STATISTIC.STAT_SUM_E_PU to "STAT_SUM Energy PowerUnit"
19
- * changed name of STATISTIC.STAT_SUM_E_WB to "STAT_SUM Energy Wallbox"
20
- * changed name of STATISTIC.LIVE_WB_ENERGY to "Live Wallbox Energy"
21
- * changed name of STATISTIC.LIVE_PU_ENERGY to "Live PowerUnit Energy"
22
- * changed name of WIZARD.PWRCFG_PEAK_PV_POWER to "Configured Peak PV Power"
23
- * enforcing conversion of number values to Number(). Otherwise they are created as String in ioBroker (manually delete existing datapoints in ioBroker to change them!)
24
- * fixed representation for temp values (off by *10)
25
- * json delivers a non-value (apparently an error message produced by senec itself). Ignoring that.
26
- * Added variable mpp_int to high priority and changed unit it. (smartpran)
27
-
28
- ### 1.0.9 (NoBl)
29
- * IP types are shown as IP again.
30
- * added datapoints for FACTORY along with more state descriptions for Battery Type, Country and System Type.
31
- * added datapoints for GRIDCONFIG
32
-
33
- ### 1.0.8 (NoBl)
34
- * Added more states to known states (please feedback if they need special handling (unit, special description, value modification, ...))
35
- * Bugfix in creating debug data
36
- * Unknown states are now reported in debug instead of info.
37
- * Code cleanup
38
-
39
- ### 1.0.7 (NoBl)
40
- * Reading all known states from SENEC.
41
- * Split states into high/low priority (heavy requesting the SENEC system renders it unable to sync with the SENEC datacenter!).
42
- * Updated adapter-core and testing versions along with current dev dependencies. Removed node 8 support.
43
- * Added more state descriptions to manual. But need input on these and those that are still not documented.
44
-
45
- ### 1.0.6 (NoBl)
46
- * Moved senec states and state attributes to libs
47
- * Added missing state descriptions
48
-
49
- ### 1.0.5 (2020-03-07) (NoBl)
50
- * Added States for: Energy: GUI_BAT_DATA_VOLTAGE, GUI_BAT_DATA_CURRENT, STAT_HOURS_OF_OPERATION; Sys_update: NPU_VER, NPU_IMAGE_VERSION, Wizard: APPLICATION_VERSION, INTERFACE_VERSION
51
- * Readme and Documentation (EN exists, now) updated
52
- * Changed behavior for unknown values completely. They will now be stored as string plus prefixed with "REPORT TO DEV:" so users can easily report back what needs updating.
53
- * added handling for "st_" values in json
54
- * added additional configuration options
55
- * changed retry-behaviour in case of connection issues, ...
56
-
57
- ### 1.0.4 (2020-03-06)
58
- * (NoBl) Repo URL updated
59
- ### 1.0.3 (2020-03-06)
60
- * (NoBl) added link to documentation in german
61
- ### 1.0.2 (2020-03-04)
62
- * (NoBl) added missing status codes (85 in total now)
63
- * (NoBl) added status code to status message for easier reference
64
- * (NoBl) added states for wallboxes and battery modules
65
- ### 1.0.1
66
- * (NoBl) updated readme
67
- ### 1.0.0
68
- * (NoBl) initial release
package/admin/admin.d.ts DELETED
@@ -1,93 +0,0 @@
1
- declare let systemDictionary: Record<string, Record<string, string>>;
2
-
3
- declare let load: (settings: Record<string, unknown>, onChange: (hasChanges: boolean) => void) => void;
4
- declare let save: (callback: (settings: Record<string, unknown>) => void) => void;
5
-
6
- // make load and save exist on the window object
7
- interface Window {
8
- load: typeof load;
9
- save: typeof save;
10
- }
11
-
12
- declare const instance: number;
13
- declare const adapter: string;
14
- /** Translates text */
15
- declare function _(text: string, arg1?: string, arg2?: string, arg3?: string): string;
16
- declare const socket: ioBrokerSocket;
17
- declare function sendTo(
18
- instance: any | null,
19
- command: string,
20
- message: any,
21
- callback: (result: SendToResult) => void | Promise<void>,
22
- ): void;
23
-
24
- interface SendToResult {
25
- error?: string | Error;
26
- result?: any;
27
- }
28
-
29
- // tslint:disable-next-line:class-name
30
- interface ioBrokerSocket {
31
- emit(
32
- command: 'subscribeObjects',
33
- pattern: string,
34
- callback?: (err?: string) => void | Promise<void>,
35
- ): void;
36
- emit(
37
- command: 'subscribeStates',
38
- pattern: string,
39
- callback?: (err?: string) => void | Promise<void>,
40
- ): void;
41
- emit(
42
- command: 'unsubscribeObjects',
43
- pattern: string,
44
- callback?: (err?: string) => void | Promise<void>,
45
- ): void;
46
- emit(
47
- command: 'unsubscribeStates',
48
- pattern: string,
49
- callback?: (err?: string) => void | Promise<void>,
50
- ): void;
51
-
52
- emit(
53
- event: 'getObjectView',
54
- view: 'system',
55
- type: 'device',
56
- options: ioBroker.GetObjectViewParams,
57
- callback: (
58
- err: string | undefined,
59
- result?: any,
60
- ) => void | Promise<void>,
61
- ): void;
62
- emit(
63
- event: 'getStates',
64
- callback: (
65
- err: string | undefined,
66
- result?: Record<string, any>,
67
- ) => void,
68
- ): void;
69
- emit(
70
- event: 'getState',
71
- id: string,
72
- callback: (err: string | undefined, result?: ioBroker.State) => void,
73
- ): void;
74
- emit(
75
- event: 'setState',
76
- id: string,
77
- state: unknown,
78
- callback: (err: string | undefined, result?: any) => void,
79
- ): void;
80
-
81
- on(event: 'objectChange', handler: ioBroker.ObjectChangeHandler): void;
82
- on(event: 'stateChange', handler: ioBroker.StateChangeHandler): void;
83
- removeEventHandler(
84
- event: 'objectChange',
85
- handler: ioBroker.ObjectChangeHandler,
86
- ): void;
87
- removeEventHandler(
88
- event: 'stateChange',
89
- handler: ioBroker.StateChangeHandler,
90
- ): void;
91
-
92
- // TODO: other events
93
- }