iobroker.device-watcher 1.0.1 → 2.0.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
@@ -6,10 +6,13 @@
6
6
 
7
7
  const utils = require('@iobroker/adapter-core');
8
8
  const adapterName = require('./package.json').name.split('.').pop();
9
+ const schedule = require('node-schedule');
10
+ const arrApart = require('./lib/arrApart.js'); // list of supported adapters
9
11
 
10
12
  // Sentry error reporting, disable when testing code!
11
13
  const enableSendSentry = true;
12
14
 
15
+ // indicator if the adapter is running or not (for intervall/shedule)
13
16
  let isUnloaded = false;
14
17
 
15
18
  class DeviceWatcher extends utils.Adapter {
@@ -27,7 +30,9 @@ class DeviceWatcher extends utils.Adapter {
27
30
  this.batteryPowered = [];
28
31
  this.batteryLowPowered = [];
29
32
  this.listAllDevices = [];
30
- this.blacklistArr = [];
33
+ this.listAllDevicesRaw = [];
34
+ this.blacklistLists = [];
35
+ this.blacklistNotify = [];
31
36
  this.arrDev = [];
32
37
  this.adapterSelected = [];
33
38
 
@@ -38,284 +43,13 @@ class DeviceWatcher extends utils.Adapter {
38
43
  this.batteryPoweredCount = 0;
39
44
  this.lowBatteryPoweredCount = 0;
40
45
 
41
- this.deviceReachable = '';
42
-
43
46
  // Interval timer
44
47
  this.refreshDataTimeout = null;
45
48
 
46
- // Information for dev: add ' 0_userdata.0. ' to selector for testing with own datapoints.
47
- /*
48
- This is the main template:
49
- 'Selektor': '',
50
- 'adapter': '',
51
- 'battery': 'none',
52
- 'reach': 'none',
53
- 'isLowBat': 'none',
54
- 'id': 'none''
55
- */
56
-
57
- // arrays of supported adapters
58
- this.arrApart = {
59
- alexa2: {
60
- 'Selektor': 'alexa2.*.online',
61
- 'adapter': 'alexa2',
62
- 'battery': 'none',
63
- 'reach': '.online',
64
- 'isLowBat': 'none'
65
- },
66
- ble: {
67
- 'Selektor': 'ble.*.rssi',
68
- 'adapter': 'ble',
69
- 'battery': '.battery',
70
- 'reach': 'none',
71
- 'isLowBat': 'none'
72
- },
73
- deconz: {
74
- 'Selektor': 'deconz.*.reachable',
75
- 'adapter': 'deconz',
76
- 'battery': '.battery',
77
- 'reach': '.reachable',
78
- 'isLowBat': 'none'
79
- },
80
- enocean: {
81
- 'Selektor': 'enocean.*.rssi',
82
- 'adapter': 'enocean',
83
- 'battery': '.BS',
84
- 'reach': 'none',
85
- 'isLowBat': 'none'
86
- },
87
- esphome: {
88
- 'Selektor': 'esphome.*._online',
89
- 'adapter': 'esphome',
90
- 'battery': 'none',
91
- 'reach': '._online',
92
- 'isLowBat': 'none',
93
- 'id': '.name'
94
- },
95
- fritzdect: {
96
- 'Selektor': 'fritzdect.*.present',
97
- 'adapter': 'fritzDect',
98
- 'battery': '.battery',
99
- 'reach': '.present',
100
- 'isLowBat': '.batterylow'
101
- },
102
- harmony: {
103
- 'Selektor': 'harmony.*.hubConnected',
104
- 'adapter': 'harmony',
105
- 'battery': 'none',
106
- 'reach': '.hubConnected',
107
- 'isLowBat': 'none'
108
- },
109
- ham: {
110
- 'Selektor': 'ham.*.Battery-Level',
111
- 'adapter': 'ham',
112
- 'battery': '.Battery-Level',
113
- 'reach': 'none',
114
- 'isLowBat': 'none',
115
- 'id': '.Name'
116
- },
117
- hmiP: {
118
- 'Selektor': 'hmip.*.rssiDeviceValue',
119
- 'adapter': 'hmiP',
120
- 'rssiState': '.rssiDeviceValue',
121
- 'battery': 'none',
122
- 'reach': '.unreach',
123
- 'isLowBat': '.lowBat',
124
- },
125
- homematic: {
126
- 'Selektor': 'hm-rpc.*.UNREACH',
127
- 'adapter': 'homematic',
128
- 'rssiState': '.RSSI_DEVICE',
129
- 'battery': '.OPERATING_VOLTAGE',
130
- 'reach': '.UNREACH',
131
- 'isLowBat': '.LOW_BAT',
132
- 'isLowBat2': '.LOWBAT',
133
- 'stateValue': '.1.STATE'
134
- },
135
- hue: {
136
- 'Selektor': 'hue.*.reachable',
137
- 'adapter': 'hue',
138
- 'battery': '.battery',
139
- 'reach': '.reachable',
140
- 'isLowBat': 'none'
141
- },
142
- hueExt: {
143
- 'Selektor': 'hue-extended.*.reachable',
144
- 'adapter': 'hue-extended',
145
- 'battery': '.config.battery',
146
- 'reach': '.reachable',
147
- 'isLowBat': 'none'
148
- },
149
- jeelink: {
150
- 'Selektor': 'jeelink.*.lowBatt',
151
- 'adapter': 'jeelink',
152
- 'battery': 'none',
153
- 'reach': 'none',
154
- 'isLowBat': '.lowBatt'
155
- },
156
- meross: {
157
- 'Selektor': 'meross.*.online',
158
- 'adapter': 'meross',
159
- 'battery': '.battery',
160
- 'reach': '.online',
161
- 'isLowBat': 'none'
162
- },
163
- mihome: {
164
- 'Selektor': 'mihome.*.percent',
165
- 'adapter': 'miHome',
166
- 'battery': '.percent',
167
- 'reach': 'none',
168
- 'isLowBat': 'none'
169
- },
170
- mihomeGW: {
171
- 'Selektor': 'mihome.*.connected',
172
- 'adapter': 'miHome',
173
- 'battery': 'none',
174
- 'reach': '.connected',
175
- 'isLowBat': 'none'
176
- },
177
- mihomeVacuum: {
178
- 'Selektor': 'mihome-vacuum.*.connection',
179
- 'adapter': 'mihomeVacuum',
180
- 'rssiState': '.deviceInfo.wifi_signal',
181
- 'battery': '.info.battery',
182
- 'battery2': '.control.battary_life',
183
- 'reach': '.info.connection',
184
- 'isLowBat': 'none',
185
- 'id': '.deviceInfo.model'
186
- },
187
- netatmo: {
188
- 'Selektor': 'netatmo.*.LastUpdate',
189
- 'adapter': 'netatmo',
190
- 'rssiState': '.WifiStatus',
191
- 'rfState': '.RfStatus',
192
- 'battery': '.BatteryStatus',
193
- 'reach': 'none',
194
- 'isLowBat': 'none'
195
- },
196
- nukiExt: {
197
- 'Selektor': 'nuki-extended.*.lastDataUpdate',
198
- 'adapter': 'nuki-extended',
199
- 'rssiState': 'none',
200
- 'battery': '.batteryChargeState',
201
- 'reach': 'none',
202
- 'isLowBat': '.batteryCritical'
203
- },
204
- nut: {
205
- 'Selektor': 'nut.*.charge',
206
- 'adapter': 'nut',
207
- 'battery': '.charge',
208
- 'reach': 'none',
209
- 'isLowBat': 'none'
210
- },
211
- ping: {
212
- 'Selektor': 'ping.*.alive',
213
- 'adapter': 'ping',
214
- 'battery': 'none',
215
- 'reach': '.alive',
216
- 'isLowBat': 'none'
217
- },
218
- roomba: {
219
- 'Selektor': 'roomba.*.signal',
220
- 'adapter': 'roomba',
221
- 'battery': '.battery',
222
- 'reach': '._connected',
223
- 'isLowBat': 'none',
224
- 'id': '.device.name'
225
- },
226
- shelly: {
227
- 'Selektor': 'shelly.*.online',
228
- 'adapter': 'shelly',
229
- 'rssiState': '.rssi',
230
- 'battery': '.sensor.battery',
231
- 'reach': '.online',
232
- 'isLowBat': 'none'
233
- },
234
- sonoff: {
235
- 'Selektor': 'sonoff.*.alive',
236
- 'adapter': 'sonoff',
237
- 'rssiState': '.Wifi_Signal',
238
- 'battery': '.battery',
239
- 'reach': '.alive',
240
- 'isLowBat': 'none'
241
- },
242
- sonos: {
243
- 'Selektor': 'sonos.*.alive',
244
- 'adapter': 'sonos',
245
- 'battery': 'none',
246
- 'reach': '.alive',
247
- 'isLowBat': 'none'
248
- },
249
- switchbotBle: {
250
- 'Selektor': 'switchbot-ble.*.rssi',
251
- 'adapter': 'switchbotBle',
252
- 'battery': '.battery',
253
- 'reach': 'none',
254
- 'isLowBat': 'none',
255
- 'id': '.id'
256
- },
257
- tado: {
258
- 'Selektor': 'tado.*.batteryState',
259
- 'adapter': 'tado',
260
- 'rssiState': 'none',
261
- 'battery': 'none',
262
- 'reach': '.connectionState.value',
263
- 'isLowBat': '.batteryState',
264
- 'id': 'none'
265
- },
266
- tradfri: {
267
- 'Selektor': 'tradfri.*.lastSeen',
268
- 'adapter': 'tradfri',
269
- 'rssiState': 'none',
270
- 'battery': '.batteryPercentage',
271
- 'reach': '.alive',
272
- 'isLowBat': 'none',
273
- 'id': 'none'
274
- },
275
- unifi: {
276
- 'Selektor': 'unifi.*.state',
277
- 'adapter': 'unifi',
278
- 'battery': 'none',
279
- 'reach': '.state',
280
- 'isLowBat': 'none',
281
- 'id': 'none'
282
- },
283
- wled: {
284
- 'Selektor': 'wled.*._online',
285
- 'adapter': 'wled',
286
- 'rssiState': '.wifi.rssi',
287
- 'battery': 'none',
288
- 'reach': '._online',
289
- 'isLowBat': 'none',
290
- 'id': 'none'
291
- },
292
- yeelight: {
293
- 'Selektor': 'yeelight-2.*.connect',
294
- 'adapter': 'yeelight-2',
295
- 'battery': 'none',
296
- 'reach': '.connect',
297
- 'isLowBat': 'none'
298
- },
299
- zigbee: {
300
- 'Selektor': 'zigbee.*.link_quality',
301
- 'adapter': 'zigbee',
302
- 'battery': '.battery',
303
- 'reach': '.available',
304
- 'isLowBat': '.battery_low'
305
- },
306
- zwave: {
307
- 'Selektor': 'zwave2.*.ready',
308
- 'adapter': 'zwave',
309
- 'battery': '.Battery.level',
310
- 'reach': '.ready',
311
- 'isLowBat': '.Battery.isLow'
312
- }
313
- };
314
-
315
49
  this.on('ready', this.onReady.bind(this));
316
- // this.on('stateChange', this.onStateChange.bind(this));
50
+ this.on('stateChange', this.onStateChange.bind(this));
317
51
  // this.on('objectChange', this.onObjectChange.bind(this));
318
- // this.on('message', this.onMessage.bind(this));
52
+ this.on('message', this.onMessage.bind(this));
319
53
  this.on('unload', this.onUnload.bind(this));
320
54
 
321
55
  }
@@ -326,6 +60,8 @@ class DeviceWatcher extends utils.Adapter {
326
60
  isUnloaded = false;
327
61
 
328
62
  try {
63
+ this.listOnlyBattery = this.config.listOnlyBattery;
64
+
329
65
  this.supAdapter = {
330
66
  alexa2: this.config.alexa2Devices,
331
67
  ble: this.config.bleDevices,
@@ -336,10 +72,13 @@ class DeviceWatcher extends utils.Adapter {
336
72
  ham: this.config.hamDevices,
337
73
  harmony: this.config.harmonyDevices,
338
74
  hmiP : this.config.hmiPDevices,
339
- homematic: this.config.homematicDevices,
75
+ hmrpc: this.config.hmrpcDevices,
76
+ hs100: this.config.hs100Devices,
340
77
  hue: this.config.hueDevices,
341
78
  hueExt: this.config.hueExtDevices,
342
79
  jeelink: this.config.jeelinkDevices,
80
+ lupusec: this.config.lupusecDevices,
81
+ maxcube: this.config.maxcubeDevices,
343
82
  meross: this.config.merossDevices,
344
83
  mihome: this.config.mihomeDevices,
345
84
  mihomeGW: this.config.mihomeDevices,
@@ -359,13 +98,54 @@ class DeviceWatcher extends utils.Adapter {
359
98
  wled: this.config.wledDevices,
360
99
  yeelight: this.config.yeelightDevices,
361
100
  zigbee: this.config.zigbeeDevices,
101
+ zigbee2MQTT: this.config.zigbee2mqttDevices,
362
102
  zwave: this.config.zwaveDevices,
363
103
  };
364
104
 
365
- for (const [id] of Object.entries(this.arrApart)) {
105
+ this.maxMinutes = {
106
+ alexa2: this.config.alexa2MaxMinutes,
107
+ ble: this.config.bleMaxMinutes,
108
+ deconz: this.config.deconzMaxMinutes,
109
+ enocean: this.config.enoceanMaxMinutes,
110
+ esphome: this.config.esphomeMaxMinutes,
111
+ fritzdect: this.config.fritzdectMaxMinutes,
112
+ ham: this.config.hamMaxMinutes,
113
+ harmony: this.config.harmonyMaxMinutes,
114
+ hmiP : this.config.hmiPMaxMinutes,
115
+ hmrpc: this.config.hmrpcMaxMinutes,
116
+ hs100: this.config.hs100MaxMinutes,
117
+ hue: this.config.hueMaxMinutes,
118
+ hueExt: this.config.hueextMaxMinutes,
119
+ jeelink: this.config.jeelinkMaxMinutes,
120
+ lupusec: this.config.lupusecMaxMinutes,
121
+ maxcube: this.config.maxcubeMaxMinutes,
122
+ meross: this.config.merossMaxMinutes,
123
+ mihome: this.config.mihomeMaxMinutes,
124
+ mihomeGW: this.config.mihomeMaxMinutes,
125
+ mihomeVacuum: this.config.mihomeVacuumMaxMinutes,
126
+ netatmo: this.config.netatmoMaxMinutes,
127
+ nukiExt: this.config.nukiextendMaxMinutes,
128
+ nut: this.config.nutMaxMinutes,
129
+ ping: this.config.pingMaxMinutes,
130
+ roomba: this.config.roombaMaxMinutes,
131
+ shelly: this.config.shellyMaxMinutes,
132
+ sonoff: this.config.sonoffMaxMinutes,
133
+ sonos: this.config.sonosMaxMinutes,
134
+ switchbotBle: this.config.switchbotMaxMinutes,
135
+ tado: this.config.tadoMaxMinutes,
136
+ tradfri: this.config.tradfriMaxMinutes,
137
+ unifi: this.config.unifiMaxMinutes,
138
+ wled: this.config.wledMaxMinutes,
139
+ yeelight: this.config.yeelightMaxMinutes,
140
+ zigbee: this.config.zigbeeMaxMinutes,
141
+ zigbee2MQTT: this.config.zigbee2mqttMaxMinutes,
142
+ zwave: this.config.zwaveMaxMinutes,
143
+ };
144
+
145
+ for (const [id] of Object.entries(arrApart)) {
366
146
  if (!isUnloaded) {
367
147
  if (this.supAdapter[id]) {
368
- this.arrDev.push(this.arrApart[id]);
148
+ this.arrDev.push(arrApart[id]);
369
149
  this.adapterSelected.push(await this.capitalize(id));
370
150
  }
371
151
  } else {
@@ -393,7 +173,7 @@ class DeviceWatcher extends utils.Adapter {
393
173
 
394
174
  //create and fill datapoints for each adapter if selected
395
175
  try {
396
- for (const [id] of Object.entries(this.arrApart)) {
176
+ for (const [id] of Object.entries(arrApart)) {
397
177
  if (!isUnloaded) {
398
178
  if ((this.supAdapter !== undefined) && (this.supAdapter[id])) {
399
179
 
@@ -417,12 +197,65 @@ class DeviceWatcher extends utils.Adapter {
417
197
  // update data in interval
418
198
  await this.refreshData();
419
199
 
200
+ // send overview for low battery devices
201
+ if (this.config.checkSendBatteryMsg) await this.sendBatteryNotifyShedule();
202
+
203
+ // send overview of offline devices
204
+ if (this.config.checkSendOfflineMsgDaily) await this.sendOfflineNotificationsShedule();
205
+
420
206
  } catch (error) {
421
207
  this.errorReporting('[onReady]', error);
422
208
  this.terminate ? this.terminate(15) : process.exit(15);
423
209
  }
424
210
  } // <-- onReady end
425
211
 
212
+ /**
213
+ * Is called if a subscribed state changes
214
+ * @param {string} id
215
+ * @param {ioBroker.State | null | undefined} state
216
+ */
217
+ onStateChange(id, state) {
218
+ if (state) {
219
+ // The state was changed
220
+ this.log.warn(`state ${id} changed: ${state.val} (ack = ${state.ack})`);
221
+ } else {
222
+ // The state was deleted
223
+ this.log.warn(`state ${id} deleted`);
224
+ }
225
+ }
226
+
227
+ /**
228
+ * @param {ioBroker.Message} obj
229
+ */
230
+ onMessage(obj) {
231
+ const devices = [];
232
+ let myCount = 0;
233
+ let result;
234
+
235
+ switch (obj.command) {
236
+ case 'devicesList':
237
+ if(obj.message){
238
+ try{
239
+ result = this.listAllDevicesRaw;
240
+ for(const element in result){
241
+ const label = 'Device: ' + result[element].Device + ' - Adapter: ' + result[element].Adapter;
242
+ const myValueObject = {deviceName: result[element].Device, adapter: result[element].Adapter, path: result[element].Path};
243
+ devices[myCount] = {label: label,value: JSON.stringify(myValueObject)};
244
+ myCount ++;
245
+ }
246
+ this.sendTo(obj.from, obj.command, devices, obj.callback);
247
+ }
248
+ catch(error){
249
+ this.sendTo(obj.from, obj.command, obj.callback);
250
+ }
251
+ }
252
+ else{
253
+ this.sendTo(obj.from, obj.command, obj.callback);
254
+ }
255
+ break;
256
+ }
257
+ }
258
+
426
259
  async refreshData() {
427
260
  const nextTimeout = this.config.updateinterval * 1000;
428
261
 
@@ -433,7 +266,6 @@ class DeviceWatcher extends utils.Adapter {
433
266
  this.log.debug('clearing old refresh timeout');
434
267
  this.clearTimeout(this.refreshDataTimeout);
435
268
  }
436
-
437
269
  if (!isUnloaded) {
438
270
  this.refreshDataTimeout = this.setTimeout(() => {
439
271
  this.log.debug('Updating Data');
@@ -450,38 +282,31 @@ class DeviceWatcher extends utils.Adapter {
450
282
  async main() {
451
283
  this.log.debug(`Function started: ${this.main.name}`);
452
284
 
285
+ // fill datapoints for each adapter if selected
453
286
  try {
454
-
455
- // fill datapoints for each adapter if selected
456
- try {
457
- for (const [id] of Object.entries(this.arrApart)) {
458
- if (!isUnloaded) {
459
- if ((this.supAdapter !== undefined) && (this.supAdapter[id])) {
460
- if (this.config.createOwnFolder) {
461
- await this.createDataForEachAdapter(id);
462
- this.log.debug(`Created and filled data for each adapter`);
463
- }
287
+ for (const [id] of Object.entries(arrApart)) {
288
+ if (!isUnloaded) {
289
+ if ((this.supAdapter !== undefined) && (this.supAdapter[id])) {
290
+ if (this.config.createOwnFolder) {
291
+ await this.createDataForEachAdapter(id);
292
+ this.log.debug(`Created and filled data for ${await this.capitalize(id)}`);
464
293
  }
465
- } else {
466
- this.log.warn('broke up');
467
- return; // cancel run if unloaded was called.
468
294
  }
295
+ } else {
296
+ this.log.warn('broke up');
297
+ return; // cancel run if unloaded was called.
469
298
  }
470
-
471
- } catch (error) {
472
- this.errorReporting('[main - create and fill datapoints for each adapter]', error);
473
- }
474
-
475
- // fill counts and lists of all selected adapter
476
- try {
477
- await this.createDataOfAllAdapter();
478
- this.log.debug(`Created and filled data for all adapters`);
479
- } catch (error) {
480
- this.errorReporting('[main - create data of all adapter]', error);
481
299
  }
300
+ } catch (error) {
301
+ this.errorReporting('[main - create and fill datapoints for each adapter]', error);
302
+ }
482
303
 
304
+ // fill counts and lists of all selected adapter
305
+ try {
306
+ await this.createDataOfAllAdapter();
307
+ this.log.debug(`Created and filled data for all adapters`);
483
308
  } catch (error) {
484
- this.errorReporting('[main]', error);
309
+ this.errorReporting('[main - create data of all adapter]', error);
485
310
  }
486
311
 
487
312
  this.log.debug(`Function finished: ${this.main.name}`);
@@ -490,15 +315,23 @@ class DeviceWatcher extends utils.Adapter {
490
315
 
491
316
  /**
492
317
  * @param {string} sentence - Word which should be capitalize
493
- **/
318
+ */
494
319
  async capitalize(sentence) {
495
320
  //make the first letter uppercase
496
321
  return sentence && sentence[0].toUpperCase() + sentence.slice(1);
497
322
  }
498
323
 
324
+ /**
325
+ * @param {number} dpValue - get Time of this datapoint
326
+ */
327
+ async getTimestamp(dpValue) {
328
+ const time = new Date();
329
+ return dpValue = Math.round((time.getTime() - dpValue) / 1000 / 60);
330
+ }
331
+
499
332
  /**
500
333
  * @param {object} obj - State of datapoint
501
- **/
334
+ */
502
335
  async getInitValue(obj) {
503
336
  //state can be null or undefinded
504
337
  const foreignState = await this.getForeignStateAsync(obj);
@@ -507,7 +340,7 @@ class DeviceWatcher extends utils.Adapter {
507
340
 
508
341
  /**
509
342
  * @param {object} obj - State of own datapoint
510
- **/
343
+ */
511
344
  async getOwnInitValue(obj) {
512
345
  //state can be null or undefinded for own states
513
346
  const stateVal = await this.getStateAsync(obj);
@@ -517,874 +350,578 @@ class DeviceWatcher extends utils.Adapter {
517
350
  async createBlacklist() {
518
351
  this.log.debug(`Function started: ${this.createBlacklist.name}`);
519
352
 
520
- const myBlacklist = this.config.tableBlacklist;
353
+ if (!isUnloaded) {
354
+ const myBlacklist = this.config.tableBlacklist;
521
355
 
522
- for (const i in myBlacklist) {
523
- if (!isUnloaded) {
524
- this.blacklistArr.push(myBlacklist[i].device);
525
- } else {
526
- return; // cancel run if unloaded was called.
356
+ for (const i in myBlacklist) {
357
+ const blacklistParse = JSON.parse(myBlacklist[i].devices);
358
+ // push devices in list to ignor device in lists
359
+ if (myBlacklist[i].checkIgnorLists) {
360
+ this.blacklistLists.push(blacklistParse.path);
361
+ }
362
+ // push devices in list to ignor device in notifications
363
+ if (myBlacklist[i].checkIgnorNotify) {
364
+ this.blacklistNotify.push(blacklistParse.deviceName);
365
+ }
527
366
  }
367
+
368
+ if (this.blacklistLists.length >= 1) this.log.info(`Found items on blacklist for lists: ${this.blacklistLists}`);
369
+ if (this.blacklistNotify.length >= 1) this.log.info(`Found items on blacklist for notificatioons: ${this.blacklistNotify}`);
370
+ } else {
371
+ return; // cancel run if unloaded was called.
528
372
  }
529
- this.log.info(`Found items on the blacklist: ${this.blacklistArr}`);
373
+
530
374
  this.log.debug(`Function finished: ${this.createBlacklist.name}`);
531
375
  }
532
376
 
533
377
  /**
534
- * @param {object} i - Device Object
535
- **/
536
- async createData(i) {
537
- const devices = await this.getForeignStatesAsync(this.arrDev[i].Selektor);
538
- const deviceAdapterName = await this.capitalize(this.arrDev[i].adapter);
539
-
540
- /*---------- Start of second main loop ----------*/
541
- for (const [id] of Object.entries(devices)) {
542
- if (!isUnloaded) {
543
- if (!this.blacklistArr.includes(id)) {
544
-
545
- const currDeviceString = id.slice(0, (id.lastIndexOf('.') + 1) - 1);
546
- const shortCurrDeviceString = currDeviceString.slice(0, (currDeviceString.lastIndexOf('.') + 1) - 1);
547
- const shortshortCurrDeviceString = shortCurrDeviceString.slice(0, (shortCurrDeviceString.lastIndexOf('.') + 1) - 1);
548
-
549
- // Get device name
550
- const deviceObject = await this.getForeignObjectAsync(currDeviceString);
551
- const shortDeviceObject = await this.getForeignObjectAsync(shortCurrDeviceString);
552
- const shortshortDeviceObject = await this.getForeignObjectAsync(shortshortCurrDeviceString);
553
- let deviceName;
554
-
555
- // Get ID with currDeviceString from datapoint
556
- switch (this.arrDev[i].adapter) {
557
- case 'switchbotBle': // Get ID for Switchbot and ESPHome Devices
558
- case 'esphome':
559
- deviceName = await this.getInitValue(currDeviceString + this.arrDev[i].id);
560
- break;
561
-
562
- // Get ID with short currDeviceString from objectjson
563
- case 'hue-extended':
564
- case 'homematic':
565
- case 'nuki-extended':
566
- case 'wled':
567
- if (shortDeviceObject && typeof shortDeviceObject === 'object') {
568
- deviceName = shortDeviceObject.common.name;
569
- }
570
- break;
571
-
572
- // Get ID with short short currDeviceString vom objectjson
573
- case 'hmiP':
574
- if (shortshortDeviceObject && typeof shortshortDeviceObject === 'object') {
575
- deviceName = shortshortDeviceObject.common.name;
576
- }
577
- break;
578
-
579
- // Get ID with short currDeviceString from datapoint
580
- case 'mihomeVacuum':
581
- case 'roomba':
582
- deviceName = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].id);
583
- break;
584
-
585
- //Get ID of foldername
586
- case 'tado':
587
- deviceName = currDeviceString.slice(currDeviceString.lastIndexOf('.') + 1);
588
- break;
589
-
590
- //Get ID of foldername
591
- case 'yeelight-2':
592
- deviceName = shortCurrDeviceString.slice(shortCurrDeviceString.lastIndexOf('.') + 1);
593
- break;
378
+ * @param {object} id - deviceID
379
+ * @param {object} i - each Device
380
+ */
381
+ async getDeviceName(id, i) {
382
+ const currDeviceString = id.slice(0, (id.lastIndexOf('.') + 1) - 1);
383
+ const shortCurrDeviceString = currDeviceString.slice(0, (currDeviceString.lastIndexOf('.') + 1) - 1);
384
+ const shortshortCurrDeviceString = shortCurrDeviceString.slice(0, (shortCurrDeviceString.lastIndexOf('.') + 1) - 1);
385
+
386
+ // Get device name
387
+ const deviceObject = await this.getForeignObjectAsync(currDeviceString);
388
+ const shortDeviceObject = await this.getForeignObjectAsync(shortCurrDeviceString);
389
+ const shortshortDeviceObject = await this.getForeignObjectAsync(shortshortCurrDeviceString);
390
+ let deviceName;
391
+
392
+ // Get ID with currDeviceString from datapoint
393
+ switch (this.arrDev[i].adapter) {
394
+ // Get ID for Switchbot and ESPHome Devices
395
+ case 'switchbotBle':
396
+ case 'esphome':
397
+ deviceName = await this.getInitValue(currDeviceString + this.arrDev[i].id);
398
+ break;
399
+
400
+ // Get ID with short currDeviceString from objectjson
401
+ case 'hue-extended':
402
+ case 'hmrpc':
403
+ case 'nuki-extended':
404
+ case 'wled':
405
+ if (shortDeviceObject && typeof shortDeviceObject === 'object') {
406
+ deviceName = shortDeviceObject.common.name;
407
+ }
408
+ break;
594
409
 
595
- // Get ID with main selektor from objectjson
596
- default:
597
- if (deviceObject && typeof deviceObject === 'object') {
598
- deviceName = deviceObject.common.name;
599
- }
600
- break;
410
+ // Get ID with short short currDeviceString from objectjson (HMiP Devices)
411
+ case 'hmiP':
412
+ if (shortshortDeviceObject && typeof shortshortDeviceObject === 'object') {
413
+ deviceName = shortshortDeviceObject.common.name;
414
+ }
415
+ break;
416
+
417
+ // Get ID with short currDeviceString from datapoint
418
+ case 'mihomeVacuum':
419
+ case 'roomba':
420
+ deviceName = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].id);
421
+ break;
422
+
423
+ //Get ID of foldername
424
+ case 'tado':
425
+ deviceName = currDeviceString.slice(currDeviceString.lastIndexOf('.') + 1);
426
+ break;
427
+
428
+ //Get ID of foldername
429
+ case 'yeelight-2':
430
+ deviceName = shortCurrDeviceString.slice(shortCurrDeviceString.lastIndexOf('.') + 1);
431
+ break;
432
+
433
+ // Get ID with main selektor from objectjson
434
+ default:
435
+ if (deviceObject && typeof deviceObject === 'object') {
436
+ if (deviceObject.common.name['de'] != undefined) {
437
+ deviceName = deviceObject.common.name['de'];
438
+ } else if (deviceObject.common.name['en'] != undefined) {
439
+ deviceName = deviceObject.common.name['en'];
440
+ } else {
441
+ deviceName = deviceObject.common.name;
601
442
  }
443
+ }
444
+ break;
445
+ }
446
+ return deviceName;
447
+ }
602
448
 
603
- const deviceMainSelector = await this.getForeignStateAsync(id);
604
- const deviceStateSelector = await this.getForeignStateAsync(shortCurrDeviceString + this.arrDev[i].stateValue); // for homematic devices
605
-
606
- // Get battery states
607
- const deviceBatteryState = await this.getInitValue(currDeviceString + this.arrDev[i].battery);
608
- const shortDeviceBatteryState = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].battery);
609
- const shortDeviceBatteryState2 = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].battery2);
610
-
611
- // Get link quality
612
- let deviceQualityState;
613
- let linkQuality;
614
-
615
- switch (this.arrDev[i].adapter) {
616
- case 'sonoff':
617
- case 'hmiP':
618
- case 'homematic':
619
- case 'wled':
620
- case 'shelly':
621
- deviceQualityState = await this.getForeignStateAsync(currDeviceString + this.arrDev[i].rssiState);
622
- break;
449
+ /**
450
+ * Create Lists
451
+ */
452
+ async createLists() {
453
+ this.linkQualityDevices = [];
454
+ this.batteryPowered = [];
455
+ this.batteryLowPowered = [];
456
+ this.listAllDevices = [];
457
+ this.offlineDevices = [];
623
458
 
624
- case 'mihomeVacuum':
625
- deviceQualityState = await this.getForeignStateAsync(shortCurrDeviceString + this.arrDev[i].rssiState);
626
- break;
459
+ for (const device of this.listAllDevicesRaw) {
460
+ if (!this.blacklistLists.includes(device['Path'])) {
461
+ this.listAllDevices.push(
462
+ {
463
+ 'Device': device['Device'],
464
+ 'Adapter': device['Adapter'],
465
+ 'Battery': device['Battery'],
466
+ 'Signal strength': device['Signal strength'],
467
+ 'Last contact': device['Last contact'],
468
+ 'Status': device['Status']
469
+ }
470
+ );
471
+ // LinkQuality lists
472
+ if (device['Signal strength'] != ' - ') {
473
+ this.linkQualityDevices.push(
474
+ {
475
+ 'Device': device['Device'],
476
+ 'Adapter': device['Adapter'],
477
+ 'Signal strength': device['Signal strength']
478
+ }
479
+ );
480
+ }
481
+ // Battery lists
482
+ if (device['Battery'] != ' - ') {
483
+ this.batteryPowered.push(
484
+ {
485
+ 'Device': device['Device'],
486
+ 'Adapter': device['Adapter'],
487
+ 'Battery': device['Battery']
488
+ }
489
+ );
490
+ }
491
+ // Low Bat lists
492
+ if (device['LowBat']) {
493
+ this.batteryLowPowered.push(
494
+ {
495
+ 'Device': device['Device'],
496
+ 'Adapter': device['Adapter'],
497
+ 'Battery': device['Battery']
498
+ }
499
+ );
500
+ }
627
501
 
628
- case 'tradfri':
629
- case 'ham':
630
- case 'meross':
631
- case 'nut':
632
- case 'miHome':
633
- case 'unifi':
634
- deviceQualityState;
635
- break;
502
+ // Offline List
503
+ if (device['Status'] === 'Offline') {
504
+ this.offlineDevices.push(
505
+ {
506
+ 'Device': device['Device'],
507
+ 'Adapter': device['Adapter'],
508
+ 'Last contact': device['Last contact']
509
+ }
510
+ );
511
+ }
512
+ }
513
+ }
514
+ }
636
515
 
637
- case 'netatmo':
638
- deviceQualityState = await this.getForeignStateAsync(currDeviceString + this.arrDev[i].rssiState);
639
- if (!deviceQualityState) {
640
- deviceQualityState = await this.getForeignStateAsync(currDeviceString + this.arrDev[i].rfState);
641
- }
642
- break;
516
+ /**
517
+ * Count devices for each type
518
+ */
519
+ async countDevices() {
520
+ // Count how many devices with link Quality
521
+ this.linkQualityCount = this.linkQualityDevices.length;
643
522
 
644
- default:
645
- deviceQualityState = await this.getForeignStateAsync(id);
646
- break;
647
- }
523
+ // Count how many devcies are offline
524
+ this.offlineDevicesCount = this.offlineDevices.length;
648
525
 
649
- if ((deviceQualityState) && (typeof deviceQualityState.val === 'number')) {
650
- if (this.config.trueState) {
651
- linkQuality = deviceQualityState.val;
652
- } else {
653
- // If Quality State is already an percent value
654
- switch (this.arrDev[i].adapter) {
655
- case 'roomba':
656
- linkQuality = deviceQualityState.val + '%';
657
- break;
526
+ // Count how many devices are with battery
527
+ this.batteryPoweredCount = this.batteryPowered.length;
658
528
 
659
- default:
660
- // If Quality State is an RSSI vaulue calculate in percent:
661
- if (deviceQualityState.val == -255) {
662
- linkQuality = ' - ';
663
- } else if (deviceQualityState.val < 0) {
664
- linkQuality = Math.min(Math.max(2 * (deviceQualityState.val + 100), 0), 100) + '%';
529
+ // 3d. Count how many devices are with low battery
530
+ this.lowBatteryPoweredCount = this.batteryLowPowered.length;
665
531
 
666
- // If Quality State is an value between 0-255 (zigbee) calculate in percent:
667
- } else if ((deviceQualityState.val) >= 0) {
668
- linkQuality = parseFloat((100 / 255 * deviceQualityState.val).toFixed(0)) + '%';
669
- }
670
- break;
671
- }
532
+ // Count how many devices are exists
533
+ this.deviceCounter = this.listAllDevices.length;
534
+ }
672
535
 
673
- }
674
- if (this.config.listOnlyBattery) {
675
- if (deviceBatteryState || shortDeviceBatteryState) {
676
- this.linkQualityDevices.push(
677
- {
678
- 'Device': deviceName,
679
- 'Adapter': deviceAdapterName,
680
- 'Signal strength': linkQuality
681
- }
682
- );
683
- }
684
- } else {
685
- this.linkQualityDevices.push(
686
- {
687
- 'Device': deviceName,
688
- 'Adapter': deviceAdapterName,
689
- 'Signal strength': linkQuality
690
- }
691
- );
692
- }
693
- } else if ((deviceQualityState) && (typeof deviceQualityState.val === 'string')) {
694
- switch (this.arrDev[i].adapter) {
695
- case 'netatmo':
696
- // for Netatmo devices
697
- linkQuality = deviceQualityState.val;
698
- break;
699
- case 'nuki-extended':
700
- linkQuality = ' - ';
701
- break;
702
- }
536
+ /**
537
+ * @param {object} i - Device Object
538
+ */
539
+ async createData(i) {
540
+ const devices = await this.getForeignStatesAsync(this.arrDev[i].Selektor);
541
+ const deviceAdapterName = await this.capitalize(this.arrDev[i].adapter);
703
542
 
704
- if (this.config.listOnlyBattery) {
705
- if (deviceBatteryState || shortDeviceBatteryState) {
706
- this.linkQualityDevices.push(
707
- {
708
- 'Device': deviceName,
709
- 'Adapter': deviceAdapterName,
710
- 'Signal strength': linkQuality
711
- }
712
- );
713
- }
714
- } else {
715
- this.linkQualityDevices.push(
716
- {
717
- 'Device': deviceName,
718
- 'Adapter': deviceAdapterName,
719
- 'Signal strength': linkQuality
720
- }
721
- );
722
- }
723
- }
724
- else {
725
- linkQuality = ' - '; // no linkQuality available for powered devices
726
- }
543
+ /*---------- Start of second main loop ----------*/
544
+ for (const [id] of Object.entries(devices)) {
545
+ if (!isUnloaded) {
727
546
 
728
- // Count how many devices with link Quality
729
- this.linkQualityCount = this.linkQualityDevices.length;
730
547
 
731
- // When was the last contact to the device?
732
- let lastContactString;
733
548
 
734
- let deviceState = 'Online';
735
- if (deviceMainSelector) {
736
- try {
737
- const time = new Date();
738
- const lastContact = Math.round((time.getTime() - deviceMainSelector.ts) / 1000 / 60);
739
- const lastStateChange = Math.round((time.getTime() - deviceMainSelector.lc) / 1000 / 60);
740
- const deviceUnreachState = await this.getInitValue(currDeviceString + this.arrDev[i].reach);
741
- const shortDeviceUnreachState = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].reach);
549
+ const deviceName = await this.getDeviceName(id, i);
742
550
 
551
+ const currDeviceString = id.slice(0, (id.lastIndexOf('.') + 1) - 1);
552
+ const shortCurrDeviceString = currDeviceString.slice(0, (currDeviceString.lastIndexOf('.') + 1) - 1);
743
553
 
744
- const getLastContact = async () => {
745
- lastContactString = this.formatDate(new Date((deviceMainSelector.ts)), 'hh:mm') + ' Uhr';
746
- if (Math.round(lastContact) > 100) {
747
- lastContactString = Math.round(lastContact / 60) + ' Stunden';
748
- }
749
- if (Math.round(lastContact / 60) > 48) {
750
- lastContactString = Math.round(lastContact / 60 / 24) + ' Tagen';
751
- }
752
- return lastContactString;
753
- };
554
+ // Get battery states
555
+ const deviceBatteryState = await this.getInitValue(currDeviceString + this.arrDev[i].battery);
556
+ const shortDeviceBatteryState = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].battery);
557
+ const shortDeviceBatteryState2 = await this.getInitValue(shortCurrDeviceString + this.arrDev[i].battery2);
754
558
 
755
- const getLastStateChange = async () => {
756
- lastContactString = this.formatDate(new Date((deviceMainSelector.lc)), 'hh:mm') + ' Uhr';
757
- if (Math.round(lastStateChange) > 100) {
758
- lastContactString = Math.round(lastStateChange / 60) + ' Stunden';
759
- }
760
- if (Math.round(lastStateChange / 60) > 48) {
761
- lastContactString = Math.round(lastStateChange / 60 / 24) + ' Tagen';
762
- }
763
- return lastContactString;
764
- };
765
559
 
560
+ //this.devices[deviceName] = currDeviceString + this.arrDev[i].reach;
766
561
 
767
- // If there is no contact since user sets minutes add device in offline list
768
- // calculate to days after 48 hours
769
- switch (this.arrDev[i].reach) {
770
- case 'none':
771
- await getLastContact();
772
- break;
562
+ /*for (const [value] of Object.entries(this.devices)) {
563
+ this.log.warn(`${value}`);
564
+ this.subscribeForeignStatesAsync(value);
565
+ }*/
566
+ //this.subscribeForeignStatesAsync(currDeviceString + this.arrDev[i].reach);
567
+ // <--- END TEST
773
568
 
774
- default:
775
- //State changed
776
- if (this.arrDev[i].adapter == 'homematic') {
777
- if (linkQuality != ' - ') {
778
- if (deviceUnreachState) {
779
- await getLastStateChange();
780
- } else {
781
- await getLastContact();
782
- }
783
- } else {
784
- if (deviceStateSelector) { // because old hm devices don't send rssi states
785
- const lastContactOfState = Math.round((time.getTime() - deviceStateSelector.ts) / 1000 / 60);
786
- const getLastContactOfState = async () => {
787
- lastContactString = this.formatDate(new Date((deviceStateSelector.ts)), 'hh:mm') + ' Uhr';
788
- if (Math.round(lastContactOfState) > 100) {
789
- lastContactString = Math.round(lastContactOfState / 60) + ' Stunden';
790
- }
791
- if (Math.round(lastContactOfState / 60) > 48) {
792
- lastContactString = Math.round(lastContactOfState / 60 / 24) + ' Tagen';
793
- }
794
- return lastContactString;
795
- };
796
- await getLastContactOfState();
797
- }
798
- }
569
+ // Get link quality
570
+ let deviceQualityState;
571
+ let linkQuality;
799
572
 
800
- } else {
801
- if ((!deviceUnreachState)) {
802
- await getLastStateChange();
803
- } else {
804
- await getLastContact();
805
- }
806
- break;
807
- }
808
- }
573
+ switch (this.arrDev[i].adapter) {
574
+ case 'mihomeVacuum':
575
+ deviceQualityState = await this.getForeignStateAsync(shortCurrDeviceString + this.arrDev[i].rssiState);
576
+ break;
809
577
 
810
- const pushOfflineDevice = async () => {
811
- if (this.config.listOnlyBattery) { //if checked, list only battery devices
812
- if (deviceBatteryState || shortDeviceBatteryState) {
813
- this.offlineDevices.push(
814
- {
815
- 'Device': deviceName,
816
- 'Adapter': deviceAdapterName,
817
- 'Last contact': lastContactString
818
- }
819
- );
820
- }
821
- } else {
822
- this.offlineDevices.push( //else push all devices
823
- {
824
- 'Device': deviceName,
825
- 'Adapter': deviceAdapterName,
826
- 'Last contact': lastContactString
827
- }
828
- );
829
- }
830
- };
578
+ case 'netatmo':
579
+ deviceQualityState = await this.getForeignStateAsync(currDeviceString + this.arrDev[i].rssiState);
580
+ if (!deviceQualityState) {
581
+ deviceQualityState = await this.getForeignStateAsync(currDeviceString + this.arrDev[i].rfState);
582
+ }
583
+ break;
831
584
 
832
- switch (this.arrDev[i].adapter) {
833
- case 'alexa2':
834
- if (this.config.alexa2MaxMinutes === -1) {
835
- if (!deviceUnreachState) {
836
- deviceState = 'Offline'; //set online state to offline
837
- await pushOfflineDevice();
838
- }
839
- } else if (lastContact > this.config.alexa2MaxMinutes) {
840
- deviceState = 'Offline'; //set online state to offline
841
- await pushOfflineDevice();
842
- }
843
- break;
844
- case 'ble':
845
- if (this.config.bleMaxMinutes === -1) {
846
- if (!deviceUnreachState) {
847
- deviceState = 'Offline'; //set online state to offline
848
- await pushOfflineDevice();
849
- }
850
- } else if (lastContact > this.config.bleMaxMinutes) {
851
- deviceState = 'Offline'; //set online state to offline
852
- await pushOfflineDevice();
853
- }
854
- break;
855
- case 'deconz':
856
- if (this.config.deconzMaxMinutes === -1) {
857
- if (!deviceUnreachState) {
858
- deviceState = 'Offline'; //set online state to offline
859
- await pushOfflineDevice();
860
- }
861
- } else if (lastContact > this.config.deconzMaxMinutes) {
862
- deviceState = 'Offline'; //set online state to offline
863
- await pushOfflineDevice();
864
- }
865
- break;
866
- case 'enocean':
867
- if (this.config.enoceanMaxMinutes === -1) {
868
- if (!deviceUnreachState) {
869
- deviceState = 'Offline'; //set online state to offline
870
- await pushOfflineDevice();
871
- }
872
- } else if (lastContact > this.config.enoceanMaxMinutes) {
873
- deviceState = 'Offline'; //set online state to offline
874
- await pushOfflineDevice();
875
- }
876
- break;
877
- case 'esphome':
878
- if (this.config.esphomeMaxMinutes === -1) {
879
- if (!deviceUnreachState) {
880
- deviceState = 'Offline'; //set online state to offline
881
- await pushOfflineDevice();
882
- }
883
- } else if (lastContact > this.config.esphomeMaxMinutes) {
884
- deviceState = 'Offline'; //set online state to offline
885
- await pushOfflineDevice();
886
- }
887
- break;
888
- case 'fritzDect':
889
- if (this.config.fritzdectMaxMinutes === -1) {
890
- if (!deviceUnreachState) {
891
- deviceState = 'Offline'; //set online state to offline
892
- await pushOfflineDevice();
893
- }
894
- } else if (lastContact > this.config.fritzdectMaxMinutes) {
895
- deviceState = 'Offline'; //set online state to offline
896
- await pushOfflineDevice();
897
- }
898
- break;
899
- case 'harmony':
900
- if (this.config.harmonyMaxMinutes === -1) {
901
- if (!deviceUnreachState) {
902
- deviceState = 'Offline'; //set online state to offline
903
- await pushOfflineDevice();
904
- }
905
- } else if (lastContact > this.config.harmonyMaxMinutes) {
906
- deviceState = 'Offline'; //set online state to offline
907
- await pushOfflineDevice();
908
- }
909
- break;
910
- case 'ham':
911
- if (this.config.hamMaxMinutes === -1) {
912
- if (!deviceUnreachState) {
913
- deviceState = 'Offline'; //set online state to offline
914
- await pushOfflineDevice();
915
- }
916
- } else if (lastContact > this.config.hamMaxMinutes) {
917
- deviceState = 'Offline'; //set online state to offline
918
- await pushOfflineDevice();
919
- }
920
- break;
921
- case 'hmiP':
922
- if (this.config.hmiPMaxMinutes === -1) {
923
- if (deviceUnreachState) {
924
- deviceState = 'Offline'; //set online state to offline
925
- await pushOfflineDevice();
926
- }
927
- } else if (lastContact > this.config.hmiPMaxMinutes) {
928
- deviceState = 'Offline'; //set online state to offline
929
- await pushOfflineDevice();
930
- }
931
- break;
932
- case 'homematic':
933
- if (this.config.homematicMaxMinutes === -1) {
934
- if (deviceUnreachState) {
935
- deviceState = 'Offline'; //set online state to offline
936
- await pushOfflineDevice();
937
- }
938
- } else if (lastContact > this.config.homematicMaxMinutes) {
939
- deviceState = 'Offline'; //set online state to offline
940
- await pushOfflineDevice();
941
- }
942
- break;
943
- case 'hue':
944
- if (this.config.hueMaxMinutes === -1) {
945
- if (!deviceUnreachState) {
946
- deviceState = 'Offline'; //set online state to offline
947
- await pushOfflineDevice();
948
- }
949
- } else if (lastContact > this.config.hueMaxMinutes) {
950
- deviceState = 'Offline'; //set online state to offline
951
- await pushOfflineDevice();
952
- }
953
- break;
954
- case 'hue-extended':
955
- if (this.config.hueextMaxMinutes === -1) {
956
- if (!deviceUnreachState) {
957
- deviceState = 'Offline'; //set online state to offline
958
- await pushOfflineDevice();
959
- }
960
- } else if (lastContact > this.config.hueextMaxMinutes) {
961
- deviceState = 'Offline'; //set online state to offline
962
- await pushOfflineDevice();
963
- }
964
- break;
965
- case 'jeelink':
966
- if (this.config.jeelinkMaxMinutes === -1) {
967
- if (!deviceUnreachState) {
968
- deviceState = 'Offline'; //set online state to offline
969
- await pushOfflineDevice();
970
- }
971
- } else if (lastContact > this.config.jeelinkMaxMinutes) {
972
- deviceState = 'Offline'; //set online state to offline
973
- await pushOfflineDevice();
974
- }
975
- break;
976
- case 'meross':
977
- if (this.config.merossMaxMinutes === -1) {
978
- if (!deviceUnreachState) {
979
- deviceState = 'Offline'; //set online state to offline
980
- await pushOfflineDevice();
981
- }
982
- } else if (lastContact > this.config.merossMaxMinutes) {
983
- deviceState = 'Offline'; //set online state to offline
984
- await pushOfflineDevice();
985
- }
986
- break;
987
- case 'miHome':
988
- if (this.config.mihomeMaxMinutes === -1) {
989
- if (!deviceUnreachState) {
990
- deviceState = 'Offline'; //set online state to offline
991
- await pushOfflineDevice();
992
- }
993
- } else if (lastContact > this.config.mihomeMaxMinutes) {
994
- deviceState = 'Offline'; //set online state to offline
995
- await pushOfflineDevice();
996
- }
997
- break;
998
- case 'mihomeVacuum':
999
- if (this.config.mihomeVacuumMaxMinutes === -1) {
1000
- if (!shortDeviceUnreachState) {
1001
- deviceState = 'Offline'; //set online state to offline
1002
- await pushOfflineDevice();
585
+ default:
586
+ deviceQualityState = await this.getForeignStateAsync(currDeviceString + this.arrDev[i].rssiState);
587
+ break;
588
+ }
589
+
590
+ if (deviceQualityState != null) {
591
+ switch (typeof deviceQualityState.val) {
592
+ case 'number':
593
+ if (this.config.trueState) {
594
+ linkQuality = deviceQualityState.val;
595
+ } else {
596
+ switch (this.arrDev[i].adapter) {
597
+ case 'roomba':
598
+ case 'sonoff':
599
+ linkQuality = deviceQualityState.val + '%'; // If quality state is already an percent value
600
+ break;
601
+ case 'lupusec':
602
+ linkQuality = deviceQualityState.val;
603
+ break;
604
+
605
+ default:
606
+ // If quality state is an RSSI value calculate in percent:
607
+ if (deviceQualityState.val == -255) {
608
+ linkQuality = ' - ';
609
+ } else if (deviceQualityState.val < 0) {
610
+ linkQuality = Math.min(Math.max(2 * (deviceQualityState.val + 100), 0), 100) + '%';
611
+ // If Quality State is an value between 0-255 (zigbee) calculate in percent:
612
+ } else if ((deviceQualityState.val) >= 0) {
613
+ linkQuality = parseFloat((100 / 255 * deviceQualityState.val).toFixed(0)) + '%';
1003
614
  }
1004
- } else if (lastContact > this.config.mihomeVacuumMaxMinutes) {
1005
- deviceState = 'Offline'; //set online state to offline
1006
- await pushOfflineDevice();
1007
- }
1008
- break;
615
+ break;
616
+ }
617
+ }
618
+ break;
619
+
620
+ case 'string':
621
+ switch (this.arrDev[i].adapter) {
1009
622
  case 'netatmo':
1010
- if (this.config.netatmoMaxMinutes === -1) {
1011
- if (!deviceUnreachState) {
1012
- deviceState = 'Offline'; //set online state to offline
1013
- await pushOfflineDevice();
1014
- }
1015
- } else if (lastContact > this.config.netatmoMaxMinutes) {
1016
- deviceState = 'Offline'; //set online state to offline
1017
- await pushOfflineDevice();
1018
- }
623
+ // for Netatmo devices
624
+ linkQuality = deviceQualityState.val;
1019
625
  break;
1020
626
  case 'nuki-extended':
1021
- if (this.config.nukiextendMaxMinutes === -1) {
1022
- if (!deviceUnreachState) {
1023
- deviceState = 'Offline'; //set online state to offline
1024
- await pushOfflineDevice();
1025
- }
1026
- } else if (lastContact > this.config.nukiextendMaxMinutes) {
1027
- deviceState = 'Offline'; //set online state to offline
1028
- await pushOfflineDevice();
1029
- }
1030
- break;
1031
- case 'nut':
1032
- if (this.config.nutMaxMinutes === -1) {
1033
- if (!deviceUnreachState) {
1034
- deviceState = 'Offline'; //set online state to offline
1035
- await pushOfflineDevice();
1036
- }
1037
- } else if (lastContact > this.config.nutMaxMinutes) {
1038
- deviceState = 'Offline'; //set online state to offline
1039
- await pushOfflineDevice();
1040
- }
1041
- break;
1042
- case 'ping':
1043
- if (this.config.pingMaxMinutes === -1) {
1044
- if (!deviceUnreachState) {
1045
- deviceState = 'Offline'; //set online state to offline
1046
- await pushOfflineDevice();
1047
- }
1048
- } else if ((lastStateChange > this.config.pingMaxMinutes) && (!deviceUnreachState)) {
1049
- deviceState = 'Offline'; //set online state to offline
1050
- await pushOfflineDevice();
1051
- }
1052
- break;
1053
- case 'roomba':
1054
- if (this.config.roombaMaxMinutes === -1) {
1055
- if (!deviceUnreachState) {
1056
- deviceState = 'Offline'; //set online state to offline
1057
- await pushOfflineDevice();
1058
- }
1059
- } else if (lastContact > this.config.roombaMaxMinutes) {
1060
- deviceState = 'Offline'; //set online state to offline
1061
- await pushOfflineDevice();
1062
- }
627
+ linkQuality = ' - ';
1063
628
  break;
1064
- case 'shelly':
1065
- if (this.config.shellyMaxMinutes === -1) {
1066
- if (!deviceUnreachState) {
1067
- deviceState = 'Offline'; //set online state to offline
1068
- await pushOfflineDevice();
629
+ }
630
+ break;
631
+ }
632
+ } else {
633
+ linkQuality = ' - ';
634
+ }
635
+
636
+ // When was the last contact to the device?
637
+ let lastContactString;
638
+ let deviceState = 'Online';
639
+ let lastDeviceUnreachStateChange;
640
+
641
+ const deviceMainSelector = await this.getForeignStateAsync(id);
642
+ const deviceStateSelector = await this.getForeignStateAsync(shortCurrDeviceString + this.arrDev[i].stateValue); // for hmrpc devices
643
+ const rssiPeerSelector = await this.getForeignStateAsync(currDeviceString + this.arrDev[i].rssiPeerState);
644
+
645
+ if (deviceMainSelector) {
646
+ try {
647
+ const lastContact = await this.getTimestamp(deviceMainSelector.ts);
648
+ const lastStateChange = await this.getTimestamp(deviceMainSelector.lc);
649
+ const deviceUnreachState = await this.getInitValue(currDeviceString + this.arrDev[i].reach);
650
+ const deviceUnreachSelector = await this.getForeignStateAsync(currDeviceString + this.arrDev[i].reach);
651
+ if (deviceUnreachSelector) {lastDeviceUnreachStateChange = await this.getTimestamp(deviceUnreachSelector.lc);}
652
+ const shortDeviceUnreachState = await this.getForeignStateAsync(shortCurrDeviceString + this.arrDev[i].reach);
653
+
654
+ const getLastContact = async () => {
655
+ lastContactString = this.formatDate(new Date((deviceMainSelector.ts)), 'hh:mm') + ' Uhr';
656
+ if (Math.round(lastContact) > 100) {
657
+ lastContactString = Math.round(lastContact / 60) + ' Stunden';
658
+ }
659
+ if (Math.round(lastContact / 60) > 48) {
660
+ lastContactString = Math.round(lastContact / 60 / 24) + ' Tagen';
661
+ }
662
+ return lastContactString;
663
+ };
664
+
665
+ const getLastStateChange = async () => {
666
+ lastContactString = this.formatDate(new Date((deviceMainSelector.lc)), 'hh:mm') + ' Uhr';
667
+ if (Math.round(lastStateChange) > 100) {
668
+ lastContactString = Math.round(lastStateChange / 60) + ' Stunden';
669
+ }
670
+ if (Math.round(lastStateChange / 60) > 48) {
671
+ lastContactString = Math.round(lastStateChange / 60 / 24) + ' Tagen';
672
+ }
673
+ return lastContactString;
674
+ };
675
+
676
+ // If there is no contact since user sets minutes add device in offline list
677
+ // calculate to days after 48 hours
678
+ switch (this.arrDev[i].reach) {
679
+ case 'none':
680
+ await getLastContact();
681
+ break;
682
+
683
+ default:
684
+ //State changed
685
+ if (this.arrDev[i].adapter === 'hmrpc') {
686
+ if (linkQuality != ' - ') {
687
+ if (deviceUnreachState) {
688
+ await getLastStateChange();
689
+ } else {
690
+ await getLastContact();
1069
691
  }
1070
- } else if (lastContact > this.config.shellyMaxMinutes) {
1071
- deviceState = 'Offline'; //set online state to offline
1072
- await pushOfflineDevice();
1073
- }
1074
- break;
1075
- case 'sonoff':
1076
- if (this.config.sonoffMaxMinutes === -1) {
1077
- if (!deviceUnreachState) {
1078
- deviceState = 'Offline'; //set online state to offline
1079
- await pushOfflineDevice();
692
+ } else {
693
+ if (deviceStateSelector) { // because old hm devices don't send rssi states
694
+ const lastContactOfState = await this.getTimestamp(deviceStateSelector.ts);
695
+ const getLastContactOfState = async () => {
696
+ lastContactString = this.formatDate(new Date((deviceStateSelector.ts)), 'hh:mm') + ' Uhr';
697
+ if (Math.round(lastContactOfState) > 100) {
698
+ lastContactString = Math.round(lastContactOfState / 60) + ' Stunden';
699
+ }
700
+ if (Math.round(lastContactOfState / 60) > 48) {
701
+ lastContactString = Math.round(lastContactOfState / 60 / 24) + ' Tagen';
702
+ }
703
+ return lastContactString;
704
+ };
705
+ await getLastContactOfState();
706
+ } else if (rssiPeerSelector) { // because old hm sensors don't send rssi/state values
707
+ const lastContactOfState = await this.getTimestamp(rssiPeerSelector.ts);
708
+ const getLastContactOfState = async () => {
709
+ lastContactString = this.formatDate(new Date((rssiPeerSelector.ts)), 'hh:mm') + ' Uhr';
710
+ if (Math.round(lastContactOfState) > 100) {
711
+ lastContactString = Math.round(lastContactOfState / 60) + ' Stunden';
712
+ }
713
+ if (Math.round(lastContactOfState / 60) > 48) {
714
+ lastContactString = Math.round(lastContactOfState / 60 / 24) + ' Tagen';
715
+ }
716
+ return lastContactString;
717
+ };
718
+ await getLastContactOfState();
1080
719
  }
1081
- } else if (lastContact > this.config.sonoffMaxMinutes) {
1082
- deviceState = 'Offline'; //set online state to offline
1083
- await pushOfflineDevice();
1084
720
  }
1085
- break;
1086
- case 'sonos':
1087
- if (this.config.sonosMaxMinutes === -1) {
1088
- if (!deviceUnreachState) {
1089
- deviceState = 'Offline'; //set online state to offline
1090
- await pushOfflineDevice();
1091
- }
1092
- } else if (lastContact > this.config.sonosMaxMinutes) {
1093
- deviceState = 'Offline'; //set online state to offline
1094
- await pushOfflineDevice();
721
+
722
+ } else {
723
+ if (!deviceUnreachState) {
724
+ await getLastStateChange();
725
+ } else {
726
+ await getLastContact();
1095
727
  }
1096
728
  break;
1097
- case 'switchbotBle':
1098
- if (this.config.switchbotMaxMinutes === -1) {
1099
- if (!deviceUnreachState) {
1100
- deviceState = 'Offline'; //set online state to offline
1101
- await pushOfflineDevice();
1102
- }
1103
- } else if (lastContact > this.config.switchbotMaxMinutes) {
729
+ }
730
+ }
731
+
732
+ const adapterID = this.arrDev[i].adapter;
733
+
734
+ switch (adapterID) {
735
+ case 'hmrpc':
736
+ case 'hmiP':
737
+ case 'maxcube':
738
+ if ((this.maxMinutes !== undefined) && (this.maxMinutes[adapterID] === -1)) {
739
+ if (deviceUnreachState) {
1104
740
  deviceState = 'Offline'; //set online state to offline
1105
- await pushOfflineDevice();
1106
741
  }
1107
- break;
1108
- case 'tado':
1109
- if (this.config.tadoMaxMinutes === -1) {
1110
- if (!deviceUnreachState) {
1111
- deviceState = 'Offline'; //set online state to offline
1112
- await pushOfflineDevice();
1113
- }
1114
- } else if (lastContact > this.config.tadoMaxMinutes) {
742
+ } else if ((this.maxMinutes !== undefined) && (lastContact > this.maxMinutes[adapterID])) {
743
+ deviceState = 'Offline'; //set online state to offline
744
+ }
745
+ break;
746
+ case 'ping':
747
+ if ((this.maxMinutes !== undefined) && (this.maxMinutes[adapterID] === -1)) {
748
+ if (!deviceUnreachState) {
1115
749
  deviceState = 'Offline'; //set online state to offline
1116
- await pushOfflineDevice();
1117
750
  }
1118
- break;
1119
- case 'tradfri':
1120
- if (this.config.tradfriMaxMinutes === -1) {
1121
- if (!deviceUnreachState) {
1122
- deviceState = 'Offline'; //set online state to offline
1123
- await pushOfflineDevice();
1124
- }
1125
- } else if (lastContact > this.config.tradfriMaxMinutes) {
751
+ } else if ((this.maxMinutes !== undefined) && (lastContact > this.maxMinutes[adapterID]) && (!deviceUnreachState)) {
752
+ deviceState = 'Offline'; //set online state to offline
753
+ }
754
+ break;
755
+ case 'unifi':
756
+ if ((this.maxMinutes !== undefined) && (this.maxMinutes[adapterID] === -1)) {
757
+ if (deviceUnreachState === 0) {
1126
758
  deviceState = 'Offline'; //set online state to offline
1127
- await pushOfflineDevice();
1128
759
  }
1129
- break;
1130
- case 'unifi':
1131
- if (this.config.unifiMaxMinutes === -1) {
1132
- if (deviceUnreachState === 0) {
1133
- deviceState = 'Offline'; //set online state to offline
1134
- await pushOfflineDevice();
1135
- }
1136
- } else if (lastContact > this.config.unifiMaxMinutes) {
760
+ } else if ((this.maxMinutes !== undefined) && (lastContact > this.maxMinutes[adapterID])) {
761
+ deviceState = 'Offline'; //set online state to offline
762
+
763
+ }
764
+ break;
765
+ case 'shelly':
766
+ case 'sonoff':
767
+ if ((this.maxMinutes !== undefined) && (this.maxMinutes[adapterID] === -1)) {
768
+ if (!deviceUnreachState) {
1137
769
  deviceState = 'Offline'; //set online state to offline
1138
- await pushOfflineDevice();
1139
770
  }
1140
- break;
1141
- case 'wled':
1142
- if (this.config.wledMaxMinutes === -1) {
1143
- if (!deviceUnreachState) {
1144
- deviceState = 'Offline'; //set online state to offline
1145
- await pushOfflineDevice();
1146
- }
1147
- } else if (lastContact > this.config.wledMaxMinutes) {
771
+ } else if ((!deviceUnreachState) && (typeof lastDeviceUnreachStateChange !== 'undefined') && (this.maxMinutes !== undefined) && (lastContact > this.maxMinutes[adapterID])) {
772
+ deviceState = 'Offline'; //set online state to offline
773
+ }
774
+ break;
775
+ case 'mihomeVacuum':
776
+ if ((this.maxMinutes !== undefined) && (this.maxMinutes[adapterID] === -1)) {
777
+ if (!shortDeviceUnreachState) {
1148
778
  deviceState = 'Offline'; //set online state to offline
1149
- await pushOfflineDevice();
1150
779
  }
1151
- break;
1152
- case 'yeelight-2':
1153
- if (this.config.yeelightMaxMinutes === -1) {
780
+ } else if ((this.maxMinutes !== undefined) && (lastContact > this.maxMinutes[adapterID])) {
781
+ deviceState = 'Offline'; //set online state to offline
782
+ }
783
+ break;
784
+ case 'miHome':
785
+ if (this.arrDev[i].battery === 'none') {
786
+ if ((this.maxMinutes !== undefined) && (this.maxMinutes[adapterID] === -1)) {
1154
787
  if (!deviceUnreachState) {
1155
788
  deviceState = 'Offline'; //set online state to offline
1156
- await pushOfflineDevice();
1157
789
  }
1158
- } else if (lastContact > this.config.yeelightMaxMinutes) {
790
+ } else if ((this.maxMinutes !== undefined) && (lastContact > this.maxMinutes[adapterID])) {
1159
791
  deviceState = 'Offline'; //set online state to offline
1160
- await pushOfflineDevice();
1161
792
  }
1162
- break;
1163
- case 'zigbee':
1164
- if (this.config.zigbeeMaxMinutes === -1) {
1165
- if (!deviceUnreachState) {
793
+ } else {
794
+ if (this.config.mihomeMaxMinutes === -1) {
795
+ if ((this.maxMinutes !== undefined) && (this.maxMinutes[adapterID] === -1)) {
1166
796
  deviceState = 'Offline'; //set online state to offline
1167
- await pushOfflineDevice();
1168
797
  }
1169
- } else if (lastContact > this.config.zigbeeMaxMinutes) {
798
+ } else if ((this.maxMinutes !== undefined) && (lastContact > this.maxMinutes[adapterID])) {
1170
799
  deviceState = 'Offline'; //set online state to offline
1171
- await pushOfflineDevice();
1172
800
  }
1173
- break;
1174
- case 'zwave':
1175
- if (this.config.zwaveMaxMinutes === -1) {
1176
- if (!deviceUnreachState) {
1177
- deviceState = 'Offline'; //set online state to offline
1178
- await pushOfflineDevice();
1179
- }
1180
- } else if (lastContact > this.config.zwaveMaxMinutes) {
1181
- deviceState = 'Offline'; //set online state to offline
1182
- await pushOfflineDevice();
801
+ }
802
+ break;
803
+ default:
804
+ if ((this.maxMinutes !== undefined) && (this.maxMinutes[adapterID] === -1)) {
805
+ if (!deviceUnreachState) {
806
+ deviceState = 'Offline'; //set online state to offline
1183
807
  }
1184
- break;
1185
- }
1186
- } catch (error) {
1187
- this.errorReporting('[getLastContact]', error);
808
+ } else if ((this.maxMinutes !== undefined) && (lastContact > this.maxMinutes[adapterID])) {
809
+ deviceState = 'Offline'; //set online state to offline
810
+ }
811
+ break;
1188
812
  }
813
+ } catch (error) {
814
+ this.errorReporting('[getLastContact]', error);
1189
815
  }
816
+ }
1190
817
 
818
+ // Get battery states
819
+ let batteryHealth;
820
+ let lowBatIndicator;
821
+ let deviceLowBatState = await this.getInitValue(currDeviceString + this.arrDev[i].isLowBat);
822
+ if (deviceLowBatState === undefined) {
823
+ deviceLowBatState = await this.getInitValue(currDeviceString + this.arrDev[i].isLowBat2);
824
+ }
1191
825
 
1192
-
1193
- // Count how many devcies are offline
1194
- this.offlineDevicesCount = this.offlineDevices.length;
1195
-
1196
- // Get battery states
1197
- let batteryHealth;
1198
- const deviceLowBatState = await this.getInitValue(currDeviceString + this.arrDev[i].isLowBat);
1199
- const deviceLowBatStateHM = await this.getInitValue(currDeviceString + this.arrDev[i].isLowBat2);
1200
-
1201
- if ((!deviceBatteryState) && (!shortDeviceBatteryState) && (!shortDeviceBatteryState2)) {
1202
- if ((deviceLowBatState !== undefined) || (deviceLowBatState !== undefined) || (deviceLowBatStateHM !== undefined)) {
1203
- switch (this.arrDev[i].isLowBat) {
1204
- case 'none':
1205
- batteryHealth = ' - ';
1206
- break;
1207
- default:
1208
- if ((!deviceLowBatState) || (deviceLowBatState == 'NORMAL')) {
1209
- batteryHealth = 'ok';
1210
- } else {
1211
- batteryHealth = 'low';
1212
- }
1213
- break;
1214
- }
1215
- switch (this.arrDev[i].isLowBat2) {
1216
- case 'none':
1217
- batteryHealth = ' - ';
1218
- break;
1219
- default:
1220
- if ((!deviceLowBatState) || (deviceLowBatState == 'NORMAL')) {
1221
- batteryHealth = 'ok';
1222
- } else {
1223
- batteryHealth = 'low';
1224
- }
1225
- break;
1226
- }
1227
- this.batteryPowered.push(
1228
- {
1229
- 'Device': deviceName,
1230
- 'Adapter': deviceAdapterName,
1231
- 'Battery': batteryHealth
1232
- }
1233
- );
1234
- } else {
1235
- batteryHealth = ' - ';
1236
- }
1237
- } else {
1238
- switch (this.arrDev[i].adapter) {
1239
- case 'homematic':
1240
- if (deviceBatteryState === 0) {
1241
- batteryHealth = ' - ';
1242
- } else {
1243
- batteryHealth = deviceBatteryState + 'V';
1244
- }
1245
-
1246
- this.batteryPowered.push(
1247
- {
1248
- 'Device': deviceName,
1249
- 'Adapter': deviceAdapterName,
1250
- 'Battery': batteryHealth
1251
- }
1252
- );
1253
- break;
1254
- case 'hue-extended':
1255
- if (shortDeviceBatteryState) {
1256
- batteryHealth = shortDeviceBatteryState + '%';
1257
- this.batteryPowered.push(
1258
- {
1259
- 'Device': deviceName,
1260
- 'Adapter': deviceAdapterName,
1261
- 'Battery': batteryHealth
1262
- }
1263
- );
1264
- }
826
+ if ((!deviceBatteryState) && (!shortDeviceBatteryState) && (!shortDeviceBatteryState2)) {
827
+ if (deviceLowBatState !== undefined) {
828
+ switch (this.arrDev[i].isLowBat || this.arrDev[i].isLowBat2) {
829
+ case 'none':
830
+ batteryHealth = ' - ';
1265
831
  break;
1266
- case 'mihomeVacuum':
1267
- if (shortDeviceBatteryState) {
1268
- batteryHealth = shortDeviceBatteryState + '%';
1269
- this.batteryPowered.push(
1270
- {
1271
- 'Device': deviceName,
1272
- 'Adapter': deviceAdapterName,
1273
- 'Battery': batteryHealth
1274
- }
1275
- );
1276
- } else if (shortDeviceBatteryState2) {
1277
- batteryHealth = shortDeviceBatteryState2 + '%';
1278
- this.batteryPowered.push(
1279
- {
1280
- 'Device': deviceName,
1281
- 'Adapter': deviceAdapterName,
1282
- 'Battery': batteryHealth
1283
- }
1284
- );
832
+ default:
833
+ if ((deviceLowBatState === false) || (deviceLowBatState === 'NORMAL') || (deviceLowBatState === 1)) {
834
+ batteryHealth = 'ok';
835
+ } else {
836
+ batteryHealth = 'low';
1285
837
  }
1286
838
  break;
1287
- default:
1288
- batteryHealth = (deviceBatteryState) + '%';
1289
- this.batteryPowered.push(
1290
- {
1291
- 'Device': deviceName,
1292
- 'Adapter': deviceAdapterName,
1293
- 'Battery': batteryHealth
1294
- }
1295
- );
1296
839
  }
840
+ } else {
841
+ batteryHealth = ' - ';
1297
842
  }
1298
-
1299
- // Count how many devices are with battery
1300
- this.batteryPoweredCount = this.batteryPowered.length;
1301
-
1302
- // Count how many devices are with low battery
1303
- const batteryWarningMin = this.config.minWarnBatterie;
1304
-
1305
- // fill list with low battery devices
843
+ } else {
1306
844
  switch (this.arrDev[i].adapter) {
1307
- case 'homematic': // there are differnt low bat states between hm and hmIp devices
1308
- if (deviceLowBatState || deviceLowBatStateHM) {
1309
- this.batteryLowPowered.push(
1310
- {
1311
- 'Device': deviceName,
1312
- 'Adapter': deviceAdapterName,
1313
- 'Battery': batteryHealth
1314
- }
1315
- );
845
+ case 'hmrpc':
846
+ if (deviceBatteryState === 0) {
847
+ batteryHealth = ' - ';
848
+ } else {
849
+ batteryHealth = deviceBatteryState + 'V';
1316
850
  }
1317
851
  break;
1318
852
 
1319
- case 'tado': // there is an string as indicator
1320
- if (deviceLowBatState != 'NORMAL') {
1321
- this.batteryLowPowered.push(
1322
- {
1323
- 'Device': deviceName,
1324
- 'Adapter': deviceAdapterName,
1325
- 'Battery': batteryHealth
1326
- }
1327
- );
853
+ case 'hue-extended':
854
+ if (shortDeviceBatteryState) {
855
+ batteryHealth = shortDeviceBatteryState + '%';
1328
856
  }
1329
857
  break;
1330
-
1331
- default: // for all other devices with low bat states
1332
- if (deviceLowBatState) {
1333
- this.batteryLowPowered.push(
1334
- {
1335
- 'Device': deviceName,
1336
- 'Adapter': deviceAdapterName,
1337
- 'Battery': batteryHealth
1338
- }
1339
- );
1340
- } else if (deviceBatteryState && (deviceBatteryState < batteryWarningMin)) { // if the battery state is under the set limit
1341
- this.batteryLowPowered.push(
1342
- {
1343
- 'Device': deviceName,
1344
- 'Adapter': deviceAdapterName,
1345
- 'Battery': batteryHealth
1346
- }
1347
- );
858
+ case 'mihomeVacuum':
859
+ if (shortDeviceBatteryState) {
860
+ batteryHealth = shortDeviceBatteryState + '%';
861
+ } else if (shortDeviceBatteryState2) {
862
+ batteryHealth = shortDeviceBatteryState2 + '%';
1348
863
  }
864
+ break;
865
+ default:
866
+ batteryHealth = (deviceBatteryState) + '%';
1349
867
  }
868
+ }
1350
869
 
1351
- // 3d. Count how many devices are with low battery
1352
- this.lowBatteryPoweredCount = this.batteryLowPowered.length;
1353
-
1354
- if (this.config.listOnlyBattery) { // 4. Add only devices with battery in the list
1355
- if (deviceBatteryState || shortDeviceBatteryState) {
1356
- this.listAllDevices.push(
1357
- {
1358
- 'Device': deviceName,
1359
- 'Adapter': deviceAdapterName,
1360
- 'Battery': batteryHealth,
1361
- 'Signal strength': linkQuality,
1362
- 'Last contact': lastContactString,
1363
- 'Status': deviceState
1364
- }
1365
- );
870
+ // fill list with low battery devices
871
+ switch (this.arrDev[i].adapter) {
872
+ case 'hmrpc': // there are differnt low bat states between hm and hmIp devices
873
+ if (deviceLowBatState) {
874
+ lowBatIndicator = true;
875
+ }
876
+ break;
877
+ case 'tado': // there is an string as indicator
878
+ if (deviceLowBatState != 'NORMAL') {
879
+ lowBatIndicator = true;
880
+ }
881
+ break;
882
+
883
+ default: // for all other devices with low bat states
884
+ if ((deviceLowBatState === true) || (deviceLowBatState === 0)) {
885
+ lowBatIndicator = true;
886
+ } else if (deviceBatteryState && (deviceBatteryState < this.config.minWarnBatterie)) { // if the battery state is under the set limit
887
+ lowBatIndicator = true;
1366
888
  }
1367
- } else if (!this.config.listOnlyBattery) { // 4. Add all devices
1368
- this.listAllDevices.push(
889
+ }
890
+ if (this.listOnlyBattery) { // Add only devices with battery in the list
891
+ if (deviceBatteryState || shortDeviceBatteryState) {
892
+ this.listAllDevicesRaw.push(
1369
893
  {
894
+ 'Path': id,
1370
895
  'Device': deviceName,
1371
896
  'Adapter': deviceAdapterName,
1372
897
  'Battery': batteryHealth,
898
+ 'LowBat': lowBatIndicator,
1373
899
  'Signal strength': linkQuality,
1374
900
  'Last contact': lastContactString,
1375
901
  'Status': deviceState
1376
902
  }
1377
903
  );
1378
904
  }
1379
-
1380
-
1381
- // 4a. Count how many devices are exists
1382
- this.deviceCounter = this.listAllDevices.length;
905
+ } else { // Add all devices
906
+ this.listAllDevicesRaw.push(
907
+ {
908
+ 'Path': id,
909
+ 'Device': deviceName,
910
+ 'Adapter': deviceAdapterName,
911
+ 'Battery': batteryHealth,
912
+ 'LowBat': lowBatIndicator,
913
+ 'Signal strength': linkQuality,
914
+ 'Last contact': lastContactString,
915
+ 'Status': deviceState
916
+ }
917
+ );
1383
918
  }
1384
919
  } else {
1385
920
  return; // cancel run if unloaded was called.
1386
921
  }
1387
922
  } // <-- end of loop
923
+ await this.createLists();
924
+ await this.countDevices();
1388
925
  } // <-- end of createData
1389
926
 
1390
927
 
@@ -1396,8 +933,6 @@ class DeviceWatcher extends utils.Adapter {
1396
933
  this.log.debug(`Function started: ${this.createDataForEachAdapter.name}`);
1397
934
 
1398
935
  try {
1399
- await this.resetVars(); // reset the arrays and counts
1400
-
1401
936
  for (let i = 0; i < this.arrDev.length; i++) {
1402
937
 
1403
938
  if (this.arrDev[i].adapter.includes(adptName)) { // list device only if selected adapter matched with device
@@ -1405,6 +940,8 @@ class DeviceWatcher extends utils.Adapter {
1405
940
  }
1406
941
  }
1407
942
  await this.writeDatapoints(adptName); // fill the datapoints
943
+ await this.resetVars(); // reset the arrays and counts
944
+
1408
945
  } catch (error) {
1409
946
  this.errorReporting('[createDataForEachAdapter]', error);
1410
947
  }
@@ -1427,10 +964,11 @@ class DeviceWatcher extends utils.Adapter {
1427
964
  }
1428
965
  }
1429
966
 
1430
- if (this.config.checkSendOfflineMsg) await this.sendOfflineNotifications(); // send message if new devices are offline
1431
- if (this.config.checkSendOfflineMsgDaily) await this.sendDailyOfflineNotifications(); // send daily overview of offline devices
1432
- if (this.config.checkSendBatteryMsg) await this.sendBatteryNotifications(); // send message for low battery devices
967
+ // send message if new devices are offline
968
+ if (this.config.checkSendOfflineMsg) await this.sendOfflineNotifications();
969
+
1433
970
  await this.writeDatapoints(); // fill the datapoints
971
+
1434
972
  } catch (error) {
1435
973
  this.errorReporting('[createDataOfAllAdapter]', error);
1436
974
  }
@@ -1442,7 +980,7 @@ class DeviceWatcher extends utils.Adapter {
1442
980
  /**
1443
981
  * Notification service
1444
982
  * @param {string} text - Text which should be send
1445
- **/
983
+ */
1446
984
  async sendNotification(text) {
1447
985
 
1448
986
  // Pushover
@@ -1560,6 +1098,55 @@ class DeviceWatcher extends utils.Adapter {
1560
1098
  }
1561
1099
  } // <-- End of sendNotification function
1562
1100
 
1101
+ async sendBatteryNotifyShedule() {
1102
+ // send message for low battery devices
1103
+
1104
+ const time = (this.config.checkSendBatteryTime).split(':');
1105
+
1106
+ const checkDays = []; // list of selected days
1107
+
1108
+ // push the selected days in list
1109
+ if (this.config.checkMonday) checkDays.push(1);
1110
+ if (this.config.checkTuesday) checkDays.push(2);
1111
+ if (this.config.checkWednesday) checkDays.push(3);
1112
+ if (this.config.checkThursday) checkDays.push(4);
1113
+ if (this.config.checkFriday) checkDays.push(5);
1114
+ if (this.config.checkSaturday) checkDays.push(6);
1115
+ if (this.config.checkSunday) checkDays.push(0);
1116
+
1117
+ if (checkDays.length >= 1) { // check if an day is selected
1118
+ this.log.debug(`Number of selected days for daily battery message: ${checkDays.length}. Send Message on: ${(checkDays).join(', ')} ...`);
1119
+ } else {
1120
+ this.log.warn(`No days selected for daily battery message. Please check the instance configuration!`);
1121
+ return; // cancel function if no day is selected
1122
+ }
1123
+
1124
+ if (!isUnloaded) {
1125
+ const cron = '10 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
1126
+ schedule.scheduleJob(cron, () => {
1127
+ try {
1128
+ let deviceList = '';
1129
+
1130
+ for (const id of this.batteryLowPowered) {
1131
+ if (!this.blacklistNotify.includes(id['Device'])) {
1132
+ deviceList = `${deviceList}\n${id['Device']} (${id['Battery']})`;
1133
+ }
1134
+ }
1135
+
1136
+ if ((this.lowBatteryPoweredCount > 0) && (deviceList.length > 0)) {
1137
+ this.log.info(`Niedrige Batteriezustände: ${deviceList}`);
1138
+ this.setStateAsync('lastNotification', `Niedrige Batteriezustände: ${deviceList}`, true);
1139
+
1140
+ this.sendNotification(`Niedriege Batteriezustände: ${deviceList}`);
1141
+
1142
+ }
1143
+
1144
+ } catch (error) {
1145
+ this.errorReporting('[sendBatteryNotifyShedule]', error);
1146
+ }
1147
+ });
1148
+ }
1149
+ } //<--End of battery notification
1563
1150
 
1564
1151
  async sendOfflineNotifications() {
1565
1152
  // send message if an device is offline
@@ -1568,24 +1155,30 @@ class DeviceWatcher extends utils.Adapter {
1568
1155
 
1569
1156
  try {
1570
1157
  let msg = '';
1158
+ let deviceList = '';
1571
1159
  const offlineDevicesCountOld = await this.getOwnInitValue('offlineCount');
1572
1160
 
1573
1161
  if ((this.offlineDevicesCount !== offlineDevicesCountOld)) {
1574
- if (this.offlineDevicesCount == 0) {
1575
- msg = 'Alle Geräte sind Online.';
1576
- } else if (this.offlineDevicesCount == 1) { // make singular if it is only one device
1577
- msg = 'Folgendes Gerät ist seit einiger Zeit nicht erreichbar: \n';
1578
- } else if (this.offlineDevicesCount >= 2) { //make plural if it is more than one device
1579
- msg = `Folgende ${this.offlineDevicesCount} Geräte sind seit einiger Zeit nicht erreichbar: \n`;
1580
- }
1581
1162
 
1582
1163
  for (const id of this.offlineDevices) {
1583
- msg = `${msg}\n${id['Device']} (${id['Last contact']})`;
1164
+ if (!this.blacklistNotify.includes(id['Device'])) {
1165
+ deviceList = `${deviceList}\n${id['Device']} (${id['Last contact']})`;
1166
+ }
1167
+ }
1168
+ if (deviceList.length > 0) {
1169
+ if (deviceList.length == 0) {
1170
+ msg = 'Alle Geräte sind Online.';
1171
+ } else if (deviceList.length == 1) { // make singular if it is only one device
1172
+ msg = 'Folgendes Gerät ist seit einiger Zeit nicht erreichbar: \n';
1173
+ } else if (deviceList.length >= 2) { //make plural if it is more than one device
1174
+ msg = `Folgende Geräte sind seit einiger Zeit nicht erreichbar: \n`;
1175
+ }
1176
+
1177
+ this.log.info(msg + deviceList);
1178
+ await this.setStateAsync('lastNotification', msg + deviceList, true);
1179
+ await this.sendNotification(msg + deviceList);
1584
1180
  }
1585
1181
 
1586
- this.log.info(msg);
1587
- await this.setStateAsync('lastNotification', msg, true);
1588
- await this.sendNotification(msg);
1589
1182
  }
1590
1183
  } catch (error) {
1591
1184
  this.errorReporting('[sendOfflineMessage]', error);
@@ -1593,107 +1186,54 @@ class DeviceWatcher extends utils.Adapter {
1593
1186
  this.log.debug(`Finished the function: ${this.sendOfflineNotifications.name}`);
1594
1187
  }//<--End of offline notification
1595
1188
 
1596
- async sendDailyOfflineNotifications() {
1189
+ async sendOfflineNotificationsShedule() {
1597
1190
  // send daily an overview with offline devices
1598
1191
 
1599
- this.log.debug(`Start the function: ${this.sendDailyOfflineNotifications.name}`);
1192
+ const time = (this.config.checkSendOfflineTime).split(':');
1600
1193
 
1601
- try {
1602
- // Check if the daily message for offline devices was already sent today
1603
- const lastOfflineNotifyIndicator = await this.getOwnInitValue('info.lastOfflineNotification');
1604
- const now = new Date(); // get date
1605
-
1606
- // set indicator for send message first to 'false', after sending to 'true'
1607
- if (now.getHours() < 11) await this.setStateAsync('info.lastOfflineNotification', false, true);
1608
-
1609
- // if time is > 11 (12:00 pm create message for offline devices devices)
1610
- if ((now.getHours() > 11) && (!lastOfflineNotifyIndicator)) {
1611
- let msg = '';
1612
-
1613
- for (const id of this.offlineDevices) {
1614
- msg = `${msg}\n${id['Device']} (${id['Last contact']})`;
1615
- }
1194
+ const checkDays = []; // list of selected days
1616
1195
 
1617
- if (this.offlineDevicesCount > 0) {
1618
- this.log.info(`Geräte Offline: ${msg}`);
1619
- await this.setStateAsync('lastNotification', `Geräte Offline: ${msg}`, true);
1196
+ // push the selected days in list
1197
+ if (this.config.checkOfflineMonday) checkDays.push(1);
1198
+ if (this.config.checkOfflineTuesday) checkDays.push(2);
1199
+ if (this.config.checkOfflineWednesday) checkDays.push(3);
1200
+ if (this.config.checkOfflineThursday) checkDays.push(4);
1201
+ if (this.config.checkOfflineFriday) checkDays.push(5);
1202
+ if (this.config.checkOfflineSaturday) checkDays.push(6);
1203
+ if (this.config.checkOfflineSunday) checkDays.push(0);
1620
1204
 
1621
- await this.sendNotification(`Geräte Offline: ${msg}`);
1622
-
1623
- await this.setStateAsync('info.lastOfflineNotification', true, true);
1624
- }
1625
- }
1626
- } catch (error) {
1627
- this.errorReporting('[sendDailyOfflineNotifications]', error);
1205
+ if (checkDays.length >= 1) { // check if an day is selected
1206
+ this.log.debug(`Number of selected days for daily offline message: ${checkDays.length}. Send Message on: ${(checkDays).join(', ')} ...`);
1207
+ } else {
1208
+ this.log.warn(`No days selected for daily offline message. Please check the instance configuration!`);
1209
+ return; // cancel function if no day is selected
1628
1210
  }
1629
- this.log.debug(`Finished the function: ${this.sendDailyOfflineNotifications.name}`);
1630
- }//<--End of daily offline notification
1631
1211
 
1632
- async sendBatteryNotifications() {
1633
- // send message for low battery devices
1212
+ if (!isUnloaded) {
1213
+ const cron = '10 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
1214
+ schedule.scheduleJob(cron, () => {
1215
+ try {
1216
+ let deviceList = '';
1217
+
1218
+ for (const id of this.offlineDevices) {
1219
+ if (!this.blacklistNotify.includes(id['Device'])) {
1220
+ deviceList = `${deviceList}\n${id['Device']} (${id['Last contact']})`;
1221
+ }
1222
+ }
1634
1223
 
1635
- this.log.debug(`Start the function: ${this.sendBatteryNotifications.name}`);
1224
+ if (deviceList.length > 0) {
1225
+ this.log.info(`Geräte Offline: ${deviceList}`);
1226
+ this.setStateAsync('lastNotification', `Geräte Offline: ${deviceList}`, true);
1636
1227
 
1637
- try {
1228
+ this.sendNotification(`Geräte Offline: ${deviceList}`);
1229
+ }
1638
1230
 
1639
- const now = new Date(); // get date
1640
- const today = now.getDay();
1641
- const checkDays = []; // list of selected days
1642
- let checkToday; // indicator if selected day is today
1643
-
1644
- // push the selected days in list
1645
- if (this.config.checkMonday) checkDays.push(1);
1646
- if (this.config.checkTuesday) checkDays.push(2);
1647
- if (this.config.checkWednesday) checkDays.push(3);
1648
- if (this.config.checkThursday) checkDays.push(4);
1649
- if (this.config.checkFriday) checkDays.push(5);
1650
- if (this.config.checkSaturday) checkDays.push(6);
1651
- if (this.config.checkSunday) checkDays.push(0);
1652
-
1653
- //Check if the message should be send today
1654
- checkDays.forEach(object => {
1655
- if ((object >= 0) && today == object) {
1656
- checkToday = true;
1231
+ } catch (error) {
1232
+ this.errorReporting('[sendOfflineNotificationsShedule]', error);
1657
1233
  }
1658
1234
  });
1659
-
1660
- if (checkDays.length >= 1) { // check if an day is selected
1661
- this.log.debug(`Number of selected days: ${checkDays.length}. Send Message on: ${(checkDays).join(', ')} ...`);
1662
- } else {
1663
- this.log.warn(`No days selected. Please check the instance configuration!`);
1664
- return; // cancel function if no day is selected
1665
- }
1666
-
1667
- // Check if the message for low battery was already sent today
1668
- const lastBatteryNotifyIndicator = await this.getOwnInitValue('info.lastBatteryNotification');
1669
-
1670
- // set indicator for send message first to 'false', after sending to 'true'
1671
- if (now.getHours() < 11) await this.setStateAsync('info.lastBatteryNotification', false, true);
1672
-
1673
- // if time is > 11 (12:00 pm create message for low battery devices)
1674
- if ((now.getHours() > 11) && (!lastBatteryNotifyIndicator) && (checkToday != undefined)) {
1675
- let msg = '';
1676
-
1677
- for (const id of this.batteryLowPowered) {
1678
- msg = `${msg}\n${id['Device']} (${id['Battery']})`;
1679
- }
1680
-
1681
- if (this.lowBatteryPoweredCount > 0) {
1682
- this.log.info(`Niedrige Batteriezustände: ${msg}`);
1683
- await this.setStateAsync('lastNotification', `Niedrige Batteriezustände: ${msg}`, true);
1684
-
1685
- await this.sendNotification(`Niedriege Batteriezustände: ${msg}`);
1686
-
1687
- await this.setStateAsync('info.lastBatteryNotification', true, true);
1688
- }
1689
- }
1690
- } catch (error) {
1691
- this.errorReporting('[sendOfflineMessage]', error);
1692
1235
  }
1693
-
1694
- this.log.debug(`Finished the function: ${this.sendBatteryNotifications.name}`);
1695
- }//<--End of battery notification
1696
-
1236
+ }//<--End of daily offline notification
1697
1237
 
1698
1238
  async resetVars() {
1699
1239
  //Reset all arrays and counts
@@ -1705,7 +1245,7 @@ class DeviceWatcher extends utils.Adapter {
1705
1245
  this.batteryPowered = [];
1706
1246
  this.batteryLowPowered = [];
1707
1247
  this.listAllDevices = [];
1708
-
1248
+ this.listAllDevicesRaw = [];
1709
1249
  // counts
1710
1250
  this.offlineDevicesCount = 0;
1711
1251
  this.deviceCounter = 0;
@@ -1713,8 +1253,6 @@ class DeviceWatcher extends utils.Adapter {
1713
1253
  this.batteryPoweredCount = 0;
1714
1254
  this.lowBatteryPoweredCount = 0;
1715
1255
 
1716
- this.deviceReachable = '';
1717
-
1718
1256
  this.log.debug(`Function finished: ${this.resetVars.name}`);
1719
1257
  } // <-- end of resetVars
1720
1258
 
@@ -1900,7 +1438,7 @@ class DeviceWatcher extends utils.Adapter {
1900
1438
  // create datapoints for each adapter
1901
1439
  /**
1902
1440
  * @param {object} adptName - Adaptername of devices
1903
- **/
1441
+ */
1904
1442
  async createDPsForEachAdapter(adptName) {
1905
1443
 
1906
1444
  await this.setObjectNotExistsAsync(`${adptName}`, {