iobroker.device-watcher 2.0.3 → 2.2.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 +24 -2
- package/admin/i18n/de/translations.json +32 -14
- package/admin/i18n/en/translations.json +16 -2
- package/admin/i18n/es/translations.json +19 -1
- package/admin/i18n/fr/translations.json +19 -1
- package/admin/i18n/it/translations.json +19 -1
- package/admin/i18n/nl/translations.json +19 -1
- package/admin/i18n/pl/translations.json +19 -1
- package/admin/i18n/pt/translations.json +19 -1
- package/admin/i18n/ru/translations.json +19 -1
- package/admin/i18n/uk/translations.json +20 -2
- package/admin/i18n/zh-cn/translations.json +19 -1
- package/admin/jsonConfig.json +234 -20
- package/admin/words.js +89 -71
- package/io-package.json +101 -31
- package/lib/arrApart.js +40 -1
- package/main.js +965 -514
- package/package.json +10 -10
- package/admin/index_m.html +0 -56
- package/admin/style.css +0 -32
package/main.js
CHANGED
|
@@ -10,7 +10,7 @@ const schedule = require('node-schedule');
|
|
|
10
10
|
const arrApart = require('./lib/arrApart.js'); // list of supported adapters
|
|
11
11
|
|
|
12
12
|
// Sentry error reporting, disable when testing code!
|
|
13
|
-
const enableSendSentry =
|
|
13
|
+
const enableSendSentry = false;
|
|
14
14
|
|
|
15
15
|
// indicator if the adapter is running or not (for intervall/shedule)
|
|
16
16
|
let isUnloaded = false;
|
|
@@ -33,23 +33,20 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
33
33
|
this.blacklistNotify = [];
|
|
34
34
|
this.arrDev = [];
|
|
35
35
|
this.adapterSelected = [];
|
|
36
|
+
this.upgradableList = [];
|
|
36
37
|
|
|
37
38
|
// raw arrays
|
|
38
39
|
this.listAllDevicesRaw = [];
|
|
39
40
|
this.batteryLowPoweredRaw = [];
|
|
40
41
|
this.offlineDevicesRaw = [];
|
|
41
42
|
|
|
42
|
-
// raw counts
|
|
43
|
-
this.offlineDevicesCountRaw = 0;
|
|
44
|
-
this.offlineDevicesCountRawOld = 0;
|
|
45
|
-
this.lowBatteryPoweredCountRaw = 0;
|
|
46
|
-
|
|
47
43
|
// counts
|
|
48
44
|
this.offlineDevicesCount = 0;
|
|
49
45
|
this.deviceCounter = 0;
|
|
50
46
|
this.linkQualityCount = 0;
|
|
51
47
|
this.batteryPoweredCount = 0;
|
|
52
48
|
this.lowBatteryPoweredCount = 0;
|
|
49
|
+
this.upgradableDevicesCount = 0;
|
|
53
50
|
|
|
54
51
|
// Interval timer
|
|
55
52
|
this.refreshDataTimeout = null;
|
|
@@ -74,6 +71,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
74
71
|
|
|
75
72
|
this.supAdapter = {
|
|
76
73
|
alexa2: this.config.alexa2Devices,
|
|
74
|
+
apcups: this.config.apcupsDevices,
|
|
77
75
|
ble: this.config.bleDevices,
|
|
78
76
|
deconz: this.config.deconzDevices,
|
|
79
77
|
enocean: this.config.enoceanDevices,
|
|
@@ -94,6 +92,9 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
94
92
|
mihome: this.config.mihomeDevices,
|
|
95
93
|
mihomeGW: this.config.mihomeDevices,
|
|
96
94
|
mihomeVacuum: this.config.mihomeVacuumDevices,
|
|
95
|
+
mqttClientZigbee2Mqtt: this.config.mqttClientZigbee2MqttDevices,
|
|
96
|
+
mqttNuki: this.config.mqttNukiDevices,
|
|
97
|
+
musiccast: this.config.musiccastDevices,
|
|
97
98
|
netatmo: this.config.netatmoDevices,
|
|
98
99
|
nukiExt: this.config.nukiExtDevices,
|
|
99
100
|
nut: this.config.nutDevices,
|
|
@@ -117,6 +118,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
117
118
|
|
|
118
119
|
this.maxMinutes = {
|
|
119
120
|
alexa2: this.config.alexa2MaxMinutes,
|
|
121
|
+
apcups: this.config.apcupsMaxMinutes,
|
|
120
122
|
ble: this.config.bleMaxMinutes,
|
|
121
123
|
deconz: this.config.deconzMaxMinutes,
|
|
122
124
|
enocean: this.config.enoceanMaxMinutes,
|
|
@@ -137,6 +139,9 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
137
139
|
mihome: this.config.mihomeMaxMinutes,
|
|
138
140
|
mihomeGW: this.config.mihomeMaxMinutes,
|
|
139
141
|
mihomeVacuum: this.config.mihomeVacuumMaxMinutes,
|
|
142
|
+
mqttClientZigbee2Mqtt: this.config.mqttClientZigbee2MqttMaxMinutes,
|
|
143
|
+
mqttNuki: this.config.mqttNukiMaxMinutes,
|
|
144
|
+
musiccast: this.config.musiccastMaxMinutes,
|
|
140
145
|
netatmo: this.config.netatmoMaxMinutes,
|
|
141
146
|
nukiExt: this.config.nukiextendMaxMinutes,
|
|
142
147
|
nut: this.config.nutMaxMinutes,
|
|
@@ -188,35 +193,41 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
188
193
|
}
|
|
189
194
|
|
|
190
195
|
//create and fill datapoints for each adapter if selected
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (
|
|
195
|
-
if (this.
|
|
196
|
+
if (this.config.createOwnFolder) {
|
|
197
|
+
try {
|
|
198
|
+
for (const [id] of Object.entries(arrApart)) {
|
|
199
|
+
if (!isUnloaded) {
|
|
200
|
+
if (this.supAdapter !== undefined && this.supAdapter[id]) {
|
|
196
201
|
await this.createDPsForEachAdapter(id);
|
|
197
202
|
if (this.config.createHtmlList) await this.createHtmlListDatapoints(id);
|
|
198
|
-
this.log.debug(`Created datapoints for ${
|
|
203
|
+
this.log.debug(`Created datapoints for ${this.capitalize(id)}`);
|
|
199
204
|
}
|
|
205
|
+
} else {
|
|
206
|
+
return; // cancel run if unloaded was called.
|
|
200
207
|
}
|
|
201
|
-
} else {
|
|
202
|
-
return; // cancel run if unloaded was called.
|
|
203
208
|
}
|
|
209
|
+
} catch (error) {
|
|
210
|
+
this.errorReporting('[onReady - create and fill datapoints for each adapter]', error);
|
|
204
211
|
}
|
|
205
|
-
} catch (error) {
|
|
206
|
-
this.errorReporting('[onReady - create and fill datapoints for each adapter]', error);
|
|
207
212
|
}
|
|
208
213
|
|
|
209
214
|
// create HTML list
|
|
210
215
|
if (this.config.createHtmlList) await this.createHtmlListDatapoints();
|
|
211
216
|
|
|
212
|
-
//
|
|
217
|
+
//read data first at start
|
|
218
|
+
await this.main();
|
|
219
|
+
|
|
220
|
+
// update last contact data in interval
|
|
213
221
|
await this.refreshData();
|
|
214
222
|
|
|
215
223
|
// send overview for low battery devices
|
|
216
|
-
if (this.config.
|
|
224
|
+
if (this.config.checkSendBatteryMsgDaily) await this.sendBatteryNotifyShedule();
|
|
217
225
|
|
|
218
226
|
// send overview of offline devices
|
|
219
227
|
if (this.config.checkSendOfflineMsgDaily) await this.sendOfflineNotificationsShedule();
|
|
228
|
+
|
|
229
|
+
// send overview of upgradeable devices
|
|
230
|
+
if (this.config.checkSendUpgradeMsgDaily) await this.sendUpgradeNotificationsShedule();
|
|
220
231
|
} catch (error) {
|
|
221
232
|
this.errorReporting('[onReady]', error);
|
|
222
233
|
this.terminate ? this.terminate(15) : process.exit(15);
|
|
@@ -228,13 +239,106 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
228
239
|
* @param {string} id
|
|
229
240
|
* @param {ioBroker.State | null | undefined} state
|
|
230
241
|
*/
|
|
231
|
-
onStateChange(id, state) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
this.log.
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
242
|
+
async onStateChange(id, state) {
|
|
243
|
+
// Admin JSON for Adapter updates
|
|
244
|
+
if (id && state) {
|
|
245
|
+
this.log.debug(`State changed: ${id} changed ${state.val}`);
|
|
246
|
+
let batteryData;
|
|
247
|
+
let oldLowBatState;
|
|
248
|
+
let contactData;
|
|
249
|
+
let oldStatus;
|
|
250
|
+
let oldSignalStrength;
|
|
251
|
+
|
|
252
|
+
for (const i of this.listAllDevicesRaw) {
|
|
253
|
+
// On statechange update available datapoint
|
|
254
|
+
switch (id) {
|
|
255
|
+
case i.UpdateDP:
|
|
256
|
+
if (state.val) {
|
|
257
|
+
i.Upgradable = state.val;
|
|
258
|
+
|
|
259
|
+
await this.createLists();
|
|
260
|
+
|
|
261
|
+
await this.writeDatapoints();
|
|
262
|
+
await this.sendDeviceUpdatesNotification(i.Device, i.Adapter, i.Path);
|
|
263
|
+
}
|
|
264
|
+
break;
|
|
265
|
+
|
|
266
|
+
case i.SignalStrengthDP:
|
|
267
|
+
oldSignalStrength = i.SignalStrength;
|
|
268
|
+
i.SignalStrength = await this.calculateSignalStrength(state, i.adapterID);
|
|
269
|
+
if (oldSignalStrength !== i.SignalStrength) {
|
|
270
|
+
await this.createLists();
|
|
271
|
+
|
|
272
|
+
await this.writeDatapoints();
|
|
273
|
+
}
|
|
274
|
+
break;
|
|
275
|
+
|
|
276
|
+
case i.batteryDP:
|
|
277
|
+
oldLowBatState = i.LowBat;
|
|
278
|
+
batteryData = await this.getBatteryData(state.val, oldLowBatState, i.adapterID);
|
|
279
|
+
|
|
280
|
+
i.Battery = batteryData[0];
|
|
281
|
+
i.BatteryRaw = batteryData[2];
|
|
282
|
+
i.LowBat = await this.setLowbatIndicator(state.val, undefined, i.LowBatDP);
|
|
283
|
+
|
|
284
|
+
if (i.LowBat && oldLowBatState !== i.LowBat) {
|
|
285
|
+
await this.createLists();
|
|
286
|
+
|
|
287
|
+
await this.writeDatapoints();
|
|
288
|
+
if (this.config.checkSendBatteryMsg) {
|
|
289
|
+
await this.sendLowBatNoticiation(i.Device, i.Adapter, i.Battery, i.Path);
|
|
290
|
+
}
|
|
291
|
+
} else if (!i.LowBat && oldLowBatState !== i.LowBat) {
|
|
292
|
+
await this.createLists();
|
|
293
|
+
|
|
294
|
+
await this.writeDatapoints();
|
|
295
|
+
}
|
|
296
|
+
break;
|
|
297
|
+
|
|
298
|
+
case i.LowBatDP:
|
|
299
|
+
oldLowBatState = i.LowBat;
|
|
300
|
+
batteryData = await this.getBatteryData(i.BatteryRaw, state.val, i.adapterID);
|
|
301
|
+
i.Battery = batteryData[0];
|
|
302
|
+
i.BatteryRaw = batteryData[2];
|
|
303
|
+
i.LowBat = await this.setLowbatIndicator(i.BatteryRaw, state.val, i.LowBatDP);
|
|
304
|
+
|
|
305
|
+
if (i.LowBat && oldLowBatState !== i.LowBat) {
|
|
306
|
+
await this.createLists();
|
|
307
|
+
|
|
308
|
+
await this.writeDatapoints();
|
|
309
|
+
if (this.config.checkSendBatteryMsg) {
|
|
310
|
+
await this.sendLowBatNoticiation(i.Device, i.Adapter, i.Battery, i.Path);
|
|
311
|
+
}
|
|
312
|
+
} else if (!i.LowBat && oldLowBatState !== i.LowBat) {
|
|
313
|
+
await this.createLists();
|
|
314
|
+
|
|
315
|
+
await this.writeDatapoints();
|
|
316
|
+
}
|
|
317
|
+
break;
|
|
318
|
+
case i.UnreachDP:
|
|
319
|
+
case i.DeviceStateSelectorDP:
|
|
320
|
+
case i.rssiPeerSelectorDP:
|
|
321
|
+
case i.Path:
|
|
322
|
+
oldStatus = i.Status;
|
|
323
|
+
i.UnreachState = await this.getInitValue(i.UnreachDP);
|
|
324
|
+
contactData = await this.getOnlineState(i.Path, i.adapterID, i.UnreachDP, i.SignalStrength, i.UnreachState, i.DeviceStateSelectorDP, i.rssiPeerSelectorDP);
|
|
325
|
+
if (contactData !== undefined) {
|
|
326
|
+
i.LastContact = contactData[0];
|
|
327
|
+
i.Status = contactData[1];
|
|
328
|
+
i.SignalStrength = contactData[2];
|
|
329
|
+
}
|
|
330
|
+
if (i.Status !== oldStatus) {
|
|
331
|
+
await this.createLists();
|
|
332
|
+
|
|
333
|
+
await this.writeDatapoints();
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (i.Status && oldStatus !== i.Status && this.config.checkSendOfflineMsg) {
|
|
337
|
+
await this.sendOfflineNotifications(i.Device, i.Adapter, i.Status, i.LastContact, i.Path);
|
|
338
|
+
}
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
238
342
|
}
|
|
239
343
|
}
|
|
240
344
|
|
|
@@ -274,11 +378,12 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
274
378
|
|
|
275
379
|
/**
|
|
276
380
|
* refresh data with interval
|
|
381
|
+
* is neccessary to refresh lastContact data, especially of devices without state changes
|
|
277
382
|
*/
|
|
278
383
|
async refreshData() {
|
|
279
384
|
const nextTimeout = this.config.updateinterval * 1000;
|
|
280
385
|
|
|
281
|
-
await this.
|
|
386
|
+
await this.checkLastContact();
|
|
282
387
|
|
|
283
388
|
// Clear existing timeout
|
|
284
389
|
if (this.refreshDataTimeout) {
|
|
@@ -303,25 +408,6 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
303
408
|
async main() {
|
|
304
409
|
this.log.debug(`Function started: ${this.main.name}`);
|
|
305
410
|
|
|
306
|
-
// fill datapoints for each adapter if selected
|
|
307
|
-
try {
|
|
308
|
-
for (const [id] of Object.entries(arrApart)) {
|
|
309
|
-
if (!isUnloaded) {
|
|
310
|
-
if (this.supAdapter !== undefined && this.supAdapter[id]) {
|
|
311
|
-
if (this.config.createOwnFolder) {
|
|
312
|
-
await this.createDataForEachAdapter(id);
|
|
313
|
-
this.log.debug(`Created and filled data for ${await this.capitalize(id)}`);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
} else {
|
|
317
|
-
this.log.warn('broke up');
|
|
318
|
-
return; // cancel run if unloaded was called.
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
} catch (error) {
|
|
322
|
-
this.errorReporting('[main - create and fill datapoints for each adapter]', error);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
411
|
// fill counts and lists of all selected adapter
|
|
326
412
|
try {
|
|
327
413
|
await this.createDataOfAllAdapter();
|
|
@@ -330,6 +416,20 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
330
416
|
this.errorReporting('[main - create data of all adapter]', error);
|
|
331
417
|
}
|
|
332
418
|
|
|
419
|
+
// fill datapoints for each adapter if selected
|
|
420
|
+
if (this.config.createOwnFolder) {
|
|
421
|
+
try {
|
|
422
|
+
for (const [id] of Object.entries(arrApart)) {
|
|
423
|
+
if (this.supAdapter !== undefined && this.supAdapter[id]) {
|
|
424
|
+
await this.createDataForEachAdapter(id);
|
|
425
|
+
this.log.debug(`Created and filled data for ${this.capitalize(id)}`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
} catch (error) {
|
|
429
|
+
this.errorReporting('[main - create and fill datapoints for each adapter]', error);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
333
433
|
this.log.debug(`Function finished: ${this.main.name}`);
|
|
334
434
|
} //<--End of main function
|
|
335
435
|
|
|
@@ -426,16 +526,22 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
426
526
|
const shortDeviceObject = await this.getForeignObjectAsync(shortCurrDeviceString);
|
|
427
527
|
const shortshortDeviceObject = await this.getForeignObjectAsync(shortshortCurrDeviceString);
|
|
428
528
|
let deviceName;
|
|
529
|
+
let folderName;
|
|
530
|
+
let deviceID;
|
|
429
531
|
|
|
430
532
|
// Get ID with currDeviceString from datapoint
|
|
431
533
|
switch (this.arrDev[i].adapterID) {
|
|
432
534
|
// Get ID for Switchbot and ESPHome Devices
|
|
433
535
|
case 'switchbotBle':
|
|
434
536
|
case 'esphome':
|
|
435
|
-
case '
|
|
537
|
+
case 'apcups':
|
|
436
538
|
deviceName = await this.getInitValue(currDeviceString + this.arrDev[i].id);
|
|
437
539
|
break;
|
|
438
540
|
|
|
541
|
+
case 'fullybrowser':
|
|
542
|
+
deviceName = (await this.getInitValue(currDeviceString + this.arrDev[i].id)) + ' ' + (await this.getInitValue(currDeviceString + this.arrDev[i].id2));
|
|
543
|
+
break;
|
|
544
|
+
|
|
439
545
|
// Get ID with short currDeviceString from objectjson
|
|
440
546
|
case 'hueExt':
|
|
441
547
|
case 'hmrpc':
|
|
@@ -456,7 +562,9 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
456
562
|
// Get ID with short currDeviceString from datapoint
|
|
457
563
|
case 'mihomeVacuum':
|
|
458
564
|
case 'roomba':
|
|
459
|
-
|
|
565
|
+
folderName = shortCurrDeviceString.slice(shortCurrDeviceString.lastIndexOf('.') + 1);
|
|
566
|
+
deviceID = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].id);
|
|
567
|
+
deviceName = `I${folderName} ${deviceID}`;
|
|
460
568
|
break;
|
|
461
569
|
|
|
462
570
|
//Get ID of foldername
|
|
@@ -495,6 +603,163 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
495
603
|
}
|
|
496
604
|
}
|
|
497
605
|
|
|
606
|
+
/**
|
|
607
|
+
* calculate Signalstrength
|
|
608
|
+
* @param {object} deviceQualityState - State value
|
|
609
|
+
* @param {object} adapterID - adapter name
|
|
610
|
+
*/
|
|
611
|
+
async calculateSignalStrength(deviceQualityState, adapterID) {
|
|
612
|
+
let linkQuality;
|
|
613
|
+
let mqttNukiValue;
|
|
614
|
+
|
|
615
|
+
if (deviceQualityState != null) {
|
|
616
|
+
switch (typeof deviceQualityState.val) {
|
|
617
|
+
case 'number':
|
|
618
|
+
if (this.config.trueState) {
|
|
619
|
+
linkQuality = deviceQualityState.val;
|
|
620
|
+
} else {
|
|
621
|
+
switch (adapterID) {
|
|
622
|
+
case 'roomba':
|
|
623
|
+
case 'sonoff':
|
|
624
|
+
linkQuality = deviceQualityState.val + '%'; // If quality state is already an percent value
|
|
625
|
+
break;
|
|
626
|
+
case 'lupusec':
|
|
627
|
+
linkQuality = deviceQualityState.val;
|
|
628
|
+
break;
|
|
629
|
+
|
|
630
|
+
default:
|
|
631
|
+
// If quality state is an RSSI value calculate in percent:
|
|
632
|
+
if (deviceQualityState.val == -255) {
|
|
633
|
+
linkQuality = ' - ';
|
|
634
|
+
} else if (deviceQualityState.val < 0) {
|
|
635
|
+
linkQuality = Math.min(Math.max(2 * (deviceQualityState.val + 100), 0), 100) + '%';
|
|
636
|
+
// If Quality State is an value between 0-255 (zigbee) calculate in percent:
|
|
637
|
+
} else if (deviceQualityState.val >= 0) {
|
|
638
|
+
linkQuality = parseFloat(((100 / 255) * deviceQualityState.val).toFixed(0)) + '%';
|
|
639
|
+
}
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
break;
|
|
644
|
+
|
|
645
|
+
case 'string':
|
|
646
|
+
switch (adapterID) {
|
|
647
|
+
case 'netatmo':
|
|
648
|
+
// for Netatmo devices
|
|
649
|
+
linkQuality = deviceQualityState.val;
|
|
650
|
+
break;
|
|
651
|
+
case 'nukiExt':
|
|
652
|
+
linkQuality = ' - ';
|
|
653
|
+
break;
|
|
654
|
+
case 'mqttNuki':
|
|
655
|
+
linkQuality = deviceQualityState.val;
|
|
656
|
+
mqttNukiValue = parseInt(linkQuality);
|
|
657
|
+
if (this.config.trueState) {
|
|
658
|
+
linkQuality = deviceQualityState.val;
|
|
659
|
+
} else if (mqttNukiValue < 0) {
|
|
660
|
+
linkQuality = Math.min(Math.max(2 * (mqttNukiValue + 100), 0), 100) + '%';
|
|
661
|
+
// If Quality State is an value between 0-255 (zigbee) calculate in percent:
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
} else {
|
|
667
|
+
linkQuality = ' - ';
|
|
668
|
+
}
|
|
669
|
+
return linkQuality;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* get battery data
|
|
674
|
+
* @param {object} deviceBatteryState - State value
|
|
675
|
+
* @param {object} deviceLowBatState - State value
|
|
676
|
+
* @param {object} adapterID - adapter name
|
|
677
|
+
*/
|
|
678
|
+
async getBatteryData(deviceBatteryState, deviceLowBatState, adapterID) {
|
|
679
|
+
let batteryHealthRaw;
|
|
680
|
+
let batteryHealth;
|
|
681
|
+
let isBatteryDevice;
|
|
682
|
+
|
|
683
|
+
if (deviceBatteryState === undefined) {
|
|
684
|
+
if (deviceLowBatState !== undefined) {
|
|
685
|
+
switch (deviceLowBatState) {
|
|
686
|
+
case 'none':
|
|
687
|
+
break;
|
|
688
|
+
default:
|
|
689
|
+
if (deviceLowBatState !== true || deviceLowBatState === 'NORMAL' || deviceLowBatState === 1) {
|
|
690
|
+
batteryHealth = 'ok';
|
|
691
|
+
isBatteryDevice = true;
|
|
692
|
+
} else {
|
|
693
|
+
batteryHealth = 'low';
|
|
694
|
+
isBatteryDevice = true;
|
|
695
|
+
}
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
} else {
|
|
699
|
+
batteryHealth = ' - ';
|
|
700
|
+
}
|
|
701
|
+
} else {
|
|
702
|
+
switch (adapterID) {
|
|
703
|
+
case 'hmrpc':
|
|
704
|
+
if (deviceBatteryState === 0 || (deviceBatteryState && deviceBatteryState >= 6)) {
|
|
705
|
+
batteryHealth = ' - ';
|
|
706
|
+
} else {
|
|
707
|
+
batteryHealth = deviceBatteryState + 'V';
|
|
708
|
+
batteryHealthRaw = deviceBatteryState;
|
|
709
|
+
isBatteryDevice = true;
|
|
710
|
+
}
|
|
711
|
+
break;
|
|
712
|
+
default:
|
|
713
|
+
batteryHealth = deviceBatteryState + '%';
|
|
714
|
+
batteryHealthRaw = deviceBatteryState;
|
|
715
|
+
isBatteryDevice = true;
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return [batteryHealth, isBatteryDevice, batteryHealthRaw];
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
*set low bat indicator
|
|
724
|
+
* @param {object} deviceBatteryState
|
|
725
|
+
* @param {object} deviceLowBatState
|
|
726
|
+
* @param {object} isLowBatDP
|
|
727
|
+
*/
|
|
728
|
+
|
|
729
|
+
async setLowbatIndicator(deviceBatteryState, deviceLowBatState, isLowBatDP) {
|
|
730
|
+
let lowBatIndicator = false;
|
|
731
|
+
/*=============================================
|
|
732
|
+
= Set Lowbat indicator =
|
|
733
|
+
=============================================*/
|
|
734
|
+
if (deviceLowBatState !== null && isLowBatDP !== 'none') {
|
|
735
|
+
switch (typeof deviceLowBatState) {
|
|
736
|
+
case 'number':
|
|
737
|
+
if (deviceLowBatState === 0) {
|
|
738
|
+
lowBatIndicator = true;
|
|
739
|
+
}
|
|
740
|
+
break;
|
|
741
|
+
|
|
742
|
+
case 'string':
|
|
743
|
+
if (deviceLowBatState !== 'NORMAL') {
|
|
744
|
+
// Tado devices
|
|
745
|
+
lowBatIndicator = true;
|
|
746
|
+
}
|
|
747
|
+
break;
|
|
748
|
+
|
|
749
|
+
case 'boolean':
|
|
750
|
+
if (deviceLowBatState) {
|
|
751
|
+
lowBatIndicator = true;
|
|
752
|
+
}
|
|
753
|
+
break;
|
|
754
|
+
}
|
|
755
|
+
} else {
|
|
756
|
+
if (deviceBatteryState < this.config.minWarnBatterie) {
|
|
757
|
+
lowBatIndicator = true;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
return lowBatIndicator;
|
|
761
|
+
}
|
|
762
|
+
|
|
498
763
|
/**
|
|
499
764
|
* get Last Contact
|
|
500
765
|
* @param {object} selector - Selector
|
|
@@ -514,109 +779,167 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
514
779
|
}
|
|
515
780
|
|
|
516
781
|
/**
|
|
517
|
-
*
|
|
782
|
+
* get online state and time
|
|
783
|
+
*
|
|
518
784
|
*/
|
|
519
|
-
async
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
this.batteryLowPowered = [];
|
|
523
|
-
this.listAllDevices = [];
|
|
524
|
-
this.offlineDevices = [];
|
|
525
|
-
this.batteryLowPoweredRaw = [];
|
|
526
|
-
this.offlineDevicesRaw = [];
|
|
785
|
+
async getOnlineState(id, adapterID, unreachDP, linkQuality, deviceUnreachState, deviceStateSelectorDP, rssiPeerSelectorDP) {
|
|
786
|
+
let lastContactString;
|
|
787
|
+
let deviceState = 'Online';
|
|
527
788
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
this.
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
Path: device['Path'],
|
|
543
|
-
Device: device['Device'],
|
|
544
|
-
Adapter: device['Adapter'],
|
|
545
|
-
'Last contact': device['Last contact'],
|
|
546
|
-
});
|
|
547
|
-
}
|
|
789
|
+
try {
|
|
790
|
+
const deviceMainSelector = await this.getForeignStateAsync(id);
|
|
791
|
+
if (deviceMainSelector) {
|
|
792
|
+
const deviceUnreachSelector = await this.getForeignStateAsync(unreachDP);
|
|
793
|
+
const deviceStateSelector = await this.getForeignStateAsync(deviceStateSelectorDP); // for hmrpc devices
|
|
794
|
+
const rssiPeerSelector = await this.getForeignStateAsync(rssiPeerSelectorDP);
|
|
795
|
+
const lastContact = await this.getTimestamp(deviceMainSelector.ts);
|
|
796
|
+
const lastDeviceUnreachStateChange = deviceUnreachSelector != undefined ? await this.getTimestamp(deviceUnreachSelector.lc) : await this.getTimestamp(deviceMainSelector.ts);
|
|
797
|
+
// If there is no contact since user sets minutes add device in offline list
|
|
798
|
+
// calculate to days after 48 hours
|
|
799
|
+
switch (unreachDP) {
|
|
800
|
+
case 'none':
|
|
801
|
+
lastContactString = await this.getLastContact(deviceMainSelector.ts);
|
|
802
|
+
break;
|
|
548
803
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
576
|
-
// Low Bat lists
|
|
577
|
-
if (device['LowBat'] && device['Status'] !== 'Offline') {
|
|
578
|
-
this.batteryLowPowered.push({
|
|
579
|
-
Device: device['Device'],
|
|
580
|
-
Adapter: device['Adapter'],
|
|
581
|
-
Battery: device['Battery'],
|
|
582
|
-
});
|
|
804
|
+
default:
|
|
805
|
+
//State changed
|
|
806
|
+
if (adapterID === 'hmrpc') {
|
|
807
|
+
if (linkQuality !== ' - ') {
|
|
808
|
+
if (deviceUnreachState) {
|
|
809
|
+
lastContactString = await this.getLastContact(deviceMainSelector.lc);
|
|
810
|
+
} else {
|
|
811
|
+
lastContactString = await this.getLastContact(deviceMainSelector.ts);
|
|
812
|
+
}
|
|
813
|
+
} else {
|
|
814
|
+
if (deviceStateSelector) {
|
|
815
|
+
// because old hm devices don't send rssi states
|
|
816
|
+
lastContactString = await this.getLastContact(deviceStateSelector.ts);
|
|
817
|
+
} else if (rssiPeerSelector) {
|
|
818
|
+
// because old hm sensors don't send rssi/state values
|
|
819
|
+
lastContactString = await this.getLastContact(rssiPeerSelector.ts);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
} else {
|
|
823
|
+
if (!deviceUnreachState) {
|
|
824
|
+
lastContactString = await this.getLastContact(deviceMainSelector.lc);
|
|
825
|
+
} else {
|
|
826
|
+
lastContactString = await this.getLastContact(deviceMainSelector.ts);
|
|
827
|
+
}
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
583
830
|
}
|
|
584
831
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
832
|
+
/*=============================================
|
|
833
|
+
= Set Online Status =
|
|
834
|
+
=============================================*/
|
|
835
|
+
if (this.maxMinutes !== undefined) {
|
|
836
|
+
switch (adapterID) {
|
|
837
|
+
case 'hmrpc':
|
|
838
|
+
case 'hmiP':
|
|
839
|
+
case 'maxcube':
|
|
840
|
+
if (this.maxMinutes[adapterID] <= 0) {
|
|
841
|
+
if (deviceUnreachState) {
|
|
842
|
+
deviceState = 'Offline'; //set online state to offline
|
|
843
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
844
|
+
}
|
|
845
|
+
} else if (lastDeviceUnreachStateChange > this.maxMinutes[adapterID] && deviceUnreachState) {
|
|
846
|
+
deviceState = 'Offline'; //set online state to offline
|
|
847
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
848
|
+
}
|
|
849
|
+
break;
|
|
850
|
+
case 'apcups':
|
|
851
|
+
case 'hue':
|
|
852
|
+
case 'hueExt':
|
|
853
|
+
case 'ping':
|
|
854
|
+
case 'deconz':
|
|
855
|
+
case 'shelly':
|
|
856
|
+
case 'sonoff':
|
|
857
|
+
case 'unifi':
|
|
858
|
+
case 'zigbee':
|
|
859
|
+
case 'zigbee2MQTT':
|
|
860
|
+
if (this.maxMinutes[adapterID] <= 0) {
|
|
861
|
+
if (!deviceUnreachState) {
|
|
862
|
+
deviceState = 'Offline'; //set online state to offline
|
|
863
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
864
|
+
}
|
|
865
|
+
} else if (!deviceUnreachState && lastDeviceUnreachStateChange > this.maxMinutes[adapterID]) {
|
|
866
|
+
deviceState = 'Offline'; //set online state to offline
|
|
867
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
868
|
+
}
|
|
869
|
+
break;
|
|
870
|
+
case 'mqttClientZigbee2Mqtt':
|
|
871
|
+
if (this.maxMinutes[adapterID] <= 0) {
|
|
872
|
+
if (deviceUnreachState !== 'online') {
|
|
873
|
+
deviceState = 'Offline'; //set online state to offline
|
|
874
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
875
|
+
}
|
|
876
|
+
} else if (deviceUnreachState !== 'online' && lastDeviceUnreachStateChange > this.maxMinutes[adapterID]) {
|
|
877
|
+
deviceState = 'Offline'; //set online state to offline
|
|
878
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
879
|
+
}
|
|
880
|
+
break;
|
|
881
|
+
case 'mihome':
|
|
882
|
+
if (deviceUnreachState !== undefined) {
|
|
883
|
+
if (this.maxMinutes[adapterID] <= 0) {
|
|
884
|
+
if (!deviceUnreachState) {
|
|
885
|
+
deviceState = 'Offline'; //set online state to offline
|
|
886
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
887
|
+
}
|
|
888
|
+
} else if (lastContact > this.maxMinutes[adapterID]) {
|
|
889
|
+
deviceState = 'Offline'; //set online state to offline
|
|
890
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
891
|
+
}
|
|
892
|
+
} else {
|
|
893
|
+
if (this.config.mihomeMaxMinutes <= 0) {
|
|
894
|
+
if (this.maxMinutes[adapterID] <= 0) {
|
|
895
|
+
deviceState = 'Offline'; //set online state to offline
|
|
896
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
897
|
+
}
|
|
898
|
+
} else if (lastContact > this.maxMinutes[adapterID]) {
|
|
899
|
+
deviceState = 'Offline'; //set online state to offline
|
|
900
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
break;
|
|
904
|
+
default:
|
|
905
|
+
if (this.maxMinutes[adapterID] <= 0) {
|
|
906
|
+
if (!deviceUnreachState) {
|
|
907
|
+
deviceState = 'Offline'; //set online state to offline
|
|
908
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
909
|
+
}
|
|
910
|
+
} else if (lastContact > this.maxMinutes[adapterID]) {
|
|
911
|
+
deviceState = 'Offline'; //set online state to offline
|
|
912
|
+
linkQuality = '0%'; // set linkQuality to nothing
|
|
913
|
+
}
|
|
914
|
+
break;
|
|
915
|
+
}
|
|
592
916
|
}
|
|
593
917
|
}
|
|
918
|
+
return [lastContactString, deviceState, linkQuality];
|
|
919
|
+
} catch (error) {
|
|
920
|
+
this.errorReporting('[getLastContact]', error);
|
|
594
921
|
}
|
|
595
922
|
}
|
|
596
923
|
|
|
597
924
|
/**
|
|
598
|
-
*
|
|
925
|
+
* when was last contact of device
|
|
599
926
|
*/
|
|
600
|
-
async
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
// raws
|
|
617
|
-
|
|
618
|
-
// Count how many devcies are offline
|
|
619
|
-
this.offlineDevicesCountRaw = this.offlineDevicesRaw.length;
|
|
927
|
+
async checkLastContact() {
|
|
928
|
+
for (const i of this.listAllDevicesRaw) {
|
|
929
|
+
const oldContactState = i.Status;
|
|
930
|
+
i.UnreachState = await this.getInitValue(i.UnreachDP);
|
|
931
|
+
const contactData = await this.getOnlineState(i.Path, i.adapterID, i.UnreachDP, i.SignalStrength, i.UnreachState, i.DeviceStateSelectorDP, i.rssiPeerSelectorDP);
|
|
932
|
+
if (contactData !== undefined) {
|
|
933
|
+
i.LastContact = contactData[0];
|
|
934
|
+
i.Status = contactData[1];
|
|
935
|
+
i.linkQuality = contactData[2];
|
|
936
|
+
}
|
|
937
|
+
if (oldContactState !== i.Status) {
|
|
938
|
+
await this.sendOfflineNotifications(i.Device, i.Adapter, i.Status, i.LastContact, i.Path);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
await this.createLists();
|
|
942
|
+
await this.writeDatapoints();
|
|
620
943
|
}
|
|
621
944
|
|
|
622
945
|
/**
|
|
@@ -648,327 +971,127 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
648
971
|
/*=============================================
|
|
649
972
|
= Get signal strength =
|
|
650
973
|
=============================================*/
|
|
974
|
+
let deviceQualityDP = currDeviceString + this.arrDev[i].rssiState;
|
|
651
975
|
let deviceQualityState;
|
|
652
|
-
let linkQuality;
|
|
653
976
|
|
|
654
977
|
switch (adapterID) {
|
|
655
978
|
case 'mihomeVacuum':
|
|
656
|
-
|
|
979
|
+
deviceQualityDP = shortCurrDeviceString + this.arrDev[i].rssiState;
|
|
980
|
+
deviceQualityState = await this.getForeignStateAsync(deviceQualityDP);
|
|
657
981
|
break;
|
|
658
982
|
|
|
659
983
|
case 'netatmo':
|
|
660
|
-
deviceQualityState = await this.getForeignStateAsync(
|
|
984
|
+
deviceQualityState = await this.getForeignStateAsync(deviceQualityDP);
|
|
661
985
|
if (!deviceQualityState) {
|
|
662
|
-
|
|
986
|
+
deviceQualityDP = currDeviceString + this.arrDev[i].rfState;
|
|
987
|
+
deviceQualityState = await this.getForeignStateAsync(deviceQualityDP);
|
|
663
988
|
}
|
|
664
989
|
break;
|
|
665
990
|
|
|
666
991
|
default:
|
|
667
|
-
deviceQualityState = await this.getForeignStateAsync(
|
|
992
|
+
deviceQualityState = await this.getForeignStateAsync(deviceQualityDP);
|
|
668
993
|
break;
|
|
669
994
|
}
|
|
995
|
+
//subscribe to states
|
|
996
|
+
this.subscribeForeignStatesAsync(deviceQualityDP);
|
|
670
997
|
|
|
671
|
-
|
|
672
|
-
switch (typeof deviceQualityState.val) {
|
|
673
|
-
case 'number':
|
|
674
|
-
if (this.config.trueState) {
|
|
675
|
-
linkQuality = deviceQualityState.val;
|
|
676
|
-
} else {
|
|
677
|
-
switch (adapterID) {
|
|
678
|
-
case 'roomba':
|
|
679
|
-
case 'sonoff':
|
|
680
|
-
linkQuality = deviceQualityState.val + '%'; // If quality state is already an percent value
|
|
681
|
-
break;
|
|
682
|
-
case 'lupusec':
|
|
683
|
-
linkQuality = deviceQualityState.val;
|
|
684
|
-
break;
|
|
685
|
-
|
|
686
|
-
default:
|
|
687
|
-
// If quality state is an RSSI value calculate in percent:
|
|
688
|
-
if (deviceQualityState.val == -255) {
|
|
689
|
-
linkQuality = ' - ';
|
|
690
|
-
} else if (deviceQualityState.val < 0) {
|
|
691
|
-
linkQuality = Math.min(Math.max(2 * (deviceQualityState.val + 100), 0), 100) + '%';
|
|
692
|
-
// If Quality State is an value between 0-255 (zigbee) calculate in percent:
|
|
693
|
-
} else if (deviceQualityState.val >= 0) {
|
|
694
|
-
linkQuality = parseFloat(((100 / 255) * deviceQualityState.val).toFixed(0)) + '%';
|
|
695
|
-
}
|
|
696
|
-
break;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
break;
|
|
700
|
-
|
|
701
|
-
case 'string':
|
|
702
|
-
switch (adapterID) {
|
|
703
|
-
case 'netatmo':
|
|
704
|
-
// for Netatmo devices
|
|
705
|
-
linkQuality = deviceQualityState.val;
|
|
706
|
-
break;
|
|
707
|
-
case 'nukiExt':
|
|
708
|
-
linkQuality = ' - ';
|
|
709
|
-
break;
|
|
710
|
-
}
|
|
711
|
-
break;
|
|
712
|
-
}
|
|
713
|
-
} else {
|
|
714
|
-
linkQuality = ' - ';
|
|
715
|
-
}
|
|
998
|
+
let linkQuality = await this.calculateSignalStrength(deviceQualityState, adapterID);
|
|
716
999
|
|
|
717
1000
|
/*=============================================
|
|
718
1001
|
= Get battery data =
|
|
719
1002
|
=============================================*/
|
|
720
|
-
let
|
|
721
|
-
let
|
|
722
|
-
let isBatteryDevice;
|
|
723
|
-
|
|
1003
|
+
let deviceBatteryStateDP;
|
|
1004
|
+
let deviceBatteryState;
|
|
724
1005
|
// Get battery states
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
// Get low bat states
|
|
737
|
-
let deviceLowBatState = await this.getInitValue(currDeviceString + this.arrDev[i].isLowBat);
|
|
738
|
-
if (deviceLowBatState === undefined) {
|
|
739
|
-
deviceLowBatState = await this.getInitValue(currDeviceString + this.arrDev[i].isLowBat2);
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
if (!deviceBatteryState && !shortDeviceBatteryState) {
|
|
743
|
-
if (deviceLowBatState !== undefined) {
|
|
744
|
-
switch (this.arrDev[i].isLowBat || this.arrDev[i].isLowBat2) {
|
|
745
|
-
case 'none':
|
|
746
|
-
batteryHealth = ' - ';
|
|
747
|
-
break;
|
|
748
|
-
default:
|
|
749
|
-
if (deviceLowBatState === false || deviceLowBatState === 'NORMAL' || deviceLowBatState === 1) {
|
|
750
|
-
batteryHealth = 'ok';
|
|
751
|
-
isBatteryDevice = true;
|
|
752
|
-
} else {
|
|
753
|
-
batteryHealth = 'low';
|
|
754
|
-
isBatteryDevice = true;
|
|
755
|
-
}
|
|
756
|
-
break;
|
|
757
|
-
}
|
|
758
|
-
} else {
|
|
759
|
-
batteryHealth = ' - ';
|
|
760
|
-
}
|
|
761
|
-
} else {
|
|
762
|
-
switch (adapterID) {
|
|
763
|
-
case 'hmrpc':
|
|
764
|
-
if (deviceBatteryState === 0 || (deviceBatteryState && deviceBatteryState >= 6)) {
|
|
765
|
-
batteryHealth = ' - ';
|
|
766
|
-
} else {
|
|
767
|
-
batteryHealth = deviceBatteryState + 'V';
|
|
768
|
-
isBatteryDevice = true;
|
|
769
|
-
}
|
|
770
|
-
break;
|
|
771
|
-
|
|
772
|
-
case 'hueExt':
|
|
773
|
-
case 'mihomeVacuum':
|
|
774
|
-
if (shortDeviceBatteryState) {
|
|
775
|
-
batteryHealth = shortDeviceBatteryState + '%';
|
|
776
|
-
isBatteryDevice = true;
|
|
777
|
-
}
|
|
778
|
-
break;
|
|
779
|
-
|
|
780
|
-
default:
|
|
781
|
-
batteryHealth = deviceBatteryState + '%';
|
|
782
|
-
isBatteryDevice = true;
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
/*=============================================
|
|
787
|
-
= Set Lowbat indicator =
|
|
788
|
-
=============================================*/
|
|
789
|
-
switch (typeof deviceLowBatState) {
|
|
790
|
-
case 'number':
|
|
791
|
-
if (deviceLowBatState === 0) {
|
|
792
|
-
lowBatIndicator = true;
|
|
793
|
-
}
|
|
794
|
-
break;
|
|
795
|
-
|
|
796
|
-
case 'string':
|
|
797
|
-
if (deviceLowBatState !== 'NORMAL') {
|
|
798
|
-
// Tado devices
|
|
799
|
-
lowBatIndicator = true;
|
|
800
|
-
}
|
|
801
|
-
break;
|
|
802
|
-
|
|
803
|
-
case 'boolean':
|
|
804
|
-
if (deviceLowBatState) {
|
|
805
|
-
lowBatIndicator = true;
|
|
1006
|
+
switch (adapterID) {
|
|
1007
|
+
case 'hueExt':
|
|
1008
|
+
case 'mihomeVacuum':
|
|
1009
|
+
case 'mqttNuki':
|
|
1010
|
+
deviceBatteryStateDP = shortCurrDeviceString + this.arrDev[i].battery;
|
|
1011
|
+
deviceBatteryState = await this.getInitValue(deviceBatteryStateDP);
|
|
1012
|
+
if (deviceBatteryState === undefined) {
|
|
1013
|
+
deviceBatteryStateDP = shortCurrDeviceString + this.arrDev[i].battery2;
|
|
1014
|
+
deviceBatteryState = await this.getInitValue(deviceBatteryStateDP);
|
|
806
1015
|
}
|
|
807
1016
|
break;
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
1017
|
+
default:
|
|
1018
|
+
deviceBatteryStateDP = currDeviceString + this.arrDev[i].battery;
|
|
1019
|
+
deviceBatteryState = await this.getInitValue(deviceBatteryStateDP);
|
|
1020
|
+
if (deviceBatteryState === undefined) {
|
|
1021
|
+
deviceBatteryStateDP = currDeviceString + this.arrDev[i].battery2;
|
|
1022
|
+
deviceBatteryState = await this.getInitValue(deviceBatteryStateDP);
|
|
812
1023
|
}
|
|
813
1024
|
break;
|
|
814
1025
|
}
|
|
815
1026
|
|
|
816
|
-
|
|
817
|
-
=
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
const deviceStateSelector = await this.getForeignStateAsync(shortCurrDeviceString + this.arrDev[i].stateValue); // for hmrpc devices
|
|
825
|
-
const rssiPeerSelector = await this.getForeignStateAsync(currDeviceString + this.arrDev[i].rssiPeerState);
|
|
826
|
-
|
|
827
|
-
if (deviceMainSelector) {
|
|
828
|
-
try {
|
|
829
|
-
const lastContact = await this.getTimestamp(deviceMainSelector.ts);
|
|
830
|
-
const deviceUnreachState = await this.getInitValue(currDeviceString + this.arrDev[i].reach);
|
|
831
|
-
const lastDeviceUnreachStateChange = deviceUnreachSelector != undefined ? await this.getTimestamp(deviceUnreachSelector.lc) : await this.getTimestamp(deviceMainSelector.ts);
|
|
832
|
-
const shortDeviceUnreachState = await this.getForeignStateAsync(shortCurrDeviceString + this.arrDev[i].reach);
|
|
833
|
-
|
|
834
|
-
// If there is no contact since user sets minutes add device in offline list
|
|
835
|
-
// calculate to days after 48 hours
|
|
836
|
-
switch (this.arrDev[i].reach) {
|
|
837
|
-
case 'none':
|
|
838
|
-
lastContactString = await this.getLastContact(deviceMainSelector.ts);
|
|
839
|
-
break;
|
|
1027
|
+
// Get low bat states
|
|
1028
|
+
let isLowBatDP = currDeviceString + this.arrDev[i].isLowBat;
|
|
1029
|
+
let deviceLowBatState = await this.getInitValue(isLowBatDP);
|
|
1030
|
+
if (deviceLowBatState === undefined) {
|
|
1031
|
+
isLowBatDP = currDeviceString + this.arrDev[i].isLowBat2;
|
|
1032
|
+
deviceLowBatState = await this.getInitValue(isLowBatDP);
|
|
1033
|
+
}
|
|
1034
|
+
if (deviceLowBatState === undefined) isLowBatDP = 'none';
|
|
840
1035
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
if (linkQuality !== ' - ') {
|
|
845
|
-
if (deviceUnreachState) {
|
|
846
|
-
lastContactString = await this.getLastContact(deviceMainSelector.lc);
|
|
847
|
-
} else {
|
|
848
|
-
lastContactString = await this.getLastContact(deviceMainSelector.ts);
|
|
849
|
-
}
|
|
850
|
-
} else {
|
|
851
|
-
if (deviceStateSelector) {
|
|
852
|
-
// because old hm devices don't send rssi states
|
|
853
|
-
lastContactString = await this.getLastContact(deviceStateSelector.ts);
|
|
854
|
-
} else if (rssiPeerSelector) {
|
|
855
|
-
// because old hm sensors don't send rssi/state values
|
|
856
|
-
lastContactString = await this.getLastContact(rssiPeerSelector.ts);
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
} else {
|
|
860
|
-
if (!deviceUnreachState) {
|
|
861
|
-
lastContactString = await this.getLastContact(deviceMainSelector.lc);
|
|
862
|
-
} else {
|
|
863
|
-
lastContactString = await this.getLastContact(deviceMainSelector.ts);
|
|
864
|
-
}
|
|
865
|
-
break;
|
|
866
|
-
}
|
|
867
|
-
}
|
|
1036
|
+
//subscribe to states
|
|
1037
|
+
this.subscribeForeignStatesAsync(deviceBatteryStateDP);
|
|
1038
|
+
this.subscribeForeignStatesAsync(isLowBatDP);
|
|
868
1039
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
break;
|
|
922
|
-
case 'mihomeVacuum':
|
|
923
|
-
if (this.maxMinutes[adapterID] <= 0) {
|
|
924
|
-
if (!shortDeviceUnreachState) {
|
|
925
|
-
deviceState = 'Offline'; //set online state to offline
|
|
926
|
-
linkQuality = '0%'; // set linkQuality to nothing
|
|
927
|
-
}
|
|
928
|
-
} else if (lastContact > this.maxMinutes[adapterID]) {
|
|
929
|
-
deviceState = 'Offline'; //set online state to offline
|
|
930
|
-
linkQuality = '0%'; // set linkQuality to nothing
|
|
931
|
-
}
|
|
932
|
-
break;
|
|
933
|
-
case 'mihome':
|
|
934
|
-
if (this.arrDev[i].battery === 'none') {
|
|
935
|
-
if (this.maxMinutes[adapterID] <= 0) {
|
|
936
|
-
if (!deviceUnreachState) {
|
|
937
|
-
deviceState = 'Offline'; //set online state to offline
|
|
938
|
-
linkQuality = '0%'; // set linkQuality to nothing
|
|
939
|
-
}
|
|
940
|
-
} else if (lastContact > this.maxMinutes[adapterID]) {
|
|
941
|
-
deviceState = 'Offline'; //set online state to offline
|
|
942
|
-
linkQuality = '0%'; // set linkQuality to nothing
|
|
943
|
-
}
|
|
944
|
-
} else {
|
|
945
|
-
if (this.config.mihomeMaxMinutes <= 0) {
|
|
946
|
-
if (this.maxMinutes[adapterID] <= 0) {
|
|
947
|
-
deviceState = 'Offline'; //set online state to offline
|
|
948
|
-
linkQuality = '0%'; // set linkQuality to nothing
|
|
949
|
-
}
|
|
950
|
-
} else if (lastContact > this.maxMinutes[adapterID]) {
|
|
951
|
-
deviceState = 'Offline'; //set online state to offline
|
|
952
|
-
linkQuality = '0%'; // set linkQuality to nothing
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
break;
|
|
956
|
-
default:
|
|
957
|
-
if (this.maxMinutes[adapterID] <= 0) {
|
|
958
|
-
if (!deviceUnreachState) {
|
|
959
|
-
deviceState = 'Offline'; //set online state to offline
|
|
960
|
-
linkQuality = '0%'; // set linkQuality to nothing
|
|
961
|
-
}
|
|
962
|
-
} else if (lastContact > this.maxMinutes[adapterID]) {
|
|
963
|
-
deviceState = 'Offline'; //set online state to offline
|
|
964
|
-
linkQuality = '0%'; // set linkQuality to nothing
|
|
965
|
-
}
|
|
966
|
-
break;
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
} catch (error) {
|
|
970
|
-
this.errorReporting('[getLastContact]', error);
|
|
1040
|
+
const batteryData = await this.getBatteryData(deviceBatteryState, deviceLowBatState, adapterID);
|
|
1041
|
+
const batteryHealth = batteryData[0];
|
|
1042
|
+
const batteryHealthRaw = batteryData[2];
|
|
1043
|
+
const isBatteryDevice = batteryData[1];
|
|
1044
|
+
let lowBatIndicator;
|
|
1045
|
+
|
|
1046
|
+
if (isBatteryDevice) {
|
|
1047
|
+
lowBatIndicator = await this.setLowbatIndicator(deviceBatteryState, deviceLowBatState, isLowBatDP);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/*=============================================
|
|
1051
|
+
= Get last contact of device =
|
|
1052
|
+
=============================================*/
|
|
1053
|
+
let unreachDP = currDeviceString + this.arrDev[i].reach;
|
|
1054
|
+
const deviceStateSelectorDP = shortCurrDeviceString + this.arrDev[i].stateValue;
|
|
1055
|
+
const rssiPeerSelectorDP = currDeviceString + this.arrDev[i].rssiPeerState;
|
|
1056
|
+
|
|
1057
|
+
let deviceUnreachState = await this.getInitValue(unreachDP);
|
|
1058
|
+
if (deviceUnreachState === undefined) {
|
|
1059
|
+
unreachDP = shortCurrDeviceString + this.arrDev[i].reach;
|
|
1060
|
+
deviceUnreachState = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].reach);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// subscribe to states
|
|
1064
|
+
this.subscribeForeignStatesAsync(id);
|
|
1065
|
+
this.subscribeForeignStatesAsync(unreachDP);
|
|
1066
|
+
this.subscribeForeignStatesAsync(deviceStateSelectorDP);
|
|
1067
|
+
this.subscribeForeignStatesAsync(rssiPeerSelectorDP);
|
|
1068
|
+
|
|
1069
|
+
const onlineState = await this.getOnlineState(id, adapterID, unreachDP, linkQuality, deviceUnreachState, deviceStateSelectorDP, rssiPeerSelectorDP);
|
|
1070
|
+
let deviceState;
|
|
1071
|
+
let lastContactString;
|
|
1072
|
+
|
|
1073
|
+
if (onlineState) {
|
|
1074
|
+
lastContactString = onlineState[0];
|
|
1075
|
+
deviceState = onlineState[1];
|
|
1076
|
+
linkQuality = onlineState[2];
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/*=============================================
|
|
1080
|
+
= Get update data =
|
|
1081
|
+
=============================================*/
|
|
1082
|
+
const deviceUpdateDP = currDeviceString + this.arrDev[i].upgrade;
|
|
1083
|
+
let isUpgradable;
|
|
1084
|
+
|
|
1085
|
+
if (this.config.checkSendDeviceUpgrade) {
|
|
1086
|
+
const deviceUpdateSelector = await this.getInitValue(deviceUpdateDP);
|
|
1087
|
+
|
|
1088
|
+
if (deviceUpdateSelector) {
|
|
1089
|
+
isUpgradable = true;
|
|
1090
|
+
} else if (!deviceUpdateSelector) {
|
|
1091
|
+
isUpgradable = false;
|
|
971
1092
|
}
|
|
1093
|
+
// subscribe to states
|
|
1094
|
+
this.subscribeForeignStatesAsync(deviceUpdateDP);
|
|
972
1095
|
}
|
|
973
1096
|
|
|
974
1097
|
/*=============================================
|
|
@@ -976,32 +1099,52 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
976
1099
|
=============================================*/
|
|
977
1100
|
|
|
978
1101
|
/* Add only devices with battery in the rawlist */
|
|
979
|
-
if (this.listOnlyBattery) {
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1102
|
+
if (this.listOnlyBattery && isBatteryDevice) {
|
|
1103
|
+
this.listAllDevicesRaw.push({
|
|
1104
|
+
Path: id,
|
|
1105
|
+
Device: deviceName,
|
|
1106
|
+
adapterID: adapterID,
|
|
1107
|
+
Adapter: adapter,
|
|
1108
|
+
isBatteryDevice: isBatteryDevice,
|
|
1109
|
+
Battery: batteryHealth,
|
|
1110
|
+
BatteryRaw: batteryHealthRaw,
|
|
1111
|
+
batteryDP: deviceBatteryStateDP,
|
|
1112
|
+
LowBat: lowBatIndicator,
|
|
1113
|
+
LowBatDP: isLowBatDP,
|
|
1114
|
+
SignalStrengthDP: deviceQualityDP,
|
|
1115
|
+
SignalStrength: linkQuality,
|
|
1116
|
+
UnreachState: deviceUnreachState,
|
|
1117
|
+
UnreachDP: unreachDP,
|
|
1118
|
+
DeviceStateSelectorDP: deviceStateSelectorDP,
|
|
1119
|
+
rssiPeerSelectorDP: rssiPeerSelectorDP,
|
|
1120
|
+
LastContact: lastContactString,
|
|
1121
|
+
Status: deviceState,
|
|
1122
|
+
UpdateDP: deviceUpdateDP,
|
|
1123
|
+
Upgradable: isUpgradable,
|
|
1124
|
+
});
|
|
993
1125
|
} else {
|
|
994
1126
|
/* Add all devices */
|
|
995
1127
|
this.listAllDevicesRaw.push({
|
|
996
1128
|
Path: id,
|
|
997
1129
|
Device: deviceName,
|
|
1130
|
+
adapterID: adapterID,
|
|
998
1131
|
Adapter: adapter,
|
|
999
1132
|
isBatteryDevice: isBatteryDevice,
|
|
1000
1133
|
Battery: batteryHealth,
|
|
1134
|
+
BatteryRaw: batteryHealthRaw,
|
|
1135
|
+
batteryDP: deviceBatteryStateDP,
|
|
1001
1136
|
LowBat: lowBatIndicator,
|
|
1002
|
-
|
|
1003
|
-
|
|
1137
|
+
LowBatDP: isLowBatDP,
|
|
1138
|
+
SignalStrengthDP: deviceQualityDP,
|
|
1139
|
+
SignalStrength: linkQuality,
|
|
1140
|
+
UnreachState: deviceUnreachState,
|
|
1141
|
+
UnreachDP: unreachDP,
|
|
1142
|
+
DeviceStateSelectorDP: deviceStateSelectorDP,
|
|
1143
|
+
rssiPeerSelectorDP: rssiPeerSelectorDP,
|
|
1144
|
+
LastContact: lastContactString,
|
|
1004
1145
|
Status: deviceState,
|
|
1146
|
+
UpdateDP: deviceUpdateDP,
|
|
1147
|
+
Upgradable: isUpgradable,
|
|
1005
1148
|
});
|
|
1006
1149
|
}
|
|
1007
1150
|
} else {
|
|
@@ -1010,9 +1153,127 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1010
1153
|
}
|
|
1011
1154
|
} // <-- end of loop
|
|
1012
1155
|
await this.createLists();
|
|
1013
|
-
await this.countDevices();
|
|
1014
1156
|
} // <-- end of createData
|
|
1015
1157
|
|
|
1158
|
+
/**
|
|
1159
|
+
* Create Lists
|
|
1160
|
+
*/
|
|
1161
|
+
async createLists() {
|
|
1162
|
+
this.linkQualityDevices = [];
|
|
1163
|
+
this.batteryPowered = [];
|
|
1164
|
+
this.batteryLowPowered = [];
|
|
1165
|
+
this.listAllDevices = [];
|
|
1166
|
+
this.offlineDevices = [];
|
|
1167
|
+
this.batteryLowPoweredRaw = [];
|
|
1168
|
+
this.offlineDevicesRaw = [];
|
|
1169
|
+
this.upgradableList = [];
|
|
1170
|
+
|
|
1171
|
+
for (const device of this.listAllDevicesRaw) {
|
|
1172
|
+
/*---------- fill raw lists ----------*/
|
|
1173
|
+
// low bat list
|
|
1174
|
+
if (device.LowBat && device.Status !== 'Offline') {
|
|
1175
|
+
this.batteryLowPoweredRaw.push({
|
|
1176
|
+
Path: device.Path,
|
|
1177
|
+
Device: device.Device,
|
|
1178
|
+
Adapter: device.Adapter,
|
|
1179
|
+
Battery: device.Battery,
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
// offline raw list
|
|
1183
|
+
if (device.Status === 'Offline') {
|
|
1184
|
+
this.offlineDevicesRaw.push({
|
|
1185
|
+
Path: device.Path,
|
|
1186
|
+
Device: device.Device,
|
|
1187
|
+
Adapter: device.Adapter,
|
|
1188
|
+
'Last contact': device.LastContact,
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
/*---------- fill user lists ----------*/
|
|
1193
|
+
if (!this.blacklistLists.includes(device.Path)) {
|
|
1194
|
+
this.listAllDevices.push({
|
|
1195
|
+
Device: device.Device,
|
|
1196
|
+
Adapter: device.Adapter,
|
|
1197
|
+
Battery: device.Battery,
|
|
1198
|
+
'Signal strength': device.SignalStrength,
|
|
1199
|
+
'Last contact': device.LastContact,
|
|
1200
|
+
Status: device.Status,
|
|
1201
|
+
});
|
|
1202
|
+
// LinkQuality lists
|
|
1203
|
+
if (device.SignalStrength != ' - ') {
|
|
1204
|
+
this.linkQualityDevices.push({
|
|
1205
|
+
Device: device.Device,
|
|
1206
|
+
Adapter: device.Adapter,
|
|
1207
|
+
'Signal strength': device.SignalStrength,
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
// Battery lists
|
|
1211
|
+
if (device['isBatteryDevice']) {
|
|
1212
|
+
this.batteryPowered.push({
|
|
1213
|
+
Device: device.Device,
|
|
1214
|
+
Adapter: device.Adapter,
|
|
1215
|
+
Battery: device.Battery,
|
|
1216
|
+
Status: device.Status,
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
// Low Bat lists
|
|
1220
|
+
if (device.LowBat && device.Status !== 'Offline') {
|
|
1221
|
+
this.batteryLowPowered.push({
|
|
1222
|
+
Device: device.Device,
|
|
1223
|
+
Adapter: device.Adapter,
|
|
1224
|
+
Battery: device.Battery,
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// Offline List
|
|
1229
|
+
if (device.Status === 'Offline') {
|
|
1230
|
+
this.offlineDevices.push({
|
|
1231
|
+
Device: device.Device,
|
|
1232
|
+
Adapter: device.Adapter,
|
|
1233
|
+
'Last contact': device.LastContact,
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
// Device update List
|
|
1238
|
+
if (device.Upgradable) {
|
|
1239
|
+
this.upgradableList.push({
|
|
1240
|
+
Device: device.Device,
|
|
1241
|
+
Adapter: device.Adapter,
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
await this.countDevices();
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
/**
|
|
1250
|
+
* Count devices for each type
|
|
1251
|
+
*/
|
|
1252
|
+
async countDevices() {
|
|
1253
|
+
// Count how many devices with link Quality
|
|
1254
|
+
this.linkQualityCount = this.linkQualityDevices.length;
|
|
1255
|
+
|
|
1256
|
+
// Count how many devcies are offline
|
|
1257
|
+
this.offlineDevicesCount = this.offlineDevices.length;
|
|
1258
|
+
|
|
1259
|
+
// Count how many devices are with battery
|
|
1260
|
+
this.batteryPoweredCount = this.batteryPowered.length;
|
|
1261
|
+
|
|
1262
|
+
// 3d. Count how many devices are with low battery
|
|
1263
|
+
this.lowBatteryPoweredCount = this.batteryLowPowered.length;
|
|
1264
|
+
|
|
1265
|
+
// Count how many devices are exists
|
|
1266
|
+
this.deviceCounter = this.listAllDevices.length;
|
|
1267
|
+
|
|
1268
|
+
// Count how many devices has update available
|
|
1269
|
+
this.upgradableDevicesCount = this.upgradableList.length;
|
|
1270
|
+
|
|
1271
|
+
// raws
|
|
1272
|
+
|
|
1273
|
+
// Count how many devcies are offline
|
|
1274
|
+
this.offlineDevicesCountRaw = this.offlineDevicesRaw.length;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1016
1277
|
/**
|
|
1017
1278
|
* @param {string} adptName - Adapter name
|
|
1018
1279
|
*/
|
|
@@ -1023,10 +1284,11 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1023
1284
|
await this.resetVars(); // reset the arrays and counts
|
|
1024
1285
|
|
|
1025
1286
|
try {
|
|
1026
|
-
for (
|
|
1027
|
-
if (
|
|
1287
|
+
for (const i of this.listAllDevicesRaw) {
|
|
1288
|
+
if (i.adapterID.includes(adptName)) {
|
|
1028
1289
|
// list device only if selected adapter matched with device
|
|
1029
|
-
await this.
|
|
1290
|
+
await this.createLists();
|
|
1291
|
+
await this.writeDatapoints();
|
|
1030
1292
|
}
|
|
1031
1293
|
}
|
|
1032
1294
|
|
|
@@ -1048,16 +1310,8 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1048
1310
|
await this.resetVars(); // reset the arrays and counts
|
|
1049
1311
|
|
|
1050
1312
|
for (let i = 0; i < this.arrDev.length; i++) {
|
|
1051
|
-
|
|
1052
|
-
await this.createData(i);
|
|
1053
|
-
} else {
|
|
1054
|
-
return; // cancel run if unloaded was called.
|
|
1055
|
-
}
|
|
1313
|
+
await this.createData(i);
|
|
1056
1314
|
}
|
|
1057
|
-
|
|
1058
|
-
// send message if new devices are offline
|
|
1059
|
-
if (this.config.checkSendOfflineMsg) await this.sendOfflineNotifications();
|
|
1060
|
-
|
|
1061
1315
|
await this.writeDatapoints(); // fill the datapoints
|
|
1062
1316
|
} catch (error) {
|
|
1063
1317
|
this.errorReporting('[createDataOfAllAdapter]', error);
|
|
@@ -1190,6 +1444,26 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1190
1444
|
} catch (error) {
|
|
1191
1445
|
this.errorReporting('[sendNotification Lovelace]', error);
|
|
1192
1446
|
}
|
|
1447
|
+
|
|
1448
|
+
// Synochat Notification
|
|
1449
|
+
try {
|
|
1450
|
+
if (this.config.instanceSynochat) {
|
|
1451
|
+
//first check if instance is living
|
|
1452
|
+
const synochatAliveState = await this.getInitValue('system.adapter.' + this.config.instanceSynochat + '.alive');
|
|
1453
|
+
|
|
1454
|
+
if (!synochatAliveState) {
|
|
1455
|
+
this.log.warn('Synochat instance is not running. Message could not be sent. Please check your instance configuration.');
|
|
1456
|
+
} else {
|
|
1457
|
+
if (this.config.channelSynochat !== undefined) {
|
|
1458
|
+
await this.setForeignStateAsync(`${this.config.instanceSynochat}.${this.config.channelSynochat}.message`, text);
|
|
1459
|
+
} else {
|
|
1460
|
+
this.log.warn('Synochat channel is not set. Message could not be sent. Please check your instance configuration.');
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
} catch (error) {
|
|
1465
|
+
this.errorReporting('[sendNotification Synochat]', error);
|
|
1466
|
+
}
|
|
1193
1467
|
} // <-- End of sendNotification function
|
|
1194
1468
|
|
|
1195
1469
|
/**
|
|
@@ -1224,15 +1498,20 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1224
1498
|
let deviceList = '';
|
|
1225
1499
|
|
|
1226
1500
|
for (const id of this.batteryLowPoweredRaw) {
|
|
1227
|
-
if (!this.blacklistNotify.includes(id
|
|
1228
|
-
|
|
1501
|
+
if (!this.blacklistNotify.includes(id.Path)) {
|
|
1502
|
+
if (!this.config.showAdapterNameinMsg) {
|
|
1503
|
+
deviceList = `${deviceList}\n${id.Device} (${id.Battery})`;
|
|
1504
|
+
} else {
|
|
1505
|
+
// Add adaptername if checkbox is checked true in options by user
|
|
1506
|
+
deviceList = `${deviceList}\n${id.Adapter}: ${id.Device} (${id.Battery})`;
|
|
1507
|
+
}
|
|
1229
1508
|
}
|
|
1230
1509
|
}
|
|
1231
1510
|
if (deviceList.length > 0) {
|
|
1232
1511
|
this.log.info(`Niedrige Batteriezustände: ${deviceList}`);
|
|
1233
1512
|
this.setStateAsync('lastNotification', `Niedrige Batteriezustände: ${deviceList}`, true);
|
|
1234
1513
|
|
|
1235
|
-
this.sendNotification(`
|
|
1514
|
+
this.sendNotification(`Niedrige Batteriezustände: ${deviceList}`);
|
|
1236
1515
|
}
|
|
1237
1516
|
} catch (error) {
|
|
1238
1517
|
this.errorReporting('[sendBatteryNotifyShedule]', error);
|
|
@@ -1241,37 +1520,66 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1241
1520
|
}
|
|
1242
1521
|
} //<--End of battery notification
|
|
1243
1522
|
|
|
1523
|
+
/**
|
|
1524
|
+
* check if device updates are available and send notification
|
|
1525
|
+
* @param {string} deviceName
|
|
1526
|
+
* @param {string} adapter
|
|
1527
|
+
* @param {string} battery
|
|
1528
|
+
* @param {string} devicePath
|
|
1529
|
+
**/
|
|
1530
|
+
async sendLowBatNoticiation(deviceName, adapter, battery, devicePath) {
|
|
1531
|
+
this.log.debug(`Start the function: ${this.sendLowBatNoticiation.name}`);
|
|
1532
|
+
|
|
1533
|
+
try {
|
|
1534
|
+
let msg = '';
|
|
1535
|
+
let deviceList = '';
|
|
1536
|
+
|
|
1537
|
+
if (!this.blacklistNotify.includes(devicePath)) {
|
|
1538
|
+
if (!this.config.showAdapterNameinMsg) {
|
|
1539
|
+
deviceList = `${deviceList}\n${deviceName} (${battery})`;
|
|
1540
|
+
} else {
|
|
1541
|
+
deviceList = `${deviceList}\n${adapter}: ${deviceName} (${battery})`;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
msg = `Gerät mit geringer Batterie erkannt: \n`;
|
|
1545
|
+
|
|
1546
|
+
this.log.info(msg + deviceList);
|
|
1547
|
+
await this.setStateAsync('lastNotification', msg + deviceList, true);
|
|
1548
|
+
await this.sendNotification(msg + deviceList);
|
|
1549
|
+
} catch (error) {
|
|
1550
|
+
this.errorReporting('[sendLowBatNoticiation]', error);
|
|
1551
|
+
}
|
|
1552
|
+
this.log.debug(`Finished the function: ${this.sendLowBatNoticiation.name}`);
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1244
1555
|
/**
|
|
1245
1556
|
* send message if an device is offline
|
|
1246
1557
|
*/
|
|
1247
|
-
async sendOfflineNotifications() {
|
|
1558
|
+
async sendOfflineNotifications(deviceName, adapter, status, lastContact, devicePath) {
|
|
1248
1559
|
this.log.debug(`Start the function: ${this.sendOfflineNotifications.name}`);
|
|
1249
1560
|
|
|
1250
1561
|
try {
|
|
1251
1562
|
let msg = '';
|
|
1252
1563
|
let deviceList = '';
|
|
1253
1564
|
|
|
1254
|
-
|
|
1255
|
-
if (!this.
|
|
1256
|
-
deviceList = `${deviceList}\n${
|
|
1565
|
+
if (!this.blacklistNotify.includes(devicePath)) {
|
|
1566
|
+
if (!this.config.showAdapterNameinMsg) {
|
|
1567
|
+
deviceList = `${deviceList}\n${deviceName} (${lastContact})`;
|
|
1568
|
+
} else {
|
|
1569
|
+
deviceList = `${deviceList}\n${adapter}: ${deviceName} (${lastContact})`;
|
|
1257
1570
|
}
|
|
1258
1571
|
}
|
|
1259
|
-
if (
|
|
1260
|
-
if
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
} else if (deviceList.length >= 2) {
|
|
1266
|
-
//make plural if it is more than one device
|
|
1267
|
-
msg = `Folgende Geräte sind seit einiger Zeit nicht erreichbar: \n`;
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
this.log.info(msg + deviceList);
|
|
1271
|
-
this.offlineDevicesCountRawOld = deviceList.length;
|
|
1272
|
-
await this.setStateAsync('lastNotification', msg + deviceList, true);
|
|
1273
|
-
await this.sendNotification(msg + deviceList);
|
|
1572
|
+
if (status === 'Online') {
|
|
1573
|
+
// make singular if it is only one device
|
|
1574
|
+
msg = 'Folgendes Gerät ist wieder erreichbar: \n';
|
|
1575
|
+
} else if (status === 'Offline') {
|
|
1576
|
+
//make plural if it is more than one device
|
|
1577
|
+
msg = `Folgendes Gerät ist seit einiger Zeit nicht erreichbar: \n`;
|
|
1274
1578
|
}
|
|
1579
|
+
|
|
1580
|
+
this.log.info(msg + deviceList);
|
|
1581
|
+
await this.setStateAsync('lastNotification', msg + deviceList, true);
|
|
1582
|
+
await this.sendNotification(msg + deviceList);
|
|
1275
1583
|
} catch (error) {
|
|
1276
1584
|
this.errorReporting('[sendOfflineMessage]', error);
|
|
1277
1585
|
}
|
|
@@ -1310,8 +1618,12 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1310
1618
|
let deviceList = '';
|
|
1311
1619
|
|
|
1312
1620
|
for (const id of this.offlineDevicesRaw) {
|
|
1313
|
-
if (!this.blacklistNotify.includes(id
|
|
1314
|
-
|
|
1621
|
+
if (!this.blacklistNotify.includes(id.Path)) {
|
|
1622
|
+
if (!this.config.showAdapterNameinMsg) {
|
|
1623
|
+
deviceList = `${deviceList}\n${id.Device} (${id.LastContact})`;
|
|
1624
|
+
} else {
|
|
1625
|
+
deviceList = `${deviceList}\n${id.Adapter}: ${id.Device} (${id.LastContact})`;
|
|
1626
|
+
}
|
|
1315
1627
|
}
|
|
1316
1628
|
}
|
|
1317
1629
|
|
|
@@ -1328,6 +1640,91 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1328
1640
|
}
|
|
1329
1641
|
} //<--End of daily offline notification
|
|
1330
1642
|
|
|
1643
|
+
/**
|
|
1644
|
+
* check if device updates are available and send notification
|
|
1645
|
+
* @param {string} deviceName
|
|
1646
|
+
* @param {string} adapter
|
|
1647
|
+
* @param {string} devicePath
|
|
1648
|
+
**/
|
|
1649
|
+
async sendDeviceUpdatesNotification(deviceName, adapter, devicePath) {
|
|
1650
|
+
this.log.debug(`Start the function: ${this.sendDeviceUpdatesNotification.name}`);
|
|
1651
|
+
|
|
1652
|
+
try {
|
|
1653
|
+
let msg = '';
|
|
1654
|
+
let deviceList = '';
|
|
1655
|
+
|
|
1656
|
+
if (!this.blacklistNotify.includes(devicePath)) {
|
|
1657
|
+
if (!this.config.showAdapterNameinMsg) {
|
|
1658
|
+
deviceList = `${deviceList}\n${deviceName}`;
|
|
1659
|
+
} else {
|
|
1660
|
+
deviceList = `${deviceList}\n${adapter}: ${deviceName}`;
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
msg = `Neue Geräte Updates vorhanden: \n`;
|
|
1664
|
+
|
|
1665
|
+
this.log.info(msg + deviceList);
|
|
1666
|
+
await this.setStateAsync('lastNotification', msg + deviceList, true);
|
|
1667
|
+
await this.sendNotification(msg + deviceList);
|
|
1668
|
+
} catch (error) {
|
|
1669
|
+
this.errorReporting('[sendDeviceUpdatesNotification]', error);
|
|
1670
|
+
}
|
|
1671
|
+
this.log.debug(`Finished the function: ${this.sendDeviceUpdatesNotification.name}`);
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
/**
|
|
1675
|
+
* send shedule message with offline devices
|
|
1676
|
+
*/
|
|
1677
|
+
async sendUpgradeNotificationsShedule() {
|
|
1678
|
+
const time = this.config.checkSendUpgradeTime.split(':');
|
|
1679
|
+
|
|
1680
|
+
const checkDays = []; // list of selected days
|
|
1681
|
+
|
|
1682
|
+
// push the selected days in list
|
|
1683
|
+
if (this.config.checkUpgradeMonday) checkDays.push(1);
|
|
1684
|
+
if (this.config.checkUpgradeTuesday) checkDays.push(2);
|
|
1685
|
+
if (this.config.checkUpgradeWednesday) checkDays.push(3);
|
|
1686
|
+
if (this.config.checkUpgradeThursday) checkDays.push(4);
|
|
1687
|
+
if (this.config.checkUpgradeFriday) checkDays.push(5);
|
|
1688
|
+
if (this.config.checkUpgradeSaturday) checkDays.push(6);
|
|
1689
|
+
if (this.config.checkUpgradeSunday) checkDays.push(0);
|
|
1690
|
+
|
|
1691
|
+
if (checkDays.length >= 1) {
|
|
1692
|
+
// check if an day is selected
|
|
1693
|
+
this.log.debug(`Number of selected days for daily Upgrade message: ${checkDays.length}. Send Message on: ${checkDays.join(', ')} ...`);
|
|
1694
|
+
} else {
|
|
1695
|
+
this.log.warn(`No days selected for daily Upgrade message. Please check the instance configuration!`);
|
|
1696
|
+
return; // cancel function if no day is selected
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
if (!isUnloaded) {
|
|
1700
|
+
const cron = '10 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
|
|
1701
|
+
schedule.scheduleJob(cron, () => {
|
|
1702
|
+
try {
|
|
1703
|
+
let deviceList = '';
|
|
1704
|
+
|
|
1705
|
+
for (const id of this.upgradableList) {
|
|
1706
|
+
if (!this.blacklistNotify.includes(id.Path)) {
|
|
1707
|
+
if (!this.config.showAdapterNameinMsg) {
|
|
1708
|
+
deviceList = `${deviceList}\n${id.Device}`;
|
|
1709
|
+
} else {
|
|
1710
|
+
deviceList = `${deviceList}\n${id.Adapter}: ${id.Device}`;
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
if (deviceList.length > 0) {
|
|
1716
|
+
this.log.info(`Geräte Upgrade: ${deviceList}`);
|
|
1717
|
+
this.setStateAsync('lastNotification', `Geräte Upgrade: ${deviceList}`, true);
|
|
1718
|
+
|
|
1719
|
+
this.sendNotification(`Geräte Upgrade:\n${deviceList}`);
|
|
1720
|
+
}
|
|
1721
|
+
} catch (error) {
|
|
1722
|
+
this.errorReporting('[sendUpgradeNotificationsShedule]', error);
|
|
1723
|
+
}
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
} //<--End of daily offline notification
|
|
1727
|
+
|
|
1331
1728
|
/**
|
|
1332
1729
|
* reset arrays and counts
|
|
1333
1730
|
*/
|
|
@@ -1341,13 +1738,11 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1341
1738
|
this.batteryPowered = [];
|
|
1342
1739
|
this.batteryLowPowered = [];
|
|
1343
1740
|
this.listAllDevices = [];
|
|
1344
|
-
this.listAllDevicesRaw = [];
|
|
1741
|
+
//this.listAllDevicesRaw = [];
|
|
1345
1742
|
|
|
1346
1743
|
// raws
|
|
1347
1744
|
this.batteryLowPoweredRaw = [];
|
|
1348
1745
|
this.offlineDevicesRaw = [];
|
|
1349
|
-
this.lowBatteryPoweredCountRaw = 0;
|
|
1350
|
-
this.offlineDevicesCountRaw = 0;
|
|
1351
1746
|
|
|
1352
1747
|
// counts
|
|
1353
1748
|
this.offlineDevicesCount = 0;
|
|
@@ -1355,6 +1750,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1355
1750
|
this.linkQualityCount = 0;
|
|
1356
1751
|
this.batteryPoweredCount = 0;
|
|
1357
1752
|
this.lowBatteryPoweredCount = 0;
|
|
1753
|
+
this.upgradableDevicesCount = 0;
|
|
1358
1754
|
|
|
1359
1755
|
this.log.debug(`Function finished: ${this.resetVars.name}`);
|
|
1360
1756
|
} // <-- end of resetVars
|
|
@@ -1380,14 +1776,15 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1380
1776
|
await this.setStateAsync(`${dpSubFolder}countAll`, { val: this.deviceCounter, ack: true });
|
|
1381
1777
|
await this.setStateAsync(`${dpSubFolder}batteryCount`, { val: this.batteryPoweredCount, ack: true });
|
|
1382
1778
|
await this.setStateAsync(`${dpSubFolder}lowBatteryCount`, { val: this.lowBatteryPoweredCount, ack: true });
|
|
1779
|
+
await this.setStateAsync(`${dpSubFolder}upgradableCount`, { val: this.upgradableDevicesCount, ack: true });
|
|
1383
1780
|
|
|
1384
|
-
if (this.deviceCounter
|
|
1781
|
+
if (this.deviceCounter === 0) {
|
|
1385
1782
|
// if no device is count, write the JSON List with default value
|
|
1386
1783
|
this.listAllDevices = [{ Device: '--none--', Adapter: '', Battery: '', 'Last contact': '', 'Signal strength': '' }];
|
|
1387
1784
|
}
|
|
1388
1785
|
await this.setStateAsync(`${dpSubFolder}listAll`, { val: JSON.stringify(this.listAllDevices), ack: true });
|
|
1389
1786
|
|
|
1390
|
-
if (this.linkQualityCount
|
|
1787
|
+
if (this.linkQualityCount === 0) {
|
|
1391
1788
|
// if no device is count, write the JSON List with default value
|
|
1392
1789
|
this.linkQualityDevices = [{ Device: '--none--', Adapter: '', 'Signal strength': '' }];
|
|
1393
1790
|
}
|
|
@@ -1396,14 +1793,8 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1396
1793
|
val: JSON.stringify(this.linkQualityDevices),
|
|
1397
1794
|
ack: true,
|
|
1398
1795
|
});
|
|
1399
|
-
//write HTML list
|
|
1400
|
-
if (this.config.createHtmlList)
|
|
1401
|
-
await this.setStateAsync(`${dpSubFolder}linkQualityListHTML`, {
|
|
1402
|
-
val: await this.creatLinkQualityListHTML(this.linkQualityDevices, this.linkQualityCount),
|
|
1403
|
-
ack: true,
|
|
1404
|
-
});
|
|
1405
1796
|
|
|
1406
|
-
if (this.offlineDevicesCount
|
|
1797
|
+
if (this.offlineDevicesCount === 0) {
|
|
1407
1798
|
// if no device is count, write the JSON List with default value
|
|
1408
1799
|
this.offlineDevices = [{ Device: '--none--', Adapter: '', 'Last contact': '' }];
|
|
1409
1800
|
}
|
|
@@ -1412,14 +1803,18 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1412
1803
|
val: JSON.stringify(this.offlineDevices),
|
|
1413
1804
|
ack: true,
|
|
1414
1805
|
});
|
|
1415
|
-
//write HTML list
|
|
1416
|
-
if (this.config.createHtmlList)
|
|
1417
|
-
await this.setStateAsync(`${dpSubFolder}offlineListHTML`, {
|
|
1418
|
-
val: await this.createOfflineListHTML(this.offlineDevices, this.offlineDevicesCount),
|
|
1419
|
-
ack: true,
|
|
1420
|
-
});
|
|
1421
1806
|
|
|
1422
|
-
if (this.
|
|
1807
|
+
if (this.upgradableDevicesCount === 0) {
|
|
1808
|
+
// if no device is count, write the JSON List with default value
|
|
1809
|
+
this.upgradableList = [{ Device: '--none--', Adapter: '', 'Last contact': '' }];
|
|
1810
|
+
}
|
|
1811
|
+
//write JSON list
|
|
1812
|
+
await this.setStateAsync(`${dpSubFolder}upgradableList`, {
|
|
1813
|
+
val: JSON.stringify(this.upgradableList),
|
|
1814
|
+
ack: true,
|
|
1815
|
+
});
|
|
1816
|
+
|
|
1817
|
+
if (this.batteryPoweredCount === 0) {
|
|
1423
1818
|
// if no device is count, write the JSON List with default value
|
|
1424
1819
|
this.batteryPowered = [{ Device: '--none--', Adapter: '', Battery: '' }];
|
|
1425
1820
|
}
|
|
@@ -1428,14 +1823,8 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1428
1823
|
val: JSON.stringify(this.batteryPowered),
|
|
1429
1824
|
ack: true,
|
|
1430
1825
|
});
|
|
1431
|
-
//write HTML list
|
|
1432
|
-
if (this.config.createHtmlList)
|
|
1433
|
-
await this.setStateAsync(`${dpSubFolder}batteryListHTML`, {
|
|
1434
|
-
val: await this.createBatteryListHTML(this.batteryPowered, this.batteryPoweredCount, false),
|
|
1435
|
-
ack: true,
|
|
1436
|
-
});
|
|
1437
1826
|
|
|
1438
|
-
if (this.lowBatteryPoweredCount
|
|
1827
|
+
if (this.lowBatteryPoweredCount === 0) {
|
|
1439
1828
|
// if no device is count, write the JSON List with default value
|
|
1440
1829
|
this.batteryLowPowered = [{ Device: '--none--', Adapter: '', Battery: '' }];
|
|
1441
1830
|
}
|
|
@@ -1444,12 +1833,26 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1444
1833
|
val: JSON.stringify(this.batteryLowPowered),
|
|
1445
1834
|
ack: true,
|
|
1446
1835
|
});
|
|
1836
|
+
|
|
1447
1837
|
//write HTML list
|
|
1448
|
-
if (this.config.createHtmlList)
|
|
1838
|
+
if (this.config.createHtmlList) {
|
|
1839
|
+
await this.setStateAsync(`${dpSubFolder}linkQualityListHTML`, {
|
|
1840
|
+
val: await this.creatLinkQualityListHTML(this.linkQualityDevices, this.linkQualityCount),
|
|
1841
|
+
ack: true,
|
|
1842
|
+
});
|
|
1843
|
+
await this.setStateAsync(`${dpSubFolder}offlineListHTML`, {
|
|
1844
|
+
val: await this.createOfflineListHTML(this.offlineDevices, this.offlineDevicesCount),
|
|
1845
|
+
ack: true,
|
|
1846
|
+
});
|
|
1847
|
+
await this.setStateAsync(`${dpSubFolder}batteryListHTML`, {
|
|
1848
|
+
val: await this.createBatteryListHTML(this.batteryPowered, this.batteryPoweredCount, false),
|
|
1849
|
+
ack: true,
|
|
1850
|
+
});
|
|
1449
1851
|
await this.setStateAsync(`${dpSubFolder}lowBatteryListHTML`, {
|
|
1450
1852
|
val: await this.createBatteryListHTML(this.batteryLowPowered, this.lowBatteryPoweredCount, true),
|
|
1451
1853
|
ack: true,
|
|
1452
1854
|
});
|
|
1855
|
+
}
|
|
1453
1856
|
|
|
1454
1857
|
// create timestamp of last run
|
|
1455
1858
|
const lastCheck = this.formatDate(new Date(), 'DD.MM.YYYY') + ' - ' + this.formatDate(new Date(), 'hh:mm:ss');
|
|
@@ -1488,7 +1891,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1488
1891
|
html += `<tr>
|
|
1489
1892
|
<td><font>${device.Device}</font></td>
|
|
1490
1893
|
<td align=center><font>${device.Adapter}</font></td>
|
|
1491
|
-
<td align=right><font>${device
|
|
1894
|
+
<td align=right><font>${device.SignalStrength}</font></td>
|
|
1492
1895
|
</tr>`;
|
|
1493
1896
|
}
|
|
1494
1897
|
|
|
@@ -1507,7 +1910,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1507
1910
|
return a.localeCompare(b);
|
|
1508
1911
|
});
|
|
1509
1912
|
let html = `<center>
|
|
1510
|
-
<b>Offline Devices: <font color=${deviceCount
|
|
1913
|
+
<b>Offline Devices: <font color=${deviceCount === 0 ? '#3bcf0e' : 'orange'}>${deviceCount}</b><small></small></font>
|
|
1511
1914
|
<p></p>
|
|
1512
1915
|
</center>
|
|
1513
1916
|
<table width=100%>
|
|
@@ -1524,7 +1927,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1524
1927
|
html += `<tr>
|
|
1525
1928
|
<td><font>${device.Device}</font></td>
|
|
1526
1929
|
<td align=center><font>${device.Adapter}</font></td>
|
|
1527
|
-
<td align=center><font color=orange>${device
|
|
1930
|
+
<td align=center><font color=orange>${device.LastContact}</font></td>
|
|
1528
1931
|
</tr>`;
|
|
1529
1932
|
}
|
|
1530
1933
|
|
|
@@ -1544,7 +1947,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1544
1947
|
return a.localeCompare(b);
|
|
1545
1948
|
});
|
|
1546
1949
|
let html = `<center>
|
|
1547
|
-
<b>${isLowBatteryList
|
|
1950
|
+
<b>${isLowBatteryList === true ? 'Schwache ' : ''}Batterie Devices: <font color=${isLowBatteryList === true ? (deviceCount > 0 ? 'orange' : '#3bcf0e') : ''}>${deviceCount}</b></font>
|
|
1548
1951
|
<p></p>
|
|
1549
1952
|
</center>
|
|
1550
1953
|
<table width=100%>
|
|
@@ -1792,6 +2195,54 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1792
2195
|
},
|
|
1793
2196
|
native: {},
|
|
1794
2197
|
});
|
|
2198
|
+
|
|
2199
|
+
await this.setObjectNotExistsAsync(`${adptName}.upgradableCount`, {
|
|
2200
|
+
type: 'state',
|
|
2201
|
+
common: {
|
|
2202
|
+
name: {
|
|
2203
|
+
en: 'Number of devices with available updates ',
|
|
2204
|
+
de: 'Anzahl der Geräte mit verfügbaren Updates',
|
|
2205
|
+
ru: 'Количество устройств с доступными обновлениями',
|
|
2206
|
+
pt: 'Número de dispositivos com atualizações disponíveis',
|
|
2207
|
+
nl: 'Nummer van apparatuur met beschikbare updates',
|
|
2208
|
+
fr: 'Nombre de dispositifs avec mises à jour disponibles',
|
|
2209
|
+
it: 'Numero di dispositivi con aggiornamenti disponibili',
|
|
2210
|
+
es: 'Número de dispositivos con actualizaciones disponibles',
|
|
2211
|
+
pl: 'Liczba urządzeń z dostępną aktualizacją',
|
|
2212
|
+
uk: 'Кількість пристроїв з доступними оновленнями',
|
|
2213
|
+
'zh-cn': '现有更新的装置数目',
|
|
2214
|
+
},
|
|
2215
|
+
type: 'number',
|
|
2216
|
+
role: 'value',
|
|
2217
|
+
read: true,
|
|
2218
|
+
write: false,
|
|
2219
|
+
},
|
|
2220
|
+
native: {},
|
|
2221
|
+
});
|
|
2222
|
+
|
|
2223
|
+
await this.setObjectNotExistsAsync(`${adptName}.upgradableList`, {
|
|
2224
|
+
type: 'state',
|
|
2225
|
+
common: {
|
|
2226
|
+
name: {
|
|
2227
|
+
en: 'JSON List of devices with available updates ',
|
|
2228
|
+
de: 'JSON Liste der Geräte mit verfügbaren Updates',
|
|
2229
|
+
ru: 'ДЖСОН Список устройств с доступными обновлениями',
|
|
2230
|
+
pt: 'J. Lista de dispositivos com atualizações disponíveis',
|
|
2231
|
+
nl: 'JSON List van apparatuur met beschikbare updates',
|
|
2232
|
+
fr: 'JSON Liste des appareils avec mises à jour disponibles',
|
|
2233
|
+
it: 'JSON Elenco dei dispositivi con aggiornamenti disponibili',
|
|
2234
|
+
es: 'JSON Lista de dispositivos con actualizaciones disponibles',
|
|
2235
|
+
pl: 'JSON Lista urządzeń korzystających z aktualizacji',
|
|
2236
|
+
uk: 'Сонце Перелік пристроїв з доступними оновленнями',
|
|
2237
|
+
'zh-cn': '附 件 现有最新设备清单',
|
|
2238
|
+
},
|
|
2239
|
+
type: 'array',
|
|
2240
|
+
role: 'json',
|
|
2241
|
+
read: true,
|
|
2242
|
+
write: false,
|
|
2243
|
+
},
|
|
2244
|
+
native: {},
|
|
2245
|
+
});
|
|
1795
2246
|
}
|
|
1796
2247
|
|
|
1797
2248
|
/**
|