iobroker.device-watcher 2.6.1 → 2.7.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
@@ -32,12 +32,14 @@ class DeviceWatcher extends utils.Adapter {
32
32
 
33
33
  // user arrays
34
34
  this.listAllInstances = [];
35
+ this.listAllActiveInstances = [];
35
36
  this.listDeactivatedInstances = [];
36
37
  this.listAdapterUpdates = [];
37
38
  this.listErrorInstance = [];
38
39
 
39
40
  //counts
40
41
  this.countAllInstances = 0;
42
+ this.countAllActiveInstances = 0;
41
43
  this.countDeactivatedInstances = 0;
42
44
  this.countAdapterUpdates = 0;
43
45
  this.countErrorInstance = 0;
@@ -78,6 +80,9 @@ class DeviceWatcher extends utils.Adapter {
78
80
  this.blacklistAdapterLists = [];
79
81
  this.blacklistNotify = [];
80
82
 
83
+ // Timelist instances
84
+ this.userTimeInstancesList = new Map();
85
+
81
86
  // Interval timer
82
87
  this.refreshDataTimeout = null;
83
88
 
@@ -110,6 +115,7 @@ class DeviceWatcher extends utils.Adapter {
110
115
  fhemTFAsensors: this.config.fhemTFAsensorsDevices,
111
116
  fritzdect: this.config.fritzdectDevices,
112
117
  fullybrowser: this.config.fullybrowserDevices,
118
+ fullyMQTT: this.config.fullyMQTTDevices,
113
119
  ham: this.config.hamDevices,
114
120
  harmony: this.config.harmonyDevices,
115
121
  hmiP: this.config.hmiPDevices,
@@ -163,6 +169,7 @@ class DeviceWatcher extends utils.Adapter {
163
169
  fhemTFAsensors: this.config.fhemTFAsensorsMaxMinutes,
164
170
  fritzdect: this.config.fritzdectMaxMinutes,
165
171
  fullybrowser: this.config.fullybrowserMaxMinutes,
172
+ fullyMQTT: this.config.fullyMQTTMaxMinutes,
166
173
  ham: this.config.hamMaxMinutes,
167
174
  harmony: this.config.harmonyMaxMinutes,
168
175
  hmiP: this.config.hmiPMaxMinutes,
@@ -227,6 +234,9 @@ class DeviceWatcher extends utils.Adapter {
227
234
  //create Blacklist
228
235
  await this.createBlacklist();
229
236
 
237
+ // create user defined list with time of error for instances
238
+ await this.createTimeListInstances();
239
+
230
240
  //create datapoints for each adapter if selected
231
241
  for (const [id] of Object.entries(arrApart)) {
232
242
  try {
@@ -253,9 +263,12 @@ class DeviceWatcher extends utils.Adapter {
253
263
  // create HTML list datapoints
254
264
  if (!this.configCreateHtmlList) {
255
265
  await this.deleteHtmlListDatapoints();
266
+ await this.deleteHtmlListDatapointsInstances();
256
267
  } else {
257
268
  await this.createHtmlListDatapoints();
269
+ if (this.config.checkAdapterInstances) await this.createHtmlListDatapointsInstances();
258
270
  }
271
+ if (!this.config.checkAdapterInstances) await this.deleteHtmlListDatapointsInstances();
259
272
 
260
273
  // read data first at start
261
274
  // devices
@@ -361,12 +374,14 @@ class DeviceWatcher extends utils.Adapter {
361
374
  let instanceStatusRaw;
362
375
  let oldInstanceHostState;
363
376
  let oldInstanceDeviceState;
377
+ let oldAdapterUpdatesCounts;
364
378
 
365
379
  try {
366
380
  if (id.endsWith('updatesJson')) {
381
+ oldAdapterUpdatesCounts = this.countAdapterUpdates;
367
382
  await this.getAdapterUpdateData(id);
368
383
  await this.createAdapterUpdateList();
369
- if (this.config.checkSendAdapterUpdateMsg) {
384
+ if (this.config.checkSendAdapterUpdateMsg && this.countAdapterUpdates > oldAdapterUpdatesCounts) {
370
385
  await this.sendStateNotifications('updateAdapter', null);
371
386
  }
372
387
  for (const instance of this.listInstanceRaw.values()) {
@@ -457,7 +472,7 @@ class DeviceWatcher extends utils.Adapter {
457
472
  case deviceData.UpdateDP:
458
473
  if (state.val !== deviceData.Upgradable) {
459
474
  deviceData.Upgradable = state.val;
460
- if (state.val) {
475
+ if (state.val === true || state.val === 1) {
461
476
  if (this.config.checkSendDeviceUpgrade && !this.blacklistNotify.includes(deviceData.Path)) {
462
477
  await this.sendStateNotifications('updateDevice', device);
463
478
  }
@@ -574,6 +589,7 @@ class DeviceWatcher extends utils.Adapter {
574
589
  onMessage(obj) {
575
590
  const devices = [];
576
591
  const instances = [];
592
+ const instancesTime = [];
577
593
  let countDevices = 0;
578
594
  let countInstances = 0;
579
595
 
@@ -601,8 +617,6 @@ class DeviceWatcher extends utils.Adapter {
601
617
  } catch (error) {
602
618
  this.errorReporting('[onMessage - deviceList for blacklisttable]', error);
603
619
  }
604
- } else {
605
- this.sendTo(obj.from, obj.command, obj.callback);
606
620
  }
607
621
  break;
608
622
 
@@ -627,10 +641,33 @@ class DeviceWatcher extends utils.Adapter {
627
641
  });
628
642
  this.sendTo(obj.from, obj.command, sortInstances, obj.callback);
629
643
  } catch (error) {
630
- this.errorReporting('[onMessage - instanceList for blacklisttable]', error);
644
+ this.errorReporting('[onMessage - instanceList]', error);
645
+ }
646
+ }
647
+ break;
648
+ case 'instancesListTime':
649
+ if (obj.message) {
650
+ try {
651
+ for (const instanceData of this.listInstanceRaw.values()) {
652
+ const label = `${instanceData.Adapter}: ${instanceData.InstanceName}`;
653
+ const valueObjectInstances = {
654
+ adapter: instanceData.Adapter,
655
+ instanceName: instanceData.InstanceName,
656
+ path: instanceData.instanceAlivePath,
657
+ };
658
+ instancesTime[countInstances] = { label: label, value: JSON.stringify(valueObjectInstances) };
659
+ countInstances++;
660
+ }
661
+ const sortInstances = instancesTime.slice(0);
662
+ sortInstances.sort(function (a, b) {
663
+ const x = a.label;
664
+ const y = b.label;
665
+ return x < y ? -1 : x > y ? 1 : 0;
666
+ });
667
+ this.sendTo(obj.from, obj.command, sortInstances, obj.callback);
668
+ } catch (error) {
669
+ this.errorReporting('[onMessage - instanceList]', error);
631
670
  }
632
- } else {
633
- this.sendTo(obj.from, obj.command, obj.callback);
634
671
  }
635
672
  break;
636
673
  }
@@ -708,11 +745,11 @@ class DeviceWatcher extends utils.Adapter {
708
745
 
709
746
  // Clear existing timeout
710
747
  if (this.refreshDataTimeout) {
711
- clearTimeout(this.refreshDataTimeout);
748
+ this.clearTimeout(this.refreshDataTimeout);
712
749
  this.refreshDataTimeout = null;
713
750
  }
714
751
 
715
- this.refreshDataTimeout = setTimeout(() => {
752
+ this.refreshDataTimeout = this.setTimeout(() => {
716
753
  this.log.debug('Updating Data');
717
754
  this.refreshData();
718
755
  }, nextTimeout);
@@ -726,55 +763,79 @@ class DeviceWatcher extends utils.Adapter {
726
763
 
727
764
  // DEVICES
728
765
  const myBlacklist = this.config.tableBlacklist;
729
-
730
- for (const i in myBlacklist) {
731
- try {
732
- const blacklistParse = this.parseData(myBlacklist[i].devices);
733
- // push devices in list to ignor device in lists
734
- if (myBlacklist[i].checkIgnorLists) {
735
- this.blacklistLists.push(blacklistParse.path);
736
- }
737
- if (myBlacklist[i].checkIgnorAdapterLists) {
738
- this.blacklistAdapterLists.push(blacklistParse.path);
739
- }
740
- // push devices in list to ignor device in notifications
741
- if (myBlacklist[i].checkIgnorNotify) {
742
- this.blacklistNotify.push(blacklistParse.path);
766
+ if (myBlacklist.length >= 1) {
767
+ for (const i in myBlacklist) {
768
+ try {
769
+ const blacklistParse = this.parseData(myBlacklist[i].devices);
770
+ // push devices in list to ignor device in lists
771
+ if (myBlacklist[i].checkIgnorLists) {
772
+ this.blacklistLists.push(blacklistParse.path);
773
+ }
774
+ if (myBlacklist[i].checkIgnorAdapterLists) {
775
+ this.blacklistAdapterLists.push(blacklistParse.path);
776
+ }
777
+ // push devices in list to ignor device in notifications
778
+ if (myBlacklist[i].checkIgnorNotify) {
779
+ this.blacklistNotify.push(blacklistParse.path);
780
+ }
781
+ } catch (error) {
782
+ this.errorReporting('[createBlacklist]', error);
743
783
  }
744
- } catch (error) {
745
- this.errorReporting('[createBlacklist]', error);
784
+ if (this.blacklistLists.length >= 1) this.log.info(`Found devices/services on blacklist for lists: ${this.blacklistLists}`);
785
+ if (this.blacklistAdapterLists.length >= 1) this.log.info(`Found devices/services on blacklist for lists: ${this.blacklistAdapterLists}`);
786
+ if (this.blacklistNotify.length >= 1) this.log.info(`Found devices/services on blacklist for notifications: ${this.blacklistNotify}`);
746
787
  }
747
788
  }
748
789
 
749
- if (this.blacklistLists.length >= 1) this.log.info(`Found items on blacklist for lists: ${this.blacklistLists}`);
750
- if (this.blacklistAdapterLists.length >= 1) this.log.info(`Found items on blacklist for lists: ${this.blacklistAdapterLists}`);
751
- if (this.blacklistNotify.length >= 1) this.log.info(`Found items on blacklist for notifications: ${this.blacklistNotify}`);
752
-
753
790
  // INSTANCES
754
791
  const myBlacklistInstances = this.config.tableBlacklistInstances;
755
-
756
- for (const i in myBlacklistInstances) {
757
- try {
758
- const blacklistParse = this.parseData(myBlacklistInstances[i].instances);
759
- // push devices in list to ignor device in lists
760
- if (myBlacklistInstances[i].checkIgnorLists) {
761
- this.blacklistInstancesLists.push(blacklistParse.path);
762
- }
763
- // push devices in list to ignor device in notifications
764
- if (myBlacklistInstances[i].checkIgnorNotify) {
765
- this.blacklistInstancesNotify.push(blacklistParse.path);
792
+ if (myBlacklistInstances.length >= 1) {
793
+ for (const i in myBlacklistInstances) {
794
+ try {
795
+ const blacklistParse = this.parseData(myBlacklistInstances[i].instances);
796
+ // push devices in list to ignor device in lists
797
+ if (myBlacklistInstances[i].checkIgnorLists) {
798
+ this.blacklistInstancesLists.push(blacklistParse.path);
799
+ }
800
+ // push devices in list to ignor device in notifications
801
+ if (myBlacklistInstances[i].checkIgnorNotify) {
802
+ this.blacklistInstancesNotify.push(blacklistParse.path);
803
+ }
804
+ } catch (error) {
805
+ this.errorReporting('[createBlacklist]', error);
766
806
  }
767
- } catch (error) {
768
- this.errorReporting('[createBlacklist]', error);
769
807
  }
808
+ if (this.blacklistInstancesLists.length >= 1) this.log.info(`Found instances items on blacklist for lists: ${this.blacklistInstancesLists}`);
809
+ if (this.blacklistInstancesNotify.length >= 1) this.log.info(`Found instances items on blacklist for notifications: ${this.blacklistInstancesNotify}`);
770
810
  }
771
-
772
- if (this.blacklistInstancesLists.length >= 1) this.log.info(`Found items on blacklist for lists: ${this.blacklistInstancesLists}`);
773
- if (this.blacklistInstancesNotify.length >= 1) this.log.info(`Found items on blacklist for notifications: ${this.blacklistInstancesNotify}`);
774
-
775
811
  this.log.debug(`Function finished: ${this.createBlacklist.name}`);
776
812
  }
777
813
 
814
+ /**
815
+ * create list with time for instances
816
+ */
817
+ async createTimeListInstances() {
818
+ // INSTANCES
819
+ const userTimeListInstances = this.config.tableTimeInstance;
820
+ if (userTimeListInstances.length >= 1) {
821
+ for (const i in userTimeListInstances) {
822
+ try {
823
+ const userTimeListparse = this.parseData(userTimeListInstances[i].instancesTime);
824
+ // push devices in list to ignor device in lists
825
+ if (userTimeListInstances[i].errorTime) {
826
+ this.userTimeInstancesList.set(userTimeListparse.path, {
827
+ instanceName: userTimeListparse.instanceName,
828
+ errorTime: userTimeListInstances[i].errorTime,
829
+ });
830
+ }
831
+ } catch (error) {
832
+ this.errorReporting('[createTimeListInstances]', error);
833
+ }
834
+ }
835
+ if (this.userTimeInstancesList.size >= 1) this.log.info(`Found instances items on lists for timesettings: ${this.blacklistInstancesLists}`);
836
+ }
837
+ }
838
+
778
839
  /**
779
840
  * @param {object} i - Device Object
780
841
  */
@@ -789,6 +850,8 @@ class DeviceWatcher extends utils.Adapter {
789
850
  = get Instanz =
790
851
  =============================================*/
791
852
  const instance = id.slice(0, id.indexOf('.') + 2);
853
+ if (id.endsWith('.')) continue; // ! Test - sometimes id's are wrong or has no name so break up here.
854
+
792
855
  const instanceDeviceConnectionDP = `${instance}.info.connection`;
793
856
  const instancedeviceConnected = await this.getInitValue(instanceDeviceConnectionDP);
794
857
  this.subscribeForeignStates(instanceDeviceConnectionDP);
@@ -1032,11 +1095,13 @@ class DeviceWatcher extends utils.Adapter {
1032
1095
  * @param {object} i - each Device
1033
1096
  */
1034
1097
  async getDeviceName(id, i) {
1035
- const currDeviceString = id.slice(0, id.lastIndexOf('.') + 1 - 1);
1036
- const shortCurrDeviceString = currDeviceString.slice(0, currDeviceString.lastIndexOf('.') + 1 - 1);
1037
- const shortshortCurrDeviceString = shortCurrDeviceString.slice(0, shortCurrDeviceString.lastIndexOf('.') + 1 - 1);
1038
-
1039
1098
  try {
1099
+ //id = id.replace(/[\]\\[.*,;'"`<>\\\s?]/g, '-');
1100
+
1101
+ const currDeviceString = id.slice(0, id.lastIndexOf('.') + 1 - 1);
1102
+ const shortCurrDeviceString = currDeviceString.slice(0, currDeviceString.lastIndexOf('.') + 1 - 1);
1103
+ const shortshortCurrDeviceString = shortCurrDeviceString.slice(0, shortCurrDeviceString.lastIndexOf('.') + 1 - 1);
1104
+
1040
1105
  // Get device name
1041
1106
  const deviceObject = await this.getForeignObjectAsync(currDeviceString);
1042
1107
  const shortDeviceObject = await this.getForeignObjectAsync(shortCurrDeviceString);
@@ -1339,162 +1404,162 @@ class DeviceWatcher extends utils.Adapter {
1339
1404
 
1340
1405
  try {
1341
1406
  const deviceTimeSelector = await this.getForeignStateAsync(timeSelector);
1342
- if (deviceTimeSelector) {
1343
- const deviceUnreachSelector = await this.getForeignStateAsync(unreachDP);
1344
- const deviceStateSelector = await this.getForeignStateAsync(deviceStateSelectorDP); // for hmrpc devices
1345
- const rssiPeerSelector = await this.getForeignStateAsync(rssiPeerSelectorDP);
1346
- const lastContact = this.getTimestamp(deviceTimeSelector.ts);
1347
- const lastDeviceUnreachStateChange = deviceUnreachSelector != undefined ? this.getTimestamp(deviceUnreachSelector.lc) : this.getTimestamp(timeSelector.ts);
1348
- // If there is no contact since user sets minutes add device in offline list
1349
- // calculate to days after 48 hours
1350
- switch (unreachDP) {
1351
- case 'none':
1352
- lastContactString = await this.getLastContact(deviceTimeSelector.ts);
1353
- break;
1407
+ const deviceUnreachSelector = await this.getForeignStateAsync(unreachDP);
1408
+ const deviceStateSelector = await this.getForeignStateAsync(deviceStateSelectorDP); // for hmrpc devices
1409
+ const rssiPeerSelector = await this.getForeignStateAsync(rssiPeerSelectorDP);
1410
+ const lastDeviceUnreachStateChange = deviceUnreachSelector != undefined ? this.getTimestamp(deviceUnreachSelector.lc) : this.getTimestamp(timeSelector.ts);
1411
+ // If there is no contact since user sets minutes add device in offline list
1412
+ // calculate to days after 48 hours
1413
+ switch (unreachDP) {
1414
+ case 'none':
1415
+ if (deviceTimeSelector) lastContactString = await this.getLastContact(deviceTimeSelector.ts);
1416
+ break;
1354
1417
 
1355
- default:
1356
- //State changed
1357
- if (adapterID === 'hmrpc') {
1358
- if (linkQuality !== ' - ') {
1359
- if (deviceUnreachState === 1) {
1360
- lastContactString = await this.getLastContact(deviceTimeSelector.lc);
1361
- } else {
1362
- lastContactString = await this.getLastContact(deviceTimeSelector.ts);
1363
- }
1364
- } else {
1365
- if (deviceStateSelector) {
1366
- // because old hm devices don't send rssi states
1367
- lastContactString = await this.getLastContact(deviceStateSelector.ts);
1368
- } else if (rssiPeerSelector) {
1369
- // because old hm sensors don't send rssi/state values
1370
- lastContactString = await this.getLastContact(rssiPeerSelector.ts);
1371
- }
1372
- }
1373
- } else {
1374
- if (deviceUnreachState === 0) {
1418
+ default:
1419
+ //State changed
1420
+ if (adapterID === 'hmrpc') {
1421
+ if (linkQuality !== ' - ' && deviceTimeSelector) {
1422
+ if (deviceUnreachState === 1) {
1375
1423
  lastContactString = await this.getLastContact(deviceTimeSelector.lc);
1376
1424
  } else {
1377
1425
  lastContactString = await this.getLastContact(deviceTimeSelector.ts);
1378
1426
  }
1379
- break;
1427
+ } else {
1428
+ if (deviceStateSelector) {
1429
+ // because old hm devices don't send rssi states
1430
+ lastContactString = await this.getLastContact(deviceStateSelector.ts);
1431
+ } else if (rssiPeerSelector) {
1432
+ // because old hm sensors don't send rssi/state values
1433
+ lastContactString = await this.getLastContact(rssiPeerSelector.ts);
1434
+ }
1380
1435
  }
1381
- }
1436
+ } else {
1437
+ if (deviceUnreachState === 0 && deviceTimeSelector) {
1438
+ lastContactString = await this.getLastContact(deviceTimeSelector.lc);
1439
+ } else {
1440
+ if (deviceTimeSelector) lastContactString = await this.getLastContact(deviceTimeSelector.ts);
1441
+ }
1442
+ break;
1443
+ }
1444
+ }
1382
1445
 
1383
- /*=============================================
1446
+ /*=============================================
1384
1447
  = Set Online Status =
1385
1448
  =============================================*/
1386
- if (this.configMaxMinutes !== undefined) {
1387
- switch (adapterID) {
1388
- case 'hmrpc':
1389
- if (this.configMaxMinutes[adapterID] <= 0) {
1390
- if (deviceUnreachState === 1) {
1391
- deviceState = 'Offline'; //set online state to offline
1392
- linkQuality = '0%'; // set linkQuality to nothing
1393
- }
1394
- } else if (lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID] && deviceUnreachState === 1) {
1449
+ let lastContact;
1450
+ if (deviceTimeSelector) lastContact = this.getTimestamp(deviceTimeSelector.ts);
1451
+
1452
+ if (this.configMaxMinutes !== undefined) {
1453
+ switch (adapterID) {
1454
+ case 'hmrpc':
1455
+ if (this.configMaxMinutes[adapterID] <= 0) {
1456
+ if (deviceUnreachState === 1) {
1395
1457
  deviceState = 'Offline'; //set online state to offline
1396
1458
  linkQuality = '0%'; // set linkQuality to nothing
1397
1459
  }
1398
- break;
1399
- case 'proxmox':
1400
- if (this.configMaxMinutes[adapterID] <= 0) {
1401
- if (deviceUnreachState !== 'running' && deviceUnreachState !== 'online') {
1402
- deviceState = 'Offline'; //set online state to offline
1403
- }
1404
- } else if (lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID] && deviceUnreachState !== 'running' && deviceUnreachState !== 'online') {
1460
+ } else if (lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID] && deviceUnreachState === 1) {
1461
+ deviceState = 'Offline'; //set online state to offline
1462
+ linkQuality = '0%'; // set linkQuality to nothing
1463
+ }
1464
+ break;
1465
+ case 'proxmox':
1466
+ if (this.configMaxMinutes[adapterID] <= 0) {
1467
+ if (deviceUnreachState !== 'running' && deviceUnreachState !== 'online') {
1468
+ deviceState = 'Offline'; //set online state to offline
1469
+ }
1470
+ } else if (lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID] && deviceUnreachState !== 'running' && deviceUnreachState !== 'online') {
1471
+ deviceState = 'Offline'; //set online state to offline
1472
+ linkQuality = '0%'; // set linkQuality to nothing
1473
+ }
1474
+ break;
1475
+ case 'hmiP':
1476
+ case 'maxcube':
1477
+ if (this.configMaxMinutes[adapterID] <= 0) {
1478
+ if (deviceUnreachState) {
1405
1479
  deviceState = 'Offline'; //set online state to offline
1406
1480
  linkQuality = '0%'; // set linkQuality to nothing
1407
1481
  }
1408
- break;
1409
- case 'hmiP':
1410
- case 'maxcube':
1411
- if (this.configMaxMinutes[adapterID] <= 0) {
1412
- if (deviceUnreachState) {
1413
- deviceState = 'Offline'; //set online state to offline
1414
- linkQuality = '0%'; // set linkQuality to nothing
1415
- }
1416
- } else if (lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID] && deviceUnreachState) {
1482
+ } else if (lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID] && deviceUnreachState) {
1483
+ deviceState = 'Offline'; //set online state to offline
1484
+ linkQuality = '0%'; // set linkQuality to nothing
1485
+ }
1486
+ break;
1487
+ case 'apcups':
1488
+ case 'hue':
1489
+ case 'hueExt':
1490
+ case 'ping':
1491
+ case 'deconz':
1492
+ case 'shelly':
1493
+ case 'sonoff':
1494
+ case 'unifi':
1495
+ case 'zigbee':
1496
+ case 'zigbee2MQTT':
1497
+ if (this.configMaxMinutes[adapterID] <= 0) {
1498
+ if (!deviceUnreachState) {
1417
1499
  deviceState = 'Offline'; //set online state to offline
1418
1500
  linkQuality = '0%'; // set linkQuality to nothing
1419
1501
  }
1420
- break;
1421
- case 'apcups':
1422
- case 'hue':
1423
- case 'hueExt':
1424
- case 'ping':
1425
- case 'deconz':
1426
- case 'shelly':
1427
- case 'sonoff':
1428
- case 'unifi':
1429
- case 'zigbee':
1430
- case 'zigbee2MQTT':
1431
- if (this.configMaxMinutes[adapterID] <= 0) {
1432
- if (!deviceUnreachState) {
1433
- deviceState = 'Offline'; //set online state to offline
1434
- linkQuality = '0%'; // set linkQuality to nothing
1435
- }
1436
- } else if (!deviceUnreachState && lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID]) {
1502
+ } else if (!deviceUnreachState && lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID]) {
1503
+ deviceState = 'Offline'; //set online state to offline
1504
+ linkQuality = '0%'; // set linkQuality to nothing
1505
+ }
1506
+ break;
1507
+ case 'mqttClientZigbee2Mqtt':
1508
+ if (this.configMaxMinutes[adapterID] <= 0) {
1509
+ if (deviceUnreachState !== 'online') {
1437
1510
  deviceState = 'Offline'; //set online state to offline
1438
1511
  linkQuality = '0%'; // set linkQuality to nothing
1439
1512
  }
1440
- break;
1441
- case 'mqttClientZigbee2Mqtt':
1513
+ } else if (deviceUnreachState !== 'online' && lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID]) {
1514
+ deviceState = 'Offline'; //set online state to offline
1515
+ linkQuality = '0%'; // set linkQuality to nothing
1516
+ }
1517
+ break;
1518
+ case 'mihome':
1519
+ if (deviceUnreachState !== undefined) {
1442
1520
  if (this.configMaxMinutes[adapterID] <= 0) {
1443
- if (deviceUnreachState !== 'online') {
1521
+ if (!deviceUnreachState) {
1444
1522
  deviceState = 'Offline'; //set online state to offline
1445
1523
  linkQuality = '0%'; // set linkQuality to nothing
1446
1524
  }
1447
- } else if (deviceUnreachState !== 'online' && lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID]) {
1525
+ } else if (lastContact && lastContact > this.configMaxMinutes[adapterID]) {
1448
1526
  deviceState = 'Offline'; //set online state to offline
1449
1527
  linkQuality = '0%'; // set linkQuality to nothing
1450
1528
  }
1451
- break;
1452
- case 'mihome':
1453
- if (deviceUnreachState !== undefined) {
1529
+ } else {
1530
+ if (this.config.mihomeMaxMinutes <= 0) {
1454
1531
  if (this.configMaxMinutes[adapterID] <= 0) {
1455
- if (!deviceUnreachState) {
1456
- deviceState = 'Offline'; //set online state to offline
1457
- linkQuality = '0%'; // set linkQuality to nothing
1458
- }
1459
- } else if (lastContact > this.configMaxMinutes[adapterID]) {
1460
- deviceState = 'Offline'; //set online state to offline
1461
- linkQuality = '0%'; // set linkQuality to nothing
1462
- }
1463
- } else {
1464
- if (this.config.mihomeMaxMinutes <= 0) {
1465
- if (this.configMaxMinutes[adapterID] <= 0) {
1466
- deviceState = 'Offline'; //set online state to offline
1467
- linkQuality = '0%'; // set linkQuality to nothing
1468
- }
1469
- } else if (lastContact > this.configMaxMinutes[adapterID]) {
1470
1532
  deviceState = 'Offline'; //set online state to offline
1471
1533
  linkQuality = '0%'; // set linkQuality to nothing
1472
1534
  }
1535
+ } else if (lastContact && lastContact > this.configMaxMinutes[adapterID]) {
1536
+ deviceState = 'Offline'; //set online state to offline
1537
+ linkQuality = '0%'; // set linkQuality to nothing
1473
1538
  }
1474
- break;
1475
- case 'smartgarden':
1476
- if (this.configMaxMinutes[adapterID] <= 0) {
1477
- if (deviceUnreachState === 'OFFLINE') {
1478
- deviceState = 'Offline'; //set online state to offline
1479
- linkQuality = '0%'; // set linkQuality to nothing
1480
- }
1481
- } else if (deviceUnreachState === 'OFFLINE' && lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID]) {
1539
+ }
1540
+ break;
1541
+ case 'smartgarden':
1542
+ if (this.configMaxMinutes[adapterID] <= 0) {
1543
+ if (deviceUnreachState === 'OFFLINE') {
1482
1544
  deviceState = 'Offline'; //set online state to offline
1483
1545
  linkQuality = '0%'; // set linkQuality to nothing
1484
1546
  }
1485
- break;
1486
- default:
1487
- if (this.configMaxMinutes[adapterID] <= 0) {
1488
- if (!deviceUnreachState) {
1489
- deviceState = 'Offline'; //set online state to offline
1490
- linkQuality = '0%'; // set linkQuality to nothing
1491
- }
1492
- } else if (lastContact > this.configMaxMinutes[adapterID]) {
1547
+ } else if (deviceUnreachState === 'OFFLINE' && lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID]) {
1548
+ deviceState = 'Offline'; //set online state to offline
1549
+ linkQuality = '0%'; // set linkQuality to nothing
1550
+ }
1551
+ break;
1552
+ default:
1553
+ if (this.configMaxMinutes[adapterID] <= 0) {
1554
+ if (!deviceUnreachState) {
1493
1555
  deviceState = 'Offline'; //set online state to offline
1494
1556
  linkQuality = '0%'; // set linkQuality to nothing
1495
1557
  }
1496
- break;
1497
- }
1558
+ } else if (lastContact && lastContact > this.configMaxMinutes[adapterID]) {
1559
+ deviceState = 'Offline'; //set online state to offline
1560
+ linkQuality = '0%'; // set linkQuality to nothing
1561
+ }
1562
+ break;
1498
1563
  }
1499
1564
  }
1500
1565
  return [lastContactString, deviceState, linkQuality];
@@ -1666,7 +1731,7 @@ class DeviceWatcher extends utils.Adapter {
1666
1731
  }
1667
1732
 
1668
1733
  // Device update List
1669
- if (device.Upgradable === true) {
1734
+ if (device.Upgradable === true || device.Upgradable === 1) {
1670
1735
  this.upgradableList.push({
1671
1736
  Device: device.Device,
1672
1737
  Adapter: device.Adapter,
@@ -1882,6 +1947,28 @@ class DeviceWatcher extends utils.Adapter {
1882
1947
  val: await this.createListHTML('batteryList', this.batteryLowPowered, this.lowBatteryPoweredCount, true),
1883
1948
  ack: true,
1884
1949
  });
1950
+ if (this.config.checkAdapterInstances) {
1951
+ await this.setStateChangedAsync(`adapterAndInstances.HTML_Lists.listAllInstancesHTML`, {
1952
+ val: await this.createListHTMLInstances('allInstancesList', this.listAllInstances, this.countAllInstances),
1953
+ ack: true,
1954
+ });
1955
+ await this.setStateChangedAsync(`adapterAndInstances.HTML_Lists.listAllActiveInstancesHTML`, {
1956
+ val: await this.createListHTMLInstances('allActiveInstancesList', this.listAllActiveInstances, this.countAllActiveInstances),
1957
+ ack: true,
1958
+ });
1959
+ await this.setStateChangedAsync(`adapterAndInstances.HTML_Lists.listInstancesErrorHTML`, {
1960
+ val: await this.createListHTMLInstances('errorInstanceList', this.listErrorInstance, this.countErrorInstance),
1961
+ ack: true,
1962
+ });
1963
+ await this.setStateChangedAsync(`adapterAndInstances.HTML_Lists.listDeactivatedInstancesHTML`, {
1964
+ val: await this.createListHTMLInstances('deactivatedInstanceList', this.listDeactivatedInstances, this.countDeactivatedInstances),
1965
+ ack: true,
1966
+ });
1967
+ await this.setStateChangedAsync(`adapterAndInstances.HTML_Lists.listAdapterUpdatesHTML`, {
1968
+ val: await this.createListHTMLInstances('updateAdapterList', this.listAdapterUpdates, this.countAdapterUpdates),
1969
+ ack: true,
1970
+ });
1971
+ }
1885
1972
  }
1886
1973
 
1887
1974
  // create timestamp of last run
@@ -2029,6 +2116,7 @@ class DeviceWatcher extends utils.Adapter {
2029
2116
  let diff;
2030
2117
  let previousCronRun = null;
2031
2118
  let isHealthy = false;
2119
+ let instanceErrorTime = 20000 / 2;
2032
2120
 
2033
2121
  switch (instanceMode) {
2034
2122
  case 'schedule':
@@ -2050,14 +2138,20 @@ class DeviceWatcher extends utils.Adapter {
2050
2138
  case 'daemon':
2051
2139
  if (!isAlive) return ['Instanz deaktiviert', false, null]; // if instance is turned off
2052
2140
  if (isDeviceConnected === undefined) isDeviceConnected = true;
2053
- // In case of (re)start, connection may take some time. We take 3 attempts.
2054
- // Attempt 1/3 - immediately
2141
+
2142
+ if (this.userTimeInstancesList.has(instanceAlivePath)) {
2143
+ instanceErrorTime = this.userTimeInstancesList.get(instanceAlivePath).errorTime;
2144
+ instanceErrorTime = (instanceErrorTime * 1000) / 2; // calculate sec to ms and divide into two
2145
+ }
2146
+
2055
2147
  if (isHostConnected && isDeviceConnected) {
2148
+ // In case of (re)start, connection may take some time. We take 3 attempts.
2149
+ // Attempt 1/3 - immediately
2056
2150
  isHealthy = true;
2057
2151
  instanceStatusString = 'Instanz okay';
2058
2152
  } else {
2059
- // Attempt 2/3 - after 10 seconds
2060
- await this.wait(10000);
2153
+ // 2/3 - after 15 seconds
2154
+ await this.wait(instanceErrorTime);
2061
2155
  isDeviceConnected = await this.getInitValue(isDeviceConnctedPath);
2062
2156
  isHostConnected = await this.getInitValue(hostConnectedPath);
2063
2157
 
@@ -2065,8 +2159,8 @@ class DeviceWatcher extends utils.Adapter {
2065
2159
  isHealthy = true;
2066
2160
  instanceStatusString = 'Instanz okay';
2067
2161
  } else {
2068
- // Attempt 3/3 - after 20 seconds in total
2069
- await this.wait(10000);
2162
+ // 3/3 - after 30 seconds in total or user time setting
2163
+ await this.wait(instanceErrorTime);
2070
2164
  isDeviceConnected = await this.getInitValue(isDeviceConnctedPath);
2071
2165
  isHostConnected = await this.getInitValue(hostConnectedPath);
2072
2166
 
@@ -2167,6 +2261,7 @@ class DeviceWatcher extends utils.Adapter {
2167
2261
  */
2168
2262
  async createInstanceList() {
2169
2263
  this.listAllInstances = [];
2264
+ this.listAllActiveInstances = [];
2170
2265
  this.listDeactivatedInstances = [];
2171
2266
  this.listErrorInstanceRaw = [];
2172
2267
  this.listErrorInstance = [];
@@ -2183,6 +2278,7 @@ class DeviceWatcher extends utils.Adapter {
2183
2278
  }
2184
2279
 
2185
2280
  if (this.blacklistInstancesLists.includes(instance.instanceAlivePath)) continue;
2281
+ // all instances
2186
2282
  this.listAllInstances.push({
2187
2283
  Adapter: instance.Adapter,
2188
2284
  Instance: instance.InstanceName,
@@ -2192,15 +2288,26 @@ class DeviceWatcher extends utils.Adapter {
2192
2288
  Updateable: instance.updateAvailable,
2193
2289
  Status: instance.status,
2194
2290
  });
2291
+
2195
2292
  if (!instance.isAlive) {
2293
+ // list with deactivated instances
2196
2294
  this.listDeactivatedInstances.push({
2197
2295
  Adapter: instance.Adapter,
2198
2296
  Instance: instance.InstanceName,
2199
2297
  Status: instance.status,
2200
2298
  });
2299
+ } else {
2300
+ // list with active instances
2301
+ this.listAllActiveInstances.push({
2302
+ Adapter: instance.Adapter,
2303
+ Instance: instance.InstanceName,
2304
+ Mode: instance.instanceMode,
2305
+ Schedule: instance.schedule,
2306
+ Status: instance.status,
2307
+ });
2201
2308
  }
2202
2309
 
2203
- // fill List for User
2310
+ // list with error instances
2204
2311
  if (instance.isAlive && !instance.isHealthy) {
2205
2312
  this.listErrorInstance.push({
2206
2313
  Adapter: instance.Adapter,
@@ -2218,10 +2325,12 @@ class DeviceWatcher extends utils.Adapter {
2218
2325
  */
2219
2326
  async countInstances() {
2220
2327
  this.countAllInstances = 0;
2328
+ this.countAllActiveInstances = 0;
2221
2329
  this.countDeactivatedInstances = 0;
2222
2330
  this.countErrorInstance = 0;
2223
2331
 
2224
2332
  this.countAllInstances = this.listAllInstances.length;
2333
+ this.countAllActiveInstances = this.listAllActiveInstances.length;
2225
2334
  this.countDeactivatedInstances = this.listDeactivatedInstances.length;
2226
2335
  this.countErrorInstance = this.listErrorInstance.length;
2227
2336
  }
@@ -2230,23 +2339,24 @@ class DeviceWatcher extends utils.Adapter {
2230
2339
  * write datapoints for instances list and counts
2231
2340
  */
2232
2341
  async writeInstanceDPs() {
2233
- // Write Datapoints for counts
2234
- await this.setStateChangedAsync(`adapterAndInstances.countAllInstances`, { val: this.countAllInstances, ack: true });
2235
- await this.setStateChangedAsync(`adapterAndInstances.countDeactivatedInstances`, { val: this.countDeactivatedInstances, ack: true });
2236
-
2237
2342
  // List all instances
2238
2343
  await this.setStateChangedAsync(`adapterAndInstances.listAllInstances`, { val: JSON.stringify(this.listAllInstances), ack: true });
2344
+ await this.setStateChangedAsync(`adapterAndInstances.countAllInstances`, { val: this.countAllInstances, ack: true });
2345
+
2346
+ // List all active instances
2347
+ await this.setStateChangedAsync(`adapterAndInstances.listAllActiveInstances`, { val: JSON.stringify(this.listAllActiveInstances), ack: true });
2348
+ await this.setStateChangedAsync(`adapterAndInstances.countAllActiveInstances`, { val: this.countAllActiveInstances, ack: true });
2239
2349
 
2240
2350
  // list deactivated instances
2241
2351
  if (this.countDeactivatedInstances === 0) {
2242
- this.listDeactivatedInstances = [{ Instance: '--none--', Version: '', Status: '' }];
2352
+ this.listDeactivatedInstances = [{ Adapter: '--none--', Instance: '', Version: '', Status: '' }];
2243
2353
  }
2244
2354
  await this.setStateChangedAsync(`adapterAndInstances.listDeactivatedInstances`, { val: JSON.stringify(this.listDeactivatedInstances), ack: true });
2245
2355
  await this.setStateChangedAsync(`adapterAndInstances.countDeactivatedInstances`, { val: this.countDeactivatedInstances, ack: true });
2246
2356
 
2247
2357
  // list error instances
2248
2358
  if (this.countErrorInstance === 0) {
2249
- this.listErrorInstance = [{ Instance: '--none--', Mode: '', Status: '' }];
2359
+ this.listErrorInstance = [{ Adapter: '--none--', Instance: '', Mode: '', Status: '' }];
2250
2360
  }
2251
2361
  await this.setStateChangedAsync(`adapterAndInstances.listInstancesError`, { val: JSON.stringify(this.listErrorInstance), ack: true });
2252
2362
  await this.setStateChangedAsync(`adapterAndInstances.countInstancesError`, { val: this.countErrorInstance, ack: true });
@@ -2323,6 +2433,53 @@ class DeviceWatcher extends utils.Adapter {
2323
2433
  },
2324
2434
  native: {},
2325
2435
  });
2436
+ // Instances
2437
+ await this.setObjectNotExistsAsync(`adapterAndInstances.listAllActiveInstances`, {
2438
+ type: 'state',
2439
+ common: {
2440
+ name: {
2441
+ en: 'JSON List of all active instances',
2442
+ de: 'JSON Liste aller aktiven Instanzen',
2443
+ ru: 'ДЖСОН Список всех активных инстанций',
2444
+ pt: 'J. Lista de todas as instâncias ativas',
2445
+ nl: 'JSON List van alle actieve instanties',
2446
+ fr: 'JSON Liste de tous les cas actifs',
2447
+ it: 'JSON Elenco di tutte le istanze attive',
2448
+ es: 'JSON Lista de todos los casos activos',
2449
+ pl: 'JSON Lista wszystkich aktywnych instancji',
2450
+ uk: 'Сонце Список всіх активних екземплярів',
2451
+ 'zh-cn': '附 件 所有积极事件清单',
2452
+ },
2453
+ type: 'array',
2454
+ role: 'json',
2455
+ read: true,
2456
+ write: false,
2457
+ },
2458
+ native: {},
2459
+ });
2460
+ await this.setObjectNotExistsAsync(`adapterAndInstances.countAllActiveInstances`, {
2461
+ type: 'state',
2462
+ common: {
2463
+ name: {
2464
+ en: 'Number of all active instances',
2465
+ de: 'Anzahl aller aktiven Instanzen',
2466
+ ru: 'Количество всех активных инстанций',
2467
+ pt: 'Número de todas as instâncias ativas',
2468
+ nl: 'Nummer van alle actieve instanties',
2469
+ fr: 'Nombre de toutes les instances actives',
2470
+ it: 'Numero di tutte le istanze attive',
2471
+ es: 'Número de casos activos',
2472
+ pl: 'Liczba wszystkich czynnych przypadków',
2473
+ uk: 'Кількість всіх активних екземплярів',
2474
+ 'zh-cn': '所有积极事件的数目',
2475
+ },
2476
+ type: 'number',
2477
+ role: 'value',
2478
+ read: true,
2479
+ write: false,
2480
+ },
2481
+ native: {},
2482
+ });
2326
2483
  await this.setObjectNotExistsAsync(`adapterAndInstances.listDeactivatedInstances`, {
2327
2484
  type: 'state',
2328
2485
  common: {
@@ -2472,6 +2629,8 @@ class DeviceWatcher extends utils.Adapter {
2472
2629
  await this.delObjectAsync(`adapterAndInstances`);
2473
2630
  await this.delObjectAsync(`adapterAndInstances.listAllInstances`);
2474
2631
  await this.delObjectAsync(`adapterAndInstances.countAllInstances`);
2632
+ await this.delObjectAsync(`adapterAndInstances.listAllActiveInstances`);
2633
+ await this.delObjectAsync(`adapterAndInstances.countAllActiveInstances`);
2475
2634
  await this.delObjectAsync(`adapterAndInstances.listDeactivatedInstances`);
2476
2635
  await this.delObjectAsync(`adapterAndInstances.countDeactivatedInstances`);
2477
2636
  await this.delObjectAsync(`adapterAndInstances.listInstancesError`);
@@ -2549,6 +2708,25 @@ class DeviceWatcher extends utils.Adapter {
2549
2708
  this.errorReporting('[sendNotification Whatsapp]', error);
2550
2709
  }
2551
2710
 
2711
+ // Matrix
2712
+ try {
2713
+ if (this.config.instanceMatrix) {
2714
+ //first check if instance is living
2715
+ const matrixAliveState = await this.getInitValue('system.adapter.' + this.config.instanceMatrix + '.alive');
2716
+
2717
+ if (!matrixAliveState) {
2718
+ this.log.warn('Matrix instance is not running. Message could not be sent. Please check your instance configuration.');
2719
+ } else {
2720
+ await this.sendToAsync(this.config.instanceMatrix, 'send', {
2721
+ html: `<h1>${this.config.titleMatrix}</h1>`,
2722
+ text: text,
2723
+ });
2724
+ }
2725
+ }
2726
+ } catch (error) {
2727
+ this.errorReporting('[sendNotification Matrix]', error);
2728
+ }
2729
+
2552
2730
  // Signal
2553
2731
  try {
2554
2732
  if (this.config.instanceSignal) {
@@ -3024,6 +3202,172 @@ class DeviceWatcher extends utils.Adapter {
3024
3202
  return html;
3025
3203
  }
3026
3204
 
3205
+ /**
3206
+ * @param {string} type - type of list
3207
+ * @param {object} instances - Instance
3208
+ * @param {number} instancesCount - Counted devices
3209
+ */
3210
+ async createListHTMLInstances(type, instances, instancesCount) {
3211
+ let html;
3212
+ switch (type) {
3213
+ case 'allInstancesList':
3214
+ instances = instances.sort((a, b) => {
3215
+ a = a.Instance || '';
3216
+ b = b.Instance || '';
3217
+ return a.localeCompare(b);
3218
+ });
3219
+ html = `<center>
3220
+ <b>All Instances:<font> ${instancesCount}</b><small></small></font>
3221
+ <p></p>
3222
+ </center>
3223
+ <table width=100%>
3224
+ <tr>
3225
+ <th align=left>Adapter</th>
3226
+ <th align=center>Instance</th>
3227
+ <th align=center width=180>Status</th>
3228
+ </tr>
3229
+ <tr>
3230
+ <td colspan="5"><hr></td>
3231
+ </tr>`;
3232
+
3233
+ for (const instance of instances) {
3234
+ html += `<tr>
3235
+ <td><font>${instance.Adapter}</font></td>
3236
+ <td align=center><font>${instance.Instance}</font></td>
3237
+ <td align=center><font>${instance.Status}</font></td>
3238
+ </tr>`;
3239
+ }
3240
+
3241
+ html += '</table>';
3242
+ break;
3243
+
3244
+ case 'allActiveInstancesList':
3245
+ instances = instances.sort((a, b) => {
3246
+ a = a.Instance || '';
3247
+ b = b.Instances || '';
3248
+ return a.localeCompare(b);
3249
+ });
3250
+ html = `<center>
3251
+ <b>Active Devices: <font> ${instancesCount}</b><small></small></font>
3252
+ <p></p>
3253
+ </center>
3254
+ <table width=100%>
3255
+ <tr>
3256
+ <th align=left>Adapter</th>
3257
+ <th align=center>Instance</th>
3258
+ <th align=center width=180>Status</th>
3259
+ </tr>
3260
+ <tr>
3261
+ <td colspan="5"><hr></td>
3262
+ </tr>`;
3263
+
3264
+ for (const instance of instances) {
3265
+ html += `<tr>
3266
+ <td><font>${instance.Adapter}</font></td>
3267
+ <td align=center><font>${instance.Instance}</font></td>
3268
+ <td align=center><font color=orange>${instance.Status}</font></td>
3269
+ </tr>`;
3270
+ }
3271
+
3272
+ html += '</table>';
3273
+ break;
3274
+
3275
+ case 'errorInstanceList':
3276
+ instances = instances.sort((a, b) => {
3277
+ a = a.Instance || '';
3278
+ b = b.Instances || '';
3279
+ return a.localeCompare(b);
3280
+ });
3281
+ html = `<center>
3282
+ <b>Error Instances: <font color=${instancesCount === 0 ? '#3bcf0e' : 'orange'}>${instancesCount}</b><small></small></font>
3283
+ <p></p>
3284
+ </center>
3285
+ <table width=100%>
3286
+ <tr>
3287
+ <th align=left>Adapter</th>
3288
+ <th align=center width=120>Instance</th>
3289
+ <th align=center>Status</th>
3290
+ </tr>
3291
+ <tr>
3292
+ <td colspan="5"><hr></td>
3293
+ </tr>`;
3294
+
3295
+ for (const instance of instances) {
3296
+ html += `<tr>
3297
+ <td><font>${instance.Adapter}</font></td>
3298
+ <td align=center><font>${instance.Instance}</font></td>
3299
+ <td align=center><font color=orange>${instance.Status}</font></td>
3300
+ </tr>`;
3301
+ }
3302
+
3303
+ html += '</table>';
3304
+ break;
3305
+
3306
+ case 'deactivatedInstanceList':
3307
+ instances = instances.sort((a, b) => {
3308
+ a = a.Instance || '';
3309
+ b = b.Instances || '';
3310
+ return a.localeCompare(b);
3311
+ });
3312
+ html = `<center>
3313
+ <b>Deactivated Instances: <font color=${instancesCount === 0 ? '#3bcf0e' : 'orange'}>${instancesCount}</b><small></small></font>
3314
+ <p></p>
3315
+ </center>
3316
+ <table width=100%>
3317
+ <tr>
3318
+ <th align=left>Adapter</th>
3319
+ <th align=center width=120>Instance</th>
3320
+ <th align=center>Status</th>
3321
+ </tr>
3322
+ <tr>
3323
+ <td colspan="5"><hr></td>
3324
+ </tr>`;
3325
+
3326
+ for (const instance of instances) {
3327
+ html += `<tr>
3328
+ <td><font>${instance.Adapter}</font></td>
3329
+ <td align=center><font>${instance.Instance}</font></td>
3330
+ <td align=center><font color=orange>${instance.Status}</font></td>
3331
+ </tr>`;
3332
+ }
3333
+
3334
+ html += '</table>';
3335
+ break;
3336
+
3337
+ case 'updateAdapterList':
3338
+ instances = instances.sort((a, b) => {
3339
+ a = a.Instance || '';
3340
+ b = b.Instances || '';
3341
+ return a.localeCompare(b);
3342
+ });
3343
+ html = `<center>
3344
+ <b>Updatable Adapter: <font color=${instancesCount === 0 ? '#3bcf0e' : 'orange'}>${instancesCount}</b><small></small></font>
3345
+ <p></p>
3346
+ </center>
3347
+ <table width=100%>
3348
+ <tr>
3349
+ <th align=left>Adapter</th>
3350
+ <th align=center>Installed Version</th>
3351
+ <th align=center>Available Version</th>
3352
+ </tr>
3353
+ <tr>
3354
+ <td colspan="5"><hr></td>
3355
+ </tr>`;
3356
+
3357
+ for (const instance of instances) {
3358
+ html += `<tr>
3359
+ <td><font>${instance.Adapter}</font></td>
3360
+ <td align=center><font>${instance['Installed Version']}</font></td>
3361
+ <td align=center><font color=orange>${instance['Available Version']}</font></td>
3362
+ </tr>`;
3363
+ }
3364
+
3365
+ html += '</table>';
3366
+ break;
3367
+ }
3368
+ return html;
3369
+ }
3370
+
3027
3371
  /*=============================================
3028
3372
  = create datapoints for each adapter =
3029
3373
  =============================================*/
@@ -3543,6 +3887,161 @@ class DeviceWatcher extends utils.Adapter {
3543
3887
  await this.delObjectAsync(`devices.${dpSubFolder}lowBatteryListHTML`);
3544
3888
  }
3545
3889
 
3890
+ /**
3891
+ * create HTML list datapoints for instances
3892
+ **/
3893
+ async createHtmlListDatapointsInstances() {
3894
+ await this.setObjectNotExistsAsync(`adapterAndInstances.HTML_Lists`, {
3895
+ type: 'channel',
3896
+ common: {
3897
+ name: {
3898
+ en: 'HTML lists for adapter and instances',
3899
+ de: 'HTML-Listen für Adapter und Instanzen',
3900
+ ru: 'HTML-списки для адаптеров и инстанций',
3901
+ pt: 'Listas HTML para adaptador e instâncias',
3902
+ nl: 'HTML lijsten voor adapter en instituut',
3903
+ fr: "Listes HTML pour l'adaptateur et les instances",
3904
+ it: 'Elenchi HTML per adattatore e istanze',
3905
+ es: 'Listas HTML para adaptador y casos',
3906
+ pl: 'Listy HTML dla adaptera i instancji',
3907
+ uk: 'Списки HTML для адаптерів та екземплярів',
3908
+ 'zh-cn': 'HTML名单',
3909
+ },
3910
+ },
3911
+ native: {},
3912
+ });
3913
+ await this.setObjectNotExistsAsync(`adapterAndInstances.HTML_Lists.listAllInstancesHTML`, {
3914
+ type: 'state',
3915
+ common: {
3916
+ name: {
3917
+ en: 'HTML List of all instances',
3918
+ de: 'HTML Liste aller Instanzen',
3919
+ ru: 'HTML Список всех инстанций',
3920
+ pt: 'HTML Lista de todas as instâncias',
3921
+ nl: 'HTM List van alle instanties',
3922
+ fr: 'HTML Liste de tous les cas',
3923
+ it: 'HTML Elenco di tutte le istanze',
3924
+ es: 'HTML Lista de todos los casos',
3925
+ pl: 'HTML Lista wszystkich instancji',
3926
+ uk: 'Українська Список всіх екземплярів',
3927
+ 'zh-cn': 'HTML 所有事例一览表',
3928
+ },
3929
+ type: 'string',
3930
+ role: 'html',
3931
+ read: true,
3932
+ write: false,
3933
+ },
3934
+ native: {},
3935
+ });
3936
+
3937
+ await this.setObjectNotExistsAsync(`adapterAndInstances.HTML_Lists.listAllActiveInstancesHTML`, {
3938
+ type: 'state',
3939
+ common: {
3940
+ name: {
3941
+ en: 'HTML List of all active instances',
3942
+ de: 'HTML Liste aller aktiven Instanzen',
3943
+ ru: 'HTML Список всех активных инстанций',
3944
+ pt: 'HTML Lista de todas as instâncias ativas',
3945
+ nl: 'HTM List van alle actieve instanties',
3946
+ fr: 'HTML Liste de tous les cas actifs',
3947
+ it: 'HTML Elenco di tutte le istanze attive',
3948
+ es: 'HTML Lista de todos los casos activos',
3949
+ pl: 'HTML Lista wszystkich aktywnych instancji',
3950
+ uk: 'Українська Список всіх активних екземплярів',
3951
+ 'zh-cn': 'HTML 所有积极事件清单',
3952
+ },
3953
+ type: 'string',
3954
+ role: 'value',
3955
+ read: true,
3956
+ write: false,
3957
+ },
3958
+ native: {},
3959
+ });
3960
+
3961
+ await this.setObjectNotExistsAsync(`adapterAndInstances.HTML_Lists.listDeactivatedInstancesHTML`, {
3962
+ type: 'state',
3963
+ common: {
3964
+ name: {
3965
+ en: 'HTML List of all deactivated instances',
3966
+ de: 'HTML Liste aller deaktivierten Instanzen',
3967
+ ru: 'HTML Список всех деактивированных инстанций',
3968
+ pt: 'HTML Lista de todas as instâncias desativadas',
3969
+ nl: 'HTM List van alle gedeactiveerde instanties',
3970
+ fr: 'HTML Liste de tous les cas désactivés',
3971
+ it: 'HTML Elenco di tutte le istanze disattivate',
3972
+ es: 'HTML Lista de todos los casos desactivados',
3973
+ pl: 'HTML Lista wszystkich przypadków deaktywowanych',
3974
+ uk: 'Українська Список всіх деактивованих екземплярів',
3975
+ 'zh-cn': 'HTML 所有违犯事件清单',
3976
+ },
3977
+ type: 'string',
3978
+ role: 'html',
3979
+ read: true,
3980
+ write: false,
3981
+ },
3982
+ native: {},
3983
+ });
3984
+
3985
+ await this.setObjectNotExistsAsync(`adapterAndInstances.HTML_Lists.listInstancesErrorHTML`, {
3986
+ type: 'state',
3987
+ common: {
3988
+ name: {
3989
+ en: 'HTML List of instances with error',
3990
+ de: 'HTML Liste der Fälle mit Fehler',
3991
+ ru: 'HTML Список инстанций с ошибкой',
3992
+ pt: 'HTML Lista de casos com erro',
3993
+ nl: 'HTM List van instoringen met fouten',
3994
+ fr: 'HTML Liste des instances avec erreur',
3995
+ it: 'HTML Elenco delle istanze con errore',
3996
+ es: 'HTML Lista de casos con error',
3997
+ pl: 'HTML Lista przykładów z błądem',
3998
+ uk: 'Українська Список екземплярів з помилкою',
3999
+ 'zh-cn': 'HTML 出现错误的情况清单',
4000
+ },
4001
+ type: 'string',
4002
+ role: 'html',
4003
+ read: true,
4004
+ write: false,
4005
+ },
4006
+ native: {},
4007
+ });
4008
+ await this.setObjectNotExistsAsync(`adapterAndInstances.HTML_Lists.listAdapterUpdatesHTML`, {
4009
+ type: 'state',
4010
+ common: {
4011
+ name: {
4012
+ en: 'HTML list of adapters with available updates',
4013
+ de: 'HTML-Liste der Adapter mit verfügbaren Updates',
4014
+ ru: 'HTML список адаптеров с доступными обновлениями',
4015
+ pt: 'Lista HTML de adaptadores com atualizações disponíveis',
4016
+ nl: 'HTML lijst met beschikbare updates',
4017
+ fr: 'Liste HTML des adaptateurs avec mises à jour disponibles',
4018
+ it: 'Elenco HTML degli adattatori con aggiornamenti disponibili',
4019
+ es: 'Lista HTML de adaptadores con actualizaciones disponibles',
4020
+ pl: 'Lista adapterów HTML z dostępnymi aktualizacjami',
4021
+ uk: 'HTML список адаптерів з доступними оновленнями',
4022
+ 'zh-cn': 'HTML 可供更新的适应者名单',
4023
+ },
4024
+ type: 'string',
4025
+ role: 'html',
4026
+ read: true,
4027
+ write: false,
4028
+ },
4029
+ native: {},
4030
+ });
4031
+ }
4032
+
4033
+ /**
4034
+ * delete html datapoints for instances
4035
+ **/
4036
+ async deleteHtmlListDatapointsInstances() {
4037
+ await this.delObjectAsync(`adapterAndInstances.HTML_Lists.listAllInstancesHTML`);
4038
+ await this.delObjectAsync(`adapterAndInstances.HTML_Lists.listAllActiveInstancesHTML`);
4039
+ await this.delObjectAsync(`adapterAndInstances.HTML_Lists.listDeactivatedInstancesHTML`);
4040
+ await this.delObjectAsync(`adapterAndInstances.HTML_Lists.listInstancesErrorHTML`);
4041
+ await this.delObjectAsync(`adapterAndInstances.HTML_Lists.listAdapterUpdatesHTML`);
4042
+ await this.delObjectAsync(`adapterAndInstances.HTML_Lists`);
4043
+ }
4044
+
3546
4045
  /*=============================================
3547
4046
  = help functions =
3548
4047
  =============================================*/
@@ -3664,7 +4163,7 @@ class DeviceWatcher extends utils.Adapter {
3664
4163
  isUnloaded = true;
3665
4164
 
3666
4165
  if (this.refreshDataTimeout) {
3667
- clearTimeout(this.refreshDataTimeout);
4166
+ this.clearTimeout(this.refreshDataTimeout);
3668
4167
  this.refreshDataTimeout = null;
3669
4168
  }
3670
4169