iobroker.device-watcher 2.4.1 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/main.js CHANGED
@@ -8,6 +8,7 @@ const utils = require('@iobroker/adapter-core');
8
8
  const adapterName = require('./package.json').name.split('.').pop();
9
9
  const schedule = require('node-schedule');
10
10
  const arrApart = require('./lib/arrApart.js'); // list of supported adapters
11
+ const cronParser = require('cron-parser');
11
12
 
12
13
  // Sentry error reporting, disable when testing code!
13
14
  const enableSendSentry = true;
@@ -23,25 +24,41 @@ class DeviceWatcher extends utils.Adapter {
23
24
  useFormatDate: true,
24
25
  });
25
26
 
27
+ // instances and adapters
28
+ // raw arrays
29
+ this.listInstanceRaw = new Map();
30
+ this.adapterUpdatesJsonRaw = [];
31
+ this.listErrorInstanceRaw = [];
32
+
33
+ // user arrays
34
+ this.listAllInstances = [];
35
+ this.listDeactivatedInstances = [];
36
+ this.listAdapterUpdates = [];
37
+ this.listErrorInstance = [];
38
+
39
+ //counts
40
+ this.countAllInstances = 0;
41
+ this.countDeactivatedInstances = 0;
42
+ this.countAdapterUpdates = 0;
43
+ this.countErrorInstance = 0;
44
+
45
+ // devices
46
+ // raw arrays
47
+ this.listAllDevicesRaw = new Map();
48
+ this.batteryLowPoweredRaw = [];
49
+ this.offlineDevicesRaw = [];
50
+ this.upgradableDevicesRaw = [];
51
+
26
52
  // arrays
27
53
  this.offlineDevices = [];
28
54
  this.linkQualityDevices = [];
29
55
  this.batteryPowered = [];
30
56
  this.batteryLowPowered = [];
31
57
  this.listAllDevices = [];
32
- this.blacklistLists = [];
33
- this.blacklistAdapterLists = [];
34
- this.blacklistNotify = [];
35
58
  this.selAdapter = [];
36
59
  this.adapterSelected = [];
37
60
  this.upgradableList = [];
38
61
 
39
- // raw arrays
40
- this.listAllDevicesRaw = [];
41
- this.batteryLowPoweredRaw = [];
42
- this.offlineDevicesRaw = [];
43
- this.upgradableDevicesRaw = [];
44
-
45
62
  // counts
46
63
  this.offlineDevicesCount = 0;
47
64
  this.deviceCounter = 0;
@@ -50,12 +67,22 @@ class DeviceWatcher extends utils.Adapter {
50
67
  this.lowBatteryPoweredCount = 0;
51
68
  this.upgradableDevicesCount = 0;
52
69
 
70
+ // Blacklist
71
+ // Instances
72
+ this.blacklistInstancesLists = [];
73
+ this.blacklistInstancesNotify = [];
74
+
75
+ // Devices
76
+ this.blacklistLists = [];
77
+ this.blacklistAdapterLists = [];
78
+ this.blacklistNotify = [];
79
+
53
80
  // Interval timer
54
81
  this.refreshDataTimeout = null;
55
82
 
56
83
  this.on('ready', this.onReady.bind(this));
57
84
  this.on('stateChange', this.onStateChange.bind(this));
58
- // this.on('objectChange', this.onObjectChange.bind(this));
85
+ this.on('objectChange', this.onObjectChange.bind(this));
59
86
  this.on('message', this.onMessage.bind(this));
60
87
  this.on('unload', this.onUnload.bind(this));
61
88
  }
@@ -104,6 +131,7 @@ class DeviceWatcher extends utils.Adapter {
104
131
  nukiExt: this.config.nukiExtDevices,
105
132
  nut: this.config.nutDevices,
106
133
  ping: this.config.pingDevices,
134
+ proxmox: this.config.proxmoxDevices,
107
135
  roomba: this.config.roombaDevices,
108
136
  shelly: this.config.shellyDevices,
109
137
  smartgarden: this.config.smartgardenDevices,
@@ -155,6 +183,7 @@ class DeviceWatcher extends utils.Adapter {
155
183
  nukiExt: this.config.nukiextendMaxMinutes,
156
184
  nut: this.config.nutMaxMinutes,
157
185
  ping: this.config.pingMaxMinutes,
186
+ proxmox: this.config.proxmoxMaxMinutes,
158
187
  roomba: this.config.roombaMaxMinutes,
159
188
  shelly: this.config.shellyMaxMinutes,
160
189
  smartgarden: this.config.smartgardenMaxMinutes,
@@ -192,19 +221,23 @@ class DeviceWatcher extends utils.Adapter {
192
221
  }
193
222
 
194
223
  //create Blacklist
195
- try {
196
- await this.createBlacklist();
197
- } catch (error) {
198
- this.errorReporting('[onReady - create blacklist]', error);
199
- }
224
+ await this.createBlacklist();
200
225
 
201
- //create and fill datapoints for each adapter if selected
202
- if (this.createOwnFolder) {
226
+ //create datapoints for each adapter if selected
227
+ for (const [id] of Object.entries(arrApart)) {
203
228
  try {
204
- for (const [id] of Object.entries(arrApart)) {
205
- if (this.configSetAdapter !== undefined && this.configSetAdapter[id]) {
229
+ if (!this.createOwnFolder) {
230
+ await this.deleteDPsForEachAdapter(id);
231
+ await this.deleteHtmlListDatapoints(id);
232
+ } else {
233
+ if (this.configSetAdapter && this.configSetAdapter[id]) {
206
234
  await this.createDPsForEachAdapter(id);
207
- if (this.createHtmlList) await this.createHtmlListDatapoints(id);
235
+ // create HTML list datapoints
236
+ if (!this.createHtmlList) {
237
+ await this.deleteHtmlListDatapoints(id);
238
+ } else {
239
+ await this.createHtmlListDatapoints(id);
240
+ }
208
241
  this.log.debug(`Created datapoints for ${this.capitalize(id)}`);
209
242
  }
210
243
  }
@@ -214,28 +247,84 @@ class DeviceWatcher extends utils.Adapter {
214
247
  }
215
248
 
216
249
  // create HTML list datapoints
217
- if (this.createHtmlList) await this.createHtmlListDatapoints();
250
+ if (!this.createHtmlList) {
251
+ await this.deleteHtmlListDatapoints();
252
+ } else {
253
+ await this.createHtmlListDatapoints();
254
+ }
218
255
 
219
- //read data first at start
256
+ // read data first at start
257
+ // devices
220
258
  await this.main();
221
259
 
260
+ // instances and adapters
261
+ if (!this.config.checkAdapterInstances) {
262
+ await this.deleteDPsForInstances();
263
+ } else {
264
+ // instances
265
+ await this.createDPsForInstances();
266
+ await this.getAllInstanceData();
267
+ // adapter updates
268
+ await this.createAdapterUpdateData();
269
+ }
270
+
222
271
  // update last contact data in interval
223
272
  await this.refreshData();
224
273
 
225
274
  // send overview for low battery devices
226
- if (this.config.checkSendBatteryMsgDaily) await this.sendBatteryNotifyShedule();
275
+ if (this.config.checkSendBatteryMsgDaily) this.sendScheduleNotifications('lowBatteryDevices');
227
276
 
228
277
  // send overview of offline devices
229
- if (this.config.checkSendOfflineMsgDaily) await this.sendOfflineNotificationsShedule();
278
+ if (this.config.checkSendOfflineMsgDaily) this.sendScheduleNotifications('offlineDevices');
230
279
 
231
280
  // send overview of upgradeable devices
232
- if (this.config.checkSendUpgradeMsgDaily) await this.sendUpgradeNotificationsShedule();
281
+ if (this.config.checkSendUpgradeMsgDaily) this.sendScheduleNotifications('updateDevices');
282
+
283
+ // send overview of updatable adapters
284
+ if (this.config.checkSendAdapterUpdateMsgDaily) this.sendScheduleNotifications('updateAdapter');
285
+
286
+ // send overview of instances with error
287
+ if (this.config.checkSendInstanceFailedDaily) this.sendScheduleNotifications('errorInstance');
233
288
  } catch (error) {
234
289
  this.errorReporting('[onReady]', error);
235
290
  this.terminate ? this.terminate(15) : process.exit(15);
236
291
  }
237
292
  } // <-- onReady end
238
293
 
294
+ // If you need to react to object changes, uncomment the following block and the corresponding line in the constructor.
295
+ // You also need to subscribe to the objects with `this.subscribeObjects`, similar to `this.subscribeStates`.
296
+ //
297
+ /**
298
+ * Is called if a subscribed object changes
299
+ * @param {string} id
300
+ * @param {ioBroker.Object | null | undefined} obj
301
+ */
302
+ async onObjectChange(id, obj) {
303
+ if (obj) {
304
+ // The object was changed
305
+ //this.log.warn(`object ${id} changed: ${JSON.stringify(obj)}`);
306
+
307
+ //read new instance data and add it to the lists
308
+ await this.getInstanceData(id);
309
+
310
+ //read devices data and renew the lists
311
+ await this.main();
312
+ } else {
313
+ // The object was deleted
314
+ //this.log.warn(`object ${id} deleted`);
315
+
316
+ // delete instance data in map
317
+ this.listInstanceRaw.delete(id);
318
+
319
+ // delete device data in map
320
+ this.listAllDevicesRaw.delete(id);
321
+
322
+ //unsubscribe of Objects and states
323
+ this.unsubscribeForeignObjects(id);
324
+ this.unsubscribeForeignStates(id);
325
+ }
326
+ }
327
+
239
328
  /**
240
329
  * Is called if a subscribed state changes
241
330
  * @param {string} id
@@ -244,124 +333,196 @@ class DeviceWatcher extends utils.Adapter {
244
333
  async onStateChange(id, state) {
245
334
  // Admin JSON for Adapter updates
246
335
  if (id && state) {
247
- this.log.debug(`State changed: ${id} changed ${state.val}`);
336
+ // this.log.debug(`State changed: ${id} changed ${state.val}`);
248
337
  let batteryData;
249
338
  let oldLowBatState;
250
339
  let contactData;
251
340
  let oldStatus;
252
341
  let isLowBatValue;
253
- let instanceDeviceConnectionDpTS;
254
- const instanceDeviceConnectionDpTSminTime = 5;
342
+ let instanceStatusRaw;
343
+ let oldInstanceHostState;
344
+ let oldInstanceDeviceState;
345
+
346
+ for (const adapter of this.adapterUpdatesJsonRaw) {
347
+ switch (id) {
348
+ case adapter.Path:
349
+ await this.getAdapterUpdateData(id);
350
+ await this.createAdapterUpdateList();
351
+ if (this.config.checkSendAdapterUpdateMsg) {
352
+ await this.sendStateNotifications('updateAdapter', null);
353
+ }
354
+ }
355
+ }
255
356
 
256
- // Wait if the conection to device was lost to avoid multiple messages.
257
- // const delay = (n) => new Promise((r) => setTimeout(r, n * 100));
357
+ for (const [instance, instanceData] of this.listInstanceRaw) {
358
+ switch (id) {
359
+ case instanceData.instanceAlivePath:
360
+ if (state.val !== instanceData.isAlive) {
361
+ instanceStatusRaw = await this.setInstanceStatus(
362
+ instanceData.instanceMode,
363
+ instanceData.schedule,
364
+ instanceData.instanceAlivePath,
365
+ instanceData.connectedHostPath,
366
+ instanceData.connectedDevicePath,
367
+ );
368
+ instanceData.isAlive = instanceStatusRaw[1];
369
+ instanceData.status = instanceStatusRaw[0];
370
+ instanceData.isHealthy = instanceStatusRaw[2];
371
+ }
372
+ break;
373
+ case instanceData.connectedHostPath:
374
+ oldInstanceHostState = instanceData.isConnectedHost;
375
+ instanceData.isConnectedHost = state.val;
376
+ if (oldInstanceHostState !== instanceData.isConnectedHost) {
377
+ instanceStatusRaw = await this.setInstanceStatus(
378
+ instanceData.instanceMode,
379
+ instanceData.schedule,
380
+ instanceData.instanceAlivePath,
381
+ instanceData.connectedHostPath,
382
+ instanceData.connectedDevicePath,
383
+ );
384
+ instanceData.isAlive = instanceStatusRaw[1];
385
+ instanceData.status = instanceStatusRaw[0];
386
+ instanceData.isHealthy = instanceStatusRaw[2];
387
+
388
+ if (!instanceData.isAlive) continue;
389
+ if (this.config.checkSendInstanceFailedMsg && !this.blacklistInstancesNotify.includes(instanceData.instanceAlivePath)) {
390
+ if (!instanceData.isHealthy) {
391
+ await this.sendStateNotifications('errorInstance', instance);
392
+ }
393
+ }
394
+ }
395
+ break;
396
+ case instanceData.connectedDevicePath:
397
+ oldInstanceDeviceState = instanceData.isConnectedDevice;
398
+ instanceData.isConnectedDevice = state.val;
399
+ if (oldInstanceDeviceState !== instanceData.isConnectedDevice) {
400
+ instanceStatusRaw = await this.setInstanceStatus(
401
+ instanceData.instanceMode,
402
+ instanceData.schedule,
403
+ instanceData.instanceAlivePath,
404
+ instanceData.connectedHostPath,
405
+ instanceData.connectedDevicePath,
406
+ );
407
+ instanceData.isAlive = instanceStatusRaw[1];
408
+ instanceData.status = instanceStatusRaw[0];
409
+ instanceData.isHealthy = instanceStatusRaw[2];
410
+
411
+ if (!instanceData.isAlive) continue;
412
+ if (this.config.checkSendInstanceFailedMsg && !this.blacklistInstancesNotify.includes(instanceData.instanceAlivePath)) {
413
+ if (!instanceData.isHealthy) {
414
+ await this.sendStateNotifications('errorInstance', instance);
415
+ }
416
+ }
417
+ }
418
+ break;
419
+ }
420
+ }
258
421
 
259
- for (const device of this.listAllDevicesRaw) {
422
+ for (const [device, deviceData] of this.listAllDevicesRaw) {
260
423
  // On statechange update available datapoint
261
424
  switch (id) {
262
- case device.instanceDeviceConnectionDP:
263
- if (state.val !== device.instancedeviceConnected) {
264
- device.instancedeviceConnected = state.val;
425
+ case deviceData.instanceDeviceConnectionDP:
426
+ if (state.val !== deviceData.instancedeviceConnected) {
427
+ deviceData.instancedeviceConnected = state.val;
265
428
  }
266
429
  break;
267
430
 
268
- case device.UpdateDP:
269
- if (state.val !== device.Upgradable) {
270
- device.Upgradable = state.val;
431
+ case deviceData.UpdateDP:
432
+ if (state.val !== deviceData.Upgradable) {
433
+ deviceData.Upgradable = state.val;
271
434
  if (state.val) {
272
- if (!this.blacklistNotify.includes(device.Path)) {
273
- await this.sendDeviceUpdatesNotification(device.Device, device.Adapter);
435
+ if (this.config.checkSendDeviceUpgrade && !this.blacklistNotify.includes(deviceData.Path)) {
436
+ await this.sendStateNotifications('updateDevice', device);
274
437
  }
275
438
  }
276
439
  }
277
440
  break;
278
441
 
279
- case device.SignalStrengthDP:
280
- device.SignalStrength = await this.calculateSignalStrength(state, device.adapterID);
442
+ case deviceData.SignalStrengthDP:
443
+ deviceData.SignalStrength = await this.calculateSignalStrength(state, deviceData.adapterID);
281
444
  break;
282
445
 
283
- case device.batteryDP:
284
- if (device.isBatteryDevice) {
285
- oldLowBatState = device.LowBat;
286
- batteryData = await this.getBatteryData(state.val, oldLowBatState, device.adapterID);
446
+ case deviceData.batteryDP:
447
+ if (deviceData.isBatteryDevice) {
448
+ oldLowBatState = deviceData.LowBat;
449
+ batteryData = await this.getBatteryData(state.val, oldLowBatState, deviceData.adapterID);
287
450
 
288
- device.Battery = batteryData[0];
289
- device.BatteryRaw = batteryData[2];
290
- if (device.LowBatDP !== 'none') {
291
- isLowBatValue = await this.getInitValue(device.LowBatDP);
451
+ deviceData.Battery = batteryData[0];
452
+ deviceData.BatteryRaw = batteryData[2];
453
+ if (deviceData.LowBatDP !== 'none') {
454
+ isLowBatValue = await this.getInitValue(deviceData.LowBatDP);
292
455
  } else {
293
456
  isLowBatValue = undefined;
294
457
  }
295
- device.LowBat = await this.setLowbatIndicator(state.val, isLowBatValue, device.faultReport, device.adapterID);
458
+ deviceData.LowBat = await this.setLowbatIndicator(state.val, isLowBatValue, deviceData.faultReport, deviceData.adapterID);
296
459
 
297
- if (device.LowBat && oldLowBatState !== device.LowBat) {
298
- if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(device.Path)) {
299
- await this.sendLowBatNoticiation(device.Device, device.Adapter, device.Battery);
460
+ if (deviceData.LowBat && oldLowBatState !== deviceData.LowBat) {
461
+ if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(deviceData.Path)) {
462
+ await this.sendStateNotifications('lowBatDevice', device);
300
463
  }
301
464
  }
302
465
  }
303
466
  break;
304
467
 
305
- case device.LowBatDP:
306
- if (device.isBatteryDevice) {
307
- oldLowBatState = device.LowBat;
308
- batteryData = await this.getBatteryData(device.BatteryRaw, state.val, device.adapterID);
309
- device.Battery = batteryData[0];
310
- device.BatteryRaw = batteryData[2];
311
- device.LowBat = await this.setLowbatIndicator(device.BatteryRaw, state.val, device.faultReport, device.adapterID);
312
-
313
- if (device.LowBat && oldLowBatState !== device.LowBat) {
314
- if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(device.Path)) {
315
- await this.sendLowBatNoticiation(device.Device, device.Adapter, device.Battery);
468
+ case deviceData.LowBatDP:
469
+ if (deviceData.isBatteryDevice) {
470
+ oldLowBatState = deviceData.LowBat;
471
+ batteryData = await this.getBatteryData(deviceData.BatteryRaw, state.val, deviceData.adapterID);
472
+ deviceData.Battery = batteryData[0];
473
+ deviceData.BatteryRaw = batteryData[2];
474
+ deviceData.LowBat = await this.setLowbatIndicator(deviceData.BatteryRaw, state.val, deviceData.faultReport, deviceData.adapterID);
475
+
476
+ if (deviceData.LowBat && oldLowBatState !== deviceData.LowBat) {
477
+ if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(deviceData.Path)) {
478
+ await this.sendStateNotifications('lowBatDevice', device);
316
479
  }
317
480
  }
318
481
  }
319
482
  break;
320
483
 
321
- case device.faultReportDP:
322
- if (device.isBatteryDevice) {
323
- oldLowBatState = device.LowBat;
324
- batteryData = await this.getBatteryData(device.BatteryRaw, oldLowBatState, device.adapterID);
484
+ case deviceData.faultReportDP:
485
+ if (deviceData.isBatteryDevice) {
486
+ oldLowBatState = deviceData.LowBat;
487
+ batteryData = await this.getBatteryData(deviceData.BatteryRaw, oldLowBatState, deviceData.adapterID);
325
488
 
326
- device.Battery = batteryData[0];
327
- device.BatteryRaw = batteryData[2];
328
- device.LowBat = await this.setLowbatIndicator(device.BatteryRaw, undefined, state.val, device.adapterID);
489
+ deviceData.Battery = batteryData[0];
490
+ deviceData.BatteryRaw = batteryData[2];
491
+ deviceData.LowBat = await this.setLowbatIndicator(deviceData.BatteryRaw, undefined, state.val, deviceData.adapterID);
329
492
 
330
- if (device.LowBat && oldLowBatState !== device.LowBat) {
331
- if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(device.Path)) {
332
- await this.sendLowBatNoticiation(device.Device, device.Adapter, device.Battery);
493
+ if (deviceData.LowBat && oldLowBatState !== deviceData.LowBat) {
494
+ if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(deviceData.Path)) {
495
+ await this.sendStateNotifications('lowBatDevice', device);
333
496
  }
334
497
  }
335
498
  }
336
499
  break;
337
500
 
338
- case device.UnreachDP:
339
- oldStatus = device.Status;
340
- device.UnreachState = await this.getInitValue(device.UnreachDP);
501
+ case deviceData.UnreachDP:
502
+ oldStatus = deviceData.Status;
503
+ deviceData.UnreachState = await this.getInitValue(deviceData.UnreachDP);
341
504
  contactData = await this.getOnlineState(
342
- device.timeSelector,
343
- device.adapterID,
344
- device.UnreachDP,
345
- device.SignalStrength,
346
- device.UnreachState,
347
- device.DeviceStateSelectorDP,
348
- device.rssiPeerSelectorDP,
505
+ deviceData.timeSelector,
506
+ deviceData.adapterID,
507
+ deviceData.UnreachDP,
508
+ deviceData.SignalStrength,
509
+ deviceData.UnreachState,
510
+ deviceData.DeviceStateSelectorDP,
511
+ deviceData.rssiPeerSelectorDP,
349
512
  );
350
513
  if (contactData !== undefined) {
351
- device.LastContact = contactData[0];
352
- device.Status = contactData[1];
353
- device.SignalStrength = contactData[2];
514
+ deviceData.LastContact = contactData[0];
515
+ deviceData.Status = contactData[1];
516
+ deviceData.SignalStrength = contactData[2];
354
517
  }
355
- if (device.instanceDeviceConnectionDP !== undefined) {
356
- instanceDeviceConnectionDpTS = await this.getTimestampConnectionDP(device.instanceDeviceConnectionDP);
357
- if (device.instancedeviceConnected !== false && instanceDeviceConnectionDpTS && instanceDeviceConnectionDpTS >= instanceDeviceConnectionDpTSminTime) {
358
- if (this.config.checkSendOfflineMsg && oldStatus !== device.Status && !this.blacklistNotify.includes(device.Path)) {
359
- await this.sendOfflineNotifications(device.Device, device.Adapter, device.Status, device.LastContact);
518
+ if (this.config.checkSendOfflineMsg && oldStatus !== deviceData.Status && !this.blacklistNotify.includes(deviceData.Path)) {
519
+ if (deviceData.instanceDeviceConnectionDP !== undefined) {
520
+ // check if the generally deviceData connected state is for a while true
521
+ if (await this.getTimestampConnectionDP(deviceData.instanceDeviceConnectionDP, 20000)) {
522
+ await this.sendStateNotifications('onlineStateDevice', device);
360
523
  }
361
- }
362
- } else {
363
- if (this.config.checkSendOfflineMsg && oldStatus !== device.Status && !this.blacklistNotify.includes(device.Path)) {
364
- await this.sendOfflineNotifications(device.Device, device.Adapter, device.Status, device.LastContact);
524
+ } else {
525
+ await this.sendStateNotifications('onlineStateDevice', device);
365
526
  }
366
527
  }
367
528
  break;
@@ -375,23 +536,23 @@ class DeviceWatcher extends utils.Adapter {
375
536
  */
376
537
  onMessage(obj) {
377
538
  const devices = [];
378
- let myCount = 0;
379
- let result;
539
+ const instances = [];
540
+ let countDevices = 0;
541
+ let countInstances = 0;
380
542
 
381
543
  switch (obj.command) {
382
544
  case 'devicesList':
383
545
  if (obj.message) {
384
546
  try {
385
- result = this.listAllDevicesRaw;
386
- for (const element in result) {
387
- const label = `${result[element].Adapter}: ${result[element].Device}`;
388
- const myValueObject = {
389
- deviceName: result[element].Device,
390
- adapter: result[element].Adapter,
391
- path: result[element].Path,
547
+ for (const deviceData of this.listAllDevicesRaw.values()) {
548
+ const label = `${deviceData.Adapter}: ${deviceData.Device}`;
549
+ const valueObjectDevices = {
550
+ deviceName: deviceData.Device,
551
+ adapter: deviceData.Adapter,
552
+ path: deviceData.Path,
392
553
  };
393
- devices[myCount] = { label: label, value: JSON.stringify(myValueObject) };
394
- myCount++;
554
+ devices[countDevices] = { label: label, value: JSON.stringify(valueObjectDevices) };
555
+ countDevices++;
395
556
  }
396
557
  const sortDevices = devices.slice(0);
397
558
  sortDevices.sort(function (a, b) {
@@ -407,6 +568,34 @@ class DeviceWatcher extends utils.Adapter {
407
568
  this.sendTo(obj.from, obj.command, obj.callback);
408
569
  }
409
570
  break;
571
+
572
+ case 'instancesList':
573
+ if (obj.message) {
574
+ try {
575
+ for (const instanceData of this.listInstanceRaw.values()) {
576
+ const label = `${instanceData.Adapter}: ${instanceData.InstanceName}`;
577
+ const valueObjectInstances = {
578
+ adapter: instanceData.Adapter,
579
+ instanceName: instanceData.InstanceName,
580
+ path: instanceData.instanceAlivePath,
581
+ };
582
+ instances[countInstances] = { label: label, value: JSON.stringify(valueObjectInstances) };
583
+ countInstances++;
584
+ }
585
+ const sortInstances = instances.slice(0);
586
+ sortInstances.sort(function (a, b) {
587
+ const x = a.label;
588
+ const y = b.label;
589
+ return x < y ? -1 : x > y ? 1 : 0;
590
+ });
591
+ this.sendTo(obj.from, obj.command, sortInstances, obj.callback);
592
+ } catch (error) {
593
+ this.sendTo(obj.from, obj.command, obj.callback);
594
+ }
595
+ } else {
596
+ this.sendTo(obj.from, obj.command, obj.callback);
597
+ }
598
+ break;
410
599
  }
411
600
  }
412
601
 
@@ -418,7 +607,11 @@ class DeviceWatcher extends utils.Adapter {
418
607
 
419
608
  // fill counts and lists of all selected adapter
420
609
  try {
421
- await this.createDataOfAllAdapter();
610
+ for (let i = 0; i < this.selAdapter.length; i++) {
611
+ await this.createData(i);
612
+ await this.createLists();
613
+ }
614
+ await this.writeDatapoints(); // fill the datapoints
422
615
  this.log.debug(`Created and filled data for all adapters`);
423
616
  } catch (error) {
424
617
  this.errorReporting('[main - create data of all adapter]', error);
@@ -428,8 +621,13 @@ class DeviceWatcher extends utils.Adapter {
428
621
  if (this.createOwnFolder) {
429
622
  try {
430
623
  for (const [id] of Object.entries(arrApart)) {
431
- if (this.configSetAdapter !== undefined && this.configSetAdapter[id]) {
432
- await this.createDataForEachAdapter(id);
624
+ if (this.configSetAdapter && this.configSetAdapter[id]) {
625
+ for (const deviceData of this.listAllDevicesRaw.values()) {
626
+ // list device only if selected adapter matched with device
627
+ if (!deviceData.adapterID.includes(id)) continue;
628
+ await this.createLists(id);
629
+ }
630
+ await this.writeDatapoints(id); // fill the datapoints
433
631
  this.log.debug(`Created and filled data for ${this.capitalize(id)}`);
434
632
  }
435
633
  }
@@ -454,7 +652,7 @@ class DeviceWatcher extends utils.Adapter {
454
652
 
455
653
  if (this.createOwnFolder) {
456
654
  for (const [id] of Object.entries(arrApart)) {
457
- if (this.configSetAdapter !== undefined && this.configSetAdapter[id]) {
655
+ if (this.configSetAdapter && this.configSetAdapter[id]) {
458
656
  await this.createLists(id);
459
657
  await this.writeDatapoints(id);
460
658
  this.log.debug(`Created and filled data for ${this.capitalize(id)}`);
@@ -462,6 +660,11 @@ class DeviceWatcher extends utils.Adapter {
462
660
  }
463
661
  }
464
662
 
663
+ if (this.config.checkAdapterInstances) {
664
+ await this.createInstanceList();
665
+ await this.writeInstanceDPs();
666
+ }
667
+
465
668
  // Clear existing timeout
466
669
  if (this.refreshDataTimeout) {
467
670
  this.log.debug('clearing old refresh timeout');
@@ -485,11 +688,12 @@ class DeviceWatcher extends utils.Adapter {
485
688
  async createBlacklist() {
486
689
  this.log.debug(`Function started: ${this.createBlacklist.name}`);
487
690
 
691
+ // DEVICES
488
692
  const myBlacklist = this.config.tableBlacklist;
489
693
 
490
694
  for (const i in myBlacklist) {
491
695
  try {
492
- const blacklistParse = await this.parseData(myBlacklist[i].devices);
696
+ const blacklistParse = this.parseData(myBlacklist[i].devices);
493
697
  // push devices in list to ignor device in lists
494
698
  if (myBlacklist[i].checkIgnorLists) {
495
699
  this.blacklistLists.push(blacklistParse.path);
@@ -508,7 +712,29 @@ class DeviceWatcher extends utils.Adapter {
508
712
 
509
713
  if (this.blacklistLists.length >= 1) this.log.info(`Found items on blacklist for lists: ${this.blacklistLists}`);
510
714
  if (this.blacklistAdapterLists.length >= 1) this.log.info(`Found items on blacklist for lists: ${this.blacklistAdapterLists}`);
511
- if (this.blacklistNotify.length >= 1) this.log.info(`Found items on blacklist for notificatioons: ${this.blacklistNotify}`);
715
+ if (this.blacklistNotify.length >= 1) this.log.info(`Found items on blacklist for notifications: ${this.blacklistNotify}`);
716
+
717
+ // INSTANCES
718
+ const myBlacklistInstances = this.config.tableBlacklistInstances;
719
+
720
+ for (const i in myBlacklistInstances) {
721
+ try {
722
+ const blacklistParse = this.parseData(myBlacklistInstances[i].instances);
723
+ // push devices in list to ignor device in lists
724
+ if (myBlacklistInstances[i].checkIgnorLists) {
725
+ this.blacklistInstancesLists.push(blacklistParse.path);
726
+ }
727
+ // push devices in list to ignor device in notifications
728
+ if (myBlacklistInstances[i].checkIgnorNotify) {
729
+ this.blacklistInstancesNotify.push(blacklistParse.path);
730
+ }
731
+ } catch (error) {
732
+ this.errorReporting('[createBlacklist]', error);
733
+ }
734
+ }
735
+
736
+ if (this.blacklistInstancesLists.length >= 1) this.log.info(`Found items on blacklist for lists: ${this.blacklistInstancesLists}`);
737
+ if (this.blacklistInstancesNotify.length >= 1) this.log.info(`Found items on blacklist for notifications: ${this.blacklistInstancesNotify}`);
512
738
 
513
739
  this.log.debug(`Function finished: ${this.createBlacklist.name}`);
514
740
  }
@@ -529,6 +755,7 @@ class DeviceWatcher extends utils.Adapter {
529
755
  const instanceDeviceConnectionDP = `${instance}.info.connection`;
530
756
  const instancedeviceConnected = await this.getInitValue(instanceDeviceConnectionDP);
531
757
  this.subscribeForeignStates(instanceDeviceConnectionDP);
758
+ this.subscribeForeignObjectsAsync(`${this.selAdapter[i].Selektor}`);
532
759
 
533
760
  /*=============================================
534
761
  = Get device name =
@@ -546,6 +773,9 @@ class DeviceWatcher extends utils.Adapter {
546
773
  const currDeviceString = id.slice(0, id.lastIndexOf('.') + 1 - 1);
547
774
  const shortCurrDeviceString = currDeviceString.slice(0, currDeviceString.lastIndexOf('.') + 1 - 1);
548
775
 
776
+ // subscribe to object device path
777
+ this.subscribeForeignObjectsAsync(currDeviceString);
778
+
549
779
  /*=============================================
550
780
  = Get signal strength =
551
781
  =============================================*/
@@ -672,8 +902,8 @@ class DeviceWatcher extends utils.Adapter {
672
902
  }
673
903
 
674
904
  /*=============================================
675
- = Get update data =
676
- =============================================*/
905
+ = Get update data =
906
+ =============================================*/
677
907
  const deviceUpdateDP = currDeviceString + this.selAdapter[i].upgrade;
678
908
  let isUpgradable;
679
909
 
@@ -692,41 +922,8 @@ class DeviceWatcher extends utils.Adapter {
692
922
  /*=============================================
693
923
  = Fill Raw Lists =
694
924
  =============================================*/
695
-
696
- /* Add only devices with battery in the rawlist */
697
- if (this.listOnlyBattery) {
698
- if (isBatteryDevice) {
699
- this.listAllDevicesRaw.push({
700
- Path: id,
701
- instanceDeviceConnectionDP: instanceDeviceConnectionDP,
702
- instancedeviceConnected: instancedeviceConnected,
703
- Device: deviceName,
704
- adapterID: adapterID,
705
- Adapter: adapter,
706
- timeSelector: timeSelector,
707
- isBatteryDevice: isBatteryDevice,
708
- Battery: batteryHealth,
709
- BatteryRaw: batteryHealthRaw,
710
- batteryDP: deviceBatteryStateDP,
711
- LowBat: lowBatIndicator,
712
- LowBatDP: isLowBatDP,
713
- faultReport: faultReportingState,
714
- faultReportDP: faultReportingDP,
715
- SignalStrengthDP: deviceQualityDP,
716
- SignalStrength: linkQuality,
717
- UnreachState: deviceUnreachState,
718
- UnreachDP: unreachDP,
719
- DeviceStateSelectorDP: deviceStateSelectorDP,
720
- rssiPeerSelectorDP: rssiPeerSelectorDP,
721
- LastContact: lastContactString,
722
- Status: deviceState,
723
- UpdateDP: deviceUpdateDP,
724
- Upgradable: isUpgradable,
725
- });
726
- }
727
- } else {
728
- /* Add all devices */
729
- this.listAllDevicesRaw.push({
925
+ const setupList = () => {
926
+ this.listAllDevicesRaw.set(currDeviceString, {
730
927
  Path: id,
731
928
  instanceDeviceConnectionDP: instanceDeviceConnectionDP,
732
929
  instancedeviceConnected: instancedeviceConnected,
@@ -753,6 +950,15 @@ class DeviceWatcher extends utils.Adapter {
753
950
  UpdateDP: deviceUpdateDP,
754
951
  Upgradable: isUpgradable,
755
952
  });
953
+ };
954
+
955
+ if (!this.listOnlyBattery) {
956
+ // Add all devices
957
+ setupList();
958
+ } else {
959
+ // Add only devices with battery in the rawlist
960
+ if (!isBatteryDevice) continue;
961
+ setupList();
756
962
  }
757
963
  } // <-- end of loop
758
964
  } // <-- end of createData
@@ -1028,7 +1234,7 @@ class DeviceWatcher extends utils.Adapter {
1028
1234
  * @param {object} selector - Selector
1029
1235
  */
1030
1236
  async getLastContact(selector) {
1031
- const lastContact = await this.getTimestamp(selector);
1237
+ const lastContact = this.getTimestamp(selector);
1032
1238
  let lastContactString;
1033
1239
 
1034
1240
  lastContactString = this.formatDate(new Date(selector), 'hh:mm') + ' Uhr';
@@ -1061,8 +1267,8 @@ class DeviceWatcher extends utils.Adapter {
1061
1267
  const deviceUnreachSelector = await this.getForeignStateAsync(unreachDP);
1062
1268
  const deviceStateSelector = await this.getForeignStateAsync(deviceStateSelectorDP); // for hmrpc devices
1063
1269
  const rssiPeerSelector = await this.getForeignStateAsync(rssiPeerSelectorDP);
1064
- const lastContact = await this.getTimestamp(deviceTimeSelector.ts);
1065
- const lastDeviceUnreachStateChange = deviceUnreachSelector != undefined ? await this.getTimestamp(deviceUnreachSelector.lc) : await this.getTimestamp(timeSelector.ts);
1270
+ const lastContact = this.getTimestamp(deviceTimeSelector.ts);
1271
+ const lastDeviceUnreachStateChange = deviceUnreachSelector != undefined ? this.getTimestamp(deviceUnreachSelector.lc) : this.getTimestamp(timeSelector.ts);
1066
1272
  // If there is no contact since user sets minutes add device in offline list
1067
1273
  // calculate to days after 48 hours
1068
1274
  switch (unreachDP) {
@@ -1114,6 +1320,16 @@ class DeviceWatcher extends utils.Adapter {
1114
1320
  linkQuality = '0%'; // set linkQuality to nothing
1115
1321
  }
1116
1322
  break;
1323
+ case 'proxmox':
1324
+ if (this.configMaxMinutes[adapterID] <= 0) {
1325
+ if (deviceUnreachState !== 'running' && deviceUnreachState !== 'online') {
1326
+ deviceState = 'Offline'; //set online state to offline
1327
+ }
1328
+ } else if (lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID] && deviceUnreachState !== 'running' && deviceUnreachState !== 'online') {
1329
+ deviceState = 'Offline'; //set online state to offline
1330
+ linkQuality = '0%'; // set linkQuality to nothing
1331
+ }
1332
+ break;
1117
1333
  case 'hmiP':
1118
1334
  case 'maxcube':
1119
1335
  if (this.configMaxMinutes[adapterID] <= 0) {
@@ -1215,26 +1431,26 @@ class DeviceWatcher extends utils.Adapter {
1215
1431
  * when was last contact of device
1216
1432
  */
1217
1433
  async checkLastContact() {
1218
- for (const device of this.listAllDevicesRaw) {
1219
- if (device.instancedeviceConnected !== false) {
1220
- const oldContactState = device.Status;
1221
- device.UnreachState = await this.getInitValue(device.UnreachDP);
1434
+ for (const [device, deviceData] of this.listAllDevicesRaw) {
1435
+ if (deviceData.instancedeviceConnected !== false) {
1436
+ const oldContactState = deviceData.Status;
1437
+ deviceData.UnreachState = await this.getInitValue(deviceData.UnreachDP);
1222
1438
  const contactData = await this.getOnlineState(
1223
- device.timeSelector,
1224
- device.adapterID,
1225
- device.UnreachDP,
1226
- device.SignalStrength,
1227
- device.UnreachState,
1228
- device.DeviceStateSelectorDP,
1229
- device.rssiPeerSelectorDP,
1439
+ deviceData.timeSelector,
1440
+ deviceData.adapterID,
1441
+ deviceData.UnreachDP,
1442
+ deviceData.SignalStrength,
1443
+ deviceData.UnreachState,
1444
+ deviceData.DeviceStateSelectorDP,
1445
+ deviceData.rssiPeerSelectorDP,
1230
1446
  );
1231
1447
  if (contactData !== undefined) {
1232
- device.LastContact = contactData[0];
1233
- device.Status = contactData[1];
1234
- device.linkQuality = contactData[2];
1448
+ deviceData.LastContact = contactData[0];
1449
+ deviceData.Status = contactData[1];
1450
+ deviceData.linkQuality = contactData[2];
1235
1451
  }
1236
- if (this.config.checkSendOfflineMsg && oldContactState !== device.Status && !this.blacklistNotify.includes(device.Path)) {
1237
- await this.sendOfflineNotifications(device.Device, device.Adapter, device.Status, device.LastContact);
1452
+ if (this.config.checkSendOfflineMsg && oldContactState !== deviceData.Status && !this.blacklistNotify.includes(deviceData.Path)) {
1453
+ await this.sendStateNotifications('onlineStateDevice', device);
1238
1454
  }
1239
1455
  }
1240
1456
  }
@@ -1258,47 +1474,45 @@ class DeviceWatcher extends utils.Adapter {
1258
1474
  adptName = '';
1259
1475
  }
1260
1476
 
1261
- for (const device of this.listAllDevicesRaw) {
1477
+ for (const deviceData of this.listAllDevicesRaw.values()) {
1262
1478
  /*---------- fill raw lists ----------*/
1263
1479
  // low bat list
1264
- if (device.LowBat && device.Status !== 'Offline') {
1480
+ if (deviceData.LowBat && deviceData.Status !== 'Offline') {
1265
1481
  this.batteryLowPoweredRaw.push({
1266
- Path: device.Path,
1267
- Device: device.Device,
1268
- Adapter: device.Adapter,
1269
- Battery: device.Battery,
1482
+ Path: deviceData.Path,
1483
+ Device: deviceData.Device,
1484
+ Adapter: deviceData.Adapter,
1485
+ Battery: deviceData.Battery,
1270
1486
  });
1271
1487
  }
1272
1488
  // offline raw list
1273
- if (device.Status === 'Offline') {
1489
+ if (deviceData.Status === 'Offline') {
1274
1490
  this.offlineDevicesRaw.push({
1275
- Path: device.Path,
1276
- Device: device.Device,
1277
- Adapter: device.Adapter,
1278
- LastContact: device.LastContact,
1491
+ Path: deviceData.Path,
1492
+ Device: deviceData.Device,
1493
+ Adapter: deviceData.Adapter,
1494
+ LastContact: deviceData.LastContact,
1279
1495
  });
1280
1496
  }
1281
1497
 
1282
1498
  // upgradable raw list
1283
- if (device.Upgradable) {
1499
+ if (deviceData.Upgradable) {
1284
1500
  this.upgradableDevicesRaw.push({
1285
- Path: device.Path,
1286
- Device: device.Device,
1287
- Adapter: device.Adapter,
1501
+ Path: deviceData.Path,
1502
+ Device: deviceData.Device,
1503
+ Adapter: deviceData.Adapter,
1288
1504
  });
1289
1505
  }
1290
1506
 
1291
- if (adptName === '' && !this.blacklistLists.includes(device.Path)) {
1292
- await this.theLists(device);
1507
+ if (adptName === '' && !this.blacklistLists.includes(deviceData.Path)) {
1508
+ await this.theLists(deviceData);
1293
1509
  }
1294
1510
 
1295
1511
  if (this.config.createOwnFolder && adptName !== '') {
1296
- if (device.adapterID.includes(adptName)) {
1297
- /*---------- fill user lists for each adapter ----------*/
1298
- if (!this.blacklistAdapterLists.includes(device.Path)) {
1299
- await this.theLists(device);
1300
- }
1301
- }
1512
+ if (!deviceData.adapterID.includes(adptName)) continue;
1513
+ /*---------- fill user lists for each adapter ----------*/
1514
+ if (this.blacklistAdapterLists.includes(deviceData.Path)) continue;
1515
+ await this.theLists(deviceData);
1302
1516
  }
1303
1517
  }
1304
1518
  await this.countDevices();
@@ -1388,47 +1602,6 @@ class DeviceWatcher extends utils.Adapter {
1388
1602
  this.upgradableDevicesCount = this.upgradableList.length;
1389
1603
  }
1390
1604
 
1391
- /**
1392
- * @param {string} adptName - Adapter name
1393
- */
1394
- async createDataForEachAdapter(adptName) {
1395
- // create Data for each Adapter in own lists
1396
- this.log.debug(`Function started: ${this.createDataForEachAdapter.name}`);
1397
-
1398
- try {
1399
- for (const device of this.listAllDevicesRaw) {
1400
- if (device.adapterID.includes(adptName)) {
1401
- // list device only if selected adapter matched with device
1402
- await this.createLists(adptName);
1403
- }
1404
- }
1405
- await this.writeDatapoints(adptName); // fill the datapoints
1406
- } catch (error) {
1407
- this.errorReporting('[createDataForEachAdapter]', error);
1408
- }
1409
-
1410
- this.log.debug(`Function finished: ${this.createDataForEachAdapter.name}`);
1411
- } // <-- end of createDataForEachAdapter
1412
-
1413
- /**
1414
- * create Data of all selected adapter in one list
1415
- */
1416
- async createDataOfAllAdapter() {
1417
- this.log.debug(`Function started: ${this.createDataOfAllAdapter.name}`);
1418
-
1419
- try {
1420
- for (let i = 0; i < this.selAdapter.length; i++) {
1421
- await this.createData(i);
1422
- await this.createLists();
1423
- }
1424
- await this.writeDatapoints(); // fill the datapoints
1425
- } catch (error) {
1426
- this.errorReporting('[createDataOfAllAdapter]', error);
1427
- }
1428
-
1429
- this.log.debug(`Function finished: ${this.createDataOfAllAdapter.name}`);
1430
- } // <-- end of createDataOfAllAdapter
1431
-
1432
1605
  /**
1433
1606
  * @param {string} [adptName] - Adaptername
1434
1607
  */
@@ -1447,18 +1620,18 @@ class DeviceWatcher extends utils.Adapter {
1447
1620
  }
1448
1621
 
1449
1622
  // Write Datapoints for counts
1450
- await this.setStateAsync(`${dpSubFolder}offlineCount`, { val: this.offlineDevicesCount, ack: true });
1451
- await this.setStateAsync(`${dpSubFolder}countAll`, { val: this.deviceCounter, ack: true });
1452
- await this.setStateAsync(`${dpSubFolder}batteryCount`, { val: this.batteryPoweredCount, ack: true });
1453
- await this.setStateAsync(`${dpSubFolder}lowBatteryCount`, { val: this.lowBatteryPoweredCount, ack: true });
1454
- await this.setStateAsync(`${dpSubFolder}upgradableCount`, { val: this.upgradableDevicesCount, ack: true });
1623
+ await this.setStateAsync(`devices.${dpSubFolder}offlineCount`, { val: this.offlineDevicesCount, ack: true });
1624
+ await this.setStateAsync(`devices.${dpSubFolder}countAll`, { val: this.deviceCounter, ack: true });
1625
+ await this.setStateAsync(`devices.${dpSubFolder}batteryCount`, { val: this.batteryPoweredCount, ack: true });
1626
+ await this.setStateAsync(`devices.${dpSubFolder}lowBatteryCount`, { val: this.lowBatteryPoweredCount, ack: true });
1627
+ await this.setStateAsync(`devices.${dpSubFolder}upgradableCount`, { val: this.upgradableDevicesCount, ack: true });
1455
1628
 
1456
1629
  // List all devices
1457
1630
  if (this.deviceCounter === 0) {
1458
1631
  // if no device is count, write the JSON List with default value
1459
1632
  this.listAllDevices = [{ Device: '--none--', Adapter: '', Battery: '', 'Last contact': '', 'Signal strength': '' }];
1460
1633
  }
1461
- await this.setStateAsync(`${dpSubFolder}listAll`, { val: JSON.stringify(this.listAllDevices), ack: true });
1634
+ await this.setStateAsync(`devices.${dpSubFolder}listAll`, { val: JSON.stringify(this.listAllDevices), ack: true });
1462
1635
 
1463
1636
  // List link quality
1464
1637
  if (this.linkQualityCount === 0) {
@@ -1466,7 +1639,7 @@ class DeviceWatcher extends utils.Adapter {
1466
1639
  this.linkQualityDevices = [{ Device: '--none--', Adapter: '', 'Signal strength': '' }];
1467
1640
  }
1468
1641
  //write JSON list
1469
- await this.setStateAsync(`${dpSubFolder}linkQualityList`, {
1642
+ await this.setStateAsync(`devices.${dpSubFolder}linkQualityList`, {
1470
1643
  val: JSON.stringify(this.linkQualityDevices),
1471
1644
  ack: true,
1472
1645
  });
@@ -1477,7 +1650,7 @@ class DeviceWatcher extends utils.Adapter {
1477
1650
  this.offlineDevices = [{ Device: '--none--', Adapter: '', 'Last contact': '' }];
1478
1651
  }
1479
1652
  //write JSON list
1480
- await this.setStateAsync(`${dpSubFolder}offlineList`, {
1653
+ await this.setStateAsync(`devices.${dpSubFolder}offlineList`, {
1481
1654
  val: JSON.stringify(this.offlineDevices),
1482
1655
  ack: true,
1483
1656
  });
@@ -1488,7 +1661,7 @@ class DeviceWatcher extends utils.Adapter {
1488
1661
  this.upgradableList = [{ Device: '--none--', Adapter: '', 'Last contact': '' }];
1489
1662
  }
1490
1663
  //write JSON list
1491
- await this.setStateAsync(`${dpSubFolder}upgradableList`, {
1664
+ await this.setStateAsync(`devices.${dpSubFolder}upgradableList`, {
1492
1665
  val: JSON.stringify(this.upgradableList),
1493
1666
  ack: true,
1494
1667
  });
@@ -1499,7 +1672,7 @@ class DeviceWatcher extends utils.Adapter {
1499
1672
  this.batteryPowered = [{ Device: '--none--', Adapter: '', Battery: '' }];
1500
1673
  }
1501
1674
  //write JSON list
1502
- await this.setStateAsync(`${dpSubFolder}batteryList`, {
1675
+ await this.setStateAsync(`devices.${dpSubFolder}batteryList`, {
1503
1676
  val: JSON.stringify(this.batteryPowered),
1504
1677
  ack: true,
1505
1678
  });
@@ -1510,43 +1683,43 @@ class DeviceWatcher extends utils.Adapter {
1510
1683
  this.batteryLowPowered = [{ Device: '--none--', Adapter: '', Battery: '' }];
1511
1684
  }
1512
1685
  //write JSON list
1513
- await this.setStateAsync(`${dpSubFolder}lowBatteryList`, {
1686
+ await this.setStateAsync(`devices.${dpSubFolder}lowBatteryList`, {
1514
1687
  val: JSON.stringify(this.batteryLowPowered),
1515
1688
  ack: true,
1516
1689
  });
1517
1690
 
1518
1691
  // set booleans datapoints
1519
1692
  if (this.offlineDevicesCount === 0) {
1520
- await this.setStateAsync(`${dpSubFolder}oneDeviceOffline`, {
1693
+ await this.setStateAsync(`devices.${dpSubFolder}oneDeviceOffline`, {
1521
1694
  val: false,
1522
1695
  ack: true,
1523
1696
  });
1524
1697
  } else {
1525
- await this.setStateAsync(`${dpSubFolder}oneDeviceOffline`, {
1698
+ await this.setStateAsync(`devices.${dpSubFolder}oneDeviceOffline`, {
1526
1699
  val: true,
1527
1700
  ack: true,
1528
1701
  });
1529
1702
  }
1530
1703
 
1531
1704
  if (this.lowBatteryPoweredCount === 0) {
1532
- await this.setStateAsync(`${dpSubFolder}oneDeviceLowBat`, {
1705
+ await this.setStateAsync(`devices.${dpSubFolder}oneDeviceLowBat`, {
1533
1706
  val: false,
1534
1707
  ack: true,
1535
1708
  });
1536
1709
  } else {
1537
- await this.setStateAsync(`${dpSubFolder}oneDeviceLowBat`, {
1710
+ await this.setStateAsync(`devices.${dpSubFolder}oneDeviceLowBat`, {
1538
1711
  val: true,
1539
1712
  ack: true,
1540
1713
  });
1541
1714
  }
1542
1715
 
1543
1716
  if (this.upgradableDevicesCount === 0) {
1544
- await this.setStateAsync(`${dpSubFolder}oneDeviceUpdatable`, {
1717
+ await this.setStateAsync(`devices.${dpSubFolder}oneDeviceUpdatable`, {
1545
1718
  val: false,
1546
1719
  ack: true,
1547
1720
  });
1548
1721
  } else {
1549
- await this.setStateAsync(`${dpSubFolder}oneDeviceUpdatable`, {
1722
+ await this.setStateAsync(`devices.${dpSubFolder}oneDeviceUpdatable`, {
1550
1723
  val: true,
1551
1724
  ack: true,
1552
1725
  });
@@ -1554,20 +1727,20 @@ class DeviceWatcher extends utils.Adapter {
1554
1727
 
1555
1728
  //write HTML list
1556
1729
  if (this.createHtmlList) {
1557
- await this.setStateAsync(`${dpSubFolder}linkQualityListHTML`, {
1558
- val: await this.creatLinkQualityListHTML(this.linkQualityDevices, this.linkQualityCount),
1730
+ await this.setStateAsync(`devices.${dpSubFolder}linkQualityListHTML`, {
1731
+ val: await this.createListHTML('linkQualityList', this.linkQualityDevices, this.linkQualityCount, null),
1559
1732
  ack: true,
1560
1733
  });
1561
- await this.setStateAsync(`${dpSubFolder}offlineListHTML`, {
1562
- val: await this.createOfflineListHTML(this.offlineDevices, this.offlineDevicesCount),
1734
+ await this.setStateAsync(`devices.${dpSubFolder}offlineListHTML`, {
1735
+ val: await this.createListHTML('offlineList', this.offlineDevices, this.offlineDevicesCount, null),
1563
1736
  ack: true,
1564
1737
  });
1565
- await this.setStateAsync(`${dpSubFolder}batteryListHTML`, {
1566
- val: await this.createBatteryListHTML(this.batteryPowered, this.batteryPoweredCount, false),
1738
+ await this.setStateAsync(`devices.${dpSubFolder}batteryListHTML`, {
1739
+ val: await this.createListHTML('batteryList', this.batteryPowered, this.batteryPoweredCount, false),
1567
1740
  ack: true,
1568
1741
  });
1569
- await this.setStateAsync(`${dpSubFolder}lowBatteryListHTML`, {
1570
- val: await this.createBatteryListHTML(this.batteryLowPowered, this.lowBatteryPoweredCount, true),
1742
+ await this.setStateAsync(`devices.${dpSubFolder}lowBatteryListHTML`, {
1743
+ val: await this.createListHTML('batteryList', this.batteryLowPowered, this.lowBatteryPoweredCount, true),
1571
1744
  ack: true,
1572
1745
  });
1573
1746
  }
@@ -1581,109 +1754,680 @@ class DeviceWatcher extends utils.Adapter {
1581
1754
  this.log.debug(`Function finished: ${this.writeDatapoints.name}`);
1582
1755
  } //<--End of writing Datapoints
1583
1756
 
1584
- /*=============================================
1585
- = functions to send notifications =
1586
- =============================================*/
1587
-
1588
1757
  /**
1589
- * Notification service
1590
- * @param {string} text - Text which should be send
1758
+ * get all Instances at start
1591
1759
  */
1592
- async sendNotification(text) {
1593
- // Pushover
1760
+ async getAllInstanceData() {
1594
1761
  try {
1595
- if (this.config.instancePushover) {
1596
- //first check if instance is living
1597
- const pushoverAliveState = await this.getInitValue('system.adapter.' + this.config.instancePushover + '.alive');
1598
-
1599
- if (!pushoverAliveState) {
1600
- this.log.warn('Pushover instance is not running. Message could not be sent. Please check your instance configuration.');
1601
- } else {
1602
- await this.sendToAsync(this.config.instancePushover, 'send', {
1603
- message: text,
1604
- title: this.config.titlePushover,
1605
- device: this.config.devicePushover,
1606
- priority: this.config.prioPushover,
1607
- });
1608
- }
1609
- }
1762
+ const allInstances = `system.adapter.*`;
1763
+ await this.getInstanceData(allInstances);
1610
1764
  } catch (error) {
1611
- this.errorReporting('[sendNotification Pushover]', error);
1765
+ this.errorReporting('[getInstance]', error);
1612
1766
  }
1767
+ }
1613
1768
 
1614
- // Telegram
1615
- try {
1616
- if (this.config.instanceTelegram) {
1617
- //first check if instance is living
1618
- const telegramAliveState = await this.getInitValue('system.adapter.' + this.config.instanceTelegram + '.alive');
1769
+ /**
1770
+ * get instance data
1771
+ *@param {string} instanceObject
1772
+ */
1773
+ async getInstanceData(instanceObject) {
1774
+ const instanceAliveDP = await this.getForeignStatesAsync(`${instanceObject}.alive`);
1619
1775
 
1620
- if (!telegramAliveState) {
1621
- this.log.warn('Telegram instance is not running. Message could not be sent. Please check your instance configuration.');
1622
- } else {
1623
- await this.sendToAsync(this.config.instanceTelegram, 'send', {
1624
- text: text,
1625
- user: this.config.deviceTelegram,
1626
- chatId: this.config.chatIdTelegram,
1627
- });
1628
- }
1629
- }
1630
- } catch (error) {
1631
- this.errorReporting('[sendNotification Telegram]', error);
1632
- }
1776
+ for (const [id] of Object.entries(instanceAliveDP)) {
1777
+ if (!(typeof id === 'string' && id.startsWith(`system.adapter.`))) continue;
1633
1778
 
1634
- // Whatsapp
1635
- try {
1636
- if (this.config.instanceWhatsapp) {
1637
- //first check if instance is living
1638
- const whatsappAliveState = await this.getInitValue('system.adapter.' + this.config.instanceWhatsapp + '.alive');
1779
+ // get instance name
1780
+ const instanceName = await this.getInstanceName(id);
1639
1781
 
1640
- if (!whatsappAliveState) {
1641
- this.log.warn('Whatsapp instance is not running. Message could not be sent. Please check your instance configuration.');
1642
- } else {
1643
- await this.sendToAsync(this.config.instanceWhatsapp, 'send', {
1644
- text: text,
1645
- phone: this.config.phoneWhatsapp,
1646
- });
1782
+ // get instance connected to host data
1783
+ const instanceConnectedHostDP = `system.adapter.${instanceName}.connected`;
1784
+ const instanceConnectedHostVal = await this.getInitValue(instanceConnectedHostDP);
1785
+
1786
+ // get instance connected to device data
1787
+ const instanceConnectedDeviceDP = `${instanceName}.info.connection`;
1788
+ let instanceConnectedDeviceVal;
1789
+ if (instanceConnectedDeviceDP !== undefined && typeof instanceConnectedDeviceDP === 'boolean') {
1790
+ instanceConnectedDeviceVal = await this.getInitValue(instanceConnectedDeviceDP);
1791
+ } else {
1792
+ instanceConnectedDeviceVal = 'N/A';
1793
+ }
1794
+
1795
+ // get adapter version
1796
+ const instanceObjectPath = `system.adapter.${instanceName}`;
1797
+ let adapterName;
1798
+ let adapterVersion;
1799
+ let instanceMode;
1800
+ let scheduleTime = 'N/A';
1801
+ const instanceObjectData = await this.getForeignObjectAsync(instanceObjectPath);
1802
+ if (instanceObjectData) {
1803
+ // @ts-ignore
1804
+ adapterName = this.capitalize(instanceObjectData.common.name);
1805
+ adapterVersion = instanceObjectData.common.version;
1806
+ instanceMode = instanceObjectData.common.mode;
1807
+
1808
+ if (instanceMode === 'schedule') {
1809
+ scheduleTime = instanceObjectData.common.schedule;
1647
1810
  }
1648
1811
  }
1649
- } catch (error) {
1650
- this.errorReporting('[sendNotification Whatsapp]', error);
1812
+
1813
+ //const adapterVersionVal = await this.getInitValue(adapterVersionDP);
1814
+ const instanceStatusRaw = await this.setInstanceStatus(instanceMode, scheduleTime, id, instanceConnectedHostDP, instanceConnectedDeviceDP);
1815
+ const isAlive = instanceStatusRaw[1];
1816
+ const instanceStatus = instanceStatusRaw[0];
1817
+ const isHealthy = instanceStatusRaw[2];
1818
+
1819
+ //subscribe to statechanges
1820
+ this.subscribeForeignStatesAsync(id);
1821
+ this.subscribeForeignStatesAsync(instanceConnectedHostDP);
1822
+ this.subscribeForeignStatesAsync(instanceConnectedDeviceDP);
1823
+ this.subscribeForeignObjectsAsync(instanceObjectPath);
1824
+
1825
+ // create raw list
1826
+ this.listInstanceRaw.set(instanceObjectPath, {
1827
+ Adapter: adapterName,
1828
+ InstanceName: instanceName,
1829
+ instanceObjectPath: instanceObjectPath,
1830
+ instanceAlivePath: id,
1831
+ instanceMode: instanceMode,
1832
+ schedule: scheduleTime,
1833
+ adapterVersion: adapterVersion,
1834
+ isAlive: isAlive,
1835
+ isHealthy: isHealthy,
1836
+ connectedHostPath: instanceConnectedHostDP,
1837
+ isConnectedHost: instanceConnectedHostVal,
1838
+ connectedDevicePath: instanceConnectedDeviceDP,
1839
+ isConnectedDevice: instanceConnectedDeviceVal,
1840
+ status: instanceStatus,
1841
+ });
1651
1842
  }
1843
+ await this.createInstanceList();
1844
+ await this.writeInstanceDPs();
1845
+ }
1652
1846
 
1653
- // Email
1654
- try {
1655
- if (this.config.instanceEmail) {
1656
- //first check if instance is living
1657
- const eMailAliveState = await this.getInitValue('system.adapter.' + this.config.instanceEmail + '.alive');
1847
+ /**
1848
+ * get Instances
1849
+ * @param {string} id - Path of alive datapoint
1850
+ */
1851
+ async getInstanceName(id) {
1852
+ let instance = id;
1853
+ instance = instance.slice(15); // remove "system.adapter."
1854
+ instance = instance.slice(0, instance.lastIndexOf('.') + 1 - 1); // remove ".alive"
1855
+ return instance;
1856
+ }
1658
1857
 
1659
- if (!eMailAliveState) {
1660
- this.log.warn('eMail instance is not running. Message could not be sent. Please check your instance configuration.');
1858
+ /**
1859
+ * set status for instance
1860
+ * @param {string} instanceMode
1861
+ * @param {string} scheduleTime
1862
+ * @param {object} instanceAlivePath
1863
+ * @param {string} hostConnectedPath
1864
+ * @param {string} isDeviceConnctedPath
1865
+ */
1866
+ async setInstanceStatus(instanceMode, scheduleTime, instanceAlivePath, hostConnectedPath, isDeviceConnctedPath) {
1867
+ const isAliveSchedule = await this.getForeignStateAsync(instanceAlivePath);
1868
+ let isHostConnected = await this.getInitValue(hostConnectedPath);
1869
+ let isAlive = await this.getInitValue(instanceAlivePath);
1870
+ let isDeviceConnected = await this.getInitValue(isDeviceConnctedPath);
1871
+ let instanceStatusString = 'Instance deactivated';
1872
+ let lastUpdate;
1873
+ let lastCronRun;
1874
+ let diff;
1875
+ let previousCronRun = null;
1876
+ let isHealthy = false;
1877
+
1878
+ switch (instanceMode) {
1879
+ case 'schedule':
1880
+ if (isAliveSchedule) {
1881
+ lastUpdate = Math.round((Date.now() - isAliveSchedule.lc) / 1000); // Last state change in seconds
1882
+ previousCronRun = this.getPreviousCronRun(scheduleTime); // When was the last cron run
1883
+ if (previousCronRun) {
1884
+ lastCronRun = Math.round(previousCronRun / 1000); // change distance to last run in seconds
1885
+ diff = lastCronRun - lastUpdate;
1886
+ if (diff > -300) {
1887
+ // if 5 minutes difference exceeded, instance is not alive
1888
+ isAlive = true;
1889
+ isHealthy = true;
1890
+ instanceStatusString = 'Instanz okay';
1891
+ }
1892
+ }
1893
+ }
1894
+ break;
1895
+ case 'daemon':
1896
+ if (!isAlive) return ['Instanz deaktiviert', false, null]; // if instance is turned off
1897
+ if (isDeviceConnected === undefined) isDeviceConnected = true;
1898
+ // In case of (re)start, connection may take some time. We take 3 attempts.
1899
+ // Attempt 1/3 - immediately
1900
+ if (isHostConnected && isDeviceConnected) {
1901
+ isHealthy = true;
1902
+ instanceStatusString = 'Instanz okay';
1661
1903
  } else {
1662
- await this.sendToAsync(this.config.instanceEmail, 'send', {
1663
- sendTo: this.config.sendToEmail,
1664
- text: text,
1665
- subject: this.config.subjectEmail,
1666
- });
1904
+ // Attempt 2/3 - after 10 seconds
1905
+ await this.wait(10000);
1906
+ isDeviceConnected = await this.getInitValue(isDeviceConnctedPath);
1907
+ isHostConnected = await this.getInitValue(hostConnectedPath);
1908
+
1909
+ if (isHostConnected && isDeviceConnected) {
1910
+ isHealthy = true;
1911
+ instanceStatusString = 'Instanz okay';
1912
+ } else {
1913
+ // Attempt 3/3 - after 20 seconds in total
1914
+ await this.wait(10000);
1915
+ isDeviceConnected = await this.getInitValue(isDeviceConnctedPath);
1916
+ isHostConnected = await this.getInitValue(hostConnectedPath);
1917
+
1918
+ if (isHostConnected && isDeviceConnected) {
1919
+ isHealthy = true;
1920
+ instanceStatusString = 'Instanz okay';
1921
+ } else {
1922
+ if (!isDeviceConnected) {
1923
+ instanceStatusString = 'Nicht verbunden mit Gerät oder Dienst';
1924
+ isHealthy = false;
1925
+ } else if (!isHostConnected) {
1926
+ instanceStatusString = 'Nicht verbunden mit Host';
1927
+ isHealthy = false;
1928
+ }
1929
+ }
1930
+ }
1667
1931
  }
1668
- }
1669
- } catch (error) {
1670
- this.errorReporting('[sendNotification eMail]', error);
1932
+ break;
1671
1933
  }
1672
1934
 
1673
- // Jarvis Notification
1674
- try {
1675
- if (this.config.instanceJarvis) {
1676
- //first check if instance is living
1677
- const jarvisAliveState = await this.getInitValue('system.adapter.' + this.config.instanceJarvis + '.alive');
1935
+ return [instanceStatusString, isAlive, isHealthy];
1936
+ }
1678
1937
 
1679
- if (!jarvisAliveState) {
1680
- this.log.warn('Jarvis instance is not running. Message could not be sent. Please check your instance configuration.');
1681
- } else {
1682
- const jsonText = JSON.stringify(text);
1683
- await this.setForeignStateAsync(
1684
- `${this.config.instanceJarvis}.addNotification`,
1685
- '{"title":"' + this.config.titleJarvis + ' (' + this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss') + ')","message": ' + jsonText + ',"display": "drawer"}',
1686
- );
1938
+ /**
1939
+ * create adapter update data
1940
+ */
1941
+ async createAdapterUpdateData() {
1942
+ const adapterUpdateListDP = `admin.*.info.updatesJson`;
1943
+
1944
+ // subscribe to datapoint
1945
+ this.subscribeForeignStates(adapterUpdateListDP);
1946
+
1947
+ await this.getAdapterUpdateData(adapterUpdateListDP);
1948
+
1949
+ await this.createAdapterUpdateList();
1950
+ }
1951
+
1952
+ /**
1953
+ * create adapter update raw lists
1954
+ * @param {string} adapterUpdateListDP
1955
+ */
1956
+ async getAdapterUpdateData(adapterUpdateListDP) {
1957
+ this.adapterUpdatesJsonRaw = [];
1958
+ const adapterUpdatesListVal = await this.getForeignStatesAsync(adapterUpdateListDP);
1959
+
1960
+ let adapterJsonList;
1961
+ let adapterUpdatesJsonPath;
1962
+
1963
+ for (const [id] of Object.entries(adapterUpdatesListVal)) {
1964
+ adapterJsonList = this.parseData(adapterUpdatesListVal[id].val);
1965
+ adapterUpdatesJsonPath = id;
1966
+ }
1967
+
1968
+ for (const [id] of Object.entries(adapterJsonList)) {
1969
+ this.adapterUpdatesJsonRaw.push({
1970
+ Path: adapterUpdatesJsonPath,
1971
+ Adapter: this.capitalize(id),
1972
+ newVersion: adapterJsonList[id].availableVersion,
1973
+ oldVersion: adapterJsonList[id].installedVersion,
1974
+ });
1975
+ }
1976
+ return this.adapterUpdatesJsonRaw;
1977
+ }
1978
+
1979
+ /**
1980
+ * create instanceList
1981
+ */
1982
+ async createAdapterUpdateList() {
1983
+ this.listAdapterUpdates = [];
1984
+ this.countAdapterUpdates = 0;
1985
+
1986
+ for (const adapter of this.adapterUpdatesJsonRaw) {
1987
+ this.listAdapterUpdates.push({
1988
+ Adapter: adapter.Adapter,
1989
+ 'Available Version': adapter.newVersion,
1990
+ 'Installed Version': adapter.oldVersion,
1991
+ });
1992
+ }
1993
+ this.countAdapterUpdates = this.listAdapterUpdates.length;
1994
+ await this.writeAdapterUpdatesDPs();
1995
+ }
1996
+
1997
+ /**
1998
+ * write datapoints for adapter with updates
1999
+ */
2000
+ async writeAdapterUpdatesDPs() {
2001
+ // Write Datapoints for counts
2002
+ await this.setStateAsync(`adapterAndInstances.countAdapterUpdates`, { val: this.countAdapterUpdates, ack: true });
2003
+
2004
+ // list deactivated instances
2005
+ if (this.countAdapterUpdates === 0) {
2006
+ this.listAdapterUpdates = [{ Adapter: '--none--', 'Available Version': '', 'Installed Version': '' }];
2007
+ }
2008
+ await this.setStateAsync(`adapterAndInstances.listAdapterUpdates`, { val: JSON.stringify(this.listAdapterUpdates), ack: true });
2009
+ }
2010
+
2011
+ /**
2012
+ * create instanceList
2013
+ */
2014
+ async createInstanceList() {
2015
+ this.listAllInstances = [];
2016
+ this.listDeactivatedInstances = [];
2017
+ this.listErrorInstanceRaw = [];
2018
+ this.listErrorInstance = [];
2019
+
2020
+ for (const instance of this.listInstanceRaw.values()) {
2021
+ // fill raw list
2022
+ if (instance.isAlive && !instance.isHealthy) {
2023
+ this.listErrorInstanceRaw.push({
2024
+ Adapter: instance.Adapter,
2025
+ Instance: instance.InstanceName,
2026
+ Mode: instance.instanceMode,
2027
+ Status: instance.status,
2028
+ });
2029
+ }
2030
+
2031
+ if (this.blacklistInstancesLists.includes(instance.instanceAlivePath)) continue;
2032
+ this.listAllInstances.push({
2033
+ Adapter: instance.Adapter,
2034
+ Instance: instance.InstanceName,
2035
+ Mode: instance.instanceMode,
2036
+ Schedule: instance.schedule,
2037
+ Version: instance.adapterVersion,
2038
+ Status: instance.status,
2039
+ });
2040
+ if (!instance.isAlive) {
2041
+ this.listDeactivatedInstances.push({
2042
+ Adapter: instance.Adapter,
2043
+ Instance: instance.InstanceName,
2044
+ Status: instance.status,
2045
+ });
2046
+ }
2047
+
2048
+ // fill List for User
2049
+ if (instance.isAlive && !instance.isHealthy) {
2050
+ this.listErrorInstance.push({
2051
+ Adapter: instance.Adapter,
2052
+ Instance: instance.InstanceName,
2053
+ Mode: instance.instanceMode,
2054
+ Status: instance.status,
2055
+ });
2056
+ }
2057
+ }
2058
+ await this.countInstances();
2059
+ }
2060
+
2061
+ /**
2062
+ * count instanceList
2063
+ */
2064
+ async countInstances() {
2065
+ this.countAllInstances = 0;
2066
+ this.countDeactivatedInstances = 0;
2067
+ this.countErrorInstance = 0;
2068
+
2069
+ this.countAllInstances = this.listAllInstances.length;
2070
+ this.countDeactivatedInstances = this.listDeactivatedInstances.length;
2071
+ this.countErrorInstance = this.listErrorInstance.length;
2072
+ }
2073
+
2074
+ /**
2075
+ * write datapoints for instances list and counts
2076
+ */
2077
+ async writeInstanceDPs() {
2078
+ // Write Datapoints for counts
2079
+ await this.setStateAsync(`adapterAndInstances.countAllInstances`, { val: this.countAllInstances, ack: true });
2080
+ await this.setStateAsync(`adapterAndInstances.countDeactivatedInstances`, { val: this.countDeactivatedInstances, ack: true });
2081
+
2082
+ // List all instances
2083
+ await this.setStateAsync(`adapterAndInstances.listAllInstances`, { val: JSON.stringify(this.listAllInstances), ack: true });
2084
+
2085
+ // list deactivated instances
2086
+ if (this.countDeactivatedInstances === 0) {
2087
+ this.listDeactivatedInstances = [{ Instance: '--none--', Version: '', Status: '' }];
2088
+ }
2089
+ await this.setStateAsync(`adapterAndInstances.listDeactivatedInstances`, { val: JSON.stringify(this.listDeactivatedInstances), ack: true });
2090
+ await this.setStateAsync(`adapterAndInstances.countDeactivatedInstances`, { val: this.countDeactivatedInstances, ack: true });
2091
+
2092
+ // list error instances
2093
+ if (this.countErrorInstance === 0) {
2094
+ this.listErrorInstance = [{ Instance: '--none--', Mode: '', Status: '' }];
2095
+ }
2096
+ await this.setStateAsync(`adapterAndInstances.listInstancesError`, { val: JSON.stringify(this.listErrorInstance), ack: true });
2097
+ await this.setStateAsync(`adapterAndInstances.countInstancesError`, { val: this.countErrorInstance, ack: true });
2098
+ }
2099
+
2100
+ /**
2101
+ * create Datapoints for Instances
2102
+ */
2103
+ async createDPsForInstances() {
2104
+ await this.setObjectNotExistsAsync(`adapterAndInstances`, {
2105
+ type: 'channel',
2106
+ common: {
2107
+ name: {
2108
+ en: 'Adapter and Instances',
2109
+ de: 'Adapter und Instanzen',
2110
+ ru: 'Адаптер и Instances',
2111
+ pt: 'Adaptador e instâncias',
2112
+ nl: 'Adapter en Instance',
2113
+ fr: 'Adaptateur et instances',
2114
+ it: 'Adattatore e istanze',
2115
+ es: 'Adaptador e instalaciones',
2116
+ pl: 'Adapter and Instances',
2117
+ uk: 'Адаптер та інстанції',
2118
+ 'zh-cn': '道歉和案',
2119
+ },
2120
+ },
2121
+ native: {},
2122
+ });
2123
+
2124
+ // Instances
2125
+ await this.setObjectNotExistsAsync(`adapterAndInstances.listAllInstances`, {
2126
+ type: 'state',
2127
+ common: {
2128
+ name: {
2129
+ en: 'JSON List of all instances',
2130
+ de: 'JSON Liste aller Instanzen',
2131
+ ru: 'ДЖСОН Список всех инстанций',
2132
+ pt: 'J. Lista de todas as instâncias',
2133
+ nl: 'JSON List van alle instanties',
2134
+ fr: 'JSON Liste de tous les cas',
2135
+ it: 'JSON Elenco di tutte le istanze',
2136
+ es: 'JSON Lista de todos los casos',
2137
+ pl: 'JSON Lista wszystkich instancji',
2138
+ uk: 'Сонце Список всіх екземплярів',
2139
+ 'zh-cn': '附 件 所有事例一览表',
2140
+ },
2141
+ type: 'array',
2142
+ role: 'json',
2143
+ read: true,
2144
+ write: false,
2145
+ },
2146
+ native: {},
2147
+ });
2148
+ await this.setObjectNotExistsAsync(`adapterAndInstances.countAllInstances`, {
2149
+ type: 'state',
2150
+ common: {
2151
+ name: {
2152
+ en: 'Number of all instances',
2153
+ de: 'Anzahl aller Instanzen',
2154
+ ru: 'Количество всех инстанций',
2155
+ pt: 'Número de todas as instâncias',
2156
+ nl: 'Nummer van alle gevallen',
2157
+ fr: 'Nombre de cas',
2158
+ it: 'Numero di tutte le istanze',
2159
+ es: 'Número de casos',
2160
+ pl: 'Liczba wszystkich instancji',
2161
+ uk: 'Кількість всіх екземплярів',
2162
+ 'zh-cn': '各类案件数目',
2163
+ },
2164
+ type: 'number',
2165
+ role: 'value',
2166
+ read: true,
2167
+ write: false,
2168
+ },
2169
+ native: {},
2170
+ });
2171
+ await this.setObjectNotExistsAsync(`adapterAndInstances.listDeactivatedInstances`, {
2172
+ type: 'state',
2173
+ common: {
2174
+ name: {
2175
+ en: 'JSON List of deactivated instances',
2176
+ de: 'JSON Liste der deaktivierten Instanzen',
2177
+ ru: 'ДЖСОН Список деактивированных инстанций',
2178
+ pt: 'J. Lista de instâncias desativadas',
2179
+ nl: 'JSON List van gedeactiveerde instanties',
2180
+ fr: 'JSON Liste des cas désactivés',
2181
+ it: 'JSON Elenco delle istanze disattivate',
2182
+ es: 'JSON Lista de casos desactivados',
2183
+ pl: 'JSON Lista przypadków deaktywowanych',
2184
+ uk: 'Сонце Перелік деактивованих екземплярів',
2185
+ 'zh-cn': '附 件 被动事例清单',
2186
+ },
2187
+ type: 'array',
2188
+ role: 'json',
2189
+ read: true,
2190
+ write: false,
2191
+ },
2192
+ native: {},
2193
+ });
2194
+ await this.setObjectNotExistsAsync(`adapterAndInstances.countDeactivatedInstances`, {
2195
+ type: 'state',
2196
+ common: {
2197
+ name: {
2198
+ en: 'Number of deactivated instances',
2199
+ de: 'Anzahl deaktivierter Instanzen',
2200
+ ru: 'Количество деактивированных инстанций',
2201
+ pt: 'Número de instâncias desativadas',
2202
+ nl: 'Nummer van gedeactiveerde instanties',
2203
+ fr: 'Nombre de cas désactivés',
2204
+ it: 'Numero di istanze disattivate',
2205
+ es: 'Número de casos desactivados',
2206
+ pl: 'Liczba deaktywowanych instancji',
2207
+ uk: 'Кількість деактивованих екземплярів',
2208
+ 'zh-cn': 'A. 递解事件的数目',
2209
+ },
2210
+ type: 'number',
2211
+ role: 'value',
2212
+ read: true,
2213
+ write: false,
2214
+ },
2215
+ native: {},
2216
+ });
2217
+ await this.setObjectNotExistsAsync(`adapterAndInstances.listInstancesError`, {
2218
+ type: 'state',
2219
+ common: {
2220
+ name: {
2221
+ en: 'JSON list of instances with error',
2222
+ de: 'JSON-Liste von Instanzen mit Fehler',
2223
+ ru: 'JSON список инстанций с ошибкой',
2224
+ pt: 'Lista de instâncias JSON com erro',
2225
+ nl: 'JSON lijst met fouten',
2226
+ fr: 'Liste des instances avec erreur',
2227
+ it: 'Elenco JSON delle istanze con errore',
2228
+ es: 'JSON lista de casos con error',
2229
+ pl: 'Lista błędów JSON',
2230
+ uk: 'JSON список екземплярів з помилкою',
2231
+ 'zh-cn': '联合工作组办公室错误事件清单',
2232
+ },
2233
+ type: 'array',
2234
+ role: 'json',
2235
+ read: true,
2236
+ write: false,
2237
+ },
2238
+ native: {},
2239
+ });
2240
+ await this.setObjectNotExistsAsync(`adapterAndInstances.countInstancesError`, {
2241
+ type: 'state',
2242
+ common: {
2243
+ name: {
2244
+ en: 'Count of instances with error',
2245
+ de: 'Anzahl der Instanzen mit Fehler',
2246
+ ru: 'Количество инстанций с ошибкой',
2247
+ pt: 'Contagem de instâncias com erro',
2248
+ nl: 'Graaf van instoringen met fouten',
2249
+ fr: 'Nombre de cas avec erreur',
2250
+ it: 'Conteggio di istanze con errore',
2251
+ es: 'Cuenta de casos con error',
2252
+ pl: 'Liczba przykładów w przypadku błędów',
2253
+ uk: 'Кількість екземплярів з помилкою',
2254
+ 'zh-cn': '发生错误的情况',
2255
+ },
2256
+ type: 'number',
2257
+ role: 'value',
2258
+ read: true,
2259
+ write: false,
2260
+ },
2261
+ native: {},
2262
+ });
2263
+
2264
+ // Adapter
2265
+ await this.setObjectNotExistsAsync(`adapterAndInstances.listAdapterUpdates`, {
2266
+ type: 'state',
2267
+ common: {
2268
+ name: {
2269
+ en: 'JSON list of adapters with available updates',
2270
+ de: 'JSON-Liste der Adapter mit verfügbaren Updates',
2271
+ ru: 'JSON список адаптеров с доступными обновлениями',
2272
+ pt: 'Lista de adaptadores JSON com atualizações disponíveis',
2273
+ nl: 'JSON lijst met beschikbare updates',
2274
+ fr: 'Liste JSON des adaptateurs avec mises à jour disponibles',
2275
+ it: 'Elenco di adattatori JSON con aggiornamenti disponibili',
2276
+ es: 'JSON lista de adaptadores con actualizaciones disponibles',
2277
+ pl: 'JSON lista adapterów z dostępnymi aktualizacjami',
2278
+ uk: 'JSON список адаптерів з доступними оновленнями',
2279
+ 'zh-cn': '附录A',
2280
+ },
2281
+ type: 'array',
2282
+ role: 'json',
2283
+ read: true,
2284
+ write: false,
2285
+ },
2286
+ native: {},
2287
+ });
2288
+ await this.setObjectNotExistsAsync(`adapterAndInstances.countAdapterUpdates`, {
2289
+ type: 'state',
2290
+ common: {
2291
+ name: {
2292
+ en: 'Number of adapters with available updates',
2293
+ de: 'Anzahl der Adapter mit verfügbaren Updates',
2294
+ ru: 'Количество адаптеров с доступными обновлениями',
2295
+ pt: 'Número de adaptadores com atualizações disponíveis',
2296
+ nl: 'Nummer van adapters met beschikbare updates',
2297
+ fr: "Nombre d'adaptateurs avec mises à jour disponibles",
2298
+ it: 'Numero di adattatori con aggiornamenti disponibili',
2299
+ es: 'Número de adaptadores con actualizaciones disponibles',
2300
+ pl: 'Liczba adapterów z dostępną aktualizacją',
2301
+ uk: 'Кількість адаптерів з доступними оновленнями',
2302
+ 'zh-cn': '更新的适应者人数',
2303
+ },
2304
+ type: 'number',
2305
+ role: 'value',
2306
+ read: true,
2307
+ write: false,
2308
+ },
2309
+ native: {},
2310
+ });
2311
+ }
2312
+
2313
+ /**
2314
+ * delete Datapoints for Instances
2315
+ */
2316
+ async deleteDPsForInstances() {
2317
+ await this.delObjectAsync(`adapterAndInstances`);
2318
+ await this.delObjectAsync(`adapterAndInstances.listAllInstances`);
2319
+ await this.delObjectAsync(`adapterAndInstances.countAllInstances`);
2320
+ await this.delObjectAsync(`adapterAndInstances.listDeactivatedInstances`);
2321
+ await this.delObjectAsync(`adapterAndInstances.countDeactivatedInstances`);
2322
+ await this.delObjectAsync(`adapterAndInstances.listInstancesError`);
2323
+ await this.delObjectAsync(`adapterAndInstances.countInstancesError`);
2324
+ await this.delObjectAsync(`adapterAndInstances.listAdapterUpdates`);
2325
+ await this.delObjectAsync(`adapterAndInstances.countAdapterUpdates`);
2326
+ }
2327
+
2328
+ /*=============================================
2329
+ = functions to send notifications =
2330
+ =============================================*/
2331
+
2332
+ /**
2333
+ * Notification service
2334
+ * @param {string} text - Text which should be send
2335
+ */
2336
+ async sendNotification(text) {
2337
+ // Pushover
2338
+ try {
2339
+ if (this.config.instancePushover) {
2340
+ //first check if instance is living
2341
+ const pushoverAliveState = await this.getInitValue('system.adapter.' + this.config.instancePushover + '.alive');
2342
+
2343
+ if (!pushoverAliveState) {
2344
+ this.log.warn('Pushover instance is not running. Message could not be sent. Please check your instance configuration.');
2345
+ } else {
2346
+ await this.sendToAsync(this.config.instancePushover, 'send', {
2347
+ message: text,
2348
+ title: this.config.titlePushover,
2349
+ device: this.config.devicePushover,
2350
+ priority: this.config.prioPushover,
2351
+ });
2352
+ }
2353
+ }
2354
+ } catch (error) {
2355
+ this.errorReporting('[sendNotification Pushover]', error);
2356
+ }
2357
+
2358
+ // Telegram
2359
+ try {
2360
+ if (this.config.instanceTelegram) {
2361
+ //first check if instance is living
2362
+ const telegramAliveState = await this.getInitValue('system.adapter.' + this.config.instanceTelegram + '.alive');
2363
+
2364
+ if (!telegramAliveState) {
2365
+ this.log.warn('Telegram instance is not running. Message could not be sent. Please check your instance configuration.');
2366
+ } else {
2367
+ await this.sendToAsync(this.config.instanceTelegram, 'send', {
2368
+ text: text,
2369
+ user: this.config.deviceTelegram,
2370
+ chatId: this.config.chatIdTelegram,
2371
+ });
2372
+ }
2373
+ }
2374
+ } catch (error) {
2375
+ this.errorReporting('[sendNotification Telegram]', error);
2376
+ }
2377
+
2378
+ // Whatsapp
2379
+ try {
2380
+ if (this.config.instanceWhatsapp) {
2381
+ //first check if instance is living
2382
+ const whatsappAliveState = await this.getInitValue('system.adapter.' + this.config.instanceWhatsapp + '.alive');
2383
+
2384
+ if (!whatsappAliveState) {
2385
+ this.log.warn('Whatsapp instance is not running. Message could not be sent. Please check your instance configuration.');
2386
+ } else {
2387
+ await this.sendToAsync(this.config.instanceWhatsapp, 'send', {
2388
+ text: text,
2389
+ phone: this.config.phoneWhatsapp,
2390
+ });
2391
+ }
2392
+ }
2393
+ } catch (error) {
2394
+ this.errorReporting('[sendNotification Whatsapp]', error);
2395
+ }
2396
+
2397
+ // Email
2398
+ try {
2399
+ if (this.config.instanceEmail) {
2400
+ //first check if instance is living
2401
+ const eMailAliveState = await this.getInitValue('system.adapter.' + this.config.instanceEmail + '.alive');
2402
+
2403
+ if (!eMailAliveState) {
2404
+ this.log.warn('eMail instance is not running. Message could not be sent. Please check your instance configuration.');
2405
+ } else {
2406
+ await this.sendToAsync(this.config.instanceEmail, 'send', {
2407
+ sendTo: this.config.sendToEmail,
2408
+ text: text,
2409
+ subject: this.config.subjectEmail,
2410
+ });
2411
+ }
2412
+ }
2413
+ } catch (error) {
2414
+ this.errorReporting('[sendNotification eMail]', error);
2415
+ }
2416
+
2417
+ // Jarvis Notification
2418
+ try {
2419
+ if (this.config.instanceJarvis) {
2420
+ //first check if instance is living
2421
+ const jarvisAliveState = await this.getInitValue('system.adapter.' + this.config.instanceJarvis + '.alive');
2422
+
2423
+ if (!jarvisAliveState) {
2424
+ this.log.warn('Jarvis instance is not running. Message could not be sent. Please check your instance configuration.');
2425
+ } else {
2426
+ const jsonText = JSON.stringify(text);
2427
+ await this.setForeignStateAsync(
2428
+ `${this.config.instanceJarvis}.addNotification`,
2429
+ '{"title":"' + this.config.titleJarvis + ' (' + this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss') + ')","message": ' + jsonText + ',"display": "drawer"}',
2430
+ );
1687
2431
  }
1688
2432
  }
1689
2433
  } catch (error) {
@@ -1731,376 +2475,379 @@ class DeviceWatcher extends utils.Adapter {
1731
2475
  }
1732
2476
  } // <-- End of sendNotification function
1733
2477
 
2478
+ /*---------- Notifications ----------*/
1734
2479
  /**
1735
- * send shedule message for low battery devices
2480
+ * Notifications on state changes
2481
+ * @param {string} type
2482
+ * @param {object} id
1736
2483
  */
1737
- async sendBatteryNotifyShedule() {
1738
- const time = this.config.checkSendBatteryTime.split(':');
1739
-
1740
- const checkDays = []; // list of selected days
1741
-
1742
- // push the selected days in list
1743
- if (this.config.checkMonday) checkDays.push(1);
1744
- if (this.config.checkTuesday) checkDays.push(2);
1745
- if (this.config.checkWednesday) checkDays.push(3);
1746
- if (this.config.checkThursday) checkDays.push(4);
1747
- if (this.config.checkFriday) checkDays.push(5);
1748
- if (this.config.checkSaturday) checkDays.push(6);
1749
- if (this.config.checkSunday) checkDays.push(0);
1750
-
1751
- if (checkDays.length >= 1) {
1752
- // check if an day is selected
1753
- this.log.debug(`Number of selected days for daily battery message: ${checkDays.length}. Send Message on: ${checkDays.join(', ')} ...`);
1754
- } else {
1755
- this.log.warn(`No days selected for daily battery message. Please check the instance configuration!`);
1756
- return; // cancel function if no day is selected
1757
- }
1758
-
1759
- if (!isUnloaded) {
1760
- const cron = '10 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
1761
- schedule.scheduleJob(cron, () => {
1762
- try {
1763
- let deviceList = '';
1764
-
1765
- for (const id of this.batteryLowPoweredRaw) {
1766
- if (!this.blacklistNotify.includes(id.Path)) {
1767
- if (!this.config.showAdapterNameinMsg) {
1768
- deviceList = `${deviceList}\n${id.Device} (${id.Battery})`;
1769
- } else {
1770
- // Add adaptername if checkbox is checked true in options by user
1771
- deviceList = `${deviceList}\n${id.Adapter}: ${id.Device} (${id.Battery})`;
1772
- }
2484
+ async sendStateNotifications(type, id) {
2485
+ if (isUnloaded) return;
2486
+ let objectData;
2487
+ let list = '';
2488
+ let message = '';
2489
+ const setMessage = async (message) => {
2490
+ this.log.info(`${message}`);
2491
+ await this.setStateAsync('lastNotification', `${message}`, true);
2492
+ await this.sendNotification(`${message}`);
2493
+ return (message = '');
2494
+ };
2495
+ switch (type) {
2496
+ case 'lowBatDevice':
2497
+ objectData = this.listAllDevicesRaw.get(id);
2498
+ if (!this.config.showAdapterNameinMsg) {
2499
+ message = `Gerät mit geringer Batterie erkannt: \n${objectData.Device} (${objectData.Battery})`;
2500
+ } else {
2501
+ message = `Gerät mit geringer Batterie erkannt: \n${objectData.Adapter}: ${objectData.Device} (${objectData.Battery})`;
2502
+ }
2503
+ setMessage(message);
2504
+ break;
2505
+ case 'onlineStateDevice':
2506
+ objectData = this.listAllDevicesRaw.get(id);
2507
+ switch (objectData.Status) {
2508
+ case 'Online':
2509
+ if (!this.config.showAdapterNameinMsg) {
2510
+ message = `Folgendes Gerät ist wieder erreichbar: \n${objectData.Device} (${objectData.LastContact})`;
2511
+ } else {
2512
+ message = `Folgendes Gerät ist wieder erreichbar: \n${objectData.Adapter}: ${objectData.Device} (${objectData.LastContact})`;
1773
2513
  }
1774
- }
1775
- if (deviceList.length > 0) {
1776
- this.log.info(`Niedrige Batteriezustände: ${deviceList}`);
1777
- this.setStateAsync('lastNotification', `Niedrige Batteriezustände: ${deviceList}`, true);
1778
-
1779
- this.sendNotification(`Niedrige Batteriezustände: ${deviceList}`);
1780
- }
1781
- } catch (error) {
1782
- this.errorReporting('[sendBatteryNotifyShedule]', error);
2514
+ break;
2515
+ case 'Offline':
2516
+ if (!this.config.showAdapterNameinMsg) {
2517
+ message = `Folgendes Gerät ist seit einiger Zeit nicht erreichbar: \n${objectData.Device} (${objectData.LastContact})`;
2518
+ } else {
2519
+ message = `Folgendes Gerät ist seit einiger Zeit nicht erreichbar: \n${objectData.Adapter}: ${objectData.Device} (${objectData.LastContact})`;
2520
+ }
2521
+ break;
1783
2522
  }
1784
- });
1785
- }
1786
- } //<--End of battery notification
1787
-
1788
- /**
1789
- * check if device updates are available and send notification
1790
- * @param {string} deviceName
1791
- * @param {string} adapter
1792
- * @param {string} battery
1793
- **/
1794
- async sendLowBatNoticiation(deviceName, adapter, battery) {
1795
- this.log.debug(`Start the function: ${this.sendLowBatNoticiation.name}`);
1796
-
1797
- try {
1798
- let msg = '';
1799
- let deviceList = '';
1800
-
1801
- if (!this.config.showAdapterNameinMsg) {
1802
- deviceList = `${deviceList}\n${deviceName} (${battery})`;
1803
- } else {
1804
- deviceList = `${deviceList}\n${adapter}: ${deviceName} (${battery})`;
1805
- }
1806
- msg = `Gerät mit geringer Batterie erkannt: \n`;
2523
+ setMessage(message);
2524
+ break;
2525
+ case 'updateDevice':
2526
+ objectData = this.listAllDevicesRaw.get(id);
2527
+ if (!this.config.showAdapterNameinMsg) {
2528
+ message = `Neue Geräte Updates vorhanden: \n${objectData.Device}`;
2529
+ } else {
2530
+ message = `Neue Geräte Updates vorhanden: \n${objectData.Adapter}: ${objectData.Device}`;
2531
+ }
2532
+ setMessage(message);
2533
+ break;
2534
+ case 'updateAdapter':
2535
+ objectData = this.listAdapterUpdates;
2536
+ list = '';
1807
2537
 
1808
- this.log.info(msg + deviceList);
1809
- await this.setStateAsync('lastNotification', msg + deviceList, true);
1810
- await this.sendNotification(msg + deviceList);
1811
- } catch (error) {
1812
- this.errorReporting('[sendLowBatNoticiation]', error);
2538
+ for (const id of objectData) {
2539
+ list = `${list}\n${id.Adapter}: v${id['Available Version']}`;
2540
+ }
2541
+ if (list.length === 0) return;
2542
+ message = `Neue Adapter Updates vorhanden: ${list}`;
2543
+ setMessage(message);
2544
+ break;
2545
+ case 'errorInstance':
2546
+ objectData = this.listInstanceRaw.get(id);
2547
+ message = `Instanz Watchdog:\n${objectData.InstanceName}: ${objectData.status}`;
2548
+ setMessage(message);
2549
+ break;
1813
2550
  }
1814
- this.log.debug(`Finished the function: ${this.sendLowBatNoticiation.name}`);
1815
2551
  }
1816
2552
 
1817
2553
  /**
1818
- * send message if an device is offline
1819
- * @param {string} deviceName
1820
- * @param {string} adapter
1821
- * @param {string} status
1822
- * @param {string} lastContact
2554
+ * Notifications per user defined schedule
2555
+ * @param {string} type
1823
2556
  */
1824
- async sendOfflineNotifications(deviceName, adapter, status, lastContact) {
1825
- this.log.debug(`Start the function: ${this.sendOfflineNotifications.name}`);
1826
-
1827
- try {
1828
- let msg = '';
1829
- let deviceList = '';
1830
-
1831
- if (!this.config.showAdapterNameinMsg) {
1832
- deviceList = `${deviceList}\n${deviceName} (${lastContact})`;
1833
- } else {
1834
- deviceList = `${deviceList}\n${adapter}: ${deviceName} (${lastContact})`;
1835
- }
1836
-
1837
- if (status === 'Online') {
1838
- // make singular if it is only one device
1839
- msg = 'Folgendes Gerät ist wieder erreichbar: \n';
1840
- } else if (status === 'Offline') {
1841
- //make plural if it is more than one device
1842
- msg = `Folgendes Gerät ist seit einiger Zeit nicht erreichbar: \n`;
1843
- }
1844
-
1845
- this.log.info(msg + deviceList);
1846
- await this.setStateAsync('lastNotification', msg + deviceList, true);
1847
- await this.sendNotification(msg + deviceList);
1848
- } catch (error) {
1849
- this.errorReporting('[sendOfflineMessage]', error);
1850
- }
1851
- this.log.debug(`Finished the function: ${this.sendOfflineNotifications.name}`);
1852
- } //<--End of offline notification
2557
+ sendScheduleNotifications(type) {
2558
+ if (isUnloaded) return;
2559
+
2560
+ let time;
2561
+ let cron;
2562
+ let list = '';
2563
+ let message = '';
2564
+ const checkDays = [];
2565
+ const setMessage = async (message) => {
2566
+ this.log.info(`${message}`);
2567
+ await this.setStateAsync('lastNotification', `${message}`, true);
2568
+ await this.sendNotification(`${message}`);
2569
+ return (message = '');
2570
+ };
2571
+
2572
+ switch (type) {
2573
+ case 'lowBatteryDevices':
2574
+ // push the selected days in list
2575
+ if (this.config.checkMonday) checkDays.push(1);
2576
+ if (this.config.checkTuesday) checkDays.push(2);
2577
+ if (this.config.checkWednesday) checkDays.push(3);
2578
+ if (this.config.checkThursday) checkDays.push(4);
2579
+ if (this.config.checkFriday) checkDays.push(5);
2580
+ if (this.config.checkSaturday) checkDays.push(6);
2581
+ if (this.config.checkSunday) checkDays.push(0);
2582
+
2583
+ time = this.config.checkSendBatteryTime.split(':');
2584
+
2585
+ if (checkDays.length === 0) {
2586
+ this.log.warn(`No days selected for daily low battery devices message. Please check the instance configuration!`);
2587
+ return; // cancel function if no day is selected
2588
+ }
2589
+ this.log.debug(`Number of selected days for daily low battery devices message: ${checkDays.length}. Send Message on: ${checkDays.join(', ')} ...`);
1853
2590
 
1854
- /**
1855
- * send shedule message with offline devices
1856
- */
1857
- async sendOfflineNotificationsShedule() {
1858
- const time = this.config.checkSendOfflineTime.split(':');
1859
-
1860
- const checkDays = []; // list of selected days
1861
-
1862
- // push the selected days in list
1863
- if (this.config.checkOfflineMonday) checkDays.push(1);
1864
- if (this.config.checkOfflineTuesday) checkDays.push(2);
1865
- if (this.config.checkOfflineWednesday) checkDays.push(3);
1866
- if (this.config.checkOfflineThursday) checkDays.push(4);
1867
- if (this.config.checkOfflineFriday) checkDays.push(5);
1868
- if (this.config.checkOfflineSaturday) checkDays.push(6);
1869
- if (this.config.checkOfflineSunday) checkDays.push(0);
1870
-
1871
- if (checkDays.length >= 1) {
1872
- // check if an day is selected
1873
- this.log.debug(`Number of selected days for daily offline message: ${checkDays.length}. Send Message on: ${checkDays.join(', ')} ...`);
1874
- } else {
1875
- this.log.warn(`No days selected for daily offline message. Please check the instance configuration!`);
1876
- return; // cancel function if no day is selected
1877
- }
2591
+ cron = '1 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
2592
+ schedule.scheduleJob(cron, () => {
2593
+ list = '';
2594
+ for (const id of this.batteryLowPoweredRaw) {
2595
+ if (this.blacklistNotify.includes(id.Path)) continue;
2596
+ if (!this.config.showAdapterNameinMsg) {
2597
+ list = `${list}\n${id.Device} (${id.Battery})`;
2598
+ } else {
2599
+ // Add adaptername if checkbox is checked true in options by user
2600
+ list = `${list}\n${id.Adapter}: ${id.Device} (${id.Battery})`;
2601
+ }
2602
+ }
2603
+ if (list.length === 0) return;
2604
+ message = `Tägliche Meldung über Geräte mit niedrigen Batteriezuständen: ${list}`;
2605
+ setMessage(message);
2606
+ });
2607
+ break;
2608
+ case 'offlineDevices':
2609
+ // push the selected days in list
2610
+ if (this.config.checkOfflineMonday) checkDays.push(1);
2611
+ if (this.config.checkOfflineTuesday) checkDays.push(2);
2612
+ if (this.config.checkOfflineWednesday) checkDays.push(3);
2613
+ if (this.config.checkOfflineThursday) checkDays.push(4);
2614
+ if (this.config.checkOfflineFriday) checkDays.push(5);
2615
+ if (this.config.checkOfflineSaturday) checkDays.push(6);
2616
+ if (this.config.checkOfflineSunday) checkDays.push(0);
2617
+
2618
+ time = this.config.checkSendOfflineTime.split(':');
2619
+
2620
+ if (checkDays.length === 0) {
2621
+ this.log.warn(`No days selected for daily offline devices message. Please check the instance configuration!`);
2622
+ return; // cancel function if no day is selected
2623
+ }
2624
+ this.log.debug(`Number of selected days for daily offline devices message: ${checkDays.length}. Send Message on: ${checkDays.join(', ')} ...`);
1878
2625
 
1879
- if (!isUnloaded) {
1880
- const cron = '10 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
1881
- schedule.scheduleJob(cron, () => {
1882
- try {
1883
- let deviceList = '';
2626
+ cron = '2 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
2627
+ schedule.scheduleJob(cron, () => {
2628
+ list = '';
1884
2629
 
1885
2630
  for (const id of this.offlineDevicesRaw) {
1886
- if (!this.blacklistNotify.includes(id.Path)) {
1887
- if (!this.config.showAdapterNameinMsg) {
1888
- deviceList = `${deviceList}\n${id.Device} (${id.LastContact})`;
1889
- } else {
1890
- deviceList = `${deviceList}\n${id.Adapter}: ${id.Device} (${id.LastContact})`;
1891
- }
2631
+ if (this.blacklistNotify.includes(id.Path)) continue;
2632
+ if (!this.config.showAdapterNameinMsg) {
2633
+ list = `${list}\n${id.Device} (${id.LastContact})`;
2634
+ } else {
2635
+ list = `${list}\n${id.Adapter}: ${id.Device} (${id.LastContact})`;
1892
2636
  }
1893
2637
  }
1894
2638
 
1895
- if (deviceList.length > 0) {
1896
- this.log.info(`Geräte Offline: ${deviceList}`);
1897
- this.setStateAsync('lastNotification', `Geräte Offline: ${deviceList}`, true);
1898
-
1899
- this.sendNotification(`Geräte Offline: ${deviceList}`);
1900
- }
1901
- } catch (error) {
1902
- this.errorReporting('[sendOfflineNotificationsShedule]', error);
2639
+ if (list.length === 0) return;
2640
+ message = `Tägliche Meldung über offline Geräte: ${list}`;
2641
+ setMessage(message);
2642
+ });
2643
+ break;
2644
+ case 'updateDevices':
2645
+ // push the selected days in list
2646
+ if (this.config.checkUpgradeMonday) checkDays.push(1);
2647
+ if (this.config.checkUpgradeTuesday) checkDays.push(2);
2648
+ if (this.config.checkUpgradeWednesday) checkDays.push(3);
2649
+ if (this.config.checkUpgradeThursday) checkDays.push(4);
2650
+ if (this.config.checkUpgradeFriday) checkDays.push(5);
2651
+ if (this.config.checkUpgradeSaturday) checkDays.push(6);
2652
+ if (this.config.checkUpgradeSunday) checkDays.push(0);
2653
+
2654
+ time = this.config.checkSendUpgradeTime.split(':');
2655
+
2656
+ if (checkDays.length === 0) {
2657
+ this.log.warn(`No days selected for daily updatable devices message. Please check the instance configuration!`);
2658
+ return; // cancel function if no day is selected
1903
2659
  }
1904
- });
1905
- }
1906
- } //<--End of daily offline notification
1907
-
1908
- /**
1909
- * check if device updates are available and send notification
1910
- * @param {string} deviceName
1911
- * @param {string} adapter
1912
- **/
1913
- async sendDeviceUpdatesNotification(deviceName, adapter) {
1914
- this.log.debug(`Start the function: ${this.sendDeviceUpdatesNotification.name}`);
1915
-
1916
- try {
1917
- let msg = '';
1918
- let deviceList = '';
1919
-
1920
- if (!this.config.showAdapterNameinMsg) {
1921
- deviceList = `${deviceList}\n${deviceName}`;
1922
- } else {
1923
- deviceList = `${deviceList}\n${adapter}: ${deviceName}`;
1924
- }
1925
-
1926
- msg = `Neue Geräte Updates vorhanden: \n`;
1927
-
1928
- this.log.info(msg + deviceList);
1929
- await this.setStateAsync('lastNotification', msg + deviceList, true);
1930
- await this.sendNotification(msg + deviceList);
1931
- } catch (error) {
1932
- this.errorReporting('[sendDeviceUpdatesNotification]', error);
1933
- }
1934
- this.log.debug(`Finished the function: ${this.sendDeviceUpdatesNotification.name}`);
1935
- }
1936
-
1937
- /**
1938
- * send shedule message with offline devices
1939
- */
1940
- async sendUpgradeNotificationsShedule() {
1941
- const time = this.config.checkSendUpgradeTime.split(':');
1942
-
1943
- const checkDays = []; // list of selected days
1944
-
1945
- // push the selected days in list
1946
- if (this.config.checkUpgradeMonday) checkDays.push(1);
1947
- if (this.config.checkUpgradeTuesday) checkDays.push(2);
1948
- if (this.config.checkUpgradeWednesday) checkDays.push(3);
1949
- if (this.config.checkUpgradeThursday) checkDays.push(4);
1950
- if (this.config.checkUpgradeFriday) checkDays.push(5);
1951
- if (this.config.checkUpgradeSaturday) checkDays.push(6);
1952
- if (this.config.checkUpgradeSunday) checkDays.push(0);
1953
-
1954
- if (checkDays.length >= 1) {
1955
- // check if an day is selected
1956
- this.log.debug(`Number of selected days for daily Upgrade message: ${checkDays.length}. Send Message on: ${checkDays.join(', ')} ...`);
1957
- } else {
1958
- this.log.warn(`No days selected for daily Upgrade message. Please check the instance configuration!`);
1959
- return; // cancel function if no day is selected
1960
- }
2660
+ this.log.debug(`Number of selected days for daily updatable devices message: ${checkDays.length}. Send Message on: ${checkDays.join(', ')} ...`);
1961
2661
 
1962
- if (!isUnloaded) {
1963
- const cron = '10 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
1964
- schedule.scheduleJob(cron, () => {
1965
- try {
1966
- let deviceList = '';
2662
+ cron = '3 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
2663
+ schedule.scheduleJob(cron, () => {
2664
+ list = '';
1967
2665
 
1968
2666
  for (const id of this.upgradableDevicesRaw) {
1969
- if (!this.blacklistNotify.includes(id.Path)) {
1970
- if (!this.config.showAdapterNameinMsg) {
1971
- deviceList = `${deviceList}\n${id.Device}`;
1972
- } else {
1973
- deviceList = `${deviceList}\n${id.Adapter}: ${id.Device}`;
1974
- }
2667
+ if (this.blacklistNotify.includes(id.Path)) continue;
2668
+ if (!this.config.showAdapterNameinMsg) {
2669
+ list = `${list}\n${id.Device}`;
2670
+ } else {
2671
+ list = `${list}\n${id.Adapter}: ${id.Device}`;
1975
2672
  }
1976
2673
  }
1977
- if (deviceList.length > 0) {
1978
- this.log.info(`Geräte Upgrade: ${deviceList}`);
1979
- this.setStateAsync('lastNotification', `Geräte Upgrade: ${deviceList}`, true);
2674
+ if (list.length === 0) return;
2675
+ message = `Tägliche Meldung über verfügbare Geräte Updates: ${list}`;
2676
+ setMessage(message);
2677
+ });
2678
+ break;
2679
+ case 'updateAdapter':
2680
+ // push the selected days in list
2681
+ if (this.config.checkAdapterUpdateMonday) checkDays.push(1);
2682
+ if (this.config.checkAdapterUpdateTuesday) checkDays.push(2);
2683
+ if (this.config.checkAdapterUpdateWednesday) checkDays.push(3);
2684
+ if (this.config.checkAdapterUpdateThursday) checkDays.push(4);
2685
+ if (this.config.checkAdapterUpdateFriday) checkDays.push(5);
2686
+ if (this.config.checkAdapterUpdateSaturday) checkDays.push(6);
2687
+ if (this.config.checkAdapterUpdateSunday) checkDays.push(0);
2688
+
2689
+ time = this.config.checkSendAdapterUpdateTime.split(':');
2690
+
2691
+ if (checkDays.length === 0) {
2692
+ this.log.warn(`No days selected for daily adapter update message. Please check the instance configuration!`);
2693
+ return; // cancel function if no day is selected
2694
+ }
2695
+ this.log.debug(`Number of selected days for daily adapter update message: ${checkDays.length}. Send Message on: ${checkDays.join(', ')} ...`);
2696
+
2697
+ cron = '4 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
2698
+ schedule.scheduleJob(cron, () => {
2699
+ list = '';
1980
2700
 
1981
- this.sendNotification(`Geräte Upgrade:\n${deviceList}`);
2701
+ for (const id of this.listAdapterUpdates) {
2702
+ list = `${list}\n${id.Adapter}: v${id['Available Version']}`;
1982
2703
  }
1983
- } catch (error) {
1984
- this.errorReporting('[sendUpgradeNotificationsShedule]', error);
2704
+ if (list.length === 0) return;
2705
+ message = `Tägliche Meldung über verfügbare Adapter Updates: ${list}`;
2706
+ setMessage(message);
2707
+ });
2708
+ break;
2709
+ case 'errorInstance':
2710
+ // push the selected days in list
2711
+ if (this.config.checkFailedInstancesMonday) checkDays.push(1);
2712
+ if (this.config.checkFailedInstancesTuesday) checkDays.push(2);
2713
+ if (this.config.checkFailedInstancesWednesday) checkDays.push(3);
2714
+ if (this.config.checkFailedInstancesThursday) checkDays.push(4);
2715
+ if (this.config.checkFailedInstancesFriday) checkDays.push(5);
2716
+ if (this.config.checkFailedInstancesSaturday) checkDays.push(6);
2717
+ if (this.config.checkFailedInstancesSunday) checkDays.push(0);
2718
+
2719
+ time = this.config.checkSendInstanceFailedTime.split(':');
2720
+
2721
+ if (checkDays.length === 0) {
2722
+ this.log.warn(`No days selected for daily instance error message. Please check the instance configuration!`);
2723
+ return; // cancel function if no day is selected
1985
2724
  }
1986
- });
2725
+ this.log.debug(`Number of selected days for daily instance error message: ${checkDays.length}. Send Message on: ${checkDays.join(', ')} ...`);
2726
+ cron = '5 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
2727
+ schedule.scheduleJob(cron, () => {
2728
+ list = '';
2729
+
2730
+ for (const id of this.listErrorInstanceRaw) {
2731
+ if (this.blacklistInstancesNotify.includes(id.instanceAlivePath)) continue;
2732
+ list = `${list}\n${id.Instance}: ${id.Status}`;
2733
+ }
2734
+ if (list.length === 0) return;
2735
+ message = `Tägliche Meldung über fehlerhafte Instanzen: ${list}`;
2736
+ setMessage(message);
2737
+ });
2738
+ break;
1987
2739
  }
1988
- } //<--End of daily offline notification
2740
+ }
1989
2741
 
1990
2742
  /*=============================================
1991
2743
  = functions to create html lists =
1992
2744
  =============================================*/
1993
-
1994
2745
  /**
2746
+ * @param {string} type - type of list
1995
2747
  * @param {object} devices - Device
1996
2748
  * @param {number} deviceCount - Counted devices
2749
+ * @param {object} isLowBatteryList - list Low Battery Devices
1997
2750
  */
1998
- async creatLinkQualityListHTML(devices, deviceCount) {
1999
- devices = devices.sort((a, b) => {
2000
- a = a.Device || '';
2001
- b = b.Device || '';
2002
- return a.localeCompare(b);
2003
- });
2004
- let html = `<center>
2005
- <b>Link Quality Devices:<font> ${deviceCount}</b><small></small></font>
2006
- <p></p>
2007
- </center>
2008
- <table width=100%>
2009
- <tr>
2010
- <th align=left>Device</th>
2011
- <th align=center width=120>Adapter</th>
2012
- <th align=right>Link Quality</th>
2013
- </tr>
2014
- <tr>
2015
- <td colspan="5"><hr></td>
2016
- </tr>`;
2017
-
2018
- for (const device of devices) {
2019
- html += `<tr>
2020
- <td><font>${device.Device}</font></td>
2021
- <td align=center><font>${device.Adapter}</font></td>
2022
- <td align=right><font>${device['Signal strength']}</font></td>
2751
+ async createListHTML(type, devices, deviceCount, isLowBatteryList) {
2752
+ let html;
2753
+ switch (type) {
2754
+ case 'linkQualityList':
2755
+ devices = devices.sort((a, b) => {
2756
+ a = a.Device || '';
2757
+ b = b.Device || '';
2758
+ return a.localeCompare(b);
2759
+ });
2760
+ html = `<center>
2761
+ <b>Link Quality Devices:<font> ${deviceCount}</b><small></small></font>
2762
+ <p></p>
2763
+ </center>
2764
+ <table width=100%>
2765
+ <tr>
2766
+ <th align=left>Device</th>
2767
+ <th align=center width=120>Adapter</th>
2768
+ <th align=right>Link Quality</th>
2769
+ </tr>
2770
+ <tr>
2771
+ <td colspan="5"><hr></td>
2023
2772
  </tr>`;
2024
- }
2025
2773
 
2026
- html += '</table>';
2027
- return html;
2028
- }
2774
+ for (const device of devices) {
2775
+ html += `<tr>
2776
+ <td><font>${device.Device}</font></td>
2777
+ <td align=center><font>${device.Adapter}</font></td>
2778
+ <td align=right><font>${device['Signal strength']}</font></td>
2779
+ </tr>`;
2780
+ }
2029
2781
 
2030
- /**
2031
- * @param {object} devices - Device
2032
- * @param {number} deviceCount - Counted devices
2033
- */
2034
- async createOfflineListHTML(devices, deviceCount) {
2035
- devices = devices.sort((a, b) => {
2036
- a = a.Device || '';
2037
- b = b.Device || '';
2038
- return a.localeCompare(b);
2039
- });
2040
- let html = `<center>
2041
- <b>Offline Devices: <font color=${deviceCount === 0 ? '#3bcf0e' : 'orange'}>${deviceCount}</b><small></small></font>
2042
- <p></p>
2043
- </center>
2044
- <table width=100%>
2045
- <tr>
2046
- <th align=left>Device</th>
2047
- <th align=center width=120>Adapter</th>
2048
- <th align=center>Letzter Kontakt</th>
2049
- </tr>
2050
- <tr>
2051
- <td colspan="5"><hr></td>
2052
- </tr>`;
2053
-
2054
- for (const device of devices) {
2055
- html += `<tr>
2056
- <td><font>${device.Device}</font></td>
2057
- <td align=center><font>${device.Adapter}</font></td>
2058
- <td align=center><font color=orange>${device['Last contact']}</font></td>
2782
+ html += '</table>';
2783
+ break;
2784
+
2785
+ case 'offlineList':
2786
+ devices = devices.sort((a, b) => {
2787
+ a = a.Device || '';
2788
+ b = b.Device || '';
2789
+ return a.localeCompare(b);
2790
+ });
2791
+ html = `<center>
2792
+ <b>Offline Devices: <font color=${deviceCount === 0 ? '#3bcf0e' : 'orange'}>${deviceCount}</b><small></small></font>
2793
+ <p></p>
2794
+ </center>
2795
+ <table width=100%>
2796
+ <tr>
2797
+ <th align=left>Device</th>
2798
+ <th align=center width=120>Adapter</th>
2799
+ <th align=center>Letzter Kontakt</th>
2800
+ </tr>
2801
+ <tr>
2802
+ <td colspan="5"><hr></td>
2059
2803
  </tr>`;
2060
- }
2061
2804
 
2062
- html += '</table>';
2063
- return html;
2064
- }
2805
+ for (const device of devices) {
2806
+ html += `<tr>
2807
+ <td><font>${device.Device}</font></td>
2808
+ <td align=center><font>${device.Adapter}</font></td>
2809
+ <td align=center><font color=orange>${device['Last contact']}</font></td>
2810
+ </tr>`;
2811
+ }
2065
2812
 
2066
- /**
2067
- * @param {object} [devices] - Device
2068
- * @param {object} [deviceCount] - Counted devices
2069
- * @param {object} [isLowBatteryList] - list Low Battery Devices
2070
- */
2071
- async createBatteryListHTML(devices, deviceCount, isLowBatteryList) {
2072
- devices = devices.sort((a, b) => {
2073
- a = a.Device || '';
2074
- b = b.Device || '';
2075
- return a.localeCompare(b);
2076
- });
2077
- let html = `<center>
2078
- <b>${isLowBatteryList === true ? 'Schwache ' : ''}Batterie Devices: <font color=${isLowBatteryList === true ? (deviceCount > 0 ? 'orange' : '#3bcf0e') : ''}>${deviceCount}</b></font>
2079
- <p></p>
2080
- </center>
2081
- <table width=100%>
2082
- <tr>
2083
- <th align=left>Device</th>
2084
- <th align=center width=120>Adapter</th>
2085
- <th align=${isLowBatteryList ? 'center' : 'right'}>Batterie</th>
2086
- </tr>
2087
- <tr>
2088
- <td colspan="5"><hr></td>
2089
- </tr>`;
2090
- for (const device of devices) {
2091
- html += `<tr>
2092
- <td><font>${device.Device}</font></td>
2093
- <td align=center><font>${device.Adapter}</font></td>`;
2094
-
2095
- if (isLowBatteryList) {
2096
- html += `<td align=center><font color=orange>${device.Battery}</font></td>`;
2097
- } else {
2098
- html += `<td align=right><font color=#3bcf0e>${device.Battery}</font></td>`;
2099
- }
2100
- html += `</tr>`;
2101
- }
2813
+ html += '</table>';
2814
+ break;
2102
2815
 
2103
- html += '</table>';
2816
+ case 'batteryList':
2817
+ devices = devices.sort((a, b) => {
2818
+ a = a.Device || '';
2819
+ b = b.Device || '';
2820
+ return a.localeCompare(b);
2821
+ });
2822
+ html = `<center>
2823
+ <b>${isLowBatteryList === true ? 'Schwache ' : ''}Batterie Devices: <font color=${isLowBatteryList === true ? (deviceCount > 0 ? 'orange' : '#3bcf0e') : ''}>${deviceCount}</b></font>
2824
+ <p></p>
2825
+ </center>
2826
+ <table width=100%>
2827
+ <tr>
2828
+ <th align=left>Device</th>
2829
+ <th align=center width=120>Adapter</th>
2830
+ <th align=${isLowBatteryList ? 'center' : 'right'}>Batterie</th>
2831
+ </tr>
2832
+ <tr>
2833
+ <td colspan="5"><hr></td>
2834
+ </tr>`;
2835
+ for (const device of devices) {
2836
+ html += `<tr>
2837
+ <td><font>${device.Device}</font></td>
2838
+ <td align=center><font>${device.Adapter}</font></td>`;
2839
+
2840
+ if (isLowBatteryList) {
2841
+ html += `<td align=center><font color=orange>${device.Battery}</font></td>`;
2842
+ } else {
2843
+ html += `<td align=right><font color=#3bcf0e>${device.Battery}</font></td>`;
2844
+ }
2845
+ html += `</tr>`;
2846
+ }
2847
+
2848
+ html += '</table>';
2849
+ break;
2850
+ }
2104
2851
  return html;
2105
2852
  }
2106
2853
 
@@ -2112,7 +2859,7 @@ class DeviceWatcher extends utils.Adapter {
2112
2859
  * @param {object} adptName - Adaptername of devices
2113
2860
  */
2114
2861
  async createDPsForEachAdapter(adptName) {
2115
- await this.setObjectNotExistsAsync(`${adptName}`, {
2862
+ await this.setObjectNotExistsAsync(`devices.${adptName}`, {
2116
2863
  type: 'channel',
2117
2864
  common: {
2118
2865
  name: adptName,
@@ -2120,7 +2867,7 @@ class DeviceWatcher extends utils.Adapter {
2120
2867
  native: {},
2121
2868
  });
2122
2869
 
2123
- await this.setObjectNotExistsAsync(`${adptName}.offlineCount`, {
2870
+ await this.setObjectNotExistsAsync(`devices.${adptName}.offlineCount`, {
2124
2871
  type: 'state',
2125
2872
  common: {
2126
2873
  name: {
@@ -2143,7 +2890,7 @@ class DeviceWatcher extends utils.Adapter {
2143
2890
  native: {},
2144
2891
  });
2145
2892
 
2146
- await this.setObjectNotExistsAsync(`${adptName}.offlineList`, {
2893
+ await this.setObjectNotExistsAsync(`devices.${adptName}.offlineList`, {
2147
2894
  type: 'state',
2148
2895
  common: {
2149
2896
  name: {
@@ -2166,7 +2913,7 @@ class DeviceWatcher extends utils.Adapter {
2166
2913
  native: {},
2167
2914
  });
2168
2915
 
2169
- await this.setObjectNotExistsAsync(`${adptName}.oneDeviceOffline`, {
2916
+ await this.setObjectNotExistsAsync(`devices.${adptName}.oneDeviceOffline`, {
2170
2917
  type: 'state',
2171
2918
  common: {
2172
2919
  name: {
@@ -2191,7 +2938,7 @@ class DeviceWatcher extends utils.Adapter {
2191
2938
  native: {},
2192
2939
  });
2193
2940
 
2194
- await this.setObjectNotExistsAsync(`${adptName}.listAll`, {
2941
+ await this.setObjectNotExistsAsync(`devices.${adptName}.listAll`, {
2195
2942
  type: 'state',
2196
2943
  common: {
2197
2944
  name: {
@@ -2214,7 +2961,7 @@ class DeviceWatcher extends utils.Adapter {
2214
2961
  native: {},
2215
2962
  });
2216
2963
 
2217
- await this.setObjectNotExistsAsync(`${adptName}.linkQualityList`, {
2964
+ await this.setObjectNotExistsAsync(`devices.${adptName}.linkQualityList`, {
2218
2965
  type: 'state',
2219
2966
  common: {
2220
2967
  name: {
@@ -2237,7 +2984,7 @@ class DeviceWatcher extends utils.Adapter {
2237
2984
  native: {},
2238
2985
  });
2239
2986
 
2240
- await this.setObjectNotExistsAsync(`${adptName}.countAll`, {
2987
+ await this.setObjectNotExistsAsync(`devices.${adptName}.countAll`, {
2241
2988
  type: 'state',
2242
2989
  common: {
2243
2990
  name: {
@@ -2260,7 +3007,7 @@ class DeviceWatcher extends utils.Adapter {
2260
3007
  native: {},
2261
3008
  });
2262
3009
 
2263
- await this.setObjectNotExistsAsync(`${adptName}.batteryList`, {
3010
+ await this.setObjectNotExistsAsync(`devices.${adptName}.batteryList`, {
2264
3011
  type: 'state',
2265
3012
  common: {
2266
3013
  name: {
@@ -2283,7 +3030,7 @@ class DeviceWatcher extends utils.Adapter {
2283
3030
  native: {},
2284
3031
  });
2285
3032
 
2286
- await this.setObjectNotExistsAsync(`${adptName}.lowBatteryList`, {
3033
+ await this.setObjectNotExistsAsync(`devices.${adptName}.lowBatteryList`, {
2287
3034
  type: 'state',
2288
3035
  common: {
2289
3036
  name: {
@@ -2306,7 +3053,7 @@ class DeviceWatcher extends utils.Adapter {
2306
3053
  native: {},
2307
3054
  });
2308
3055
 
2309
- await this.setObjectNotExistsAsync(`${adptName}.lowBatteryCount`, {
3056
+ await this.setObjectNotExistsAsync(`devices.${adptName}.lowBatteryCount`, {
2310
3057
  type: 'state',
2311
3058
  common: {
2312
3059
  name: {
@@ -2329,7 +3076,7 @@ class DeviceWatcher extends utils.Adapter {
2329
3076
  native: {},
2330
3077
  });
2331
3078
 
2332
- await this.setObjectNotExistsAsync(`${adptName}.oneDeviceLowBat`, {
3079
+ await this.setObjectNotExistsAsync(`devices.${adptName}.oneDeviceLowBat`, {
2333
3080
  type: 'state',
2334
3081
  common: {
2335
3082
  name: {
@@ -2354,7 +3101,7 @@ class DeviceWatcher extends utils.Adapter {
2354
3101
  native: {},
2355
3102
  });
2356
3103
 
2357
- await this.setObjectNotExistsAsync(`${adptName}.batteryCount`, {
3104
+ await this.setObjectNotExistsAsync(`devices.${adptName}.batteryCount`, {
2358
3105
  type: 'state',
2359
3106
  common: {
2360
3107
  name: {
@@ -2377,7 +3124,7 @@ class DeviceWatcher extends utils.Adapter {
2377
3124
  native: {},
2378
3125
  });
2379
3126
 
2380
- await this.setObjectNotExistsAsync(`${adptName}.upgradableCount`, {
3127
+ await this.setObjectNotExistsAsync(`devices.${adptName}.upgradableCount`, {
2381
3128
  type: 'state',
2382
3129
  common: {
2383
3130
  name: {
@@ -2401,7 +3148,7 @@ class DeviceWatcher extends utils.Adapter {
2401
3148
  native: {},
2402
3149
  });
2403
3150
 
2404
- await this.setObjectNotExistsAsync(`${adptName}.upgradableList`, {
3151
+ await this.setObjectNotExistsAsync(`devices.${adptName}.upgradableList`, {
2405
3152
  type: 'state',
2406
3153
  common: {
2407
3154
  name: {
@@ -2425,7 +3172,7 @@ class DeviceWatcher extends utils.Adapter {
2425
3172
  native: {},
2426
3173
  });
2427
3174
 
2428
- await this.setObjectNotExistsAsync(`${adptName}.oneDeviceUpdatable`, {
3175
+ await this.setObjectNotExistsAsync(`devices.${adptName}.oneDeviceUpdatable`, {
2429
3176
  type: 'state',
2430
3177
  common: {
2431
3178
  name: {
@@ -2452,6 +3199,29 @@ class DeviceWatcher extends utils.Adapter {
2452
3199
  }
2453
3200
 
2454
3201
  /**
3202
+ * delete datapoints for each adapter
3203
+ * @param {object} adptName - Adaptername of devices
3204
+ */
3205
+ async deleteDPsForEachAdapter(adptName) {
3206
+ await this.delObjectAsync(`devices.${adptName}`);
3207
+ await this.delObjectAsync(`devices.${adptName}.offlineCount`);
3208
+ await this.delObjectAsync(`devices.${adptName}.offlineList`);
3209
+ await this.delObjectAsync(`devices.${adptName}.oneDeviceOffline`);
3210
+ await this.delObjectAsync(`devices.${adptName}.listAll`);
3211
+ await this.delObjectAsync(`devices.${adptName}.linkQualityList`);
3212
+ await this.delObjectAsync(`devices.${adptName}.countAll`);
3213
+ await this.delObjectAsync(`devices.${adptName}.batteryList`);
3214
+ await this.delObjectAsync(`devices.${adptName}.lowBatteryList`);
3215
+ await this.delObjectAsync(`devices.${adptName}.lowBatteryCount`);
3216
+ await this.delObjectAsync(`devices.${adptName}.oneDeviceLowBat`);
3217
+ await this.delObjectAsync(`devices.${adptName}.batteryCount`);
3218
+ await this.delObjectAsync(`devices.${adptName}.upgradableCount`);
3219
+ await this.delObjectAsync(`devices.${adptName}.upgradableList`);
3220
+ await this.delObjectAsync(`devices.${adptName}.oneDeviceUpdatable`);
3221
+ }
3222
+
3223
+ /**
3224
+ * create HTML list datapoints
2455
3225
  * @param {object} [adptName] - Adaptername of devices
2456
3226
  **/
2457
3227
  async createHtmlListDatapoints(adptName) {
@@ -2463,7 +3233,7 @@ class DeviceWatcher extends utils.Adapter {
2463
3233
  dpSubFolder = '';
2464
3234
  }
2465
3235
 
2466
- await this.setObjectNotExistsAsync(`${dpSubFolder}offlineListHTML`, {
3236
+ await this.setObjectNotExistsAsync(`devices.${dpSubFolder}offlineListHTML`, {
2467
3237
  type: 'state',
2468
3238
  common: {
2469
3239
  name: {
@@ -2486,7 +3256,7 @@ class DeviceWatcher extends utils.Adapter {
2486
3256
  native: {},
2487
3257
  });
2488
3258
 
2489
- await this.setObjectNotExistsAsync(`${dpSubFolder}linkQualityListHTML`, {
3259
+ await this.setObjectNotExistsAsync(`devices.${dpSubFolder}linkQualityListHTML`, {
2490
3260
  type: 'state',
2491
3261
  common: {
2492
3262
  name: {
@@ -2509,7 +3279,7 @@ class DeviceWatcher extends utils.Adapter {
2509
3279
  native: {},
2510
3280
  });
2511
3281
 
2512
- await this.setObjectNotExistsAsync(`${dpSubFolder}batteryListHTML`, {
3282
+ await this.setObjectNotExistsAsync(`devices.${dpSubFolder}batteryListHTML`, {
2513
3283
  type: 'state',
2514
3284
  common: {
2515
3285
  name: {
@@ -2532,7 +3302,7 @@ class DeviceWatcher extends utils.Adapter {
2532
3302
  native: {},
2533
3303
  });
2534
3304
 
2535
- await this.setObjectNotExistsAsync(`${dpSubFolder}lowBatteryListHTML`, {
3305
+ await this.setObjectNotExistsAsync(`devices.${dpSubFolder}lowBatteryListHTML`, {
2536
3306
  type: 'state',
2537
3307
  common: {
2538
3308
  name: {
@@ -2556,6 +3326,25 @@ class DeviceWatcher extends utils.Adapter {
2556
3326
  });
2557
3327
  }
2558
3328
 
3329
+ /**
3330
+ * delete html datapoints
3331
+ * @param {object} [adptName] - Adaptername of devices
3332
+ **/
3333
+ async deleteHtmlListDatapoints(adptName) {
3334
+ // delete the datapoints in subfolders with the adaptername otherwise delete the dP's in the root folder
3335
+ let dpSubFolder;
3336
+ if (adptName) {
3337
+ dpSubFolder = `${adptName}.`;
3338
+ } else {
3339
+ dpSubFolder = '';
3340
+ }
3341
+
3342
+ await this.delObjectAsync(`devices.${dpSubFolder}offlineListHTML`);
3343
+ await this.delObjectAsync(`devices.${dpSubFolder}linkQualityListHTML`);
3344
+ await this.delObjectAsync(`devices.${dpSubFolder}batteryListHTML`);
3345
+ await this.delObjectAsync(`devices.${dpSubFolder}lowBatteryListHTML`);
3346
+ }
3347
+
2559
3348
  /*=============================================
2560
3349
  = help functions =
2561
3350
  =============================================*/
@@ -2571,20 +3360,27 @@ class DeviceWatcher extends utils.Adapter {
2571
3360
  /**
2572
3361
  * @param {number} dpValue - get Time of this datapoint
2573
3362
  */
2574
- async getTimestamp(dpValue) {
3363
+ getTimestamp(dpValue) {
2575
3364
  const time = new Date();
2576
3365
  return (dpValue = Math.round((time.getTime() - dpValue) / 1000 / 60));
2577
3366
  }
2578
3367
 
2579
3368
  /**
2580
3369
  * @param {string} dp - get Time of this datapoint
3370
+ * @param {number} ms - milliseconds
2581
3371
  */
2582
- async getTimestampConnectionDP(dp) {
3372
+ async getTimestampConnectionDP(dp, ms) {
2583
3373
  const time = new Date();
2584
3374
  const dpValue = await this.getForeignStateAsync(dp);
2585
- if (dpValue !== null && dpValue !== undefined) {
2586
- const dpLastStateChange = Math.round((time.getTime() - dpValue.lc) / 1000);
2587
- return dpLastStateChange;
3375
+ if (dpValue) {
3376
+ if (!dpValue.val) return false;
3377
+
3378
+ const dpLastStateChange = Math.round(time.getTime() - dpValue.lc); // calculate in ms
3379
+ if (dpLastStateChange >= ms) {
3380
+ return true;
3381
+ } else {
3382
+ return false;
3383
+ }
2588
3384
  }
2589
3385
  }
2590
3386
 
@@ -2609,13 +3405,39 @@ class DeviceWatcher extends utils.Adapter {
2609
3405
  /**
2610
3406
  * @param {object} data - object
2611
3407
  */
2612
- async parseData(data) {
3408
+ parseData(data) {
2613
3409
  if (!data) return {};
2614
3410
  if (typeof data === 'object') return data;
2615
3411
  if (typeof data === 'string') return JSON.parse(data);
2616
3412
  return {};
2617
3413
  }
2618
3414
 
3415
+ /**
3416
+ * @param {number} time
3417
+ */
3418
+ wait(time) {
3419
+ return new Promise(function (resolve) {
3420
+ setTimeout(resolve, time);
3421
+ });
3422
+ }
3423
+
3424
+ /**
3425
+ * Get previous run of cron job schedule
3426
+ * Requires cron-parser!
3427
+ * Inspired by https://stackoverflow.com/questions/68134104/
3428
+ * @param {string} lastCronRun
3429
+ */
3430
+ getPreviousCronRun(lastCronRun) {
3431
+ try {
3432
+ const interval = cronParser.parseExpression(lastCronRun);
3433
+ const previous = interval.prev();
3434
+ return Math.floor(Date.now() - previous.getTime()); // in ms
3435
+ } catch (error) {
3436
+ this.log.warn(error);
3437
+ return;
3438
+ }
3439
+ }
3440
+
2619
3441
  /**
2620
3442
  * @param {string} codePart - Message Prefix
2621
3443
  * @param {object} error - Sentry message