iobroker.senec 1.6.1 → 1.6.3

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/README.md CHANGED
@@ -366,6 +366,12 @@ This channel contains calculated values. Currently these are day/week/month/year
366
366
  *Read-only number, which designates the number of wallbox [0..3]. This is only available on systems with configured wallboxes.*
367
367
 
368
368
  ## Changelog
369
+ ### 1.6.3 (NoBl)
370
+ * Code optimization
371
+
372
+ ### 1.6.2 (NoBl)
373
+ * Added statistics values from API along with some own calculations.
374
+
369
375
  ### 1.6.1 (NoBl)
370
376
  * Bugfixes
371
377
 
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "senec",
4
- "version": "1.6.1",
4
+ "version": "1.6.3",
5
5
  "news": {
6
+ "1.6.3": {
7
+ "en": "Bugfixes for API reading.",
8
+ "de": "Bugfixes im API Handling.",
9
+ "ru": "Bugfixes для чтения API.",
10
+ "pt": "Bugfixes para leitura de API.",
11
+ "nl": "Bugfixes voor API-lezing.",
12
+ "fr": "Bugfixes pour la lecture de l'API.",
13
+ "it": "Bugfixes per la lettura API.",
14
+ "es": "Bugfixes para la lectura de API.",
15
+ "pl": "Bugfixes for API reading (ang.).",
16
+ "uk": "Виправлення помилок для читання API.",
17
+ "zh-cn": "评 注."
18
+ },
19
+ "1.6.2": {
20
+ "en": "Added statistics values from API along with some own calculations.",
21
+ "de": "Statistikwerte von API zusammen mit einigen eigenen Berechnungen hinzugefügt.",
22
+ "ru": "Добавлены статистические значения из API наряду с некоторыми собственными расчетами.",
23
+ "pt": "Adicionados valores estatísticos da API junto com alguns próprios cálculos.",
24
+ "nl": "Voeg statistieken toe van API samen met wat eigen berekeningen.",
25
+ "fr": "Ajout des valeurs statistiques de l'API avec certains propres calculs.",
26
+ "it": "Aggiunti i valori statistici da API con alcuni propri calcoli.",
27
+ "es": "Valores estadísticos añadidos de API junto con algunos cálculos propios.",
28
+ "pl": "Wstępne dane z API wraz z kilkoma własnymi obliczeniami.",
29
+ "uk": "Додано значення статистичних даних з API разом з деякими власними підрахунками.",
30
+ "zh-cn": "加上非传染性疾病的统计价值以及一些本身的计算。."
31
+ },
6
32
  "1.6.1": {
7
33
  "en": "Bugfixes for API reading.",
8
34
  "de": "Bugfixes im API Handling.",
@@ -93,32 +119,6 @@
93
119
  "pl": "Dodana opcja do używania https dla połączenia z SENEC (w sposób aktywowana, jeśli dana osoba obsługuje / wymaga to)",
94
120
  "uk": "Додано можливість використовувати HTTPS для підключення до SENEC (тільки активуйте, якщо підтримує додаток / вимагає цього)",
95
121
  "zh-cn": "增加使用连接到SENEC的网站的选择(如果你的可靠支持/要求这样做)"
96
- },
97
- "1.4.1": {
98
- "en": "Autarky calculations are working again.",
99
- "de": "Autarkieberechnungen funktionieren wieder.",
100
- "ru": "Расчеты Autarky снова работают.",
101
- "pt": "Cálculos autarcos estão a funcionar outra vez.",
102
- "nl": "Autarische berekeningen werken weer.",
103
- "fr": "Les calculs Autarky fonctionnent à nouveau.",
104
- "it": "I calcoli autarky funzionano di nuovo.",
105
- "es": "Los cálculos autárquicos están funcionando de nuevo.",
106
- "pl": "Ponowne obliczenia autarktyczne działają ponownie.",
107
- "uk": "Аутарки знову працюють.",
108
- "zh-cn": "Autarky的计算正再次工作。."
109
- },
110
- "1.4.0": {
111
- "en": "Added object caching and minor code updates. Due to the amount of objects we deal with caching is about mandatory.",
112
- "de": "Objekt-Caching und kleinere Code-Updates hinzugefügt. Aufgrund der Menge an Objekten, die der Adapter bearbeitet, ist Caching zwingend notwendig.",
113
- "ru": "Добавлена кэшировка объекта и незначительные обновления кода. В связи с количеством объектов, с которыми мы занимаемся кэшированием, является обязательным.",
114
- "pt": "Adicionado cache de objeto e pequenas atualizações de código. Devido à quantidade de objetos que lidamos com caching é sobre obrigatória.",
115
- "nl": "Toegevoegd voorwerp caching en kleine code updates. Gezien de hoeveelheid objecten die we met caching hebben, gaat het over verplichting.",
116
- "fr": "Ajout de cache d'objet et de mises à jour de code mineur. En raison de la quantité d'objets que nous traitons avec le cache est environ obligatoire.",
117
- "it": "Aggiunti caching oggetto e aggiornamenti di codice minori. A causa della quantità di oggetti che abbiamo a che fare con il caching è circa obbligatorio.",
118
- "es": "Añadido objeto caching y actualizaciones de código menor. Debido a la cantidad de objetos que tratamos con el caché es sobre obligatorio.",
119
- "pl": "Dodany obiekt caching i drobnych aktualizacji kodu. Ze względu na ilość przedmiotów, które traktują z cachingiem, dotyczy obowiązkowych.",
120
- "uk": "Додано кешування об'єкта та оновлення коду неповного розміру. У зв'язку з кількістю об'єктів, які ми маємо справу з кешуванням, є обов'язковим.",
121
- "zh-cn": "添加了目标包和小法典的更新。 由于我们所处理的物品数量是强制性的。."
122
122
  }
123
123
  },
124
124
  "docs": {
@@ -0,0 +1,29 @@
1
+ const api_trans = {
2
+ 'THIS_DAY': {
3
+ api: 'TAG',
4
+ dp: 'Today'
5
+ },
6
+ 'LAST_DAY': {
7
+ api: 'TAG',
8
+ dp: 'Yesterday'
9
+ },
10
+ 'THIS_MONTH': {
11
+ api: 'MONAT',
12
+ dp: 'This Month'
13
+ },
14
+ 'LAST_MONTH': {
15
+ api: 'MONAT',
16
+ dp: 'Last Month'
17
+ },
18
+ 'THIS_YEAR': {
19
+ api: 'JAHR',
20
+ dp: 'This Year'
21
+ },
22
+ 'LAST_YEAR': {
23
+ api: 'JAHR',
24
+ dp: 'Last Year'
25
+ }
26
+
27
+ }
28
+
29
+ module.exports = api_trans;
package/main.js CHANGED
@@ -14,6 +14,9 @@ axios.defaults.headers.post['Content-Type'] = "application/json";
14
14
 
15
15
  const state_attr = require(__dirname + '/lib/state_attr.js');
16
16
  const state_trans = require(__dirname + '/lib/state_trans.js');
17
+ const api_trans = require(__dirname + '/lib/api_trans.js');
18
+ const kiloList = ["W", "Wh"];
19
+
17
20
  const apiUrl = "https://app-gateway-prod.senecops.com/v1/senec";
18
21
  const apiLoginUrl = apiUrl + "/login";
19
22
  const apiSystemsUrl = apiUrl + "/anlagen";
@@ -26,6 +29,7 @@ let retryLowPrio = 0; // retry-counter
26
29
  let connectVia = "http://";
27
30
 
28
31
  const allKnownObjects = new Set(["BAT1","BAT1OBJ1","BAT1OBJ2","BAT1OBJ3","BMS","BMS_PARA","CASC","DEBUG","DISPLAY","ENERGY","FACTORY","FEATURES","FILE","GRIDCONFIG","ISKRA","LOG","PM1","PM1OBJ1","PM1OBJ2","PV1","PWR_UNIT","RTC","SELFTEST_RESULTS","SOCKETS","STATISTIC","STECA","SYS_UPDATE","TEMPMEASURE","TEST","UPDATE","WALLBOX","WIZARD"]);
32
+ // STATISTICS is faded out by senec. Keeping it while we still have machines getting it. This will also deprecate all calculated valued in the "_calc" branch.
29
33
 
30
34
  const highPrioObjects = new Map;
31
35
  let lowPrioForm = "";
@@ -65,7 +69,7 @@ class Senec extends utils.Adapter {
65
69
  if (apiConnected) await this.getApiSystems();
66
70
  await this.pollSenec(true, 0); // highPrio
67
71
  await this.pollSenec(false, 0); // lowPrio
68
- await this.pollSenecAppApi(0); // App API
72
+ if (apiConnected) await this.pollSenecAppApi(0); // App API
69
73
  this.setState('info.connection', true, true);
70
74
  } catch (error) {
71
75
  this.log.error(error);
@@ -127,6 +131,7 @@ class Senec extends utils.Adapter {
127
131
  if (this.config.disclaimer && this.config.highPrio_PM1OBJ2_active) this.addUserDps(value, objectsSet, this.config.highPrio_PM1OBJ2);
128
132
  break;
129
133
  case "STATISTIC":
134
+ // soon to be deprecated
130
135
  ["LIVE_GRID_EXPORT","LIVE_GRID_IMPORT","LIVE_HOUSE_CONS","LIVE_PV_GEN","LIVE_BAT_CHARGE_MASTER","LIVE_BAT_DISCHARGE_MASTER"].forEach(item => objectsSet.add(item));
131
136
  if (this.config.disclaimer && this.config.highPrio_STATISTIC_active) this.addUserDps(value, objectsSet, this.config.highPrio_STATISTIC);
132
137
  break;
@@ -262,6 +267,7 @@ class Senec extends utils.Adapter {
262
267
  apiConnected = true;
263
268
  axios.defaults.headers.get['authorization'] = apiLoginToken;
264
269
  } catch (error) {
270
+ apiConnected = false;
265
271
  throw new Error("Error connecting to Senec AppAPI. Exiting! (" + error + ").");
266
272
  }
267
273
  }
@@ -285,7 +291,10 @@ class Senec extends utils.Adapter {
285
291
  const systemId = value.id;
286
292
  apiKnownSystems.push(systemId);
287
293
  for (const[key2, value2] of Object.entries(value)) {
288
- this.doState(pfx + systemId + "." + key2, JSON.stringify(value2), "", "", false);
294
+ if (typeof value2 === "object")
295
+ this.doState(pfx + systemId + "." + key2, JSON.stringify(value2), "", "", false);
296
+ else
297
+ this.doState(pfx + systemId + "." + key2, value2, "", "", false);
289
298
  }
290
299
  }
291
300
  this.doState(pfx + 'IDs', JSON.stringify(apiKnownSystems), "Anlagen IDs", "", false);
@@ -382,15 +391,41 @@ class Senec extends utils.Adapter {
382
391
  * Read values from Senec App API
383
392
  */
384
393
  async pollSenecAppApi(retry) {
385
- var interval = this.config.api_interval * 60000;
394
+ if (!this.config.api_use || !apiConnected) {
395
+ this.log.info('Usage of SENEC App API not configured or not connected.');
396
+ return;
397
+ }
398
+ const interval = this.config.api_interval * 60000;
399
+ const dates = new Map([
400
+ ["THIS_DAY", new Date().toISOString().split('T')[0]],
401
+ ["LAST_DAY", new Date(new Date().setDate(new Date().getDate()-1)).toISOString().split('T')[0]],
402
+ ["THIS_MONTH", new Date().toISOString().split('T')[0]],
403
+ ["LAST_MONTH", new Date(new Date().setDate(0)).toISOString().split('T')[0]],
404
+ ["THIS_YEAR", new Date().toISOString().split('T')[0]],
405
+ ["LAST_YEAR", new Date(new Date().getFullYear() - 1, 1, 1).toISOString().split('T')[0]]
406
+ ]);
407
+
386
408
  this.log.debug("Polling API ...");
387
409
  var body = "";
388
410
  try {
389
411
  for (let i = 0; i < apiKnownSystems.length; i++) {
412
+ const baseUrl = apiSystemsUrl + "/" + apiKnownSystems[i]
413
+ var url = "";
414
+ const tzObj = await this.getStateAsync("_api.Anlagen." + apiKnownSystems[i] + ".zeitzone");
415
+ const tz = tzObj ? encodeURIComponent(tzObj.val) : encodeURIComponent("Europe/Berlin");
416
+
390
417
  // dashboard
391
- var url = apiSystemsUrl + "/" + apiKnownSystems[i] + "/dashboard";
418
+ url = baseUrl + "/dashboard";
392
419
  body = await this.doGet(url, "", this, this.config.pollingTimeout, false);
393
420
  await this.decodeDashboard(apiKnownSystems[i], JSON.parse(body));
421
+
422
+ for (let[key, value] of dates.entries()) {
423
+ // statistik today
424
+ url = baseUrl + "/statistik?periode=" + api_trans[key].api + "&datum=" + value + "&locale=de_DE&timezone=" + tz;
425
+ body = await this.doGet(url, "", this, this.config.pollingTimeout, false);
426
+ await this.decodeStatistik(apiKnownSystems[i], JSON.parse(body), api_trans[key].dp);
427
+ }
428
+
394
429
  // // wallboxes - only if wallbox exists? - Without: error 500
395
430
  //var url = apiSystemsUrl + "/" + apiKnownSystems[i] + "/wallboxes/1";
396
431
  //body = await this.doGet(url, "", this, this.config.pollingTimeout, false);
@@ -419,12 +454,32 @@ class Senec extends utils.Adapter {
419
454
  this.doState(pfx + key, value, "", "", false);
420
455
  } else {
421
456
  for (const[key2, value2] of Object.entries(value)) {
422
- this.doState(pfx + key + "." + key2, value2.wert, "", value2.einheit, false);
457
+ this.doState(pfx + key + "." + key2, (value2.wert).toFixed(2), "", value2.einheit, false);
458
+ if (kiloList.includes(value2.einheit)) {
459
+ this.doState(pfx + key + "." + key2 + " (k" + value2.einheit + ")", (value2.wert / 1000).toFixed(2), "", "k" + value2.einheit, false);
460
+ }
423
461
  }
424
462
  }
425
463
  }
426
464
 
427
465
  }
466
+
467
+ async decodeStatistik(system, obj, period) {
468
+ const pfx = "_api.Anlagen." + system + ".Statistik." + period + ".";
469
+ for (const[key, value] of Object.entries(obj.aggregation)) {
470
+ // only reading 'aggregation' - no interest in fine granular information
471
+ if (key == "startzeitpunkt") {
472
+ this.doState(pfx + key, value, "", "", false);
473
+ } else {
474
+ this.doState(pfx + key, (value.wert).toFixed(2), "", value.einheit, false);
475
+ if (kiloList.includes(value.einheit)) {
476
+ this.doState(pfx + key + " (k"+ value.einheit + ")", (value.wert / 1000).toFixed(2), "", "k" + value.einheit, false);
477
+ }
478
+ }
479
+ }
480
+ const autarky = (((obj.aggregation.stromerzeugung.wert - obj.aggregation.netzeinspeisung.wert - obj.aggregation.speicherbeladung.wert + obj.aggregation.speicherentnahme.wert) / obj.aggregation.stromverbrauch.wert) * 100).toFixed(2);
481
+ this.doState(pfx + "Autarkie", autarky, "", "%", false);
482
+ }
428
483
 
429
484
  /**
430
485
  * sets a state's value and creates the state if it doesn't exist yet
@@ -481,7 +536,7 @@ class Senec extends utils.Adapter {
481
536
  val: value,
482
537
  ack: true
483
538
  });
484
- await this.checkUpdateSelfStat(name);
539
+ await this.checkUpdateSelfStat(name); // soon to be deprecated
485
540
  await this.doDecode(name, value);
486
541
  }
487
542
 
@@ -512,6 +567,7 @@ class Senec extends utils.Adapter {
512
567
  * Helper routine
513
568
  */
514
569
  async checkUpdateSelfStat(name) {
570
+ // soon to be deprecated
515
571
  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") {
516
572
  await this.updateSelfStat(name);
517
573
  }
@@ -546,6 +602,7 @@ class Senec extends utils.Adapter {
546
602
  }
547
603
 
548
604
  async updateSelfStat(name, value) {
605
+ // soon to be deprecated
549
606
  await this.updateSelfStatHelper(name, value, ".today", ".yesterday", ".refValue", "Day", getCurDay());
550
607
  await this.updateSelfStatHelper(name, value, ".week", ".lastWeek", ".refValueWeek", "Week", getCurWeek());
551
608
  await this.updateSelfStatHelper(name, value, ".month", ".lastMonth", ".refValueMonth", "Month", getCurMonth());
@@ -554,6 +611,7 @@ class Senec extends utils.Adapter {
554
611
  }
555
612
 
556
613
  async updateSelfStatHelper(name, value, today, yesterday, refValue, day, curDay) {
614
+ // soon to be deprecated
557
615
  const key = "_calc." + name.substring(10);
558
616
 
559
617
  const refDayObj = await this.getStateAsync(key + ".ref" + day);
@@ -598,6 +656,7 @@ class Senec extends utils.Adapter {
598
656
  }
599
657
 
600
658
  async updateAutarkyHelper(today, yesterday, day, curDay) {
659
+ // soon to be deprecated
601
660
  const key = "_calc.Autarky";
602
661
 
603
662
  // reference object to decide on change of day
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.senec",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "description": "Senec Home",
5
5
  "author": {
6
6
  "name": "NoBl",