iobroker.device-watcher 2.13.1 → 2.15.0-alpha.1

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
@@ -3,7 +3,8 @@
3
3
  const utils = require('@iobroker/adapter-core');
4
4
  const adapterName = require('./package.json').name.split('.').pop();
5
5
  const schedule = require('node-schedule');
6
- const arrApart = require('./lib/arrApart.js'); // list of supported adapters
6
+ const cronParserLib = require('cron-parser');
7
+ const adapterArray = require('./lib/adapterArray.js'); // list of supported adapters
7
8
  const translations = require('./lib/translations.js');
8
9
  const tools = require('./lib/tools.js');
9
10
  const crud = require('./lib/crud.js');
@@ -90,9 +91,6 @@ class DeviceWatcher extends utils.Adapter {
90
91
  this.on('objectChange', this.onObjectChange.bind(this));
91
92
  this.on('message', this.onMessage.bind(this));
92
93
  this.on('unload', this.onUnload.bind(this));
93
-
94
-
95
-
96
94
  }
97
95
 
98
96
  /**
@@ -116,146 +114,23 @@ class DeviceWatcher extends utils.Adapter {
116
114
  this.configCreateOwnFolder = this.config.createOwnFolder;
117
115
  this.configCreateHtmlList = this.config.createHtmlList;
118
116
 
119
- this.configSetAdapter = {
120
- alexa2: this.config.alexa2Devices,
121
- apcups: this.config.apcupsDevices,
122
- ble: this.config.bleDevices,
123
- deconz: this.config.deconzDevices,
124
- ecovacsdeebot: this.config.ecovacsdeebotDevices,
125
- enocean: this.config.enoceanDevices,
126
- esphome: this.config.esphomeDevices,
127
- eusec: this.config.eusecDevices,
128
- fhemTFAsensors: this.config.fhemTFAsensorsDevices,
129
- fritzdect: this.config.fritzdectDevices,
130
- fullybrowser: this.config.fullybrowserDevices,
131
- fullybrowserV3: this.config.fullybrowserV3Devices,
132
- fullyMQTT: this.config.fullyMQTTDevices,
133
- ham: this.config.hamDevices,
134
- harmony: this.config.harmonyDevices,
135
- hmiP: this.config.hmiPDevices,
136
- hmrpc: this.config.hmrpcDevices,
137
- homeconnect: this.config.homeconnectDevices,
138
- homekitController: this.config.homekitControllerDevices,
139
- hs100: this.config.hs100Devices,
140
- hue: this.config.hueDevices,
141
- hueExt: this.config.hueExtDevices,
142
- innogy: this.config.innogyDevices,
143
- jeelink: this.config.jeelinkDevices,
144
- loqedSmartLock: this.config.loqedSmartLockDevices,
145
- lupusec: this.config.lupusecDevices,
146
- maxcube: this.config.maxcubeDevices,
147
- meross: this.config.merossDevices,
148
- mihome: this.config.mihomeDevices,
149
- mihomeGW: this.config.mihomeDevices,
150
- mihomeVacuum: this.config.mihomeVacuumDevices,
151
- mqttClientZigbee2Mqtt: this.config.mqttClientZigbee2MqttDevices,
152
- mqttNuki: this.config.mqttNukiDevices,
153
- musiccast: this.config.musiccastDevices,
154
- netatmo: this.config.netatmoDevices,
155
- nukiExt: this.config.nukiExtDevices,
156
- nut: this.config.nutDevices,
157
- ping: this.config.pingDevices,
158
- proxmox: this.config.proxmoxDevices,
159
- ring: this.config.ringDevices,
160
- roomba: this.config.roombaDevices,
161
- shelly: this.config.shellyDevices,
162
- smartgarden: this.config.smartgardenDevices,
163
- sonoff: this.config.sonoffDevices,
164
- sonos: this.config.sonosDevices,
165
- sureflap: this.config.sureflapDevices,
166
- switchbotBle: this.config.switchbotBleDevices,
167
- tado: this.config.tadoDevices,
168
- tapo: this.config.tapoDevices,
169
- tradfri: this.config.tradfriDevices,
170
- tuya: this.config.tuyaDevices,
171
- unifi: this.config.unifiDevices,
172
- viessmann: this.config.viessmannDevices,
173
- wifilight: this.config.wifilightDevices,
174
- wled: this.config.wledDevices,
175
- xsense: this.config.xsenseDevices,
176
- yeelight: this.config.yeelightDevices,
177
- zigbee: this.config.zigbeeDevices,
178
- zigbee2MQTT: this.config.zigbee2mqttDevices,
179
- zwave2: this.config.zwaveDevices,
180
- };
181
-
182
- this.configMaxMinutes = {
183
- alexa2: this.config.alexa2MaxMinutes,
184
- apcups: this.config.apcupsMaxMinutes,
185
- ble: this.config.bleMaxMinutes,
186
- deconz: this.config.deconzMaxMinutes,
187
- ecovacsdeebot: this.config.ecovacsdeebotMaxMinutes,
188
- enocean: this.config.enoceanMaxMinutes,
189
- esphome: this.config.esphomeMaxMinutes,
190
- eusec: this.config.eusecMaxMinutes,
191
- fhemTFAsensors: this.config.fhemTFAsensorsMaxMinutes,
192
- fritzdect: this.config.fritzdectMaxMinutes,
193
- fullybrowser: this.config.fullybrowserMaxMinutes,
194
- fullybrowserV3: this.config.fullybrowserV3MaxMinutes,
195
- fullyMQTT: this.config.fullyMQTTMaxMinutes,
196
- ham: this.config.hamMaxMinutes,
197
- harmony: this.config.harmonyMaxMinutes,
198
- hmiP: this.config.hmiPMaxMinutes,
199
- hmrpc: this.config.hmrpcMaxMinutes,
200
- homeconnect: this.config.homeconnectMaxMinutes,
201
- homekitController: this.config.homekitControllerMaxMinutes,
202
- hs100: this.config.hs100MaxMinutes,
203
- hue: this.config.hueMaxMinutes,
204
- hueExt: this.config.hueextMaxMinutes,
205
- innogy: this.config.innogyMaxMinutes,
206
- jeelink: this.config.jeelinkMaxMinutes,
207
- loqedSmartLock: this.config.loqedSmartLockMaxMinutes,
208
- lupusec: this.config.lupusecMaxMinutes,
209
- maxcube: this.config.maxcubeMaxMinutes,
210
- meross: this.config.merossMaxMinutes,
211
- mihome: this.config.mihomeMaxMinutes,
212
- mihomeGW: this.config.mihomeMaxMinutes,
213
- mihomeVacuum: this.config.mihomeVacuumMaxMinutes,
214
- mqttClientZigbee2Mqtt: this.config.mqttClientZigbee2MqttMaxMinutes,
215
- mqttNuki: this.config.mqttNukiMaxMinutes,
216
- musiccast: this.config.musiccastMaxMinutes,
217
- netatmo: this.config.netatmoMaxMinutes,
218
- nukiExt: this.config.nukiextendMaxMinutes,
219
- nut: this.config.nutMaxMinutes,
220
- ping: this.config.pingMaxMinutes,
221
- proxmox: this.config.proxmoxMaxMinutes,
222
- ring: this.config.ringMaxMinutes,
223
- roomba: this.config.roombaMaxMinutes,
224
- shelly: this.config.shellyMaxMinutes,
225
- smartgarden: this.config.smartgardenMaxMinutes,
226
- sonoff: this.config.sonoffMaxMinutes,
227
- sonos: this.config.sonosMaxMinutes,
228
- sureflap: this.config.sureflapMaxMinutes,
229
- switchbotBle: this.config.switchbotMaxMinutes,
230
- tado: this.config.tadoMaxMinutes,
231
- tapo: this.config.tapoMaxMinutes,
232
- tradfri: this.config.tradfriMaxMinutes,
233
- tuya: this.config.tuyaMaxMinutes,
234
- unifi: this.config.unifiMaxMinutes,
235
- viessmann: this.config.viessmannMaxMinutes,
236
- wifilight: this.config.wifilightMaxMinutes,
237
- wled: this.config.wledMaxMinutes,
238
- xsense: this.config.xsenseMaxMinutes,
239
- yeelight: this.config.yeelightMaxMinutes,
240
- zigbee: this.config.zigbeeMaxMinutes,
241
- zigbee2MQTT: this.config.zigbee2mqttMaxMinutes,
242
- zwave2: this.config.zwaveMaxMinutes,
243
- };
244
-
245
117
  try {
246
- // create list with selected adapters for monitor devices
247
- for (const [id] of Object.entries(arrApart)) {
248
- if (this.configSetAdapter[id]) {
249
- this.selAdapter.push(arrApart[id]);
250
- this.adapterSelected.push(tools.capitalize(id));
118
+ // create list with enabled adapters for monitor devices
119
+ for (const device of Object.values(this.config.tableDevices)) {
120
+ if (device.enabled) {
121
+ for (const [adapterName, adapter] of Object.entries(adapterArray)) {
122
+ if (String(adapter.adapterKey).toLowerCase() === String(device.adapterKey).toLowerCase()) {
123
+ this.selAdapter.push(adapter);
124
+ this.adapterSelected.push(adapter.adapterKey);
125
+ break;
126
+ }
127
+ }
251
128
  }
252
129
  }
253
130
 
254
131
  // Check if an adapter to monitor devices is selected.
255
132
  if (this.adapterSelected.length >= 1) {
256
- // show list in debug log
257
133
  this.log.debug(JSON.stringify(this.selAdapter));
258
-
259
134
  this.log.info(`Number of selected adapters to monitor devices: ${this.adapterSelected.length}. Loading data from: ${this.adapterSelected.join(', ')} ...`);
260
135
  } else {
261
136
  this.log.info(`No adapters selected to monitor devices.`);
@@ -268,13 +143,15 @@ class DeviceWatcher extends utils.Adapter {
268
143
  await crud.createTimeListInstances(this);
269
144
 
270
145
  //create datapoints for each adapter if selected
271
- for (const [id] of Object.entries(arrApart)) {
146
+ for (const [id] of Object.entries(adapterArray)) {
272
147
  try {
273
148
  if (!this.configCreateOwnFolder) {
274
149
  await crud.deleteDPsForEachAdapter(this, id);
275
150
  await crud.deleteHtmlListDatapoints(this, id);
276
151
  } else {
277
- if (this.configSetAdapter && this.configSetAdapter[id]) {
152
+ const adapter = adapterArray[id];
153
+
154
+ if (this.adapterSelected.includes(adapter.adapterKey)) {
278
155
  await crud.createDPsForEachAdapter(this, id);
279
156
  // create HTML list datapoints
280
157
  if (!this.configCreateHtmlList) {
@@ -296,10 +173,13 @@ class DeviceWatcher extends utils.Adapter {
296
173
  await crud.deleteHtmlListDatapointsInstances(this);
297
174
  } else {
298
175
  await crud.createHtmlListDatapoints(this);
299
- if (this.config.checkAdapterInstances) await crud.createHtmlListDatapointsInstances(this);
176
+ if (this.config.checkAdapterInstances) {
177
+ await crud.createHtmlListDatapointsInstances(this);
178
+ }
179
+ }
180
+ if (!this.config.checkAdapterInstances) {
181
+ await crud.deleteHtmlListDatapointsInstances(this);
300
182
  }
301
- if (!this.config.checkAdapterInstances) await crud.deleteHtmlListDatapointsInstances(this);
302
-
303
183
 
304
184
  // instances and adapters
305
185
  if (this.configCreateInstanceList) {
@@ -318,24 +198,35 @@ class DeviceWatcher extends utils.Adapter {
318
198
  await this.refreshData();
319
199
 
320
200
  // send overview for low battery devices
321
- if (this.config.checkSendBatteryMsgDaily) await this.sendScheduleNotifications('lowBatteryDevices');
201
+ if (this.config.checkSendBatteryMsgDaily) {
202
+ await this.sendScheduleNotifications('lowBatteryDevices');
203
+ }
322
204
 
323
205
  // send overview of offline devices
324
- if (this.config.checkSendOfflineMsgDaily) await this.sendScheduleNotifications('offlineDevices');
206
+ if (this.config.checkSendOfflineMsgDaily) {
207
+ await this.sendScheduleNotifications('offlineDevices');
208
+ }
325
209
 
326
210
  // send overview of upgradeable devices
327
- if (this.config.checkSendUpgradeMsgDaily) await this.sendScheduleNotifications('updateDevices');
211
+ if (this.config.checkSendUpgradeMsgDaily) {
212
+ await this.sendScheduleNotifications('updateDevices');
213
+ }
328
214
 
329
215
  // send overview of updatable adapters
330
- if (this.config.checkSendAdapterUpdateMsgDaily) await this.sendScheduleNotifications('updateAdapter');
216
+ if (this.config.checkSendAdapterUpdateMsgDaily) {
217
+ await this.sendScheduleNotifications('updateAdapter');
218
+ }
331
219
 
332
220
  // send overview of deactivated instances
333
- if (this.config.checkSendInstanceDeactivatedDaily) await this.sendScheduleNotifications('deactivatedInstance');
221
+ if (this.config.checkSendInstanceDeactivatedDaily) {
222
+ await this.sendScheduleNotifications('deactivatedInstance');
223
+ }
334
224
 
335
225
  // send overview of instances with error
336
- if (this.config.checkSendInstanceFailedDaily) await this.sendScheduleNotifications('errorInstance');
337
-
338
- } catch (error) {
226
+ if (this.config.checkSendInstanceFailedDaily) {
227
+ await this.sendScheduleNotifications('errorInstance');
228
+ }
229
+ } catch (error) {
339
230
  this.log.error(`[onReady] - ${error}`);
340
231
  this.terminate ? this.terminate(15) : process.exit(15);
341
232
  }
@@ -349,7 +240,9 @@ class DeviceWatcher extends utils.Adapter {
349
240
  this.mainRunning = true;
350
241
 
351
242
  // cancel run if no adapter is selected
352
- if (this.adapterSelected.length === 0) return;
243
+ if (this.adapterSelected.length === 0) {
244
+ return;
245
+ }
353
246
 
354
247
  // fill counts and lists of all selected adapter
355
248
  try {
@@ -366,11 +259,15 @@ class DeviceWatcher extends utils.Adapter {
366
259
  // fill datapoints for each adapter if selected
367
260
  if (this.configCreateOwnFolder) {
368
261
  try {
369
- for (const [id] of Object.entries(arrApart)) {
370
- if (this.configSetAdapter && this.configSetAdapter[id]) {
262
+ for (const [id] of Object.entries(adapterArray)) {
263
+ const adapter = adapterArray[id];
264
+
265
+ if (this.adapterSelected.includes(adapter.adapterKey)) {
371
266
  for (const deviceData of this.listAllDevicesRaw.values()) {
372
267
  // list device only if selected adapter matched with device
373
- if (!deviceData.adapterID.includes(id)) continue;
268
+ if (!deviceData.adapterID.includes(id)) {
269
+ continue;
270
+ }
374
271
  await crud.createLists(this, id);
375
272
  }
376
273
  await crud.writeDatapoints(this, id); // fill the datapoints
@@ -388,11 +285,7 @@ class DeviceWatcher extends utils.Adapter {
388
285
  // If you need to react to object changes, uncomment the following block and the corresponding line in the constructor.
389
286
  // You also need to subscribe to the objects with `this.subscribeObjects`, similar to `this.subscribeStates`.
390
287
  //
391
- /**
392
- * Is called if a subscribed object changes
393
- * @param {string} id
394
- * @param {ioBroker.Object | null | undefined} obj
395
- */
288
+
396
289
  async onObjectChange(id, obj) {
397
290
  if (obj) {
398
291
  try {
@@ -440,11 +333,6 @@ class DeviceWatcher extends utils.Adapter {
440
333
  }
441
334
  }
442
335
 
443
- /**
444
- * Is called if a subscribed state changes
445
- * @param {string} id
446
- * @param {ioBroker.State | null | undefined} state
447
- */
448
336
  async onStateChange(id, state) {
449
337
  if (state) {
450
338
  // this.log.debug(`State changed: ${id} changed ${state.val}`);
@@ -470,7 +358,7 @@ class DeviceWatcher extends utils.Adapter {
470
358
  await this.renewDeviceData(id, state);
471
359
  }
472
360
  } catch (error) {
473
- this.log.error(`Issue at state change: ${error}`);
361
+ this.log.error(`Issue at state change: ${id}`);
474
362
  }
475
363
  } else {
476
364
  // The state was deleted
@@ -478,9 +366,6 @@ class DeviceWatcher extends utils.Adapter {
478
366
  }
479
367
  }
480
368
 
481
- /**
482
- * @param {ioBroker.Message} obj
483
- */
484
369
  onMessage(obj) {
485
370
  const devices = [];
486
371
  const instances = [];
@@ -571,7 +456,9 @@ class DeviceWatcher extends utils.Adapter {
571
456
  * is neccessary to refresh lastContact data, especially of devices without state changes
572
457
  */
573
458
  async refreshData() {
574
- if (isUnloaded) return; // cancel run if unloaded was called.
459
+ if (isUnloaded) {
460
+ return;
461
+ } // cancel run if unloaded was called.
575
462
  const nextTimeout = this.config.updateinterval * 1000;
576
463
 
577
464
  // devices data
@@ -581,8 +468,10 @@ class DeviceWatcher extends utils.Adapter {
581
468
 
582
469
  // devices data in own adapter folder
583
470
  if (this.configCreateOwnFolder) {
584
- for (const [id] of Object.entries(arrApart)) {
585
- if (this.configSetAdapter && this.configSetAdapter[id]) {
471
+ for (const [id] of Object.entries(adapterArray)) {
472
+ const adapter = adapterArray[id];
473
+
474
+ if (this.adapterSelected.includes(adapter.adapterKey)) {
586
475
  await crud.createLists(this, id);
587
476
  await crud.writeDatapoints(this, id);
588
477
  this.log.debug(`Created and filled data for ${tools.capitalize(id)}`);
@@ -634,7 +523,7 @@ class DeviceWatcher extends utils.Adapter {
634
523
 
635
524
  switch (this.selAdapter[i].adapterID) {
636
525
  case 'fullybrowser':
637
- deviceName = (await tools.getInitValue(this,currDeviceString + this.selAdapter[i].id)) + ' ' + (await tools.getInitValue(this,currDeviceString + this.selAdapter[i].id2));
526
+ deviceName = `${await tools.getInitValue(this, currDeviceString + this.selAdapter[i].id)} ${await tools.getInitValue(this, currDeviceString + this.selAdapter[i].id2)}`;
638
527
  break;
639
528
 
640
529
  // Get ID with short currDeviceString from objectjson
@@ -663,7 +552,7 @@ class DeviceWatcher extends utils.Adapter {
663
552
  case 'mihomeVacuum':
664
553
  case 'roomba':
665
554
  folderName = shortCurrDeviceString.slice(shortCurrDeviceString.lastIndexOf('.') + 1);
666
- deviceID = await tools.getInitValue(this,shortCurrDeviceString + this.selAdapter[i].id);
555
+ deviceID = await tools.getInitValue(this, shortCurrDeviceString + this.selAdapter[i].id);
667
556
  deviceName = `I${folderName} ${deviceID}`;
668
557
  break;
669
558
 
@@ -671,7 +560,7 @@ class DeviceWatcher extends utils.Adapter {
671
560
  case 'tado':
672
561
  case 'wifilight':
673
562
  case 'fullybrowserV3':
674
- case 'sonoff':
563
+ case 'sonoff':
675
564
  deviceName = currDeviceString.slice(currDeviceString.lastIndexOf('.') + 1);
676
565
  break;
677
566
 
@@ -679,7 +568,6 @@ class DeviceWatcher extends utils.Adapter {
679
568
  case 'sureflap':
680
569
  if (deviceObject && typeof deviceObject === 'object' && deviceObject.common) {
681
570
  deviceName = deviceObject.common.name
682
- // @ts-ignore FIXME: fix syntax error
683
571
  .replace(/'/g, '')
684
572
  .replace(/\(\d+\)/g, '')
685
573
  .trim()
@@ -695,7 +583,9 @@ class DeviceWatcher extends utils.Adapter {
695
583
 
696
584
  // Get ID with main selektor from objectjson
697
585
  default:
698
- if (this.selAdapter[i].id !== 'none' || this.selAdapter[i].id !== undefined) deviceName = await tools.getInitValue(this,currDeviceString + this.selAdapter[i].id);
586
+ if (this.selAdapter[i].id !== 'none' || this.selAdapter[i].id !== undefined) {
587
+ deviceName = await tools.getInitValue(this, currDeviceString + this.selAdapter[i].id);
588
+ }
699
589
  if (deviceName === null || deviceName === undefined) {
700
590
  if (deviceObject && typeof deviceObject === 'object' && deviceObject.common) {
701
591
  deviceName = deviceObject.common.name;
@@ -711,6 +601,7 @@ class DeviceWatcher extends utils.Adapter {
711
601
 
712
602
  /**
713
603
  * calculate Signalstrength
604
+ *
714
605
  * @param {object} deviceQualityState - State value
715
606
  * @param {object} adapterID - adapter name
716
607
  */
@@ -778,6 +669,7 @@ class DeviceWatcher extends utils.Adapter {
778
669
 
779
670
  /**
780
671
  * get battery data
672
+ *
781
673
  * @param {object} deviceBatteryState - State value
782
674
  * @param {object} deviceLowBatState - State value
783
675
  * @param {object} faultReportingState - State value
@@ -790,6 +682,17 @@ class DeviceWatcher extends utils.Adapter {
790
682
  let batteryHealthUnitRaw;
791
683
 
792
684
  switch (adapterID) {
685
+ case 'lupusec':
686
+ if (deviceBatteryState === undefined) {
687
+ if (deviceLowBatState === 1) {
688
+ batteryHealth = 'ok';
689
+ isBatteryDevice = true;
690
+ } else {
691
+ batteryHealth = 'low';
692
+ isBatteryDevice = true;
693
+ }
694
+ }
695
+ break;
793
696
  case 'hmrpc':
794
697
  if (deviceBatteryState === undefined) {
795
698
  if (faultReportingState !== undefined && faultReportingState !== 6) {
@@ -829,7 +732,7 @@ class DeviceWatcher extends utils.Adapter {
829
732
  break;
830
733
  default:
831
734
  batteryHealth = 'error';
832
- }
735
+ }
833
736
  }
834
737
  break;
835
738
  default:
@@ -845,12 +748,10 @@ class DeviceWatcher extends utils.Adapter {
845
748
  }
846
749
  } else {
847
750
  if (typeof deviceBatteryState === 'string') {
848
- if (deviceBatteryState === 'high' || deviceBatteryState === 'medium')
849
- {
751
+ if (deviceBatteryState === 'high' || deviceBatteryState === 'medium') {
850
752
  batteryHealth = 'ok';
851
753
  isBatteryDevice = true;
852
- }
853
- else if (deviceBatteryState === 'low') {
754
+ } else if (deviceBatteryState === 'low') {
854
755
  batteryHealth = 'low';
855
756
  isBatteryDevice = true;
856
757
  }
@@ -869,6 +770,7 @@ class DeviceWatcher extends utils.Adapter {
869
770
 
870
771
  /**
871
772
  * set low bat indicator
773
+ *
872
774
  * @param {object} deviceBatteryState
873
775
  * @param {object} deviceLowBatState
874
776
  * @param {object} faultReportState
@@ -896,7 +798,7 @@ class DeviceWatcher extends utils.Adapter {
896
798
  }
897
799
  } else if (typeof deviceBatteryState === 'number' && deviceBatteryState < this.config.minWarnBatterie) {
898
800
  lowBatIndicator = true;
899
- } else if (typeof deviceBatteryState === 'string' && deviceBatteryState === 'low') {
801
+ } else if (typeof deviceBatteryState === 'string' && deviceBatteryState === 'low') {
900
802
  lowBatIndicator = true;
901
803
  }
902
804
 
@@ -905,209 +807,217 @@ class DeviceWatcher extends utils.Adapter {
905
807
 
906
808
  /**
907
809
  * get Last Contact
810
+ *
908
811
  * @param {object} selector - Selector
909
812
  */
910
813
  async getLastContact(selector) {
911
- const lastContact = tools.getTimestamp(selector);
912
- let lastContactString;
814
+ const lastContact = tools.getTimestamp(selector); // z. B. Differenz in Sekunden?
913
815
 
914
- lastContactString = `${this.formatDate(new Date(selector), 'hh:mm')}`;
915
- if (Math.round(lastContact) > 100) {
916
- lastContactString = `${Math.round(lastContact / 60)} ${translations.hours[this.config.userSelectedLanguage]}`;
816
+ let lastContactString = `${this.formatDate(new Date(selector), 'hh:mm:ss')}`;
817
+
818
+ // Falls du die vergangene Zeit in Sekunden anzeigen willst:
819
+ if (Math.round(lastContact) >= 0) {
820
+ lastContactString = `${Math.round(lastContact)} ${translations.secs[this.config.userSelectedLanguage]}`;
917
821
  }
918
- if (Math.round(lastContact / 60) > 48) {
919
- lastContactString = `${Math.round(lastContact / 60 / 24)} ${translations.days[this.config.userSelectedLanguage]}`;
822
+
823
+ // Optional: Wenn du ab einem bestimmten Wert lieber Minuten oder Stunden willst
824
+ if (lastContact >= 3600) {
825
+ lastContactString = `${(lastContact / 3600).toFixed(1)} ${translations.hours[this.config.userSelectedLanguage]}`;
826
+ } else {
827
+ lastContactString = `${Math.round(lastContact / 60)} ${translations.minits[this.config.userSelectedLanguage]}`;
920
828
  }
829
+
921
830
  return lastContactString;
922
831
  }
923
832
 
924
- /**
925
- * get online state and time
926
- * @param {object} timeSelector - device Timeselector
927
- * @param {string} adapterID - ID of Adapter
928
- * @param {string} unreachDP - Datapoint of Unreach
929
- * @param {object} linkQuality - Linkquality Value
930
- * @param {object} deviceUnreachState - State of deviceUnreach datapoint
931
- * @param {string} deviceStateSelectorHMRPC - Selector of device state (like .state)
932
- * @param {string} rssiPeerSelectorHMRPC - HM RSSI Peer Datapoint
933
- */
934
- async getOnlineState(timeSelector, adapterID, unreachDP, linkQuality, deviceUnreachState, deviceStateSelectorHMRPC, rssiPeerSelectorHMRPC) {
833
+ async getOnlineState(timeSelector, adapterID, treeDP, linkQuality, deviceUnreachState, deviceStateSelectorHMRPC, rssiPeerSelectorHMRPC) {
935
834
  let lastContactString;
835
+ let lastContact;
936
836
  let deviceState = 'Online';
837
+ let linkQualitySet = linkQuality ?? '0%';
937
838
 
938
839
  try {
939
840
  const deviceTimeSelector = await this.getForeignStateAsync(timeSelector);
940
- const deviceUnreachSelector = await this.getForeignStateAsync(unreachDP);
941
- const deviceStateSelector = await this.getForeignStateAsync(deviceStateSelectorHMRPC); // for hmrpc devices
942
- const rssiPeerSelector = await this.getForeignStateAsync(rssiPeerSelectorHMRPC);
841
+ const deviceUnreachSelector = await this.getForeignStateAsync(treeDP);
842
+
943
843
  const lastDeviceUnreachStateChange = deviceUnreachSelector != undefined ? tools.getTimestamp(deviceUnreachSelector.lc) : tools.getTimestamp(timeSelector.ts);
944
844
 
945
845
  // ignore disabled device from zigbee2MQTT
946
846
  if (adapterID === 'zigbee2MQTT') {
947
- const is_device_disabled = await tools.isDisabledDevice(this, unreachDP.substring(0, unreachDP.lastIndexOf('.')));
847
+ const is_device_disabled = await tools.isDisabledDevice(this, treeDP.substring(0, treeDP.lastIndexOf('.')));
948
848
 
949
849
  if (is_device_disabled) {
950
- return [null, 'disabled', '0%'];
850
+ return [null, 'disabled', ' - '];
951
851
  }
952
852
  }
953
853
 
954
- // If there is no contact since user sets minutes add device in offline list
955
- // calculate to days after 48 hours
956
- switch (unreachDP) {
957
- case 'none':
958
- if (deviceTimeSelector) lastContactString = await this.getLastContact(deviceTimeSelector.ts);
959
- break;
854
+ if (adapterID === 'hmrpc') {
855
+ const deviceState = await this.getForeignStateAsync(deviceStateSelectorHMRPC);
856
+ const rssiPeer = await this.getForeignStateAsync(rssiPeerSelectorHMRPC);
857
+
858
+ if (linkQuality !== ' - ' && deviceTimeSelector) {
859
+ const ts = deviceUnreachState === 1 ? deviceTimeSelector.lc : deviceTimeSelector.ts;
860
+ lastContactString = await this.getLastContact(ts);
861
+ } else if (deviceState) {
862
+ lastContactString = await this.getLastContact(deviceState.ts);
863
+ } else if (rssiPeer) {
864
+ lastContactString = await this.getLastContact(rssiPeer.ts);
865
+ }
866
+ } else if (deviceTimeSelector) {
867
+ const ts = !deviceUnreachState ? deviceTimeSelector.lc : deviceTimeSelector.ts;
868
+ lastContactString = await this.getLastContact(ts);
869
+ }
960
870
 
961
- default:
962
- //State changed
963
- if (adapterID === 'hmrpc') {
964
- if (linkQuality !== ' - ' && deviceTimeSelector) {
965
- if (deviceUnreachState === 1) {
966
- lastContactString = await this.getLastContact(deviceTimeSelector.lc);
967
- } else {
968
- lastContactString = await this.getLastContact(deviceTimeSelector.ts);
969
- }
970
- } else {
971
- if (deviceStateSelector) {
972
- // because old hm devices don't send rssi states
973
- lastContactString = await this.getLastContact(deviceStateSelector.ts);
974
- } else if (rssiPeerSelector) {
975
- // because old hm sensors don't send rssi/state values
976
- lastContactString = await this.getLastContact(rssiPeerSelector.ts);
977
- }
978
- }
979
- } else {
980
- if ((!deviceUnreachState || deviceUnreachState === 0) && deviceTimeSelector) {
981
- lastContactString = await this.getLastContact(deviceTimeSelector.lc);
982
- } else {
983
- if (deviceTimeSelector) lastContactString = await this.getLastContact(deviceTimeSelector.ts);
984
- }
985
- break;
986
- }
871
+ if (deviceTimeSelector) {
872
+ lastContact = tools.getTimestamp(deviceTimeSelector.ts);
987
873
  }
988
874
 
989
- /*=============================================
990
- = Set Online Status =
991
- =============================================*/
992
- let lastContact;
993
- if (deviceTimeSelector) lastContact = tools.getTimestamp(deviceTimeSelector.ts);
875
+ const gefundenerAdapter = Object.values(adapterArray).find((adapter) => adapter.adapterID === adapterID);
876
+ const device = Object.values(this.config.tableDevices).find((adapter) => adapter.adapterKey === gefundenerAdapter.adapterKey);
877
+ const maxSecondDevicesOffline = device.maxSecondDevicesOffline;
994
878
 
995
- if (this.configMaxMinutes !== undefined) {
996
- switch (adapterID) {
997
- case 'hmrpc':
998
- if (this.configMaxMinutes[adapterID] <= 0) {
999
- if (deviceUnreachState === 1) {
1000
- deviceState = 'Offline'; //set online state to offline
1001
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
1002
- }
1003
- } else if (lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID] && deviceUnreachState === 1) {
879
+ switch (adapterID) {
880
+ case 'hmrpc': {
881
+ if (maxSecondDevicesOffline <= 0) {
882
+ if (deviceUnreachState === 1) {
1004
883
  deviceState = 'Offline'; //set online state to offline
1005
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
884
+ if (linkQuality !== ' - ') {
885
+ linkQualitySet = '0%';
886
+ } // set linkQuality to nothing
1006
887
  }
1007
- break;
1008
- case 'proxmox':
1009
- if (this.configMaxMinutes[adapterID] <= 0) {
1010
- if (deviceUnreachState !== 'running' && deviceUnreachState !== 'online') {
1011
- deviceState = 'Offline'; //set online state to offline
1012
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
1013
- }
1014
- } else if (lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID] && deviceUnreachState !== 'running' && deviceUnreachState !== 'online') {
888
+ } else if (lastDeviceUnreachStateChange > maxSecondDevicesOffline && deviceUnreachState === 1) {
889
+ deviceState = 'Offline'; //set online state to offline
890
+ if (linkQuality !== ' - ') {
891
+ linkQualitySet = '0%';
892
+ } // set linkQuality to nothing
893
+ }
894
+ break;
895
+ }
896
+ case 'proxmox': {
897
+ if (maxSecondDevicesOffline <= 0) {
898
+ if (deviceUnreachState !== 'running' && deviceUnreachState !== 'online') {
1015
899
  deviceState = 'Offline'; //set online state to offline
1016
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
900
+ if (linkQuality !== ' - ') {
901
+ linkQualitySet = '0%';
902
+ } // set linkQuality to nothing
1017
903
  }
1018
- break;
1019
- case 'hmiP':
1020
- case 'maxcube':
1021
- if (this.configMaxMinutes[adapterID] <= 0) {
1022
- if (deviceUnreachState) {
1023
- deviceState = 'Offline'; //set online state to offline
1024
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
1025
- }
1026
- } else if (lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID] && deviceUnreachState) {
904
+ } else if (lastDeviceUnreachStateChange > maxSecondDevicesOffline && deviceUnreachState !== 'running' && deviceUnreachState !== 'online') {
905
+ deviceState = 'Offline'; //set online state to offline
906
+ if (linkQuality !== ' - ') {
907
+ linkQualitySet = '0%';
908
+ } // set linkQuality to nothing
909
+ }
910
+ break;
911
+ }
912
+ case 'hmiP':
913
+ case 'maxcube': {
914
+ if (maxSecondDevicesOffline <= 0) {
915
+ if (deviceUnreachState) {
1027
916
  deviceState = 'Offline'; //set online state to offline
1028
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
917
+ if (linkQuality !== ' - ') {
918
+ linkQualitySet = '0%';
919
+ } // set linkQuality to nothing
1029
920
  }
1030
- break;
1031
- case 'apcups':
1032
- case 'hue':
1033
- case 'hueExt':
1034
- case 'ping':
1035
- case 'deconz':
1036
- case 'shelly':
1037
- case 'sonoff':
1038
- case 'tradfri':
1039
- case 'unifi':
1040
- case 'zigbee':
1041
- case 'zigbee2MQTT':
1042
- if (this.configMaxMinutes[adapterID] <= 0) {
1043
- if (!deviceUnreachState) {
1044
- deviceState = 'Offline'; //set online state to offline
1045
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
1046
- }
1047
- } else if (!deviceUnreachState && lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID]) {
921
+ } else if (lastDeviceUnreachStateChange > maxSecondDevicesOffline && deviceUnreachState) {
922
+ deviceState = 'Offline'; //set online state to offline
923
+ if (linkQuality !== ' - ') {
924
+ linkQualitySet = '0%';
925
+ } // set linkQuality to nothing
926
+ }
927
+ break;
928
+ }
929
+ case 'apcups':
930
+ case 'hue':
931
+ case 'hueExt':
932
+ case 'ping':
933
+ case 'deconz':
934
+ case 'shelly':
935
+ case 'sonoff':
936
+ case 'tradfri':
937
+ case 'unifi':
938
+ case 'zigbee':
939
+ case 'zigbee2MQTT': {
940
+ if (maxSecondDevicesOffline <= 0) {
941
+ if (!deviceUnreachState) {
1048
942
  deviceState = 'Offline'; //set online state to offline
1049
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
943
+ if (linkQuality !== ' - ') {
944
+ linkQualitySet = '0%';
945
+ } // set linkQuality to nothing
1050
946
  }
1051
- break;
1052
- case 'mqttClientZigbee2Mqtt':
1053
- if (this.configMaxMinutes[adapterID] <= 0) {
1054
- if (deviceUnreachState !== 'online') {
1055
- deviceState = 'Offline'; //set online state to offline
1056
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
1057
- }
1058
- } else if (deviceUnreachState !== 'online' && lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID]) {
947
+ } else if (!deviceUnreachState && lastDeviceUnreachStateChange > maxSecondDevicesOffline) {
948
+ deviceState = 'Offline'; //set online state to offline
949
+ if (linkQuality !== ' - ') {
950
+ linkQualitySet = '0%';
951
+ } // set linkQuality to nothing
952
+ }
953
+ break;
954
+ }
955
+ case 'mqttClientZigbee2Mqtt': {
956
+ if (maxSecondDevicesOffline <= 0) {
957
+ if (deviceUnreachState !== 'online') {
1059
958
  deviceState = 'Offline'; //set online state to offline
1060
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
959
+ if (linkQuality !== ' - ') {
960
+ linkQualitySet = '0%';
961
+ } // set linkQuality to nothing
1061
962
  }
1062
- break;
1063
- case 'mihome':
1064
- if (deviceUnreachState !== undefined) {
1065
- if (this.configMaxMinutes[adapterID] <= 0) {
1066
- if (!deviceUnreachState) {
1067
- deviceState = 'Offline'; //set online state to offline
1068
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
1069
- }
1070
- } else if (lastContact && lastContact > this.configMaxMinutes[adapterID]) {
1071
- deviceState = 'Offline'; //set online state to offline
1072
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
1073
- }
1074
- } else {
1075
- if (this.config.mihomeMaxMinutes <= 0) {
1076
- if (this.configMaxMinutes[adapterID] <= 0) {
1077
- deviceState = 'Offline'; //set online state to offline
1078
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
1079
- }
1080
- } else if (lastContact && lastContact > this.configMaxMinutes[adapterID]) {
1081
- deviceState = 'Offline'; //set online state to offline
1082
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
1083
- }
963
+ } else if (deviceUnreachState !== 'online' && lastDeviceUnreachStateChange > maxSecondDevicesOffline) {
964
+ deviceState = 'Offline'; //set online state to offline
965
+ if (linkQuality !== ' - ') {
966
+ linkQualitySet = '0%';
1084
967
  }
1085
- break;
1086
- case 'smartgarden':
1087
- if (this.configMaxMinutes[adapterID] <= 0) {
1088
- if (deviceUnreachState === 'OFFLINE') {
1089
- deviceState = 'Offline'; //set online state to offline
1090
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
1091
- }
1092
- } else if (deviceUnreachState === 'OFFLINE' && lastDeviceUnreachStateChange > this.configMaxMinutes[adapterID]) {
1093
- deviceState = 'Offline'; //set online state to offline
1094
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
968
+ }
969
+ break;
970
+ }
971
+ case 'mihome': {
972
+ const offlineByTime = maxSecondDevicesOffline <= 0 || (lastContact && lastContact > maxSecondDevicesOffline);
973
+ const offlineByState = deviceUnreachState !== undefined ? !deviceUnreachState && offlineByTime : offlineByTime;
974
+
975
+ if (offlineByState) {
976
+ deviceState = 'Offline';
977
+ if (linkQuality !== ' - ') {
978
+ linkQualitySet = '0%';
1095
979
  }
1096
- break;
1097
- default:
1098
- if (this.configMaxMinutes[adapterID] <= 0) {
1099
- if (!deviceUnreachState) {
1100
- deviceState = 'Offline'; //set online state to offline
1101
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
1102
- }
1103
- } else if (lastContact && lastContact > this.configMaxMinutes[adapterID]) {
980
+ }
981
+ break;
982
+ }
983
+ case 'smartgarden': {
984
+ if (maxSecondDevicesOffline <= 0) {
985
+ if (deviceUnreachState === 'OFFLINE') {
1104
986
  deviceState = 'Offline'; //set online state to offline
1105
- if (linkQuality !== ' - ') linkQuality = '0%'; // set linkQuality to nothing
987
+ if (linkQuality !== ' - ') {
988
+ linkQualitySet = '0%';
989
+ } // set linkQuality to nothing
1106
990
  }
1107
- break;
991
+ } else if (deviceUnreachState === 'OFFLINE' && lastDeviceUnreachStateChange > maxSecondDevicesOffline) {
992
+ deviceState = 'Offline'; //set online state to offline
993
+ if (linkQuality !== ' - ') {
994
+ linkQualitySet = '0%';
995
+ } // set linkQuality to nothing
996
+ }
997
+ break;
998
+ }
999
+ default: {
1000
+ // Gerät gilt als offline, wenn es unerreichbar ist und keine Wartezeit definiert ist, oder wenn der letzte Kontakt zu lange her ist als Wartezeit
1001
+ let shouldBeOffline = false;
1002
+
1003
+ if (maxSecondDevicesOffline <= 0) {
1004
+ if (!deviceUnreachState) {
1005
+ shouldBeOffline = true;
1006
+ }
1007
+ } else if (lastContact && lastContact > maxSecondDevicesOffline) {
1008
+ shouldBeOffline = true;
1009
+ }
1010
+
1011
+ if (shouldBeOffline) {
1012
+ deviceState = 'Offline'; // Gerät auf offline setzen
1013
+ if (linkQuality !== ' - ') {
1014
+ linkQualitySet = '0%';
1015
+ }
1016
+ }
1108
1017
  }
1109
1018
  }
1110
- return [lastContactString, deviceState, linkQuality];
1019
+
1020
+ return [lastContactString, deviceState, linkQualitySet];
1111
1021
  } catch (error) {
1112
1022
  this.log.error(`[getLastContact] - ${error}`);
1113
1023
  }
@@ -1118,31 +1028,22 @@ class DeviceWatcher extends utils.Adapter {
1118
1028
  * @param {string | number | boolean | null} deviceUpdateSelector
1119
1029
  */
1120
1030
  async checkDeviceUpdate(adapterID, deviceUpdateSelector) {
1121
- let isUpgradable;
1031
+ let isUpgradable = false;
1122
1032
 
1123
1033
  switch (adapterID) {
1124
1034
  case 'hmiP':
1125
- if (deviceUpdateSelector === 'UPDATE_AVAILABLE') {
1126
- isUpgradable = true;
1127
- } else {
1128
- isUpgradable = false;
1129
- }
1035
+ isUpgradable = deviceUpdateSelector === 'UPDATE_AVAILABLE';
1130
1036
  break;
1037
+
1131
1038
  case 'ring':
1132
- if (deviceUpdateSelector !== 'Up to Date') {
1133
- isUpgradable = true;
1134
- } else {
1135
- isUpgradable = false;
1136
- }
1039
+ isUpgradable = deviceUpdateSelector !== 'Up to Date';
1137
1040
  break;
1041
+
1138
1042
  default:
1139
- if (deviceUpdateSelector !== null && typeof deviceUpdateSelector === 'boolean') {
1140
- if (deviceUpdateSelector) {
1141
- isUpgradable = true;
1142
- } else if (!deviceUpdateSelector) {
1143
- isUpgradable = false;
1144
- }
1043
+ if (typeof deviceUpdateSelector === 'boolean') {
1044
+ isUpgradable = deviceUpdateSelector;
1145
1045
  }
1046
+ break;
1146
1047
  }
1147
1048
 
1148
1049
  return isUpgradable;
@@ -1150,17 +1051,17 @@ class DeviceWatcher extends utils.Adapter {
1150
1051
 
1151
1052
  /**
1152
1053
  * fill the lists for user
1054
+ *
1153
1055
  * @param {object} device
1154
1056
  */
1155
1057
  async theLists(device) {
1156
1058
  // Raw List with all devices for user
1157
1059
  if (device.Status !== 'disabled') {
1158
-
1159
1060
  this.listAllDevicesUserRaw.push({
1160
1061
  Device: device.Device,
1161
1062
  Adapter: device.Adapter,
1162
1063
  Instance: device.instance,
1163
- 'Instance connected': device.instancedeviceConnected,
1064
+ 'Instance connected': device.instanceDeviceConnected,
1164
1065
  isBatteryDevice: device.isBatteryDevice,
1165
1066
  Battery: device.Battery,
1166
1067
  BatteryRaw: device.BatteryRaw,
@@ -1230,12 +1131,12 @@ class DeviceWatcher extends utils.Adapter {
1230
1131
  }
1231
1132
  }
1232
1133
 
1233
-
1234
1134
  /**
1235
1135
  * @param {string | string[]} id
1236
1136
  * @param {ioBroker.State} state
1237
1137
  */
1238
1138
  async renewDeviceData(id, state) {
1139
+ const regex = /^([^.]+\.\d+\.[^.]+)/;
1239
1140
  let batteryData;
1240
1141
  let signalData;
1241
1142
  let oldLowBatState;
@@ -1243,16 +1144,21 @@ class DeviceWatcher extends utils.Adapter {
1243
1144
  let oldStatus;
1244
1145
  let isLowBatValue;
1245
1146
 
1246
- const deviceID = id.slice(0, id.lastIndexOf('.') + 1 - 1);
1147
+ const deviceID = id.match(regex)[1];
1247
1148
  const deviceData = this.listAllDevicesRaw.get(deviceID);
1248
1149
 
1150
+ this.log.debug(`[renewDeviceData] - ${id}`);
1151
+
1249
1152
  if (deviceData) {
1153
+ const gefundenerAdapter = Object.values(adapterArray).find((adapter) => adapter.adapterID === deviceData.adapterID);
1154
+ const silentEnabled = Object.values(this.config.tableDevices).find((adapter) => adapter.adapterKey === gefundenerAdapter.adapterKey);
1155
+
1250
1156
  // On statechange update available datapoint
1251
1157
  switch (id) {
1252
1158
  // device connection
1253
1159
  case deviceData.instanceDeviceConnectionDP:
1254
- if (state.val !== deviceData.instancedeviceConnected) {
1255
- deviceData.instancedeviceConnected = state.val;
1160
+ if (state.val !== deviceData.instanceDeviceConnected) {
1161
+ deviceData.instanceDeviceConnected = state.val;
1256
1162
  }
1257
1163
  break;
1258
1164
 
@@ -1262,7 +1168,7 @@ class DeviceWatcher extends utils.Adapter {
1262
1168
  deviceData.Upgradable = await this.checkDeviceUpdate(deviceData.adapterID, state.val);
1263
1169
  if (deviceData.Upgradable === true) {
1264
1170
  if (this.config.checkSendDeviceUpgrade && !this.blacklistNotify.includes(deviceData.Path)) {
1265
- await this.sendStateNotifications('Devices', 'updateDevice', deviceID);
1171
+ await this.sendStateNotifications('Devices', 'updateDevice', deviceID, silentEnabled.telegramSilent);
1266
1172
  }
1267
1173
  }
1268
1174
  }
@@ -1279,14 +1185,16 @@ class DeviceWatcher extends utils.Adapter {
1279
1185
  case deviceData.batteryDP:
1280
1186
  if (deviceData.isBatteryDevice) {
1281
1187
  oldLowBatState = deviceData.LowBat;
1282
- if (state.val === 0 && deviceData.BatteryRaw >= 5) return;
1188
+ if (state.val === 0 && deviceData.BatteryRaw >= 5) {
1189
+ return;
1190
+ }
1283
1191
  batteryData = await this.getBatteryData(state.val, oldLowBatState, deviceData.faultReport, deviceData.adapterID);
1284
1192
 
1285
1193
  deviceData.Battery = batteryData[0];
1286
1194
  deviceData.BatteryRaw = batteryData[2];
1287
1195
  deviceData.BatteryUnitRaw = batteryData[3];
1288
1196
  if (deviceData.LowBatDP !== 'none') {
1289
- isLowBatValue = await tools.getInitValue(this,deviceData.LowBatDP);
1197
+ isLowBatValue = await tools.getInitValue(this, deviceData.LowBatDP);
1290
1198
  } else {
1291
1199
  isLowBatValue = undefined;
1292
1200
  }
@@ -1294,7 +1202,7 @@ class DeviceWatcher extends utils.Adapter {
1294
1202
 
1295
1203
  if (deviceData.LowBat && oldLowBatState !== deviceData.LowBat) {
1296
1204
  if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(deviceData.Path)) {
1297
- await this.sendStateNotifications('Devices', 'lowBatDevice', deviceID);
1205
+ await this.sendStateNotifications('Devices', 'lowBatDevice', deviceID, silentEnabled.telegramSilent);
1298
1206
  }
1299
1207
  }
1300
1208
  }
@@ -1312,7 +1220,7 @@ class DeviceWatcher extends utils.Adapter {
1312
1220
 
1313
1221
  if (deviceData.LowBat && oldLowBatState !== deviceData.LowBat) {
1314
1222
  if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(deviceData.Path)) {
1315
- await this.sendStateNotifications('Devices', 'lowBatDevice', deviceID);
1223
+ await this.sendStateNotifications('Devices', 'lowBatDevice', deviceID, silentEnabled.telegramSilent);
1316
1224
  }
1317
1225
  }
1318
1226
  }
@@ -1331,7 +1239,7 @@ class DeviceWatcher extends utils.Adapter {
1331
1239
 
1332
1240
  if (deviceData.LowBat && oldLowBatState !== deviceData.LowBat) {
1333
1241
  if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(deviceData.Path)) {
1334
- await this.sendStateNotifications('Devices', 'lowBatDevice', deviceID);
1242
+ await this.sendStateNotifications('Devices', 'lowBatDevice', deviceID, silentEnabled.telegramSilent);
1335
1243
  }
1336
1244
  }
1337
1245
  }
@@ -1339,10 +1247,11 @@ class DeviceWatcher extends utils.Adapter {
1339
1247
 
1340
1248
  // device unreach
1341
1249
  case deviceData.UnreachDP:
1342
- if (deviceData.instancedeviceConnected !== undefined) {
1250
+ if (deviceData.instanceDeviceConnected !== undefined) {
1343
1251
  if (deviceData.UnreachState !== state.val) {
1344
1252
  oldStatus = deviceData.Status;
1345
1253
  deviceData.UnreachState = state.val;
1254
+
1346
1255
  contactData = await this.getOnlineState(
1347
1256
  deviceData.timeSelector,
1348
1257
  deviceData.adapterID,
@@ -1352,20 +1261,21 @@ class DeviceWatcher extends utils.Adapter {
1352
1261
  deviceData.deviceStateSelectorHMRPC,
1353
1262
  deviceData.rssiPeerSelectorHMRPC,
1354
1263
  );
1355
- if (contactData !== undefined && contactData !== null) {
1264
+
1265
+ if (contactData !== undefined || contactData !== null) {
1356
1266
  deviceData.LastContact = contactData[0];
1357
1267
  deviceData.Status = contactData[1];
1358
1268
  deviceData.SignalStrength = contactData[2];
1359
1269
  }
1270
+
1360
1271
  if (this.config.checkSendOfflineMsg && oldStatus !== deviceData.Status && !this.blacklistNotify.includes(deviceData.Path)) {
1361
1272
  // check if the generally deviceData connected state is for a while true
1362
1273
  if (await tools.getTimestampConnectionDP(this, deviceData.instanceDeviceConnectionDP, 50000)) {
1363
- await this.sendStateNotifications('Devices', 'onlineStateDevice', deviceID);
1274
+ await this.sendStateNotifications('Devices', 'onlineStateDevice', deviceID, silentEnabled.telegramSilent);
1364
1275
  }
1365
1276
  }
1366
1277
  }
1367
1278
  }
1368
- break;
1369
1279
  }
1370
1280
  }
1371
1281
  }
@@ -1384,6 +1294,7 @@ class DeviceWatcher extends utils.Adapter {
1384
1294
 
1385
1295
  /**
1386
1296
  * get instance data
1297
+ *
1387
1298
  *@param {string} instanceObject
1388
1299
  */
1389
1300
  async getInstanceData(instanceObject) {
@@ -1392,22 +1303,23 @@ class DeviceWatcher extends utils.Adapter {
1392
1303
 
1393
1304
  this.adapterUpdatesJsonRaw = await this.getAdapterUpdateData(adapterUpdateListDP);
1394
1305
 
1395
-
1396
1306
  for (const [id] of Object.entries(instanceAliveDP)) {
1397
- if (!(typeof id === 'string' && id.startsWith(`system.adapter.`))) continue;
1307
+ if (!(typeof id === 'string' && id.startsWith(`system.adapter.`))) {
1308
+ continue;
1309
+ }
1398
1310
 
1399
1311
  // get instance name
1400
1312
  const instanceID = await this.getInstanceName(id);
1401
1313
 
1402
1314
  // get instance connected to host data
1403
1315
  const instanceConnectedHostDP = `system.adapter.${instanceID}.connected`;
1404
- const instanceConnectedHostVal = await tools.getInitValue(this,instanceConnectedHostDP);
1316
+ const instanceConnectedHostVal = await tools.getInitValue(this, instanceConnectedHostDP);
1405
1317
 
1406
1318
  // get instance connected to device data
1407
1319
  const instanceConnectedDeviceDP = `${instanceID}.info.connection`;
1408
1320
  let instanceConnectedDeviceVal;
1409
1321
  if (instanceConnectedDeviceDP !== undefined && typeof instanceConnectedDeviceDP === 'boolean') {
1410
- instanceConnectedDeviceVal = await tools.getInitValue(this,instanceConnectedDeviceDP);
1322
+ instanceConnectedDeviceVal = await tools.getInitValue(this, instanceConnectedDeviceDP);
1411
1323
  } else {
1412
1324
  instanceConnectedDeviceVal = 'N/A';
1413
1325
  }
@@ -1421,7 +1333,6 @@ class DeviceWatcher extends utils.Adapter {
1421
1333
  let scheduleTime = 'N/A';
1422
1334
  const instanceObjectData = await this.getForeignObjectAsync(instanceObjectPath);
1423
1335
  if (instanceObjectData) {
1424
- // @ts-ignore
1425
1336
  adapterName = tools.capitalize(instanceObjectData.common.name);
1426
1337
  adapterVersion = instanceObjectData.common.version;
1427
1338
  instanceMode = instanceObjectData.common.mode;
@@ -1431,10 +1342,7 @@ class DeviceWatcher extends utils.Adapter {
1431
1342
  }
1432
1343
  }
1433
1344
 
1434
-
1435
- const updateEntry = this.adapterUpdatesJsonRaw.find(
1436
- entry => entry.adapter.toLowerCase() === adapterName.toLowerCase()
1437
- );
1345
+ const updateEntry = this.adapterUpdatesJsonRaw.find((entry) => entry.adapter.toLowerCase() === adapterName.toLowerCase());
1438
1346
 
1439
1347
  if (updateEntry) {
1440
1348
  adapterAvailableUpdate = updateEntry.newVersion;
@@ -1492,6 +1400,7 @@ class DeviceWatcher extends utils.Adapter {
1492
1400
 
1493
1401
  /**
1494
1402
  * get Instances
1403
+ *
1495
1404
  * @param {string} id - Path of alive datapoint
1496
1405
  */
1497
1406
  async getInstanceName(id) {
@@ -1503,12 +1412,13 @@ class DeviceWatcher extends utils.Adapter {
1503
1412
 
1504
1413
  /**
1505
1414
  * Check if instance is alive and ok
1415
+ *
1506
1416
  * @param {string} instanceID
1507
1417
  */
1508
1418
  async checkDaemonIsHealthy(instanceID) {
1509
- const connectedHostState = await tools.getInitValue(this,`system.adapter.${instanceID}.connected`);
1510
- const isAlive = await tools.getInitValue(this,`system.adapter.${instanceID}.alive`);
1511
- let connectedDeviceState = await tools.getInitValue(this,`${instanceID}.info.connection`);
1419
+ const connectedHostState = await tools.getInitValue(this, `system.adapter.${instanceID}.connected`);
1420
+ const isAlive = await tools.getInitValue(this, `system.adapter.${instanceID}.alive`);
1421
+ let connectedDeviceState = await tools.getInitValue(this, `${instanceID}.info.connection`);
1512
1422
  if (connectedDeviceState === undefined) {
1513
1423
  connectedDeviceState = true;
1514
1424
  }
@@ -1532,11 +1442,12 @@ class DeviceWatcher extends utils.Adapter {
1532
1442
 
1533
1443
  /**
1534
1444
  * Check if instance is alive and ok
1445
+ *
1535
1446
  * @param {string} instanceID
1536
1447
  * @param {number} instanceDeactivationTime
1537
1448
  */
1538
1449
  async checkDaemonIsAlive(instanceID, instanceDeactivationTime) {
1539
- let isAlive = await tools.getInitValue(this,`system.adapter.${instanceID}.alive`);
1450
+ let isAlive = await tools.getInitValue(this, `system.adapter.${instanceID}.alive`);
1540
1451
  let daemonIsAlive;
1541
1452
  let isHealthy = false;
1542
1453
  let instanceStatusString = isAlive ? translations.instance_activated[this.config.userSelectedLanguage] : translations.instance_deactivated[this.config.userSelectedLanguage];
@@ -1573,7 +1484,7 @@ class DeviceWatcher extends utils.Adapter {
1573
1484
 
1574
1485
  if (isAliveSchedule) {
1575
1486
  lastUpdate = Math.round((Date.now() - isAliveSchedule.lc) / 1000); // Last state change in seconds
1576
- previousCronRun = tools.getPreviousCronRun(this, scheduleTime); // When was the last cron run
1487
+ previousCronRun = this.getPreviousCronRun(scheduleTime); // When was the last cron run
1577
1488
  if (previousCronRun) {
1578
1489
  lastCronRun = Math.round(previousCronRun / 1000); // change distance to last run in seconds
1579
1490
  diff = lastCronRun - lastUpdate;
@@ -1591,6 +1502,7 @@ class DeviceWatcher extends utils.Adapter {
1591
1502
 
1592
1503
  /**
1593
1504
  * set status for instance
1505
+ *
1594
1506
  * @param {string} instanceMode
1595
1507
  * @param {string} scheduleTime
1596
1508
  * @param {any} instanceID
@@ -1655,33 +1567,29 @@ class DeviceWatcher extends utils.Adapter {
1655
1567
 
1656
1568
  /**
1657
1569
  * create adapter update raw lists
1570
+ *
1658
1571
  * @param {string} adapterUpdateListDP
1659
1572
  */
1660
1573
  async getAdapterUpdateData(adapterUpdateListDP) {
1661
1574
  // Clear the existing adapter updates data
1662
1575
  let adapterUpdatesJsonRaw = [];
1576
+ let adapterJsonList;
1663
1577
 
1664
1578
  // Fetch the adapter updates list
1665
1579
  const adapterUpdatesListVal = await this.getForeignStatesAsync(adapterUpdateListDP);
1666
1580
 
1667
- let adapterJsonList;
1668
- let adapterUpdatesJsonPath;
1669
-
1670
1581
  // Extract adapter data from the list
1671
1582
  for (const [id, value] of Object.entries(adapterUpdatesListVal)) {
1672
1583
  adapterJsonList = tools.parseData(value.val);
1673
- adapterUpdatesJsonPath = id;
1674
1584
  }
1675
1585
 
1676
1586
  // Populate the adapter updates data
1677
1587
  for (const [id, adapterData] of Object.entries(adapterJsonList)) {
1678
- adapterUpdatesJsonRaw.push(
1679
- {
1680
- adapter: tools.capitalize(id),
1681
- newVersion: adapterData.availableVersion,
1682
- oldVersion: adapterData.installedVersion,
1683
- }
1684
- );
1588
+ adapterUpdatesJsonRaw.push({
1589
+ adapter: tools.capitalize(id),
1590
+ newVersion: adapterData.availableVersion,
1591
+ oldVersion: adapterData.installedVersion,
1592
+ });
1685
1593
  }
1686
1594
 
1687
1595
  return adapterUpdatesJsonRaw;
@@ -1746,7 +1654,9 @@ class DeviceWatcher extends utils.Adapter {
1746
1654
  });
1747
1655
  }
1748
1656
 
1749
- if (this.blacklistInstancesLists.includes(instance)) continue;
1657
+ if (this.blacklistInstancesLists.includes(instance)) {
1658
+ continue;
1659
+ }
1750
1660
  // all instances
1751
1661
  this.listAllInstances.push({
1752
1662
  [translations.Adapter[this.config.userSelectedLanguage]]: instanceData.Adapter,
@@ -1862,9 +1772,7 @@ class DeviceWatcher extends utils.Adapter {
1862
1772
 
1863
1773
  // Update instances with available adapter updates
1864
1774
  for (const instance of this.listInstanceRaw.values()) {
1865
- const adapterUpdate = this.adapterUpdatesJsonRaw.find(
1866
- entry => entry.adapter.toLowerCase() === instance.Adapter.toLowerCase()
1867
- );
1775
+ const adapterUpdate = this.adapterUpdatesJsonRaw.find((entry) => entry.adapter.toLowerCase() === instance.Adapter.toLowerCase());
1868
1776
 
1869
1777
  if (adapterUpdate) {
1870
1778
  instance.updateAvailable = adapterUpdate.newVersion;
@@ -1875,6 +1783,7 @@ class DeviceWatcher extends utils.Adapter {
1875
1783
  }
1876
1784
  /**
1877
1785
  * call function on state change, renew data and send messages
1786
+ *
1878
1787
  * @param {string} id
1879
1788
  * @param {ioBroker.State} state
1880
1789
  */
@@ -1900,7 +1809,9 @@ class DeviceWatcher extends utils.Adapter {
1900
1809
  await checkInstance(instanceID, instanceData);
1901
1810
  // send message when instance was deactivated
1902
1811
  if (this.config.checkSendInstanceDeactivatedMsg && !instanceData.isAlive) {
1903
- if (this.blacklistInstancesNotify.includes(instanceID)) return;
1812
+ if (this.blacklistInstancesNotify.includes(instanceID)) {
1813
+ return;
1814
+ }
1904
1815
  await this.sendStateNotifications('Instances', 'deactivatedInstance', instanceID);
1905
1816
  }
1906
1817
  }
@@ -1911,7 +1822,9 @@ class DeviceWatcher extends utils.Adapter {
1911
1822
  await checkInstance(instanceID, instanceData);
1912
1823
  // send message when instance has an error
1913
1824
  if (this.config.checkSendInstanceFailedMsg && !instanceData.isHealthy && instanceData.isAlive) {
1914
- if (this.blacklistInstancesNotify.includes(instanceID)) return;
1825
+ if (this.blacklistInstancesNotify.includes(instanceID)) {
1826
+ return;
1827
+ }
1915
1828
  await this.sendStateNotifications('Instances', 'errorInstance', instanceID);
1916
1829
  }
1917
1830
  }
@@ -1922,7 +1835,9 @@ class DeviceWatcher extends utils.Adapter {
1922
1835
  await checkInstance(instanceID, instanceData);
1923
1836
  // send message when instance has an error
1924
1837
  if (this.config.checkSendInstanceFailedMsg && !instanceData.isHealthy && instanceData.isAlive) {
1925
- if (this.blacklistInstancesNotify.includes(instanceID)) return;
1838
+ if (this.blacklistInstancesNotify.includes(instanceID)) {
1839
+ return;
1840
+ }
1926
1841
  await this.sendStateNotifications('Instances', 'errorInstance', instanceID);
1927
1842
  }
1928
1843
  }
@@ -1937,14 +1852,16 @@ class DeviceWatcher extends utils.Adapter {
1937
1852
 
1938
1853
  /**
1939
1854
  * Notification service
1855
+ *
1940
1856
  * @param {string} text - Text which should be send
1857
+ * @param silent
1941
1858
  */
1942
- async sendNotification(text) {
1859
+ async sendNotification(text, silent = false) {
1943
1860
  // Pushover
1944
1861
  if (this.config.instancePushover) {
1945
1862
  try {
1946
1863
  //first check if instance is living
1947
- const pushoverAliveState = await tools.getInitValue(this,'system.adapter.' + this.config.instancePushover + '.alive');
1864
+ const pushoverAliveState = await tools.getInitValue(this, `system.adapter.${this.config.instancePushover}.alive`);
1948
1865
 
1949
1866
  if (!pushoverAliveState) {
1950
1867
  this.log.warn('Pushover instance is not running. Message could not be sent. Please check your instance configuration.');
@@ -1966,7 +1883,7 @@ class DeviceWatcher extends utils.Adapter {
1966
1883
  if (this.config.instanceTelegram) {
1967
1884
  try {
1968
1885
  //first check if instance is living
1969
- const telegramAliveState = await tools.getInitValue(this,'system.adapter.' + this.config.instanceTelegram + '.alive');
1886
+ const telegramAliveState = await tools.getInitValue(this, `system.adapter.${this.config.instanceTelegram}.alive`);
1970
1887
 
1971
1888
  if (!telegramAliveState) {
1972
1889
  this.log.warn('Telegram instance is not running. Message could not be sent. Please check your instance configuration.');
@@ -1975,6 +1892,7 @@ class DeviceWatcher extends utils.Adapter {
1975
1892
  text: text,
1976
1893
  user: this.config.deviceTelegram,
1977
1894
  chatId: this.config.chatIdTelegram,
1895
+ disable_notification: silent,
1978
1896
  });
1979
1897
  }
1980
1898
  } catch (error) {
@@ -1986,7 +1904,7 @@ class DeviceWatcher extends utils.Adapter {
1986
1904
  if (this.config.instanceWhatsapp) {
1987
1905
  try {
1988
1906
  //first check if instance is living
1989
- const whatsappAliveState = await tools.getInitValue(this,'system.adapter.' + this.config.instanceWhatsapp + '.alive');
1907
+ const whatsappAliveState = await tools.getInitValue(this, `system.adapter.${this.config.instanceWhatsapp}.alive`);
1990
1908
 
1991
1909
  if (!whatsappAliveState) {
1992
1910
  this.log.warn('Whatsapp instance is not running. Message could not be sent. Please check your instance configuration.');
@@ -2005,7 +1923,7 @@ class DeviceWatcher extends utils.Adapter {
2005
1923
  if (this.config.instanceMatrix) {
2006
1924
  try {
2007
1925
  //first check if instance is living
2008
- const matrixAliveState = await tools.getInitValue(this,'system.adapter.' + this.config.instanceMatrix + '.alive');
1926
+ const matrixAliveState = await tools.getInitValue(this, `system.adapter.${this.config.instanceMatrix}.alive`);
2009
1927
 
2010
1928
  if (!matrixAliveState) {
2011
1929
  this.log.warn('Matrix instance is not running. Message could not be sent. Please check your instance configuration.');
@@ -2024,7 +1942,7 @@ class DeviceWatcher extends utils.Adapter {
2024
1942
  if (this.config.instanceSignal) {
2025
1943
  try {
2026
1944
  //first check if instance is living
2027
- const signalAliveState = await tools.getInitValue(this,'system.adapter.' + this.config.instanceSignal + '.alive');
1945
+ const signalAliveState = await tools.getInitValue(this, `system.adapter.${this.config.instanceSignal}.alive`);
2028
1946
 
2029
1947
  if (!signalAliveState) {
2030
1948
  this.log.warn('Signal instance is not running. Message could not be sent. Please check your instance configuration.');
@@ -2043,7 +1961,7 @@ class DeviceWatcher extends utils.Adapter {
2043
1961
  if (this.config.instanceEmail) {
2044
1962
  try {
2045
1963
  //first check if instance is living
2046
- const eMailAliveState = await tools.getInitValue(this,'system.adapter.' + this.config.instanceEmail + '.alive');
1964
+ const eMailAliveState = await tools.getInitValue(this, `system.adapter.${this.config.instanceEmail}.alive`);
2047
1965
 
2048
1966
  if (!eMailAliveState) {
2049
1967
  this.log.warn('eMail instance is not running. Message could not be sent. Please check your instance configuration.');
@@ -2063,7 +1981,7 @@ class DeviceWatcher extends utils.Adapter {
2063
1981
  if (this.config.instanceJarvis) {
2064
1982
  try {
2065
1983
  //first check if instance is living
2066
- const jarvisAliveState = await tools.getInitValue(this,'system.adapter.' + this.config.instanceJarvis + '.alive');
1984
+ const jarvisAliveState = await tools.getInitValue(this, `system.adapter.${this.config.instanceJarvis}.alive`);
2067
1985
 
2068
1986
  if (!jarvisAliveState) {
2069
1987
  this.log.warn('Jarvis instance is not running. Message could not be sent. Please check your instance configuration.');
@@ -2071,7 +1989,7 @@ class DeviceWatcher extends utils.Adapter {
2071
1989
  const jsonText = JSON.stringify(text);
2072
1990
  await this.setForeignStateAsync(
2073
1991
  `${this.config.instanceJarvis}.addNotification`,
2074
- '{"title":"' + this.config.titleJarvis + ' (' + this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss') + ')","message": ' + jsonText + ',"display": "drawer"}',
1992
+ `{"title":"${this.config.titleJarvis} (${this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss')})","message": ${jsonText},"display": "drawer"}`,
2075
1993
  );
2076
1994
  }
2077
1995
  } catch (error) {
@@ -2083,7 +2001,7 @@ class DeviceWatcher extends utils.Adapter {
2083
2001
  if (this.config.instanceLovelace) {
2084
2002
  try {
2085
2003
  //first check if instance is living
2086
- const lovelaceAliveState = await tools.getInitValue(this,'system.adapter.' + this.config.instanceLovelace + '.alive');
2004
+ const lovelaceAliveState = await tools.getInitValue(this, `system.adapter.${this.config.instanceLovelace}.alive`);
2087
2005
 
2088
2006
  if (!lovelaceAliveState) {
2089
2007
  this.log.warn('Lovelace instance is not running. Message could not be sent. Please check your instance configuration.');
@@ -2091,7 +2009,7 @@ class DeviceWatcher extends utils.Adapter {
2091
2009
  const jsonText = JSON.stringify(text);
2092
2010
  await this.setForeignStateAsync(
2093
2011
  `${this.config.instanceLovelace}.notifications.add`,
2094
- '{"message":' + jsonText + ', "title":"' + this.config.titleLovelace + ' (' + this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss') + ')"}',
2012
+ `{"message":${jsonText}, "title":"${this.config.titleLovelace} (${this.formatDate(new Date(), 'DD.MM.YYYY - hh:mm:ss')})"}`,
2095
2013
  );
2096
2014
  }
2097
2015
  } catch (error) {
@@ -2103,7 +2021,7 @@ class DeviceWatcher extends utils.Adapter {
2103
2021
  if (this.config.instanceSynochat) {
2104
2022
  try {
2105
2023
  //first check if instance is living
2106
- const synochatAliveState = await tools.getInitValue(this,'system.adapter.' + this.config.instanceSynochat + '.alive');
2024
+ const synochatAliveState = await tools.getInitValue(this, `system.adapter.${this.config.instanceSynochat}.alive`);
2107
2025
 
2108
2026
  if (!synochatAliveState) {
2109
2027
  this.log.warn('Synochat instance is not running. Message could not be sent. Please check your instance configuration.');
@@ -2123,12 +2041,16 @@ class DeviceWatcher extends utils.Adapter {
2123
2041
  /*---------- Notifications ----------*/
2124
2042
  /**
2125
2043
  * Notifications on state changes
2044
+ *
2126
2045
  * @param {string} mainType
2127
2046
  * @param {string} type
2128
2047
  * @param {object} id
2048
+ * @param silent
2129
2049
  */
2130
- async sendStateNotifications(mainType, type, id) {
2131
- if (isUnloaded) return;
2050
+ async sendStateNotifications(mainType, type, id, silent = false) {
2051
+ if (isUnloaded) {
2052
+ return;
2053
+ }
2132
2054
  let objectData;
2133
2055
  let adapterName;
2134
2056
  let list = '';
@@ -2146,7 +2068,7 @@ class DeviceWatcher extends utils.Adapter {
2146
2068
  const setMessage = async (message) => {
2147
2069
  this.log.info(message);
2148
2070
  await this.setStateAsync('lastNotification', message, true);
2149
- await this.sendNotification(message);
2071
+ await this.sendNotification(message, silent);
2150
2072
  };
2151
2073
 
2152
2074
  switch (type) {
@@ -2174,7 +2096,9 @@ class DeviceWatcher extends utils.Adapter {
2174
2096
  break;
2175
2097
 
2176
2098
  case 'updateAdapter':
2177
- if (this.countAdapterUpdates === 0) return;
2099
+ if (this.countAdapterUpdates === 0) {
2100
+ return;
2101
+ }
2178
2102
 
2179
2103
  objectData = this.listAdapterUpdates;
2180
2104
  list = '';
@@ -2197,10 +2121,14 @@ class DeviceWatcher extends utils.Adapter {
2197
2121
 
2198
2122
  /**
2199
2123
  * Notifications per user defined schedule
2124
+ *
2200
2125
  * @param {string} type
2126
+ * @param silent
2201
2127
  */
2202
- async sendScheduleNotifications(type) {
2203
- if (isUnloaded) return;
2128
+ async sendScheduleNotifications(type, silent = false) {
2129
+ if (isUnloaded) {
2130
+ return;
2131
+ }
2204
2132
 
2205
2133
  const checkDays = [];
2206
2134
  const dayConfigKeys = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
@@ -2211,28 +2139,34 @@ class DeviceWatcher extends utils.Adapter {
2211
2139
  this.log.info(message);
2212
2140
  await this.setStateAsync('lastNotification', message, true);
2213
2141
  if (!message.includes('no updates')) {
2214
- await this.sendNotification(message);
2142
+ await this.sendNotification(message, silent);
2215
2143
  }
2216
2144
  };
2217
2145
 
2218
2146
  const processDeviceList = (deviceList, property1, property2) => {
2219
2147
  list = '';
2220
2148
  for (const id of deviceList) {
2221
- if (this.blacklistNotify.includes(id.Path)) continue;
2222
- list += `\n${!this.config.showAdapterNameinMsg ? '' : id.Adapter + ': '}${id[property1]}${property2 ? ` (${id[property2]})` : ''}`;
2149
+ if (this.blacklistNotify.includes(id.Path)) {
2150
+ continue;
2151
+ }
2152
+ list += `\n${!this.config.showAdapterNameinMsg ? '' : `${id.Adapter}: `}${id[property1]}${property2 ? ` (${id[property2]})` : ''}`;
2223
2153
  }
2224
2154
  };
2225
2155
 
2226
2156
  const processInstanceList = (instanceList, property) => {
2227
2157
  list = '';
2228
2158
  for (const id of instanceList) {
2229
- if (this.blacklistInstancesNotify.includes(id[translations['Instance'][this.config.userSelectedLanguage]])) continue;
2159
+ if (this.blacklistInstancesNotify.includes(id[translations['Instance'][this.config.userSelectedLanguage]])) {
2160
+ continue;
2161
+ }
2230
2162
  list += `\n${id[translations['Instance'][this.config.userSelectedLanguage]]}${property ? `: ${id[property]}` : ''}`;
2231
2163
  }
2232
2164
  };
2233
2165
 
2234
2166
  const processNotification = async (list, messageType) => {
2235
- if (list.length === 0) return;
2167
+ if (list.length === 0) {
2168
+ return;
2169
+ }
2236
2170
 
2237
2171
  switch (checkDays.length) {
2238
2172
  case 1:
@@ -2251,7 +2185,7 @@ class DeviceWatcher extends utils.Adapter {
2251
2185
 
2252
2186
  switch (type) {
2253
2187
  case 'lowBatteryDevices':
2254
- checkDays.push(...dayConfigKeys.map((day, index) => (this.config['check' + day] ? index : null)).filter((day) => day !== null));
2188
+ checkDays.push(...dayConfigKeys.map((day, index) => (this.config[`check${day}`] ? index : null)).filter((day) => day !== null));
2255
2189
 
2256
2190
  if (checkDays.length === 0) {
2257
2191
  this.log.warn(`No days selected for daily low battery devices message. Please check the instance configuration!`);
@@ -2267,7 +2201,7 @@ class DeviceWatcher extends utils.Adapter {
2267
2201
  break;
2268
2202
 
2269
2203
  case 'offlineDevices':
2270
- checkDays.push(...dayConfigKeys.map((day, index) => (this.config['checkOffline' + day] ? index : null)).filter((day) => day !== null));
2204
+ checkDays.push(...dayConfigKeys.map((day, index) => (this.config[`checkOffline${day}`] ? index : null)).filter((day) => day !== null));
2271
2205
 
2272
2206
  if (checkDays.length === 0) {
2273
2207
  this.log.warn(`No days selected for daily offline devices message. Please check the instance configuration!`);
@@ -2283,7 +2217,7 @@ class DeviceWatcher extends utils.Adapter {
2283
2217
  break;
2284
2218
 
2285
2219
  case 'updateDevices':
2286
- checkDays.push(...dayConfigKeys.map((day, index) => (this.config['checkUpgrade' + day] ? index : null)).filter((day) => day !== null));
2220
+ checkDays.push(...dayConfigKeys.map((day, index) => (this.config[`checkUpgrade${day}`] ? index : null)).filter((day) => day !== null));
2287
2221
 
2288
2222
  if (checkDays.length === 0) {
2289
2223
  this.log.warn(`No days selected for daily updatable devices message. Please check the instance configuration!`);
@@ -2299,7 +2233,7 @@ class DeviceWatcher extends utils.Adapter {
2299
2233
  break;
2300
2234
 
2301
2235
  case 'updateAdapter':
2302
- checkDays.push(...dayConfigKeys.map((day, index) => (this.config['checkAdapterUpdate' + day] ? index : null)).filter((day) => day !== null));
2236
+ checkDays.push(...dayConfigKeys.map((day, index) => (this.config[`checkAdapterUpdate${day}`] ? index : null)).filter((day) => day !== null));
2303
2237
 
2304
2238
  if (checkDays.length === 0) {
2305
2239
  this.log.warn(`No days selected for daily adapter update message. Please check the instance configuration!`);
@@ -2317,7 +2251,7 @@ class DeviceWatcher extends utils.Adapter {
2317
2251
  break;
2318
2252
 
2319
2253
  case 'errorInstance':
2320
- checkDays.push(...dayConfigKeys.map((day, index) => (this.config['checkFailedInstances' + day] ? index : null)).filter((day) => day !== null));
2254
+ checkDays.push(...dayConfigKeys.map((day, index) => (this.config[`checkFailedInstances${day}`] ? index : null)).filter((day) => day !== null));
2321
2255
 
2322
2256
  if (checkDays.length === 0) {
2323
2257
  this.log.warn(`No days selected for daily instance error message. Please check the instance configuration!`);
@@ -2333,7 +2267,7 @@ class DeviceWatcher extends utils.Adapter {
2333
2267
  break;
2334
2268
 
2335
2269
  case 'deactivatedInstance':
2336
- checkDays.push(...dayConfigKeys.map((day, index) => (this.config['checkInstanceDeactivated' + day] ? index : null)).filter((day) => day !== null));
2270
+ checkDays.push(...dayConfigKeys.map((day, index) => (this.config[`checkInstanceDeactivated${day}`] ? index : null)).filter((day) => day !== null));
2337
2271
 
2338
2272
  if (checkDays.length === 0) {
2339
2273
  this.log.warn(`No days selected for daily instance deactivated message. Please check the instance configuration!`);
@@ -2349,6 +2283,19 @@ class DeviceWatcher extends utils.Adapter {
2349
2283
  break;
2350
2284
  }
2351
2285
  }
2286
+ async getPreviousCronRun(lastCronRun) {
2287
+ try {
2288
+ const cronParser = cronParserLib.parseExpression
2289
+ ? cronParserLib // klassischer Import
2290
+ : cronParserLib.default; // ESM-Fallback
2291
+
2292
+ const interval = cronParser.parseExpression(lastCronRun);
2293
+ const previous = interval.prev();
2294
+ return Math.floor(Date.now() - previous.getTime()); // in ms
2295
+ } catch (error) {
2296
+ this.log.error(`[getPreviousCronRun] - ${error}`);
2297
+ }
2298
+ }
2352
2299
 
2353
2300
  /**
2354
2301
  * @param {() => void} callback
@@ -2373,11 +2320,10 @@ class DeviceWatcher extends utils.Adapter {
2373
2320
  }
2374
2321
  }
2375
2322
 
2376
- // @ts-ignore parent is a valid property on module
2377
2323
  if (require.main !== module) {
2378
2324
  // Export the constructor in compact mode
2379
2325
  /**
2380
- * @param {Partial<utils.AdapterOptions>} [options={}]
2326
+ * @param {Partial<utils.AdapterOptions>} [options]
2381
2327
  */
2382
2328
  module.exports = (options) => new DeviceWatcher(options);
2383
2329
  } else {