iobroker.senec 1.5.1 → 1.6.0

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,10 @@ 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.0 (NoBl)
370
+ * Added option to also poll SENEC App API. This requires user credentials for mein-senec.de
371
+ * We are starting with just some information - more to follow. But with Dashboard we at least have current values and day statistics back.
372
+
369
373
  ### 1.5.1 (NoBl)
370
374
  * Added more datapoints. If you experience messages in log - feel free to add them yourself to state_attr on github (pull request)
371
375
  * Autarky calculations will stopp working because SENEC removed STATISTICS branch.
@@ -1086,6 +1086,163 @@
1086
1086
  "newLine": false
1087
1087
  }
1088
1088
  }
1089
+ },
1090
+ "_api": {
1091
+ "type": "panel",
1092
+ "label": {
1093
+ "en": "SENEC API",
1094
+ "de": "SENEC API",
1095
+ "ru": "SENEC API",
1096
+ "pt": "API SENEC",
1097
+ "nl": "SENEC",
1098
+ "fr": "SENEC API",
1099
+ "it": "API SENEC",
1100
+ "es": "SENEC API",
1101
+ "pl": "SENEC API",
1102
+ "uk": "СЕНЕК API",
1103
+ "zh-cn": "SENECAPI"
1104
+ },
1105
+ "items": {
1106
+ "api_use": {
1107
+ "type": "checkbox",
1108
+ "sm": 12,
1109
+ "md": 6,
1110
+ "lg": 6,
1111
+ "label": {
1112
+ "en": "Use SENEC API?",
1113
+ "de": "SENEC API nutzen?",
1114
+ "ru": "Используйте SENEC API?",
1115
+ "pt": "Usar API SENEC?",
1116
+ "nl": "SENEC API gebruiken?",
1117
+ "fr": "Utilisez l'API SENEC?",
1118
+ "it": "Utilizzare API SENEC?",
1119
+ "es": "¿Usar SENEC API?",
1120
+ "pl": "Zastosowanie API SENEC?",
1121
+ "uk": "Використовуйте SENEC API?",
1122
+ "zh-cn": "使用ENECAPI?"
1123
+ },
1124
+ "help": {
1125
+ "en": "Check if the adapter shall make use of the SENEC API.",
1126
+ "de": "Aktivieren, falls der Adapter die SENEC API nutzen soll.",
1127
+ "ru": "Проверьте, следует ли адаптер использовать SENEC API.",
1128
+ "pt": "Verifique se o adaptador deve fazer uso da API SENEC.",
1129
+ "nl": "Kijk of de adapter gebruik maakt van de SENEC API.",
1130
+ "fr": "Vérifiez si l'adaptateur doit utiliser l'API SENEC.",
1131
+ "it": "Controllare se l'adattatore deve utilizzare l'API SENEC.",
1132
+ "es": "Compruebe si el adaptador hará uso de la API SENEC.",
1133
+ "pl": "W przypadku, gdy adapter będzie korzystał z API SENEC.",
1134
+ "uk": "Перевірте, чи використовує адаптер SENEC API.",
1135
+ "zh-cn": "如果适应者应使用ENECAPI。."
1136
+ },
1137
+ "default": "",
1138
+ "newLine": true
1139
+ },
1140
+ "api_mail": {
1141
+ "type": "text",
1142
+ "sm": 12,
1143
+ "md": 6,
1144
+ "lg": 6,
1145
+ "label": {
1146
+ "en": "Email-Address",
1147
+ "de": "E-Mail-Adresse",
1148
+ "ru": "Email-Адрес",
1149
+ "pt": "Endereço de email",
1150
+ "nl": "E-Addres",
1151
+ "fr": "Email-Address",
1152
+ "it": "Indirizzo e-mail",
1153
+ "es": "Email-Address",
1154
+ "pl": "Email-Addresser",
1155
+ "uk": "Електронна пошта",
1156
+ "zh-cn": "Email-Addres"
1157
+ },
1158
+ "help": {
1159
+ "en": "Email-Address used to login to mein-senec.de",
1160
+ "de": "Email-Adresse, um sich bei mein-senec.de anzumelden",
1161
+ "ru": "Email-адрес используется для входа в mein-senec.de",
1162
+ "pt": "Email-Endereço usado para login para mein-senec.de",
1163
+ "nl": "Email-Address loge in mein-senec",
1164
+ "fr": "Email-Adresse utilisé pour se connecter à mein-senec.de",
1165
+ "it": "Email-Address usato per accedere a mein-senec.de",
1166
+ "es": "Email-Address solía iniciar sesión en mein-senec.de",
1167
+ "pl": "Email-Address używany do logowania mein-senec",
1168
+ "uk": "Email-Address використовується для входу в mein-senec.de",
1169
+ "zh-cn": "Email-Address used to mein-senec.de"
1170
+ },
1171
+ "default": "",
1172
+ "newLine": true
1173
+ },
1174
+ "api_pwd": {
1175
+ "type": "password",
1176
+ "visible": true,
1177
+ "sm": 12,
1178
+ "md": 6,
1179
+ "lg": 6,
1180
+ "label": {
1181
+ "en": "Password",
1182
+ "de": "Passwort",
1183
+ "ru": "Пароль",
1184
+ "pt": "Senha",
1185
+ "nl": "Wachtwoord",
1186
+ "fr": "Mot de passe",
1187
+ "it": "Password",
1188
+ "es": "Contraseña",
1189
+ "pl": "Password",
1190
+ "uk": "Логін",
1191
+ "zh-cn": "护照"
1192
+ },
1193
+ "help": {
1194
+ "en": "Password used to login to mein-senec.de",
1195
+ "de": "Passwort für die Anmeldung an mein-senec.de",
1196
+ "ru": "Пароль используется для входа в mein-senec.de",
1197
+ "pt": "Senha usada para login para mein-senec.de",
1198
+ "nl": "Het wachtwoord loginde in mein-senec",
1199
+ "fr": "Mot de passe utilisé pour se connecter à mein-senec.de",
1200
+ "it": "Password usata per accedere a mein-senec.de",
1201
+ "es": "Contraseña usada para iniciar sesión en mein-senec.de",
1202
+ "pl": "Miecz używany do logowania na mein-senec.de",
1203
+ "uk": "Пароль використовується для входу в mein-senec.de",
1204
+ "zh-cn": "目 录"
1205
+ },
1206
+ "default": "",
1207
+ "newLine": false
1208
+ },
1209
+ "api_interval": {
1210
+ "type": "number",
1211
+ "sm": 12,
1212
+ "md": 6,
1213
+ "lg": 6,
1214
+ "label": {
1215
+ "en": "Polling Interval (minutes)",
1216
+ "de": "Polling Interval (Minuten)",
1217
+ "ru": "Поллинг Интервал (минуты)",
1218
+ "pt": "Polling Interval (minutos)",
1219
+ "nl": "Polling Interval (minuten)",
1220
+ "fr": "Intervalle de vote (minutes)",
1221
+ "it": "Polling Interval (minuti)",
1222
+ "es": "Intervalo de votación (minutos)",
1223
+ "pl": "Polling Interval (ang.)",
1224
+ "uk": "Поллінг Інтервал (хвилини)",
1225
+ "zh-cn": "中间(分钟)"
1226
+ },
1227
+ "help": {
1228
+ "en": "Here you can define the polling interval [min 3, max 1440 minutes]. Default = 5. SENEC updates API Data every 5 minutes.",
1229
+ "de": "Hier können Sie das Abfrageintervall definieren [min 3, max 1440 Minuten]. Standard = 5. SENEC aktualisiert die API-Daten alle 5 Minuten.",
1230
+ "ru": "Здесь вы можете определить интервал опроса [мин 3, макс 1440 минут]. По умолчанию = 5. SENEC обновление API Данные каждые 5 минут.",
1231
+ "pt": "Aqui você pode definir o intervalo de votação [min 3, max 1440 minutes]. Padrão = 5. API de atualizações do SENEC Dados a cada 5 minutos.",
1232
+ "nl": "Hier kun je de peiling interval definiëren. SenEC updates Data om de vijf minuten.",
1233
+ "fr": "Ici vous pouvez définir l'intervalle de vote [min 3, max 1440 minutes]. Défaut = 5. Données toutes les 5 minutes.",
1234
+ "it": "Qui è possibile definire l'intervallo di polling [min 3, max 1440 minuti]. Default = 5. Aggiornamenti SENEC API Dati ogni 5 minuti.",
1235
+ "es": "Aquí puede definir el intervalo de votación [min 3, max 1440 minutos]. Default = 5. Actualización de SENEC API Datos cada 5 minutos.",
1236
+ "pl": "Może ona zdefiniować przedział wyborczy (min 3, max 1440 minut). Default = 5. Dane co 5 minut.",
1237
+ "uk": "Тут можна визначити інтервал опитування [min 3, макс. 1440 хвилин]. JavaScript licenses API Веб-сайт Дані кожні 5 хвилин.",
1238
+ "zh-cn": "在此,你可以界定投票间隔[3, max1440分钟]。 Default=5 SENEC最新情况 数据每5分钟。."
1239
+ },
1240
+ "default": 5,
1241
+ "min": 3,
1242
+ "max": 1440,
1243
+ "newLine": true
1244
+ },
1245
+ }
1089
1246
  }
1090
1247
  }
1091
1248
  }
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "senec",
4
- "version": "1.5.1",
4
+ "version": "1.6.0",
5
5
  "news": {
6
+ "1.6.0": {
7
+ "en": "You can now configure to request SENEC App API.",
8
+ "de": "Sie können nun die SENEC App API abfragen.",
9
+ "ru": "Теперь вы можете настроить для запроса SENEC App API.",
10
+ "pt": "Agora você pode configurar para solicitar a API do SENEC App.",
11
+ "nl": "Je kunt nu configureren om SENEC App API te vragen.",
12
+ "fr": "Vous pouvez maintenant configurer pour demander l'API App SENEC.",
13
+ "it": "Ora è possibile configurare per richiedere l'API SENEC App.",
14
+ "es": "Ahora puede configurarse para solicitar SENEC App API.",
15
+ "pl": "Możesz teraz skonfigurować żądanie SENEC App API.",
16
+ "uk": "Ви можете налаштувати запит на SENEC App API.",
17
+ "zh-cn": "如今,你可以准备要求SENECSP。."
18
+ },
19
+ "1.5.2": {
20
+ "en": "Added more datapoints. If you experience messages in log - feel free to add them yourself to state_attr on github (pull request)",
21
+ "de": "Weitere Datenpunkte hinzugefügt. Du kennst weitere? Bitte PullRequest auf Github für state_attr.",
22
+ "ru": "Добавили больше точек данных. Если вы испытываете сообщения в логе - не стесняйтесь добавлять их самостоятельно в state_attr на github (по запросу)",
23
+ "pt": "Adicionado mais datapoints. Se você tiver mensagens no log - sinta-se livre para adicioná-las ao state_attr no github (requisito de envio)",
24
+ "nl": "Voegde meer datapoints toe. Als je berichten in het logboek ervaart, voel je vrij om ze zelf toe te voegen aan github (pull verzoek)",
25
+ "fr": "Ajout d'autres points de données. Si vous éprouvez des messages dans log - n'hésitez pas à les ajouter à state_attr sur github (demande de puissance)",
26
+ "it": "Aggiunti altri datapoint. Se si verificano messaggi in log - sentitevi liberi di aggiungerli a state_attr su github (domanda di voto)",
27
+ "es": "Se agregaron más puntos de datos. Si experimentas mensajes en el registro - no dudes en añadirlos a state_attr en github (pregunta completa)",
28
+ "pl": "Dodać więcej danych. Jeśli znajdziesz wiadomości w dzienniku – czuje się wolny, aby dodać ich do stanu_attr na github (pułki)",
29
+ "uk": "Додано більше точок даних. Якщо ви відчуваєте повідомлення в журналі - не соромтеся додати їх до стану_attr на github",
30
+ "zh-cn": "增加数据点。 如果你在逻辑上有信息,就认为可以自由地补充你自己的国家:对Tithub(要求)表示怀疑。"
31
+ },
6
32
  "1.5.1": {
7
33
  "en": "Added more datapoints. If you experience messages in log - feel free to add them yourself to state_attr on github (pull request)",
8
34
  "de": "Weitere Datenpunkte hinzugefügt. Du kennst weitere? Bitte PullRequest auf Github für state_attr.",
@@ -182,7 +208,13 @@
182
208
  "highPrio_BAT1OBJ4": "",
183
209
  "highPrio_BAT1OBJ4_active": false,
184
210
  "highPrio_TEMPMEASURE": "",
185
- "highPrio_TEMPMEASURE_active": false
211
+ "highPrio_TEMPMEASURE_active": false,
212
+ "api_use": false,
213
+ "api_interval": 5
214
+ },
215
+ "nativeEncrypted": {
216
+ "api_mail": "",
217
+ "api_pwd": ""
186
218
  },
187
219
  "objects": [],
188
220
  "instanceObjects": [{
package/lib/state_attr.js CHANGED
@@ -7413,6 +7413,110 @@ const state_attr = {
7413
7413
  iptype: false,
7414
7414
  multiply: 1
7415
7415
  },
7416
+ 'WIZARD.SG_READY_POWER_NORMAL': {
7417
+ name: 'SG_READY_POWER_NORMAL',
7418
+ unit: '',
7419
+ booltype: true,
7420
+ datetype: false,
7421
+ iptype: false,
7422
+ multiply: 1
7423
+ },
7424
+ 'WALLBOX.NUMBER_OF_PHASE': {
7425
+ name: 'NUMBER_OF_PHASE',
7426
+ unit: '',
7427
+ booltype: false,
7428
+ datetype: false,
7429
+ iptype: false,
7430
+ multiply: 1
7431
+ },
7432
+ 'WALLBOX.ERROR_DETAILS': {
7433
+ name: 'ERROR_DETAILS',
7434
+ unit: '',
7435
+ booltype: false,
7436
+ datetype: false,
7437
+ iptype: false,
7438
+ multiply: 1
7439
+ },
7440
+ 'LOG.LOG_IN_NOK_COUNT': {
7441
+ name: 'LOG_IN_NOK_COUNT',
7442
+ unit: '',
7443
+ booltype: false,
7444
+ datetype: false,
7445
+ iptype: false,
7446
+ multiply: 1
7447
+ },
7448
+ 'GRIDCONFIG.VDEPT1RESPONSETIME': {
7449
+ name: 'VDEPT1RESPONSETIME',
7450
+ unit: '',
7451
+ booltype: false,
7452
+ datetype: false,
7453
+ iptype: false,
7454
+ multiply: 1
7455
+ },
7456
+ 'FACTORY.EPA_GRID_FILTER': {
7457
+ name: 'EPA_GRID_FILTER',
7458
+ unit: '',
7459
+ booltype: false,
7460
+ datetype: false,
7461
+ iptype: false,
7462
+ multiply: 1
7463
+ },
7464
+ 'BMS_PARA.OPERATIONAL_MODE': {
7465
+ name: 'OPERATIONAL_MODE',
7466
+ unit: '',
7467
+ booltype: false,
7468
+ datetype: false,
7469
+ iptype: false,
7470
+ multiply: 1
7471
+ },
7472
+ 'BMS_PARA.MAX_MODULE_DISCHARGE_CURRENT_LIMIT_A': {
7473
+ name: 'MAX_MODULE_DISCHARGE_CURRENT_LIMIT_A',
7474
+ unit: 'A',
7475
+ booltype: false,
7476
+ datetype: false,
7477
+ iptype: false,
7478
+ multiply: 1
7479
+ },
7480
+ 'BMS_PARA.MAX_MODULE_CHARGE_CURRENT_LIMIT_A': {
7481
+ name: 'MAX_MODULE_CHARGE_CURRENT_LIMIT_A',
7482
+ unit: 'A',
7483
+ booltype: false,
7484
+ datetype: false,
7485
+ iptype: false,
7486
+ multiply: 1
7487
+ },
7488
+ 'BMS_PARA.FULL_CELL_VOLTAGE_MV': {
7489
+ name: 'FULL_CELL_VOLTAGE_MV',
7490
+ unit: 'V',
7491
+ booltype: false,
7492
+ datetype: false,
7493
+ iptype: false,
7494
+ multiply: 1
7495
+ },
7496
+ 'BMS_PARA.FORCE_OP_MODE': {
7497
+ name: 'FORCE_OP_MODE',
7498
+ unit: '',
7499
+ booltype: true,
7500
+ datetype: false,
7501
+ iptype: false,
7502
+ multiply: 1
7503
+ },
7504
+ 'BMS_PARA.FORCE_BMS_ERROR': {
7505
+ name: 'FORCE_BMS_ERROR',
7506
+ unit: '',
7507
+ booltype: true,
7508
+ datetype: false,
7509
+ iptype: false,
7510
+ multiply: 1
7511
+ },
7512
+ 'BMS_PARA.USE_ROA_PARAMETER': {
7513
+ name: 'USE_ROA_PARAMETER',
7514
+ unit: '',
7515
+ booltype: true,
7516
+ datetype: false,
7517
+ iptype: false,
7518
+ multiply: 1
7519
+ },
7416
7520
 
7417
7521
  }
7418
7522
 
package/main.js CHANGED
@@ -8,10 +8,19 @@ const agent = new https.Agent({
8
8
  });
9
9
 
10
10
  const utils = require('@iobroker/adapter-core');
11
+
11
12
  const axios = require('axios').default;
13
+ axios.defaults.headers.common['Content-Type'] = "application/json";
14
+
12
15
  const state_attr = require(__dirname + '/lib/state_attr.js');
13
16
  const state_trans = require(__dirname + '/lib/state_trans.js');
17
+ const apiUrl = "https://app-gateway-prod.senecops.com/v1/senec";
18
+ const apiLoginUrl = apiUrl + "/login";
19
+ const apiSystemsUrl = apiUrl + "/anlagen";
20
+ const apiKnownSystems = []
14
21
 
22
+ let apiConnected = false;
23
+ let apiLoginToken = "";
15
24
  let retry = 0; // retry-counter
16
25
  let retryLowPrio = 0; // retry-counter
17
26
  let connectVia = "http://";
@@ -52,8 +61,12 @@ class Senec extends utils.Adapter {
52
61
  await this.checkConfig();
53
62
  await this.initPollSettings();
54
63
  await this.checkConnection();
64
+ await this.initSenecAppApi();
65
+ if (apiConnected) await this.getApiSystems();
55
66
  await this.pollSenec(true, 0); // highPrio
56
67
  await this.pollSenec(false, 0); // lowPrio
68
+ await this.pollSenecAppApi(0); // App API
69
+ this.setState('info.connection', true, true);
57
70
  } catch (error) {
58
71
  this.log.error(error);
59
72
  this.setState('info.connection', false, true);
@@ -70,8 +83,8 @@ class Senec extends utils.Adapter {
70
83
  if (this.timer) {
71
84
  clearTimeout(this.timer);
72
85
  }
73
- if (this.timerLowPrio) {
74
- clearTimeout(this.timerLowPrio);
86
+ if (this.timerAPI) {
87
+ clearTimeout(this.timerAPI);
75
88
  }
76
89
  this.log.info('cleaned everything up...');
77
90
  this.setState('info.connection', false, true);
@@ -207,6 +220,11 @@ class Senec extends utils.Adapter {
207
220
  connectVia = "https://";
208
221
  this.log.debug("(checkConf) Switching to https ... " + this.config.useHttps);
209
222
  }
223
+ this.log.debug("(checkConf) Configured api polling interval: " + this.config.api_interval);
224
+ if (this.config.api_interval < 3 || this.config.api_interval > 1440) {
225
+ this.log.warn("(checkConf) Config api polling interval " + this.config.api_interval + " not [3..1440] seconds. Using default: 5");
226
+ this.config.api_interval = 5;
227
+ }
210
228
  }
211
229
 
212
230
  /**
@@ -217,23 +235,74 @@ class Senec extends utils.Adapter {
217
235
  const form = '{"ENERGY":{"STAT_STATE":""}}';
218
236
  try {
219
237
  this.log.info('connecting to Senec: ' + url);
220
- const body = await this.doGet(url, form, this, this.config.pollingTimeout);
238
+ const body = await this.doGet(url, form, this, this.config.pollingTimeout, true);
221
239
  this.log.info('connected to Senec: ' + url);
222
- this.setState('info.connection', true, true);
223
240
  } catch (error) {
224
241
  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.");
225
242
  }
226
243
  }
244
+
245
+ /**
246
+ * Inits connection to senec app api
247
+ */
248
+ async initSenecAppApi() {
249
+ if (!this.config.api_use) {
250
+ this.log.info('Usage of SENEC App API not configured. Not using it');
251
+ return;
252
+ }
253
+ this.log.info('connecting to Senec App API: ' + apiLoginUrl);
254
+ const loginData = JSON.stringify({
255
+ password: this.config.api_pwd,
256
+ username: this.config.api_mail
257
+ });
258
+ try {
259
+ const body = await this.doGet(apiLoginUrl, loginData, this, this.config.pollingTimeout, true);
260
+ this.log.info('connected to Senec AppAPI.');
261
+ apiLoginToken = JSON.parse(body).token;
262
+ apiConnected = true;
263
+ axios.defaults.headers.common['authorization'] = apiLoginToken;
264
+ } catch (error) {
265
+ throw new Error("Error connecting to Senec AppAPI. Exiting! (" + error + ").");
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Reads system data from senec app api
271
+ */
272
+ async getApiSystems() {
273
+ const pfx = "_api.Anlagen.";
274
+ if (!this.config.api_use || !apiConnected) {
275
+ this.log.info('Usage of SENEC App API not configured or not connected.');
276
+ return;
277
+ }
278
+ this.log.info('Reading Systems Information from Senec App API ' + apiSystemsUrl);
279
+ try {
280
+ const body = await this.doGet(apiSystemsUrl, "", this, this.config.pollingTimeout, false);
281
+ this.log.info('Read Systems Information from Senec AppAPI.');
282
+ var obj = JSON.parse(body);
283
+ const systems = [];
284
+ for (const[key, value] of Object.entries(obj)) {
285
+ const systemId = value.id;
286
+ apiKnownSystems.push(systemId);
287
+ for (const[key2, value2] of Object.entries(value)) {
288
+ this.doState(pfx + systemId + "." + key2, JSON.stringify(value2), "", "", false);
289
+ }
290
+ }
291
+ this.doState(pfx + 'IDs', JSON.stringify(apiKnownSystems), "Anlagen IDs", "", false);
292
+ } catch (error) {
293
+ throw new Error("Error reading Systems Information from Senec AppAPI. (" + error + ").");
294
+ }
295
+ }
227
296
 
228
297
  /**
229
298
  * Read from url via axios
230
299
  * @param url to read from
231
300
  * @param form to post
232
301
  */
233
- doGet(pUrl, pForm, caller, pollingTimeout) {
302
+ doGet(pUrl, pForm, caller, pollingTimeout, isPost) {
234
303
  return new Promise(function (resolve, reject) {
235
304
  axios({
236
- method: 'post',
305
+ method: isPost ? 'post' : 'get',
237
306
  httpsAgent: agent,
238
307
  url: pUrl,
239
308
  data: pForm,
@@ -251,6 +320,10 @@ class Senec extends utils.Adapter {
251
320
  if (error.response) {
252
321
  // The request was made and the server responded with a status code
253
322
  caller.log.warn('(Poll) received error ' + error.response.status + ' response from SENEC with content: ' + JSON.stringify(error.response.data));
323
+ if (error.response.status == 403 && apiConnected) {
324
+ apiConnected = false; // apparently the api is inaccessible
325
+ this.initSenecAppApi();
326
+ }
254
327
  reject(error.response.status);
255
328
  } else if (error.request) {
256
329
  // The request was made but no response was received
@@ -280,7 +353,7 @@ class Senec extends utils.Adapter {
280
353
  }
281
354
 
282
355
  try {
283
- var body = await this.doGet(url, (isHighPrio ? highPrioForm : lowPrioForm), this, this.config.pollingTimeout);
356
+ var body = await this.doGet(url, (isHighPrio ? highPrioForm : lowPrioForm), this, this.config.pollingTimeout, true);
284
357
  if (body.includes('\\"')) {
285
358
  // in rare cases senec reports back extra escape sequences on some machines ...
286
359
  this.log.info("(Poll) Double escapes detected! Body inc: " + body);
@@ -303,6 +376,53 @@ class Senec extends utils.Adapter {
303
376
  this.timer = setTimeout(() => this.pollSenec(isHighPrio, retry), interval * this.config.retrymultiplier * retry);
304
377
  }
305
378
  }
379
+ }
380
+
381
+ /**
382
+ * Read values from Senec App API
383
+ */
384
+ async pollSenecAppApi(retry) {
385
+ var interval = this.config.api_interval * 60000;
386
+ this.log.debug("Polling API ...");
387
+ var body = "";
388
+ try {
389
+ for (let i = 0; i < apiKnownSystems.length; i++) {
390
+ // dashboard
391
+ var url = apiSystemsUrl + "/" + apiKnownSystems[i] + "/dashboard";
392
+ body = await this.doGet(url, "", this, this.config.pollingTimeout, false);
393
+ await this.decodeDashboard(apiKnownSystems[i], JSON.parse(body));
394
+ // // wallboxes - only if wallbox exists? - Without: error 500
395
+ //var url = apiSystemsUrl + "/" + apiKnownSystems[i] + "/wallboxes/1";
396
+ //body = await this.doGet(url, "", this, this.config.pollingTimeout, false);
397
+ //this.log.info("Abilities: " + body);
398
+ //await this.decodeWallbox(apiKnownSystems[i], JSON.parse(body));
399
+ }
400
+ retry = 0;
401
+ if (unloaded) return;
402
+ this.timerAPI = setTimeout(() => this.pollSenecAppApi(retry), interval);
403
+ } catch (error) {
404
+ if ((retry == this.config.retries) && this.config.retries < 999) {
405
+ this.log.error("Error reading from Senec AppAPI. Retried " + retry + " times. Giving up now. Check config and restart adapter. (" + error + ")");
406
+ this.setState('info.connection', false, true);
407
+ } else {
408
+ retry += 1;
409
+ this.log.warn("Error reading from Senec AppAPI. Retry " + retry + "/" + this.config.retries + " in " + (interval * this.config.retrymultiplier * retry) / 1000 + " seconds! (" + error + ")");
410
+ this.timerAPI = setTimeout(() => this.pollSenecAppApi(retry), interval * this.config.retrymultiplier * retry);
411
+ }
412
+ }
413
+ }
414
+
415
+ async decodeDashboard(system, obj) {
416
+ const pfx = "_api.Anlagen." + system + ".Dashboard.";
417
+ for (const[key, value] of Object.entries(obj)) {
418
+ if (key == "zeitstempel" || key == "electricVehicleConnected") {
419
+ this.doState(pfx + key, value, "", "", false);
420
+ } else {
421
+ for (const[key2, value2] of Object.entries(value)) {
422
+ this.doState(pfx + key + "." + key2, value2.wert, "", value2.einheit, false);
423
+ }
424
+ }
425
+ }
306
426
 
307
427
  }
308
428
 
@@ -408,7 +528,7 @@ class Senec extends utils.Adapter {
408
528
  if (value2 !== "VARIABLE_NOT_FOUND" && key2 !== "OBJECT_NOT_FOUND") {
409
529
  const key = key1 + '.' + key2;
410
530
  if (state_attr[key] === undefined) {
411
- this.log.info('REPORT_TO_DEV: State attribute definition missing for: ' + key + ', Val: ' + value2);
531
+ this.log.debug('REPORT_TO_DEV: State attribute definition missing for: ' + key + ', Val: ' + value2);
412
532
  }
413
533
  const desc = (state_attr[key] !== undefined) ? state_attr[key].name : key2;
414
534
  const unit = (state_attr[key] !== undefined) ? state_attr[key].unit : "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.senec",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Senec Home",
5
5
  "author": {
6
6
  "name": "NoBl",
@@ -28,21 +28,21 @@
28
28
  "@iobroker/adapter-core": "^2.6.8"
29
29
  },
30
30
  "devDependencies": {
31
- "@alcalzone/release-script": "^3.5.9",
31
+ "@alcalzone/release-script": "^3.6.0",
32
32
  "@alcalzone/release-script-plugin-iobroker": "^3.5.9",
33
33
  "@alcalzone/release-script-plugin-license": "^3.5.9",
34
34
  "@alcalzone/release-script-plugin-manual-review": "^3.5.9",
35
35
  "@iobroker/adapter-dev": "^1.2.0",
36
36
  "@iobroker/testing": "^4.1.0",
37
- "@tsconfig/node14": "^1.0.3",
37
+ "@tsconfig/node14": "^14.1.0",
38
38
  "@types/chai": "^4.3.5",
39
39
  "@types/chai-as-promised": "^7.1.5",
40
40
  "@types/mocha": "^10.0.1",
41
- "@types/node": "^20.4.10",
41
+ "@types/node": "^20.5.7",
42
42
  "@types/proxyquire": "^1.3.28",
43
- "@types/sinon": "^10.0.13",
43
+ "@types/sinon": "^10.0.16",
44
44
  "@types/sinon-chai": "^3.2.9",
45
- "chai": "^4.3.7",
45
+ "chai": "^4.3.8",
46
46
  "chai-as-promised": "^7.1.1",
47
47
  "eslint": "^8.47.0",
48
48
  "mocha": "^10.2.0",