iobroker.device-watcher 0.2.4 → 0.3.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/main.js CHANGED
@@ -26,156 +26,172 @@ class DeviceWatcher extends utils.Adapter {
26
26
  this.on('unload', this.onUnload.bind(this));
27
27
 
28
28
  // arrays
29
- this.offlineDevices = [],
30
- this.linkQualityDevices = [];
31
- this.batteryPowered = [];
32
- this.batteryLowPowered = [];
33
- this.listAllDevices = [];
34
- this.blacklistArr = [];
35
- this.arrDev = [];
36
- this.adapterSelected = [];
29
+ this.offlineDevices = [];
30
+ this.linkQualityDevices = [];
31
+ this.batteryPowered = [];
32
+ this.batteryLowPowered = [];
33
+ this.listAllDevices = [];
34
+ this.blacklistArr = [];
35
+ this.arrDev = [];
36
+ this.adapterSelected = [];
37
37
 
38
38
  // counts
39
- this.offlineDevicesCount = 0;
40
- this.deviceCounter = 0;
41
- this.linkQualityCount = 0;
42
- this.batteryPoweredCount = 0;
43
- this.lowBatteryPoweredCount = 0;
39
+ this.offlineDevicesCount = 0;
40
+ this.deviceCounter = 0;
41
+ this.linkQualityCount = 0;
42
+ this.batteryPoweredCount = 0;
43
+ this.lowBatteryPoweredCount = 0;
44
44
 
45
- this.deviceReachable = '';
45
+ this.deviceReachable = '';
46
46
 
47
47
  // arrays of supported adapters
48
48
  this.arrApart = {
49
- alexa2: {
50
- 'Selektor':'alexa2.*.online',
51
- 'adapter':'alexa2',
52
- 'battery':'none',
53
- 'reach':'.online',
54
- 'isLowBat':'none'
49
+ alexa2: {
50
+ 'Selektor': 'alexa2.*.online',
51
+ 'adapter': 'alexa2',
52
+ 'battery': 'none',
53
+ 'reach': '.online',
54
+ 'isLowBat': 'none'
55
55
  },
56
- ble: {
57
- 'Selektor':'ble.*.rssi',
58
- 'adapter':'ble',
59
- 'battery':'.battery',
60
- 'reach':'none',
61
- 'isLowBat':'none'
56
+ ble: {
57
+ 'Selektor': 'ble.*.rssi',
58
+ 'adapter': 'ble',
59
+ 'battery': '.battery',
60
+ 'reach': 'none',
61
+ 'isLowBat': 'none'
62
62
  },
63
- esphome: {
64
- 'Selektor':'esphome.*._online',
65
- 'adapter':'esphome',
66
- 'battery':'none',
67
- 'reach':'._online',
68
- 'isLowBat':'none',
69
- 'id':'.name'
63
+ deconz: {
64
+ 'Selektor': 'deconz.*.reachable',
65
+ 'adapter': 'deconz',
66
+ 'battery': '.battery',
67
+ 'reach': '.reachable',
68
+ 'isLowBat': 'none'
70
69
  },
71
- zigbee: {
72
- 'Selektor':'zigbee.*.link_quality',
73
- 'adapter':'zigbee',
74
- 'battery':'.battery',
75
- 'reach':'.available',
76
- 'isLowBat':'.battery_low'
70
+ enocean: {
71
+ 'Selektor': 'enocean.*.rssi',
72
+ 'adapter': 'enocean',
73
+ 'battery': '.BS',
74
+ 'reach': 'none',
75
+ 'isLowBat': 'none'
77
76
  },
78
- sonoff: {
79
- 'Selektor':'sonoff.*.Uptime',
80
- 'adapter':'sonoff',
81
- 'rssiState': '.Wifi_RSSI',
82
- 'battery':'.battery',
83
- 'reach':'.alive',
84
- 'isLowBat':'none'
77
+ esphome: {
78
+ 'Selektor': 'esphome.*._online',
79
+ 'adapter': 'esphome',
80
+ 'battery': 'none',
81
+ 'reach': '._online',
82
+ 'isLowBat': 'none',
83
+ 'id': '.name'
85
84
  },
86
- shelly: {
87
- 'Selektor':'shelly.*.rssi',
88
- 'adapter':'shelly',
89
- 'battery':'.sensor.battery',
90
- 'reach':'.online',
91
- 'isLowBat':'none'
85
+ fritzdect: {
86
+ 'Selektor': 'fritzdect.*.present',
87
+ 'adapter': 'fritzDect',
88
+ 'battery': '.battery',
89
+ 'reach': '.present',
90
+ 'isLowBat': '.batterylow'
92
91
  },
93
- homematic: {
94
- 'Selektor':'hm-rpc.*.UNREACH',
95
- 'adapter':'homematic',
96
- 'rssiState':'.RSSI_DEVICE',
97
- 'battery':'.OPERATING_VOLTAGE',
98
- 'reach':'.UNREACH',
99
- 'isLowBat':'.LOW_BAT',
100
- 'isLowBat2':'.LOWBAT'
92
+ homematic: {
93
+ 'Selektor': 'hm-rpc.*.UNREACH',
94
+ 'adapter': 'homematic',
95
+ 'rssiState': '.RSSI_DEVICE',
96
+ 'battery': '.OPERATING_VOLTAGE',
97
+ 'reach': '.UNREACH',
98
+ 'isLowBat': '.LOW_BAT',
99
+ 'isLowBat2': '.LOWBAT'
101
100
  },
102
- deconz: {
103
- 'Selektor':'deconz.*.reachable',
104
- 'adapter':'deconz',
105
- 'battery':'.battery',
106
- 'reach':'.reachable',
107
- 'isLowBat':'none'
101
+ hue: {
102
+ 'Selektor': 'hue.*.reachable',
103
+ 'adapter': 'hue',
104
+ 'battery': '.battery',
105
+ 'reach': '.reachable',
106
+ 'isLowBat': 'none'
108
107
  },
109
- zwave: {
110
- 'Selektor':'zwave2.*.ready',
111
- 'adapter':'zwave',
112
- 'battery':'.Battery.level',
113
- 'reach':'.ready',
114
- 'isLowBat':'.Battery.isLow'
108
+ hueExt: {
109
+ 'Selektor': 'hue-extended.*.reachable',
110
+ 'adapter': 'hue-extended',
111
+ 'battery': '.config.battery',
112
+ 'reach': '.reachable',
113
+ 'isLowBat': 'none'
115
114
  },
116
- dect: {
117
- 'Selektor':'fritzdect.*.present',
118
- 'adapter':'fritzDect',
119
- 'battery':'.battery',
120
- 'reach':'.present',
121
- 'isLowBat':'.batterylow'
115
+ mihome: {
116
+ 'Selektor': 'mihome.*.percent',
117
+ 'adapter': 'miHome',
118
+ 'battery': '.percent',
119
+ 'reach': 'none',
120
+ 'isLowBat': 'none'
122
121
  },
123
- hue: {
124
- 'Selektor':'hue.*.reachable',
125
- 'adapter':'hue',
126
- 'battery':'.battery',
127
- 'reach':'.reachable',
128
- 'isLowBat':'none'
122
+ mihomeGW: {
123
+ 'Selektor': 'mihome.*.connected',
124
+ 'adapter': 'miHome',
125
+ 'battery': 'none',
126
+ 'reach': '.connected',
127
+ 'isLowBat': 'none'
129
128
  },
130
- hueExt: {
131
- 'Selektor':'hue-extended.*.reachable',
132
- 'adapter':'hue-extended',
133
- 'battery':'.config.battery',
134
- 'reach':'.reachable',
135
- 'isLowBat':'none'
129
+ mihomeVacuum: {
130
+ 'Selektor': 'mihome-vacuum.*.wifi_signal',
131
+ 'adapter': 'mihomeVacuum',
132
+ 'rssiState': '.wifi_signal',
133
+ 'battery': '.info.battery',
134
+ 'battery2': '.control.battary_life',
135
+ 'reach': '.connection',
136
+ 'isLowBat': 'none'
136
137
  },
137
- ping: {
138
- 'Selektor':'ping.*.alive',
139
- 'adapter':'ping',
140
- 'battery':'none',
141
- 'reach':'.alive',
142
- 'isLowBat':'none'
138
+ nukiExt: {
139
+ 'Selektor': 'nuki-extended.*.batteryCritical',
140
+ 'adapter': 'nuki-extended',
141
+ 'battery': '.batteryCharge',
142
+ 'reach': 'none',
143
+ 'isLowBat': '.batteryCritical'
143
144
  },
144
- switchbotBle: {
145
- 'Selektor':'switchbot-ble.*.rssi',
146
- 'adapter':'switchbotBle',
147
- 'battery':'.battery',
148
- 'reach':'none',
149
- 'isLowBat':'none',
150
- 'id':'.id'
145
+ ping: {
146
+ 'Selektor': 'ping.*.alive',
147
+ 'adapter': 'ping',
148
+ 'battery': 'none',
149
+ 'reach': '.alive',
150
+ 'isLowBat': 'none'
151
151
  },
152
- sonos: {
153
- 'Selektor':'sonos.*.alive',
154
- 'adapter':'sonos',
155
- 'battery':'none',
156
- 'reach':'.alive',
157
- 'isLowBat':'none'
152
+ shelly: {
153
+ 'Selektor': 'shelly.*.rssi',
154
+ 'adapter': 'shelly',
155
+ 'battery': '.sensor.battery',
156
+ 'reach': '.online',
157
+ 'isLowBat': 'none'
158
158
  },
159
- mihome: {
160
- 'Selektor':'mihome.*.percent',
161
- 'adapter':'miHome',
162
- 'battery':'.percent',
163
- 'reach':'none',
164
- 'isLowBat':'none'
159
+ sonoff: {
160
+ 'Selektor': 'sonoff.*.Uptime',
161
+ 'adapter': 'sonoff',
162
+ 'rssiState': '.Wifi_Signal',
163
+ 'battery': '.battery',
164
+ 'reach': '.alive',
165
+ 'isLowBat': 'none'
165
166
  },
166
- mihomeGW: {
167
- 'Selektor':'mihome.*.connected',
168
- 'adapter':'miHome',
169
- 'battery':'none',
170
- 'reach':'.connected',
171
- 'isLowBat':'none'
167
+ sonos: {
168
+ 'Selektor': 'sonos.*.alive',
169
+ 'adapter': 'sonos',
170
+ 'battery': 'none',
171
+ 'reach': '.alive',
172
+ 'isLowBat': 'none'
172
173
  },
173
- nukiExt: {
174
- 'Selektor':'nuki-extended.*.batteryCritical',
175
- 'adapter':'nuki-extended',
176
- 'battery':'.batteryCharge',
177
- 'reach':'none',
178
- 'isLowBat':'.batteryCritical'
174
+ switchbotBle: {
175
+ 'Selektor': 'switchbot-ble.*.rssi',
176
+ 'adapter': 'switchbotBle',
177
+ 'battery': '.battery',
178
+ 'reach': 'none',
179
+ 'isLowBat': 'none',
180
+ 'id': '.id'
181
+ },
182
+ zigbee: {
183
+ 'Selektor': 'zigbee.*.link_quality',
184
+ 'adapter': 'zigbee',
185
+ 'battery': '.battery',
186
+ 'reach': '.available',
187
+ 'isLowBat': '.battery_low'
188
+ },
189
+ zwave: {
190
+ 'Selektor': 'zwave2.*.ready',
191
+ 'adapter': 'zwave',
192
+ 'battery': '.Battery.level',
193
+ 'reach': '.ready',
194
+ 'isLowBat': '.Battery.isLow'
179
195
  }
180
196
  };
181
197
  }
@@ -200,27 +216,29 @@ class DeviceWatcher extends utils.Adapter {
200
216
 
201
217
  try {
202
218
  this.supAdapter = {
203
- alexa2: this.config.alexa2Devices,
204
- esphome: this.config.esphomeDevices,
205
- zigbee: this.config.zigbeeDevices,
206
- ble: this.config.bleDevices,
207
- sonoff: this.config.sonoffDevices,
208
- shelly: this.config.shellyDevices,
209
- homematic: this.config.homematicDevices,
210
- deconz: this.config.deconzDevices,
211
- zwave: this.config.zwaveDevices,
212
- dect: this.config.dectDevices,
213
- hue: this.config.hueDevices,
214
- hueExt: this.config.hueExtDevices,
215
- nukiExt: this.config.nukiExtDevices,
216
- ping: this.config.pingDevices,
217
- switchbotBle: this.config.switchbotBleDevices,
218
- sonos: this.config.sonosDevices,
219
- mihome: this.config.mihomeDevices,
220
- mihomeGW: this.config.mihomeDevices
219
+ alexa2: this.config.alexa2Devices,
220
+ ble: this.config.bleDevices,
221
+ deconz: this.config.deconzDevices,
222
+ enocean: this.config.enoceanDevices,
223
+ esphome: this.config.esphomeDevices,
224
+ fritzdect: this.config.fritzdectDevices,
225
+ homematic: this.config.homematicDevices,
226
+ hue: this.config.hueDevices,
227
+ hueExt: this.config.hueExtDevices,
228
+ mihome: this.config.mihomeDevices,
229
+ mihomeGW: this.config.mihomeDevices,
230
+ mihomeVacuum: this.config.mihomeVacuumDevices,
231
+ nukiExt: this.config.nukiExtDevices,
232
+ ping: this.config.pingDevices,
233
+ shelly: this.config.shellyDevices,
234
+ sonoff: this.config.sonoffDevices,
235
+ sonos: this.config.sonosDevices,
236
+ switchbotBle: this.config.switchbotBleDevices,
237
+ zigbee: this.config.zigbeeDevices,
238
+ zwave: this.config.zwaveDevices,
221
239
  };
222
240
 
223
- for(const [id] of Object.entries(this.arrApart)) {
241
+ for (const [id] of Object.entries(this.arrApart)) {
224
242
  if (this.supAdapter[id]) {
225
243
  this.arrDev.push(this.arrApart[id]);
226
244
  this.adapterSelected.push(await this.capitalize(id));
@@ -238,11 +256,12 @@ class DeviceWatcher extends utils.Adapter {
238
256
 
239
257
  //create and fill datapoints for each adapter if selected
240
258
  try {
241
- for(const [id] of Object.entries(this.arrApart)) {
259
+ for (const [id] of Object.entries(this.arrApart)) {
242
260
  if (this.supAdapter[id]) {
243
261
 
244
262
  if (this.config.createOwnFolder) {
245
263
  await this.createDPsForEachAdapter(id);
264
+ if (this.config.createHtmlList) await this.createHtmlListDatapoints(id);
246
265
  this.log.debug(`Created datapoints for ${await this.capitalize(id)}`);
247
266
  await this.createDataForEachAdapter(id);
248
267
  this.log.debug(`Created and filled data for each adapter`);
@@ -255,6 +274,7 @@ class DeviceWatcher extends utils.Adapter {
255
274
 
256
275
  // creating counts and lists of all selected adapter
257
276
  try {
277
+ if (this.config.createHtmlList) await this.createHtmlListDatapoints();
258
278
  await this.createDataOfAllAdapter();
259
279
  this.log.debug(`Created and filled data for all adapters`);
260
280
  } catch (error) {
@@ -270,17 +290,16 @@ class DeviceWatcher extends utils.Adapter {
270
290
 
271
291
 
272
292
  /**
273
- * @param {string} [sentence] - Word which should be capitalize
274
- **/
275
- async capitalize(sentence)
276
- {
293
+ * @param {string} [sentence] - Word which should be capitalize
294
+ **/
295
+ async capitalize(sentence) {
277
296
  //make the first letter uppercase
278
297
  return sentence && sentence[0].toUpperCase() + sentence.slice(1);
279
298
  }
280
299
 
281
300
  /**
282
- * @param {object} [obj] - State of datapoint
283
- **/
301
+ * @param {object} [obj] - State of datapoint
302
+ **/
284
303
  async getInitValue(obj) {
285
304
  //state can be null or undefinded
286
305
  const foreignState = await this.getForeignStateAsync(obj);
@@ -288,8 +307,8 @@ class DeviceWatcher extends utils.Adapter {
288
307
  }
289
308
 
290
309
  /**
291
- * @param {object} [obj] - State of own datapoint
292
- **/
310
+ * @param {object} [obj] - State of own datapoint
311
+ **/
293
312
  async getOwnInitValue(obj) {
294
313
  //state can be null or undefinded for own states
295
314
  const stateVal = await this.getStateAsync(obj);
@@ -298,8 +317,8 @@ class DeviceWatcher extends utils.Adapter {
298
317
 
299
318
  //create datapoints for each adapter
300
319
  /**
301
- * @param {object} [adptName] - Adaptername of devices
302
- **/
320
+ * @param {object} [adptName] - Adaptername of devices
321
+ **/
303
322
  async createDPsForEachAdapter(adptName) {
304
323
 
305
324
  await this.setObjectNotExistsAsync(`${adptName}`, {
@@ -332,6 +351,7 @@ class DeviceWatcher extends utils.Adapter {
332
351
  },
333
352
  'native': {}
334
353
  });
354
+
335
355
  await this.setObjectNotExistsAsync(`${adptName}.offlineList`, {
336
356
  'type': 'state',
337
357
  'common': {
@@ -354,6 +374,7 @@ class DeviceWatcher extends utils.Adapter {
354
374
  },
355
375
  'native': {}
356
376
  });
377
+
357
378
  await this.setObjectNotExistsAsync(`${adptName}.listAll`, {
358
379
  'type': 'state',
359
380
  'common': {
@@ -376,6 +397,7 @@ class DeviceWatcher extends utils.Adapter {
376
397
  },
377
398
  'native': {}
378
399
  });
400
+
379
401
  await this.setObjectNotExistsAsync(`${adptName}.linkQualityList`, {
380
402
  'type': 'state',
381
403
  'common': {
@@ -398,6 +420,7 @@ class DeviceWatcher extends utils.Adapter {
398
420
  },
399
421
  'native': {}
400
422
  });
423
+
401
424
  await this.setObjectNotExistsAsync(`${adptName}.countAll`, {
402
425
  'type': 'state',
403
426
  'common': {
@@ -420,6 +443,7 @@ class DeviceWatcher extends utils.Adapter {
420
443
  },
421
444
  'native': {}
422
445
  });
446
+
423
447
  await this.setObjectNotExistsAsync(`${adptName}.batteryList`, {
424
448
  'type': 'state',
425
449
  'common': {
@@ -442,6 +466,7 @@ class DeviceWatcher extends utils.Adapter {
442
466
  },
443
467
  'native': {}
444
468
  });
469
+
445
470
  await this.setObjectNotExistsAsync(`${adptName}.lowBatteryList`, {
446
471
  'type': 'state',
447
472
  'common': {
@@ -464,6 +489,7 @@ class DeviceWatcher extends utils.Adapter {
464
489
  },
465
490
  'native': {}
466
491
  });
492
+
467
493
  await this.setObjectNotExistsAsync(`${adptName}.lowBatteryCount`, {
468
494
  'type': 'state',
469
495
  'common': {
@@ -486,6 +512,7 @@ class DeviceWatcher extends utils.Adapter {
486
512
  },
487
513
  'native': {}
488
514
  });
515
+
489
516
  await this.setObjectNotExistsAsync(`${adptName}.batteryCount`, {
490
517
  'type': 'state',
491
518
  'common': {
@@ -511,25 +538,131 @@ class DeviceWatcher extends utils.Adapter {
511
538
  }
512
539
 
513
540
  /**
514
- * @param {object} [i] - Device Object
515
- **/
541
+ * @param {object} [adptName] - Adaptername of devices
542
+ **/
543
+ async createHtmlListDatapoints(adptName) {
544
+
545
+ let dpSubFolder;
546
+ //write the datapoints in subfolders with the adaptername otherwise write the dP's in the root folder
547
+ if (adptName) {
548
+ dpSubFolder = `${adptName}.`;
549
+ } else {
550
+ dpSubFolder = '';
551
+ }
552
+
553
+ await this.setObjectNotExistsAsync(`${dpSubFolder}offlineListHTML`, {
554
+ 'type': 'state',
555
+ 'common': {
556
+ 'name': {
557
+ 'en': 'HTML List of offline devices',
558
+ 'de': 'HTML Liste der Offline-Geräte',
559
+ 'ru': 'HTML Список оффлайн устройств',
560
+ 'pt': 'HTML Lista de dispositivos off-line',
561
+ 'nl': 'HTML List van offline apparatuur',
562
+ 'fr': 'HTML Liste des dispositifs hors ligne',
563
+ 'it': 'HTML Elenco dei dispositivi offline',
564
+ 'es': 'HTML Lista de dispositivos sin conexión',
565
+ 'pl': 'HTML Lista urządzeń offline',
566
+ 'zh-cn': 'HTML 线装置清单'
567
+ },
568
+ 'type': 'string',
569
+ 'role': 'html',
570
+ 'read': true,
571
+ 'write': false,
572
+ },
573
+ 'native': {}
574
+ });
575
+
576
+ await this.setObjectNotExistsAsync(`${dpSubFolder}linkQualityListHTML`, {
577
+ 'type': 'state',
578
+ 'common': {
579
+ 'name': {
580
+ 'en': 'HTML List of devices with signal strength',
581
+ 'de': 'HTML Liste der Geräte mit Signalstärke',
582
+ 'ru': 'HTML Список устройств с силой сигнала',
583
+ 'pt': 'HTML Lista de dispositivos com força de sinal',
584
+ 'nl': 'HTML List van apparaten met signaalkracht',
585
+ 'fr': 'HTML Liste des dispositifs avec force de signal',
586
+ 'it': 'HTML Elenco dei dispositivi con forza del segnale',
587
+ 'es': 'HTML Lista de dispositivos con fuerza de señal',
588
+ 'pl': 'HTML Lista urządzeń z siłą sygnałową',
589
+ 'zh-cn': 'HTML 具有信号实力的装置清单'
590
+ },
591
+ 'type': 'string',
592
+ 'role': 'value',
593
+ 'read': true,
594
+ 'write': false,
595
+ },
596
+ 'native': {}
597
+ });
598
+
599
+ await this.setObjectNotExistsAsync(`${dpSubFolder}batteryListHTML`, {
600
+ 'type': 'state',
601
+ 'common': {
602
+ 'name': {
603
+ 'en': 'HTML List of devices with battery state',
604
+ 'de': 'HTML Liste der Geräte mit Batteriezustand',
605
+ 'ru': 'HTML Список устройств с состоянием батареи',
606
+ 'pt': 'HTML Lista de dispositivos com estado da bateria',
607
+ 'nl': 'HTML List van apparaten met batterij staat',
608
+ 'fr': 'HTML Liste des appareils avec état de batterie',
609
+ 'it': 'HTML Elenco dei dispositivi con stato della batteria',
610
+ 'es': 'HTML Lista de dispositivos con estado de batería',
611
+ 'pl': 'HTML Lista urządzeń z baterią stanową',
612
+ 'zh-cn': 'HTML 电池国装置清单'
613
+ },
614
+ 'type': 'string',
615
+ 'role': 'html',
616
+ 'read': true,
617
+ 'write': false,
618
+ },
619
+ 'native': {}
620
+ });
621
+
622
+ await this.setObjectNotExistsAsync(`${dpSubFolder}lowBatteryListHTML`, {
623
+ 'type': 'state',
624
+ 'common': {
625
+ 'name': {
626
+ 'en': 'HTML List of devices with low battery state',
627
+ 'de': 'HTML Liste der Geräte mit niedrigem Batteriezustand',
628
+ 'ru': 'HTML Список устройств с низким состоянием батареи',
629
+ 'pt': 'HTML Lista de dispositivos com baixo estado da bateria',
630
+ 'nl': 'HTML List van apparaten met lage batterij staat',
631
+ 'fr': 'HTML Liste des appareils à faible état de batterie',
632
+ 'it': 'HTML Elenco di dispositivi con stato di batteria basso',
633
+ 'es': 'HTML Lista de dispositivos con estado de batería bajo',
634
+ 'pl': 'HTML Lista urządzeń o niskim stanie baterii',
635
+ 'zh-cn': 'HTML 低电池国家装置清单'
636
+ },
637
+ 'type': 'string',
638
+ 'role': 'html',
639
+ 'read': true,
640
+ 'write': false,
641
+ },
642
+ 'native': {}
643
+ });
644
+ }
645
+
646
+ /**
647
+ * @param {object} [i] - Device Object
648
+ **/
516
649
  async createData(i) {
517
- const devices = await this.getForeignStatesAsync(this.arrDev[i].Selektor);
650
+ const devices = await this.getForeignStatesAsync(this.arrDev[i].Selektor);
518
651
  const deviceAdapterName = await this.capitalize(this.arrDev[i].adapter);
519
- const myBlacklist = this.config.tableBlacklist;
652
+ const myBlacklist = this.config.tableBlacklist;
520
653
 
521
654
  /*---------- Loop for blacklist ----------*/
522
- for(const i in myBlacklist){
655
+ for (const i in myBlacklist) {
523
656
  this.blacklistArr.push(myBlacklist[i].device);
524
657
  this.log.debug(`Found items on the blacklist: ${this.blacklistArr}`);
525
658
  }
526
659
 
527
660
  /*---------- Start of second main loop ----------*/
528
- for(const [id] of Object.entries(devices)) {
661
+ for (const [id] of Object.entries(devices)) {
529
662
  if (!this.blacklistArr.includes(id)) {
530
663
 
531
- const currDeviceString = id.slice(0, (id.lastIndexOf('.') + 1) - 1);
532
- const shortCurrDeviceString = currDeviceString.slice(0, (currDeviceString.lastIndexOf('.') + 1) - 1);
664
+ const currDeviceString = id.slice(0, (id.lastIndexOf('.') + 1) - 1);
665
+ const shortCurrDeviceString = currDeviceString.slice(0, (currDeviceString.lastIndexOf('.') + 1) - 1);
533
666
 
534
667
  //Get device name
535
668
  const deviceObject = await this.getForeignObjectAsync(currDeviceString);
@@ -543,7 +676,9 @@ class DeviceWatcher extends utils.Adapter {
543
676
  break;
544
677
 
545
678
  case 'hue-extended':
546
- if (shortDeviceObject && typeof shortDeviceObject === 'object') {
679
+ case 'mihomeVacuum':
680
+ case 'homematic':
681
+ if (shortDeviceObject && typeof shortDeviceObject === 'object') {
547
682
  deviceName = shortDeviceObject.common.name;
548
683
  }
549
684
  break;
@@ -556,31 +691,34 @@ class DeviceWatcher extends utils.Adapter {
556
691
  }
557
692
 
558
693
  const deviceMainSelector = await this.getForeignStateAsync(id);
694
+
559
695
  // 3. Get battery states
560
- const deviceBatteryState = await this.getInitValue(currDeviceString + this.arrDev[i].battery);
561
- const shortDeviceBatteryState = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].battery);
696
+ const deviceBatteryState = await this.getInitValue(currDeviceString + this.arrDev[i].battery);
697
+ const shortDeviceBatteryState = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].battery);
698
+ const shortDeviceBatteryState2 = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].battery2);
562
699
 
563
700
  // 1. Get link quality
564
701
  let deviceQualityState;
565
702
  let linkQuality;
566
703
 
567
704
  switch (this.arrDev[i].adapter) {
568
- case 'homematic':
569
705
  case 'sonoff':
706
+ case 'mihomeVacuum':
707
+ case 'homematic':
570
708
  deviceQualityState = await this.getForeignStateAsync(currDeviceString + this.arrDev[i].rssiState);
571
709
  break;
572
710
  default:
573
711
  deviceQualityState = await this.getForeignStateAsync(id);
574
712
  }
575
713
 
576
- if ((deviceQualityState) && (typeof deviceQualityState.val === 'number')){
714
+ if ((deviceQualityState) && (typeof deviceQualityState.val === 'number')) {
577
715
  if (this.config.trueState) {
578
716
  linkQuality = deviceQualityState.val;
579
717
  } else {
580
718
  if (deviceQualityState.val < 0) {
581
719
  linkQuality = Math.min(Math.max(2 * (deviceQualityState.val + 100), 0), 100) + '%';
582
720
  } else if ((deviceQualityState.val) >= 0) {
583
- linkQuality = parseFloat((100/255 * deviceQualityState.val).toFixed(0)) + '%';
721
+ linkQuality = parseFloat((100 / 255 * deviceQualityState.val).toFixed(0)) + '%';
584
722
  }
585
723
  }
586
724
  if (this.config.listOnlyBattery) {
@@ -603,7 +741,7 @@ class DeviceWatcher extends utils.Adapter {
603
741
  );
604
742
  }
605
743
  } else {
606
- // no linkQuality available for powered devices
744
+ // no linkQuality available for powered devices
607
745
  linkQuality = ' - ';
608
746
  }
609
747
 
@@ -621,14 +759,13 @@ class DeviceWatcher extends utils.Adapter {
621
759
  const lastStateChange = Math.round((time.getTime() - deviceMainSelector.lc) / 1000 / 60);
622
760
  const deviceUnreachState = await this.getInitValue(currDeviceString + this.arrDev[i].reach);
623
761
 
624
-
625
762
  const getLastContact = async () => {
626
763
  lastContactString = this.formatDate(new Date((deviceMainSelector.ts)), 'hh:mm') + ' Uhr';
627
764
  if (Math.round(lastContact) > 100) {
628
- lastContactString = Math.round(lastContact/60) + ' Stunden';
765
+ lastContactString = Math.round(lastContact / 60) + ' Stunden';
629
766
  }
630
- if (Math.round(lastContact/60) > 48) {
631
- lastContactString = Math.round(lastContact/60/24) + ' Tagen';
767
+ if (Math.round(lastContact / 60) > 48) {
768
+ lastContactString = Math.round(lastContact / 60 / 24) + ' Tagen';
632
769
  }
633
770
  return lastContactString;
634
771
  };
@@ -636,10 +773,10 @@ class DeviceWatcher extends utils.Adapter {
636
773
  const getLastStateChange = async () => {
637
774
  lastContactString = this.formatDate(new Date((deviceMainSelector.lc)), 'hh:mm') + ' Uhr';
638
775
  if (Math.round(lastStateChange) > 100) {
639
- lastContactString = Math.round(lastStateChange/60) + ' Stunden';
776
+ lastContactString = Math.round(lastStateChange / 60) + ' Stunden';
640
777
  }
641
- if (Math.round(lastStateChange/60) > 48) {
642
- lastContactString = Math.round(lastStateChange/60/24) + ' Tagen';
778
+ if (Math.round(lastStateChange / 60) > 48) {
779
+ lastContactString = Math.round(lastStateChange / 60 / 24) + ' Tagen';
643
780
  }
644
781
  return lastContactString;
645
782
  };
@@ -717,6 +854,17 @@ class DeviceWatcher extends utils.Adapter {
717
854
  await pushOfflineDevice();
718
855
  }
719
856
  break;
857
+ case 'enocean':
858
+ if (this.config.enoceanMaxMinutes === -1) {
859
+ if (!deviceUnreachState) {
860
+ deviceState = 'Offline'; //set online state to offline
861
+ await pushOfflineDevice();
862
+ }
863
+ } else if (lastContact > this.config.enoceanMaxMinutes) {
864
+ deviceState = 'Offline'; //set online state to offline
865
+ await pushOfflineDevice();
866
+ }
867
+ break;
720
868
  case 'esphome':
721
869
  if (this.config.esphomeMaxMinutes === -1) {
722
870
  if (!deviceUnreachState) {
@@ -783,6 +931,17 @@ class DeviceWatcher extends utils.Adapter {
783
931
  await pushOfflineDevice();
784
932
  }
785
933
  break;
934
+ case 'mihomeVacuum':
935
+ if (this.config.mihomeVacuumMaxMinutes === -1) {
936
+ if (!deviceUnreachState) {
937
+ deviceState = 'Offline'; //set online state to offline
938
+ await pushOfflineDevice();
939
+ }
940
+ } else if (lastContact > this.config.mihomeVacuumMaxMinutes) {
941
+ deviceState = 'Offline'; //set online state to offline
942
+ await pushOfflineDevice();
943
+ }
944
+ break;
786
945
  case 'nuki-extended':
787
946
  if (this.config.nukiextendMaxMinutes === -1) {
788
947
  if (!deviceUnreachState) {
@@ -917,6 +1076,27 @@ class DeviceWatcher extends utils.Adapter {
917
1076
  );
918
1077
  }
919
1078
  break;
1079
+ case 'mihomeVacuum':
1080
+ if (shortDeviceBatteryState) {
1081
+ batteryHealth = shortDeviceBatteryState + '%';
1082
+ this.batteryPowered.push(
1083
+ {
1084
+ 'Device': deviceName,
1085
+ 'Adapter': deviceAdapterName,
1086
+ 'Battery': batteryHealth
1087
+ }
1088
+ );
1089
+ } else if (shortDeviceBatteryState2) {
1090
+ batteryHealth = shortDeviceBatteryState2 + '%';
1091
+ this.batteryPowered.push(
1092
+ {
1093
+ 'Device': deviceName,
1094
+ 'Adapter': deviceAdapterName,
1095
+ 'Battery': batteryHealth
1096
+ }
1097
+ );
1098
+ }
1099
+ break;
920
1100
  default:
921
1101
  batteryHealth = (deviceBatteryState) + '%';
922
1102
  this.batteryPowered.push(
@@ -933,9 +1113,9 @@ class DeviceWatcher extends utils.Adapter {
933
1113
  this.batteryPoweredCount = this.batteryPowered.length;
934
1114
 
935
1115
  // 3c. Count how many devices are with low battery
936
- const batteryWarningMin = this.config.minWarnBatterie;
937
- const deviceLowBatState = await this.getInitValue(currDeviceString + this.arrDev[i].isLowBat);
938
- const deviceLowBatStateHM = await this.getInitValue(currDeviceString + this.arrDev[i].isLowBat2);
1116
+ const batteryWarningMin = this.config.minWarnBatterie;
1117
+ const deviceLowBatState = await this.getInitValue(currDeviceString + this.arrDev[i].isLowBat);
1118
+ const deviceLowBatStateHM = await this.getInitValue(currDeviceString + this.arrDev[i].isLowBat2);
939
1119
 
940
1120
  switch (this.arrDev[i].adapter) {
941
1121
  case 'homematic':
@@ -1008,8 +1188,8 @@ class DeviceWatcher extends utils.Adapter {
1008
1188
 
1009
1189
 
1010
1190
  /**
1011
- * @param {string} [adptName] - Adapter name
1012
- */
1191
+ * @param {string} [adptName] - Adapter name
1192
+ */
1013
1193
  async createDataForEachAdapter(adptName) {
1014
1194
  // create Data for each Adapter in own lists
1015
1195
  this.log.debug(`Function started: ${this.createDataForEachAdapter.name}`);
@@ -1057,8 +1237,8 @@ class DeviceWatcher extends utils.Adapter {
1057
1237
 
1058
1238
  /**
1059
1239
  * Notification service
1060
- * @param {string} [text] - Text which should be send
1061
- **/
1240
+ * @param {string} [text] - Text which should be send
1241
+ **/
1062
1242
  async sendNotification(text) {
1063
1243
 
1064
1244
  // Pushover
@@ -1151,7 +1331,7 @@ class DeviceWatcher extends utils.Adapter {
1151
1331
  this.log.warn('Jarvis instance is not running. Message could not be sent. Please check your instance configuration.');
1152
1332
  } else {
1153
1333
  const jsonText = JSON.stringify(text);
1154
- await this.setForeignStateAsync(`${this.config.instanceJarvis}.addNotification`, '{"title":"'+ this.config.titleJarvis +' (' + this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss') + ')","message": ' + jsonText + ',"display": "drawer"}');
1334
+ await this.setForeignStateAsync(`${this.config.instanceJarvis}.addNotification`, '{"title":"' + this.config.titleJarvis + ' (' + this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss') + ')","message": ' + jsonText + ',"display": "drawer"}');
1155
1335
  }
1156
1336
  }
1157
1337
  } catch (error) {
@@ -1168,7 +1348,7 @@ class DeviceWatcher extends utils.Adapter {
1168
1348
  this.log.warn('Lovelace instance is not running. Message could not be sent. Please check your instance configuration.');
1169
1349
  } else {
1170
1350
  const jsonText = JSON.stringify(text);
1171
- await this.setForeignStateAsync(`${this.config.instanceLovelace}.notifications.add`, '{"message":' + jsonText + ', "title":"'+ this.config.titleLovelace +' (' + this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss') + ')"}');
1351
+ await this.setForeignStateAsync(`${this.config.instanceLovelace}.notifications.add`, '{"message":' + jsonText + ', "title":"' + this.config.titleLovelace + ' (' + this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss') + ')"}');
1172
1352
  }
1173
1353
  }
1174
1354
  } catch (error) {
@@ -1230,7 +1410,7 @@ class DeviceWatcher extends utils.Adapter {
1230
1410
 
1231
1411
  //Check if the message should be send today
1232
1412
  checkDays.forEach(object => {
1233
- if((object >= 0) && today == object){
1413
+ if ((object >= 0) && today == object) {
1234
1414
  checkToday = true;
1235
1415
  }
1236
1416
  });
@@ -1246,10 +1426,10 @@ class DeviceWatcher extends utils.Adapter {
1246
1426
  const lastBatteryNotifyIndicator = await this.getOwnInitValue('info.lastBatteryNotification');
1247
1427
 
1248
1428
  // set indicator for send message first to 'false', after sending to 'true'
1249
- if (now.getHours() < 11) {await this.setStateAsync('info.lastBatteryNotification', false, true);}
1429
+ if (now.getHours() < 11) { await this.setStateAsync('info.lastBatteryNotification', false, true); }
1250
1430
 
1251
1431
  // if time is > 11 (12:00 pm create message for low battery devices)
1252
- if ((now.getHours() > 11) && (!lastBatteryNotifyIndicator) && (checkToday != undefined)){
1432
+ if ((now.getHours() > 11) && (!lastBatteryNotifyIndicator) && (checkToday != undefined)) {
1253
1433
  let msg = '';
1254
1434
 
1255
1435
  for (const id of this.batteryLowPowered) {
@@ -1260,7 +1440,7 @@ class DeviceWatcher extends utils.Adapter {
1260
1440
  this.log.info(`Niedrige Batteriezustände: ${msg}`);
1261
1441
  await this.setStateAsync('lastNotification', `Niedrige Batteriezustände: ${msg}`, true);
1262
1442
 
1263
- await this.sendNotification(msg);
1443
+ await this.sendNotification(`Niedriege Batteriezustände: ${msg}`);
1264
1444
 
1265
1445
  await this.setStateAsync('info.lastBatteryNotification', true, true);
1266
1446
  }
@@ -1278,28 +1458,28 @@ class DeviceWatcher extends utils.Adapter {
1278
1458
  this.log.debug(`Function started: ${this.resetVars.name}`);
1279
1459
 
1280
1460
  // arrays
1281
- this.offlineDevices = [],
1282
- this.linkQualityDevices = [];
1283
- this.batteryPowered = [];
1284
- this.batteryLowPowered = [];
1285
- this.listAllDevices = [];
1461
+ this.offlineDevices = [],
1462
+ this.linkQualityDevices = [];
1463
+ this.batteryPowered = [];
1464
+ this.batteryLowPowered = [];
1465
+ this.listAllDevices = [];
1286
1466
 
1287
1467
  // counts
1288
- this.offlineDevicesCount = 0;
1289
- this.deviceCounter = 0;
1290
- this.linkQualityCount = 0;
1291
- this.batteryPoweredCount = 0;
1292
- this.lowBatteryPoweredCount = 0;
1468
+ this.offlineDevicesCount = 0;
1469
+ this.deviceCounter = 0;
1470
+ this.linkQualityCount = 0;
1471
+ this.batteryPoweredCount = 0;
1472
+ this.lowBatteryPoweredCount = 0;
1293
1473
 
1294
- this.deviceReachable = '';
1474
+ this.deviceReachable = '';
1295
1475
 
1296
1476
  this.log.debug(`Function finished: ${this.resetVars.name}`);
1297
1477
  } // <-- end of resetVars
1298
1478
 
1299
1479
 
1300
1480
  /**
1301
- * @param {string} [adptName] - Adaptername
1302
- */
1481
+ * @param {string} [adptName] - Adaptername
1482
+ */
1303
1483
  async writeDatapoints(adptName) {
1304
1484
  // fill the datapoints
1305
1485
 
@@ -1312,58 +1492,55 @@ class DeviceWatcher extends utils.Adapter {
1312
1492
  if (adptName) {
1313
1493
  dpSubFolder = adptName + '.';
1314
1494
  } else {
1315
- dpSubFolder = '';}
1495
+ dpSubFolder = '';
1496
+ }
1316
1497
 
1317
- await this.setStateAsync(`${dpSubFolder}offlineCount`, {val: this.offlineDevicesCount, ack: true});
1318
- await this.setStateAsync(`${dpSubFolder}countAll`, {val: this.deviceCounter, ack: true});
1319
- await this.setStateAsync(`${dpSubFolder}batteryCount`, {val: this.batteryPoweredCount, ack: true});
1320
- await this.setStateAsync(`${dpSubFolder}lowBatteryCount`, {val: this.lowBatteryPoweredCount, ack: true});
1498
+ await this.setStateAsync(`${dpSubFolder}offlineCount`, { val: this.offlineDevicesCount, ack: true });
1499
+ await this.setStateAsync(`${dpSubFolder}countAll`, { val: this.deviceCounter, ack: true });
1500
+ await this.setStateAsync(`${dpSubFolder}batteryCount`, { val: this.batteryPoweredCount, ack: true });
1501
+ await this.setStateAsync(`${dpSubFolder}lowBatteryCount`, { val: this.lowBatteryPoweredCount, ack: true });
1321
1502
 
1322
1503
  if (this.deviceCounter == 0) {
1323
1504
  // if no device is count, write the JSON List with default value
1324
- this.listAllDevices = [{'Device': '--none--', 'Adapter': '', 'Battery': '', 'Last contact': '', 'Signal strength': ''}];
1325
-
1326
- await this.setStateAsync(`${dpSubFolder}listAll`, {val: JSON.stringify(this.listAllDevices), ack: true});
1327
- } else {
1328
- await this.setStateAsync(`${dpSubFolder}listAll`, {val: JSON.stringify(this.listAllDevices), ack: true});
1505
+ this.listAllDevices = [{ 'Device': '--none--', 'Adapter': '', 'Battery': '', 'Last contact': '', 'Signal strength': '' }];
1329
1506
  }
1507
+ await this.setStateAsync(`${dpSubFolder}listAll`, { val: JSON.stringify(this.listAllDevices), ack: true });
1330
1508
 
1331
1509
  if (this.linkQualityCount == 0) {
1332
1510
  // if no device is count, write the JSON List with default value
1333
- this.linkQualityDevices = [{'Device': '--none--', 'Adapter': '', 'Signal strength': ''}];
1334
-
1335
- await this.setStateAsync(`${dpSubFolder}linkQualityList`, {val: JSON.stringify(this.linkQualityDevices), ack: true});
1336
- } else {
1337
- await this.setStateAsync(`${dpSubFolder}linkQualityList`, {val: JSON.stringify(this.linkQualityDevices), ack: true});
1511
+ this.linkQualityDevices = [{ 'Device': '--none--', 'Adapter': '', 'Signal strength': '' }];
1338
1512
  }
1339
-
1513
+ //write JSON list
1514
+ await this.setStateAsync(`${dpSubFolder}linkQualityList`, { val: JSON.stringify(this.linkQualityDevices), ack: true });
1515
+ //write HTML list
1516
+ if (this.config.createHtmlList) await this.setStateAsync(`${dpSubFolder}linkQualityListHTML`, { val: await this.creatLinkQualityListHTML(this.linkQualityDevices, this.linkQualityCount), ack: true });
1340
1517
 
1341
1518
  if (this.offlineDevicesCount == 0) {
1342
1519
  // if no device is count, write the JSON List with default value
1343
- this.offlineDevices = [{'Device': '--none--', 'Adapter': '', 'Last contact': ''}];
1344
-
1345
- await this.setStateAsync(`${dpSubFolder}offlineList`, {val: JSON.stringify(this.offlineDevices), ack: true});
1346
- } else {
1347
- await this.setStateAsync(`${dpSubFolder}offlineList`, {val: JSON.stringify(this.offlineDevices), ack: true});
1520
+ this.offlineDevices = [{ 'Device': '--none--', 'Adapter': '', 'Last contact': '' }];
1348
1521
  }
1522
+ //write JSON list
1523
+ await this.setStateAsync(`${dpSubFolder}offlineList`, { val: JSON.stringify(this.offlineDevices), ack: true });
1524
+ //write HTML list
1525
+ if (this.config.createHtmlList) await this.setStateAsync(`${dpSubFolder}offlineListHTML`, { val: await this.createOfflineListHTML(this.offlineDevices, this.offlineDevicesCount), ack: true });
1349
1526
 
1350
1527
  if (this.batteryPoweredCount == 0) {
1351
1528
  // if no device is count, write the JSON List with default value
1352
- this.batteryPowered = [{'Device': '--none--', 'Adapter': '', 'Battery': ''}];
1353
-
1354
- await this.setStateAsync(`${dpSubFolder}batteryList`, {val: JSON.stringify(this.batteryPowered), ack: true});
1355
- } else {
1356
- await this.setStateAsync(`${dpSubFolder}batteryList`, {val: JSON.stringify(this.batteryPowered), ack: true});
1529
+ this.batteryPowered = [{ 'Device': '--none--', 'Adapter': '', 'Battery': '' }];
1357
1530
  }
1531
+ //write JSON list
1532
+ await this.setStateAsync(`${dpSubFolder}batteryList`, { val: JSON.stringify(this.batteryPowered), ack: true });
1533
+ //write HTML list
1534
+ if (this.config.createHtmlList) await this.setStateAsync(`${dpSubFolder}batteryListHTML`, { val: await this.createBatteryListHTML(this.batteryPowered, this.batteryPoweredCount, false), ack: true });
1358
1535
 
1359
1536
  if (this.lowBatteryPoweredCount == 0) {
1360
1537
  // if no device is count, write the JSON List with default value
1361
- this.batteryLowPowered = [{'Device': '--none--', 'Adapter': '', 'Battery': ''}];
1362
-
1363
- await this.setStateAsync(`${dpSubFolder}lowBatteryList`, {val: JSON.stringify(this.batteryLowPowered), ack: true});
1364
- } else {
1365
- await this.setStateAsync(`${dpSubFolder}lowBatteryList`, {val: JSON.stringify(this.batteryLowPowered), ack: true});
1538
+ this.batteryLowPowered = [{ 'Device': '--none--', 'Adapter': '', 'Battery': '' }];
1366
1539
  }
1540
+ //write JSON list
1541
+ await this.setStateAsync(`${dpSubFolder}lowBatteryList`, { val: JSON.stringify(this.batteryLowPowered), ack: true });
1542
+ //write HTML list
1543
+ if (this.config.createHtmlList) await this.setStateAsync(`${dpSubFolder}lowBatteryListHTML`, { val: await this.createBatteryListHTML(this.batteryLowPowered, this.lowBatteryPoweredCount, true), ack: true });
1367
1544
 
1368
1545
  // create timestamp of last run
1369
1546
  const lastCheck = this.formatDate(new Date(), 'DD.MM.YYYY') + ' - ' + this.formatDate(new Date(), 'hh:mm:ss');
@@ -1376,9 +1553,112 @@ class DeviceWatcher extends utils.Adapter {
1376
1553
  }//<--End of writing Datapoints
1377
1554
 
1378
1555
  /**
1379
- * @param {string} [codePart] - Message Prefix
1380
- * @param {object} [error] - Sentry message
1381
- */
1556
+ * @param {object} [devices] - Device
1557
+ * @param {number} [deviceCount] - Counted devices
1558
+ */
1559
+ async creatLinkQualityListHTML(devices, deviceCount) {
1560
+ devices = devices.sort((a, b) => { return a.Device.localeCompare(b.Device); });
1561
+ let html = `<center>
1562
+ <b>Link Quality Devices:<font> ${deviceCount}</b><small></small></font>
1563
+ <p></p>
1564
+ </center>
1565
+ <table width=100%>
1566
+ <tr>
1567
+ <th align=left>Device</th>
1568
+ <th align=center width=120>Adapter</th>
1569
+ <th align=right>Link Quality</th>
1570
+ </tr>
1571
+ <tr>
1572
+ <td colspan="5"><hr></td>
1573
+ </tr>`;
1574
+
1575
+ for (const device of devices) {
1576
+ html += `<tr>
1577
+ <td><font>${device.Device}</font></td>
1578
+ <td align=center><font>${device.Adapter}</font></td>
1579
+ <td align=right><font>${device['Signal strength']}</font></td>
1580
+ </tr>`;
1581
+ }
1582
+
1583
+ html += '</table>';
1584
+ return html;
1585
+ }
1586
+
1587
+ /**
1588
+ * @param {object} [devices] - Device
1589
+ * @param {number} [deviceCount] - Counted devices
1590
+ */
1591
+ async createOfflineListHTML(devices, deviceCount) {
1592
+ devices = devices.sort((a, b) => { return a.Device.localeCompare(b.Device); });
1593
+ let html = `<center>
1594
+ <b>Offline Devices: <font color=${deviceCount == 0 ? '#3bcf0e' : 'orange'}>${deviceCount}</b><small></small></font>
1595
+ <p></p>
1596
+ </center>
1597
+ <table width=100%>
1598
+ <tr>
1599
+ <th align=left>Device</th>
1600
+ <th align=center width=120>Adapter</th>
1601
+ <th align=center>Letzter Kontakt</th>
1602
+ </tr>
1603
+ <tr>
1604
+ <td colspan="5"><hr></td>
1605
+ </tr>`;
1606
+
1607
+ for (const device of devices) {
1608
+ html += `<tr>
1609
+ <td><font>${device.Device}</font></td>
1610
+ <td align=center><font>${device.Adapter}</font></td>
1611
+ <td align=center><font color=orange>${device['Last contact']}</font></td>
1612
+ </tr>`;
1613
+ }
1614
+
1615
+ html += '</table>';
1616
+ return html;
1617
+ }
1618
+
1619
+ /**
1620
+ * @param {object} [devices] - Device
1621
+ * @param {object} [deviceCount] - Counted devices
1622
+ * @param {object} [isLowBatteryList] - list Low Battery Devices
1623
+ */
1624
+ async createBatteryListHTML(devices, deviceCount, isLowBatteryList) {
1625
+ devices = devices.sort((a, b) => { return a.Device.localeCompare(b.Device); });
1626
+ let html = `<center>
1627
+ <b>${isLowBatteryList == true ? 'Schwache ' : ''}Batterie Devices: <font color=${isLowBatteryList == true ? (deviceCount > 0 ? 'orange' : '#3bcf0e') : ''}>${deviceCount}</b></font>
1628
+ <p></p>
1629
+ </center>
1630
+ <table width=100%>
1631
+ <tr>
1632
+ <th align=left>Device</th>
1633
+ <th align=center width=120>Adapter</th>
1634
+ <th align=${isLowBatteryList ? 'center' : 'right'}>Batterie</th>
1635
+ </tr>
1636
+ <tr>
1637
+ <td colspan="5"><hr></td>
1638
+ </tr>`;
1639
+
1640
+ for (const device of devices) {
1641
+ html += `<tr>
1642
+ <td><font>${device.Device}</font></td>
1643
+ <td align=center><font>${device.Adapter}</font></td>`;
1644
+
1645
+ if (isLowBatteryList) {
1646
+ html += `<td align=center><font color=orange>${device.Battery == ' - ' ? 'schwach' : device.Battery}</font></td>`;
1647
+ } else {
1648
+ html += `<td align=right><font color=#3bcf0e>${device.Battery == ' - ' ? 'ok' : device.Battery}</font></td>`;
1649
+ }
1650
+
1651
+ html += `</tr>`;
1652
+ }
1653
+
1654
+ html += '</table>';
1655
+ return html;
1656
+ }
1657
+
1658
+ /**
1659
+ * @param {string} [codePart] - Message Prefix
1660
+ * @param {object} [error] - Sentry message
1661
+ */
1382
1662
  errorReporting(codePart, error) {
1383
1663
  const msg = `[${codePart}] error: ${error.message}`;
1384
1664
  if (enableSendSentry) {