iobroker.device-watcher 2.4.0 → 2.5.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/README.md +10 -0
- package/admin/i18n/de/translations.json +120 -104
- package/admin/i18n/en/translations.json +17 -1
- package/admin/i18n/es/translations.json +17 -1
- package/admin/i18n/fr/translations.json +17 -1
- package/admin/i18n/it/translations.json +17 -1
- package/admin/i18n/nl/translations.json +17 -1
- package/admin/i18n/pl/translations.json +17 -1
- package/admin/i18n/pt/translations.json +17 -1
- package/admin/i18n/ru/translations.json +17 -1
- package/admin/i18n/uk/translations.json +17 -1
- package/admin/i18n/zh-cn/translations.json +17 -1
- package/admin/jsonConfig.json +255 -13
- package/io-package.json +171 -88
- package/main.js +1056 -159
- package/package.json +2 -1
package/main.js
CHANGED
|
@@ -8,6 +8,7 @@ const utils = require('@iobroker/adapter-core');
|
|
|
8
8
|
const adapterName = require('./package.json').name.split('.').pop();
|
|
9
9
|
const schedule = require('node-schedule');
|
|
10
10
|
const arrApart = require('./lib/arrApart.js'); // list of supported adapters
|
|
11
|
+
const cronParser = require('cron-parser');
|
|
11
12
|
|
|
12
13
|
// Sentry error reporting, disable when testing code!
|
|
13
14
|
const enableSendSentry = true;
|
|
@@ -23,6 +24,27 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
23
24
|
useFormatDate: true,
|
|
24
25
|
});
|
|
25
26
|
|
|
27
|
+
// instances and adapters
|
|
28
|
+
// raw arrays
|
|
29
|
+
this.adapterUpdatesJsonRaw = [];
|
|
30
|
+
this.listInstanceRaw = [];
|
|
31
|
+
this.listErrorInstanceRaw = [];
|
|
32
|
+
|
|
33
|
+
// user arrays
|
|
34
|
+
this.blacklistInstancesLists = [];
|
|
35
|
+
this.blacklistInstancesNotify = [];
|
|
36
|
+
this.listAllInstances = [];
|
|
37
|
+
this.listDeactivatedInstances = [];
|
|
38
|
+
this.listAdapterUpdates = [];
|
|
39
|
+
this.listErrorInstance = [];
|
|
40
|
+
|
|
41
|
+
//counts
|
|
42
|
+
this.countAllInstances = 0;
|
|
43
|
+
this.countDeactivatedInstances = 0;
|
|
44
|
+
this.countAdapterUpdates = 0;
|
|
45
|
+
this.countErrorInstance = 0;
|
|
46
|
+
|
|
47
|
+
// devices
|
|
26
48
|
// arrays
|
|
27
49
|
this.offlineDevices = [];
|
|
28
50
|
this.linkQualityDevices = [];
|
|
@@ -219,6 +241,11 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
219
241
|
//read data first at start
|
|
220
242
|
await this.main();
|
|
221
243
|
|
|
244
|
+
if (this.config.checkAdapterInstances) {
|
|
245
|
+
await this.getInstanceData();
|
|
246
|
+
await this.createAdapterUpdateData();
|
|
247
|
+
}
|
|
248
|
+
|
|
222
249
|
// update last contact data in interval
|
|
223
250
|
await this.refreshData();
|
|
224
251
|
|
|
@@ -229,7 +256,10 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
229
256
|
if (this.config.checkSendOfflineMsgDaily) await this.sendOfflineNotificationsShedule();
|
|
230
257
|
|
|
231
258
|
// send overview of upgradeable devices
|
|
232
|
-
if (this.config.checkSendUpgradeMsgDaily) await this.
|
|
259
|
+
if (this.config.checkSendUpgradeMsgDaily) await this.sendDeviceUpdateNotificationsShedule();
|
|
260
|
+
|
|
261
|
+
// send overview of instances with error
|
|
262
|
+
if (this.config.checkSendInstanceFailedDaily) await this.sendInstanceErrorNotificationShedule();
|
|
233
263
|
} catch (error) {
|
|
234
264
|
this.errorReporting('[onReady]', error);
|
|
235
265
|
this.terminate ? this.terminate(15) : process.exit(15);
|
|
@@ -250,19 +280,95 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
250
280
|
let contactData;
|
|
251
281
|
let oldStatus;
|
|
252
282
|
let isLowBatValue;
|
|
283
|
+
let instanceStatusRaw;
|
|
284
|
+
let instanceDeviceConnectionDpTS;
|
|
285
|
+
const instanceDeviceConnectionDpTSminTime = 10;
|
|
286
|
+
|
|
287
|
+
/*
|
|
288
|
+
if (this.config.checkAdapterInstances) {
|
|
289
|
+
for (const adapter of this.adapterUpdatesJsonRaw) {
|
|
290
|
+
switch (id) {
|
|
291
|
+
case adapter.Path:
|
|
292
|
+
|
|
293
|
+
this.sendAdapterUpdatesNotification(id, state);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}*/
|
|
297
|
+
|
|
298
|
+
for (const instance of this.listInstanceRaw) {
|
|
299
|
+
switch (id) {
|
|
300
|
+
case instance.instanceAlivePath:
|
|
301
|
+
if (state.val !== instance.isAlive) {
|
|
302
|
+
instanceStatusRaw = await this.setInstanceStatus(
|
|
303
|
+
instance.instanceMode,
|
|
304
|
+
instance.schedule,
|
|
305
|
+
instance.instanceAlivePath,
|
|
306
|
+
state.val,
|
|
307
|
+
instance.isConnectedHost,
|
|
308
|
+
instance.isConnectedDevice,
|
|
309
|
+
);
|
|
310
|
+
instance.isAlive = instanceStatusRaw[1];
|
|
311
|
+
instance.status = instanceStatusRaw[0];
|
|
312
|
+
instance.isHealthy = instanceStatusRaw[2];
|
|
313
|
+
}
|
|
314
|
+
break;
|
|
315
|
+
case instance.connectedHostPath:
|
|
316
|
+
if (instance.isAlive && state.val !== instance.isConnectedHost) {
|
|
317
|
+
instance.isConnectedHost = state.val;
|
|
318
|
+
instanceStatusRaw = await this.setInstanceStatus(
|
|
319
|
+
instance.instanceMode,
|
|
320
|
+
instance.schedule,
|
|
321
|
+
instance.instanceAlivePath,
|
|
322
|
+
instance.isAlive,
|
|
323
|
+
state.val,
|
|
324
|
+
instance.isConnectedDevice,
|
|
325
|
+
);
|
|
326
|
+
instance.isAlive = instanceStatusRaw[1];
|
|
327
|
+
instance.status = instanceStatusRaw[0];
|
|
328
|
+
instance.isHealthy = instanceStatusRaw[2];
|
|
329
|
+
|
|
330
|
+
if (this.config.checkSendInstanceFailedMsg && !instance.isHealthy && !this.blacklistNotify.includes(instance.instanceAlivePath)) {
|
|
331
|
+
await this.sendInstanceErrorNotification(instance.InstanceName, instance.status);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
break;
|
|
335
|
+
case instance.connectedDevicePath:
|
|
336
|
+
if (instance.isAlive && state.val !== instance.isConnectedDevice) {
|
|
337
|
+
instance.isConnectedDevice = state.val;
|
|
338
|
+
instanceStatusRaw = await this.setInstanceStatus(
|
|
339
|
+
instance.instanceMode,
|
|
340
|
+
instance.schedule,
|
|
341
|
+
instance.instanceAlivePath,
|
|
342
|
+
instance.isAlive,
|
|
343
|
+
instance.isConnectedHost,
|
|
344
|
+
state.val,
|
|
345
|
+
);
|
|
346
|
+
instance.isAlive = instanceStatusRaw[1];
|
|
347
|
+
instance.status = instanceStatusRaw[0];
|
|
348
|
+
instance.isHealthy = instanceStatusRaw[2];
|
|
349
|
+
|
|
350
|
+
if (this.config.checkSendInstanceFailedMsg && !instance.isHealthy && !this.blacklistNotify.includes(instance.instanceAlivePath)) {
|
|
351
|
+
await this.sendInstanceErrorNotification(instance.InstanceName, instance.status);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
253
357
|
|
|
254
358
|
for (const device of this.listAllDevicesRaw) {
|
|
255
359
|
// On statechange update available datapoint
|
|
256
360
|
switch (id) {
|
|
257
|
-
case device.
|
|
258
|
-
|
|
361
|
+
case device.instanceDeviceConnectionDP:
|
|
362
|
+
if (state.val !== device.instancedeviceConnected) {
|
|
363
|
+
device.instancedeviceConnected = state.val;
|
|
364
|
+
}
|
|
259
365
|
break;
|
|
260
366
|
|
|
261
367
|
case device.UpdateDP:
|
|
262
|
-
if (device.
|
|
368
|
+
if (state.val !== device.Upgradable) {
|
|
263
369
|
device.Upgradable = state.val;
|
|
264
370
|
if (state.val) {
|
|
265
|
-
if (!this.blacklistNotify.includes(device.Path)) {
|
|
371
|
+
if (this.config.checkSendDeviceUpgrade && !this.blacklistNotify.includes(device.Path)) {
|
|
266
372
|
await this.sendDeviceUpdatesNotification(device.Device, device.Adapter);
|
|
267
373
|
}
|
|
268
374
|
}
|
|
@@ -270,91 +376,89 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
270
376
|
break;
|
|
271
377
|
|
|
272
378
|
case device.SignalStrengthDP:
|
|
273
|
-
|
|
274
|
-
device.SignalStrength = await this.calculateSignalStrength(state, device.adapterID);
|
|
275
|
-
}
|
|
379
|
+
device.SignalStrength = await this.calculateSignalStrength(state, device.adapterID);
|
|
276
380
|
break;
|
|
277
381
|
|
|
278
382
|
case device.batteryDP:
|
|
279
|
-
if (device.
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
device.LowBat = await this.setLowbatIndicator(state.val, isLowBatValue, device.faultReport, device.adapterID);
|
|
383
|
+
if (device.isBatteryDevice) {
|
|
384
|
+
oldLowBatState = device.LowBat;
|
|
385
|
+
batteryData = await this.getBatteryData(state.val, oldLowBatState, device.adapterID);
|
|
386
|
+
|
|
387
|
+
device.Battery = batteryData[0];
|
|
388
|
+
device.BatteryRaw = batteryData[2];
|
|
389
|
+
if (device.LowBatDP !== 'none') {
|
|
390
|
+
isLowBatValue = await this.getInitValue(device.LowBatDP);
|
|
391
|
+
} else {
|
|
392
|
+
isLowBatValue = undefined;
|
|
393
|
+
}
|
|
394
|
+
device.LowBat = await this.setLowbatIndicator(state.val, isLowBatValue, device.faultReport, device.adapterID);
|
|
292
395
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
396
|
+
if (device.LowBat && oldLowBatState !== device.LowBat) {
|
|
397
|
+
if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(device.Path)) {
|
|
398
|
+
await this.sendLowBatNoticiation(device.Device, device.Adapter, device.Battery);
|
|
297
399
|
}
|
|
298
400
|
}
|
|
299
401
|
}
|
|
300
402
|
break;
|
|
301
403
|
|
|
302
404
|
case device.LowBatDP:
|
|
303
|
-
if (device.
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if (
|
|
312
|
-
|
|
313
|
-
await this.sendLowBatNoticiation(device.Device, device.Adapter, device.Battery);
|
|
314
|
-
}
|
|
405
|
+
if (device.isBatteryDevice) {
|
|
406
|
+
oldLowBatState = device.LowBat;
|
|
407
|
+
batteryData = await this.getBatteryData(device.BatteryRaw, state.val, device.adapterID);
|
|
408
|
+
device.Battery = batteryData[0];
|
|
409
|
+
device.BatteryRaw = batteryData[2];
|
|
410
|
+
device.LowBat = await this.setLowbatIndicator(device.BatteryRaw, state.val, device.faultReport, device.adapterID);
|
|
411
|
+
|
|
412
|
+
if (device.LowBat && oldLowBatState !== device.LowBat) {
|
|
413
|
+
if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(device.Path)) {
|
|
414
|
+
await this.sendLowBatNoticiation(device.Device, device.Adapter, device.Battery);
|
|
315
415
|
}
|
|
316
416
|
}
|
|
317
417
|
}
|
|
318
418
|
break;
|
|
319
419
|
|
|
320
420
|
case device.faultReportDP:
|
|
321
|
-
if (device.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
if (
|
|
331
|
-
|
|
332
|
-
await this.sendLowBatNoticiation(device.Device, device.Adapter, device.Battery);
|
|
333
|
-
}
|
|
421
|
+
if (device.isBatteryDevice) {
|
|
422
|
+
oldLowBatState = device.LowBat;
|
|
423
|
+
batteryData = await this.getBatteryData(device.BatteryRaw, oldLowBatState, device.adapterID);
|
|
424
|
+
|
|
425
|
+
device.Battery = batteryData[0];
|
|
426
|
+
device.BatteryRaw = batteryData[2];
|
|
427
|
+
device.LowBat = await this.setLowbatIndicator(device.BatteryRaw, undefined, state.val, device.adapterID);
|
|
428
|
+
|
|
429
|
+
if (device.LowBat && oldLowBatState !== device.LowBat) {
|
|
430
|
+
if (this.config.checkSendBatteryMsg && !this.blacklistNotify.includes(device.Path)) {
|
|
431
|
+
await this.sendLowBatNoticiation(device.Device, device.Adapter, device.Battery);
|
|
334
432
|
}
|
|
335
433
|
}
|
|
336
434
|
}
|
|
337
435
|
break;
|
|
338
436
|
|
|
339
437
|
case device.UnreachDP:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
438
|
+
oldStatus = device.Status;
|
|
439
|
+
device.UnreachState = await this.getInitValue(device.UnreachDP);
|
|
440
|
+
contactData = await this.getOnlineState(
|
|
441
|
+
device.timeSelector,
|
|
442
|
+
device.adapterID,
|
|
443
|
+
device.UnreachDP,
|
|
444
|
+
device.SignalStrength,
|
|
445
|
+
device.UnreachState,
|
|
446
|
+
device.DeviceStateSelectorDP,
|
|
447
|
+
device.rssiPeerSelectorDP,
|
|
448
|
+
);
|
|
449
|
+
if (contactData !== undefined) {
|
|
450
|
+
device.LastContact = contactData[0];
|
|
451
|
+
device.Status = contactData[1];
|
|
452
|
+
device.SignalStrength = contactData[2];
|
|
453
|
+
}
|
|
454
|
+
if (device.instanceDeviceConnectionDP !== undefined) {
|
|
455
|
+
instanceDeviceConnectionDpTS = await this.getTimestampConnectionDP(device.instanceDeviceConnectionDP);
|
|
456
|
+
if (device.instancedeviceConnected !== false && instanceDeviceConnectionDpTS && instanceDeviceConnectionDpTS >= instanceDeviceConnectionDpTSminTime) {
|
|
457
|
+
if (this.config.checkSendOfflineMsg && oldStatus !== device.Status && !this.blacklistNotify.includes(device.Path)) {
|
|
458
|
+
await this.sendOfflineNotifications(device.Device, device.Adapter, device.Status, device.LastContact);
|
|
459
|
+
}
|
|
356
460
|
}
|
|
357
|
-
|
|
461
|
+
} else {
|
|
358
462
|
if (this.config.checkSendOfflineMsg && oldStatus !== device.Status && !this.blacklistNotify.includes(device.Path)) {
|
|
359
463
|
await this.sendOfflineNotifications(device.Device, device.Adapter, device.Status, device.LastContact);
|
|
360
464
|
}
|
|
@@ -372,6 +476,9 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
372
476
|
const devices = [];
|
|
373
477
|
let myCount = 0;
|
|
374
478
|
let result;
|
|
479
|
+
const instances = [];
|
|
480
|
+
let myCountInstances = 0;
|
|
481
|
+
let resultInstances;
|
|
375
482
|
|
|
376
483
|
switch (obj.command) {
|
|
377
484
|
case 'devicesList':
|
|
@@ -402,6 +509,35 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
402
509
|
this.sendTo(obj.from, obj.command, obj.callback);
|
|
403
510
|
}
|
|
404
511
|
break;
|
|
512
|
+
|
|
513
|
+
case 'instancesList':
|
|
514
|
+
if (obj.message) {
|
|
515
|
+
try {
|
|
516
|
+
resultInstances = this.listInstanceRaw;
|
|
517
|
+
for (const element in resultInstances) {
|
|
518
|
+
const label = `${resultInstances[element].Adapter}: ${resultInstances[element].InstanceName}`;
|
|
519
|
+
const myValueObject = {
|
|
520
|
+
adapter: resultInstances[element].Adapter,
|
|
521
|
+
instanceName: resultInstances[element].InstanceName,
|
|
522
|
+
path: resultInstances[element].instanceAlivePath,
|
|
523
|
+
};
|
|
524
|
+
instances[myCountInstances] = { label: label, value: JSON.stringify(myValueObject) };
|
|
525
|
+
myCountInstances++;
|
|
526
|
+
}
|
|
527
|
+
const sortInstances = instances.slice(0);
|
|
528
|
+
sortInstances.sort(function (a, b) {
|
|
529
|
+
const x = a.label;
|
|
530
|
+
const y = b.label;
|
|
531
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
532
|
+
});
|
|
533
|
+
this.sendTo(obj.from, obj.command, sortInstances, obj.callback);
|
|
534
|
+
} catch (error) {
|
|
535
|
+
this.sendTo(obj.from, obj.command, obj.callback);
|
|
536
|
+
}
|
|
537
|
+
} else {
|
|
538
|
+
this.sendTo(obj.from, obj.command, obj.callback);
|
|
539
|
+
}
|
|
540
|
+
break;
|
|
405
541
|
}
|
|
406
542
|
}
|
|
407
543
|
|
|
@@ -457,6 +593,11 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
457
593
|
}
|
|
458
594
|
}
|
|
459
595
|
|
|
596
|
+
if (this.config.checkAdapterInstances) {
|
|
597
|
+
await this.createInstanceList();
|
|
598
|
+
await this.writeInstanceDPs();
|
|
599
|
+
}
|
|
600
|
+
|
|
460
601
|
// Clear existing timeout
|
|
461
602
|
if (this.refreshDataTimeout) {
|
|
462
603
|
this.log.debug('clearing old refresh timeout');
|
|
@@ -480,6 +621,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
480
621
|
async createBlacklist() {
|
|
481
622
|
this.log.debug(`Function started: ${this.createBlacklist.name}`);
|
|
482
623
|
|
|
624
|
+
// DEVICES
|
|
483
625
|
const myBlacklist = this.config.tableBlacklist;
|
|
484
626
|
|
|
485
627
|
for (const i in myBlacklist) {
|
|
@@ -505,6 +647,28 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
505
647
|
if (this.blacklistAdapterLists.length >= 1) this.log.info(`Found items on blacklist for lists: ${this.blacklistAdapterLists}`);
|
|
506
648
|
if (this.blacklistNotify.length >= 1) this.log.info(`Found items on blacklist for notificatioons: ${this.blacklistNotify}`);
|
|
507
649
|
|
|
650
|
+
// INSTANCES
|
|
651
|
+
const myBlacklistInstances = this.config.tableBlacklistInstances;
|
|
652
|
+
|
|
653
|
+
for (const i in myBlacklistInstances) {
|
|
654
|
+
try {
|
|
655
|
+
const blacklistParse = await this.parseData(myBlacklistInstances[i].instances);
|
|
656
|
+
// push devices in list to ignor device in lists
|
|
657
|
+
if (myBlacklistInstances[i].checkIgnorLists) {
|
|
658
|
+
this.blacklistInstancesLists.push(blacklistParse.path);
|
|
659
|
+
}
|
|
660
|
+
// push devices in list to ignor device in notifications
|
|
661
|
+
if (myBlacklistInstances[i].checkIgnorNotify) {
|
|
662
|
+
this.blacklistInstancesNotify.push(blacklistParse.path);
|
|
663
|
+
}
|
|
664
|
+
} catch (error) {
|
|
665
|
+
this.errorReporting('[createBlacklist]', error);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
if (this.blacklistInstancesLists.length >= 1) this.log.info(`Found items on blacklist for lists: ${this.blacklistInstancesLists}`);
|
|
670
|
+
if (this.blacklistInstancesNotify.length >= 1) this.log.info(`Found items on blacklist for notificatioons: ${this.blacklistInstancesNotify}`);
|
|
671
|
+
|
|
508
672
|
this.log.debug(`Function finished: ${this.createBlacklist.name}`);
|
|
509
673
|
}
|
|
510
674
|
|
|
@@ -521,9 +685,9 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
521
685
|
= get Instanz =
|
|
522
686
|
=============================================*/
|
|
523
687
|
const instance = id.slice(0, id.indexOf('.') + 2);
|
|
524
|
-
const
|
|
525
|
-
const
|
|
526
|
-
this.subscribeForeignStates(
|
|
688
|
+
const instanceDeviceConnectionDP = `${instance}.info.connection`;
|
|
689
|
+
const instancedeviceConnected = await this.getInitValue(instanceDeviceConnectionDP);
|
|
690
|
+
this.subscribeForeignStates(instanceDeviceConnectionDP);
|
|
527
691
|
|
|
528
692
|
/*=============================================
|
|
529
693
|
= Get device name =
|
|
@@ -689,40 +853,42 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
689
853
|
=============================================*/
|
|
690
854
|
|
|
691
855
|
/* Add only devices with battery in the rawlist */
|
|
692
|
-
if (this.listOnlyBattery
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
856
|
+
if (this.listOnlyBattery) {
|
|
857
|
+
if (isBatteryDevice) {
|
|
858
|
+
this.listAllDevicesRaw.push({
|
|
859
|
+
Path: id,
|
|
860
|
+
instanceDeviceConnectionDP: instanceDeviceConnectionDP,
|
|
861
|
+
instancedeviceConnected: instancedeviceConnected,
|
|
862
|
+
Device: deviceName,
|
|
863
|
+
adapterID: adapterID,
|
|
864
|
+
Adapter: adapter,
|
|
865
|
+
timeSelector: timeSelector,
|
|
866
|
+
isBatteryDevice: isBatteryDevice,
|
|
867
|
+
Battery: batteryHealth,
|
|
868
|
+
BatteryRaw: batteryHealthRaw,
|
|
869
|
+
batteryDP: deviceBatteryStateDP,
|
|
870
|
+
LowBat: lowBatIndicator,
|
|
871
|
+
LowBatDP: isLowBatDP,
|
|
872
|
+
faultReport: faultReportingState,
|
|
873
|
+
faultReportDP: faultReportingDP,
|
|
874
|
+
SignalStrengthDP: deviceQualityDP,
|
|
875
|
+
SignalStrength: linkQuality,
|
|
876
|
+
UnreachState: deviceUnreachState,
|
|
877
|
+
UnreachDP: unreachDP,
|
|
878
|
+
DeviceStateSelectorDP: deviceStateSelectorDP,
|
|
879
|
+
rssiPeerSelectorDP: rssiPeerSelectorDP,
|
|
880
|
+
LastContact: lastContactString,
|
|
881
|
+
Status: deviceState,
|
|
882
|
+
UpdateDP: deviceUpdateDP,
|
|
883
|
+
Upgradable: isUpgradable,
|
|
884
|
+
});
|
|
885
|
+
}
|
|
720
886
|
} else {
|
|
721
887
|
/* Add all devices */
|
|
722
888
|
this.listAllDevicesRaw.push({
|
|
723
889
|
Path: id,
|
|
724
|
-
|
|
725
|
-
|
|
890
|
+
instanceDeviceConnectionDP: instanceDeviceConnectionDP,
|
|
891
|
+
instancedeviceConnected: instancedeviceConnected,
|
|
726
892
|
Device: deviceName,
|
|
727
893
|
adapterID: adapterID,
|
|
728
894
|
Adapter: adapter,
|
|
@@ -1209,24 +1375,26 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1209
1375
|
*/
|
|
1210
1376
|
async checkLastContact() {
|
|
1211
1377
|
for (const device of this.listAllDevicesRaw) {
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1378
|
+
if (device.instancedeviceConnected !== false) {
|
|
1379
|
+
const oldContactState = device.Status;
|
|
1380
|
+
device.UnreachState = await this.getInitValue(device.UnreachDP);
|
|
1381
|
+
const contactData = await this.getOnlineState(
|
|
1382
|
+
device.timeSelector,
|
|
1383
|
+
device.adapterID,
|
|
1384
|
+
device.UnreachDP,
|
|
1385
|
+
device.SignalStrength,
|
|
1386
|
+
device.UnreachState,
|
|
1387
|
+
device.DeviceStateSelectorDP,
|
|
1388
|
+
device.rssiPeerSelectorDP,
|
|
1389
|
+
);
|
|
1390
|
+
if (contactData !== undefined) {
|
|
1391
|
+
device.LastContact = contactData[0];
|
|
1392
|
+
device.Status = contactData[1];
|
|
1393
|
+
device.linkQuality = contactData[2];
|
|
1394
|
+
}
|
|
1395
|
+
if (this.config.checkSendOfflineMsg && oldContactState !== device.Status && !this.blacklistNotify.includes(device.Path)) {
|
|
1396
|
+
await this.sendOfflineNotifications(device.Device, device.Adapter, device.Status, device.LastContact);
|
|
1397
|
+
}
|
|
1230
1398
|
}
|
|
1231
1399
|
}
|
|
1232
1400
|
}
|
|
@@ -1438,18 +1606,18 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1438
1606
|
}
|
|
1439
1607
|
|
|
1440
1608
|
// Write Datapoints for counts
|
|
1441
|
-
await this.setStateAsync(
|
|
1442
|
-
await this.setStateAsync(
|
|
1443
|
-
await this.setStateAsync(
|
|
1444
|
-
await this.setStateAsync(
|
|
1445
|
-
await this.setStateAsync(
|
|
1609
|
+
await this.setStateAsync(`devices.${dpSubFolder}offlineCount`, { val: this.offlineDevicesCount, ack: true });
|
|
1610
|
+
await this.setStateAsync(`devices.${dpSubFolder}countAll`, { val: this.deviceCounter, ack: true });
|
|
1611
|
+
await this.setStateAsync(`devices.${dpSubFolder}batteryCount`, { val: this.batteryPoweredCount, ack: true });
|
|
1612
|
+
await this.setStateAsync(`devices.${dpSubFolder}lowBatteryCount`, { val: this.lowBatteryPoweredCount, ack: true });
|
|
1613
|
+
await this.setStateAsync(`devices.${dpSubFolder}upgradableCount`, { val: this.upgradableDevicesCount, ack: true });
|
|
1446
1614
|
|
|
1447
1615
|
// List all devices
|
|
1448
1616
|
if (this.deviceCounter === 0) {
|
|
1449
1617
|
// if no device is count, write the JSON List with default value
|
|
1450
1618
|
this.listAllDevices = [{ Device: '--none--', Adapter: '', Battery: '', 'Last contact': '', 'Signal strength': '' }];
|
|
1451
1619
|
}
|
|
1452
|
-
await this.setStateAsync(
|
|
1620
|
+
await this.setStateAsync(`devices.${dpSubFolder}listAll`, { val: JSON.stringify(this.listAllDevices), ack: true });
|
|
1453
1621
|
|
|
1454
1622
|
// List link quality
|
|
1455
1623
|
if (this.linkQualityCount === 0) {
|
|
@@ -1457,7 +1625,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1457
1625
|
this.linkQualityDevices = [{ Device: '--none--', Adapter: '', 'Signal strength': '' }];
|
|
1458
1626
|
}
|
|
1459
1627
|
//write JSON list
|
|
1460
|
-
await this.setStateAsync(
|
|
1628
|
+
await this.setStateAsync(`devices.${dpSubFolder}linkQualityList`, {
|
|
1461
1629
|
val: JSON.stringify(this.linkQualityDevices),
|
|
1462
1630
|
ack: true,
|
|
1463
1631
|
});
|
|
@@ -1468,7 +1636,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1468
1636
|
this.offlineDevices = [{ Device: '--none--', Adapter: '', 'Last contact': '' }];
|
|
1469
1637
|
}
|
|
1470
1638
|
//write JSON list
|
|
1471
|
-
await this.setStateAsync(
|
|
1639
|
+
await this.setStateAsync(`devices.${dpSubFolder}offlineList`, {
|
|
1472
1640
|
val: JSON.stringify(this.offlineDevices),
|
|
1473
1641
|
ack: true,
|
|
1474
1642
|
});
|
|
@@ -1479,7 +1647,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1479
1647
|
this.upgradableList = [{ Device: '--none--', Adapter: '', 'Last contact': '' }];
|
|
1480
1648
|
}
|
|
1481
1649
|
//write JSON list
|
|
1482
|
-
await this.setStateAsync(
|
|
1650
|
+
await this.setStateAsync(`devices.${dpSubFolder}upgradableList`, {
|
|
1483
1651
|
val: JSON.stringify(this.upgradableList),
|
|
1484
1652
|
ack: true,
|
|
1485
1653
|
});
|
|
@@ -1490,7 +1658,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1490
1658
|
this.batteryPowered = [{ Device: '--none--', Adapter: '', Battery: '' }];
|
|
1491
1659
|
}
|
|
1492
1660
|
//write JSON list
|
|
1493
|
-
await this.setStateAsync(
|
|
1661
|
+
await this.setStateAsync(`devices.${dpSubFolder}batteryList`, {
|
|
1494
1662
|
val: JSON.stringify(this.batteryPowered),
|
|
1495
1663
|
ack: true,
|
|
1496
1664
|
});
|
|
@@ -1501,43 +1669,43 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1501
1669
|
this.batteryLowPowered = [{ Device: '--none--', Adapter: '', Battery: '' }];
|
|
1502
1670
|
}
|
|
1503
1671
|
//write JSON list
|
|
1504
|
-
await this.setStateAsync(
|
|
1672
|
+
await this.setStateAsync(`devices.${dpSubFolder}lowBatteryList`, {
|
|
1505
1673
|
val: JSON.stringify(this.batteryLowPowered),
|
|
1506
1674
|
ack: true,
|
|
1507
1675
|
});
|
|
1508
1676
|
|
|
1509
1677
|
// set booleans datapoints
|
|
1510
1678
|
if (this.offlineDevicesCount === 0) {
|
|
1511
|
-
await this.setStateAsync(
|
|
1679
|
+
await this.setStateAsync(`devices.${dpSubFolder}oneDeviceOffline`, {
|
|
1512
1680
|
val: false,
|
|
1513
1681
|
ack: true,
|
|
1514
1682
|
});
|
|
1515
1683
|
} else {
|
|
1516
|
-
await this.setStateAsync(
|
|
1684
|
+
await this.setStateAsync(`devices.${dpSubFolder}oneDeviceOffline`, {
|
|
1517
1685
|
val: true,
|
|
1518
1686
|
ack: true,
|
|
1519
1687
|
});
|
|
1520
1688
|
}
|
|
1521
1689
|
|
|
1522
1690
|
if (this.lowBatteryPoweredCount === 0) {
|
|
1523
|
-
await this.setStateAsync(
|
|
1691
|
+
await this.setStateAsync(`devices.${dpSubFolder}oneDeviceLowBat`, {
|
|
1524
1692
|
val: false,
|
|
1525
1693
|
ack: true,
|
|
1526
1694
|
});
|
|
1527
1695
|
} else {
|
|
1528
|
-
await this.setStateAsync(
|
|
1696
|
+
await this.setStateAsync(`devices.${dpSubFolder}oneDeviceLowBat`, {
|
|
1529
1697
|
val: true,
|
|
1530
1698
|
ack: true,
|
|
1531
1699
|
});
|
|
1532
1700
|
}
|
|
1533
1701
|
|
|
1534
1702
|
if (this.upgradableDevicesCount === 0) {
|
|
1535
|
-
await this.setStateAsync(
|
|
1703
|
+
await this.setStateAsync(`devices.${dpSubFolder}oneDeviceUpdatable`, {
|
|
1536
1704
|
val: false,
|
|
1537
1705
|
ack: true,
|
|
1538
1706
|
});
|
|
1539
1707
|
} else {
|
|
1540
|
-
await this.setStateAsync(
|
|
1708
|
+
await this.setStateAsync(`devices.${dpSubFolder}oneDeviceUpdatable`, {
|
|
1541
1709
|
val: true,
|
|
1542
1710
|
ack: true,
|
|
1543
1711
|
});
|
|
@@ -1545,19 +1713,19 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1545
1713
|
|
|
1546
1714
|
//write HTML list
|
|
1547
1715
|
if (this.createHtmlList) {
|
|
1548
|
-
await this.setStateAsync(
|
|
1716
|
+
await this.setStateAsync(`devices.${dpSubFolder}linkQualityListHTML`, {
|
|
1549
1717
|
val: await this.creatLinkQualityListHTML(this.linkQualityDevices, this.linkQualityCount),
|
|
1550
1718
|
ack: true,
|
|
1551
1719
|
});
|
|
1552
|
-
await this.setStateAsync(
|
|
1720
|
+
await this.setStateAsync(`devices.${dpSubFolder}offlineListHTML`, {
|
|
1553
1721
|
val: await this.createOfflineListHTML(this.offlineDevices, this.offlineDevicesCount),
|
|
1554
1722
|
ack: true,
|
|
1555
1723
|
});
|
|
1556
|
-
await this.setStateAsync(
|
|
1724
|
+
await this.setStateAsync(`devices.${dpSubFolder}batteryListHTML`, {
|
|
1557
1725
|
val: await this.createBatteryListHTML(this.batteryPowered, this.batteryPoweredCount, false),
|
|
1558
1726
|
ack: true,
|
|
1559
1727
|
});
|
|
1560
|
-
await this.setStateAsync(
|
|
1728
|
+
await this.setStateAsync(`devices.${dpSubFolder}lowBatteryListHTML`, {
|
|
1561
1729
|
val: await this.createBatteryListHTML(this.batteryLowPowered, this.lowBatteryPoweredCount, true),
|
|
1562
1730
|
ack: true,
|
|
1563
1731
|
});
|
|
@@ -1572,6 +1740,534 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1572
1740
|
this.log.debug(`Function finished: ${this.writeDatapoints.name}`);
|
|
1573
1741
|
} //<--End of writing Datapoints
|
|
1574
1742
|
|
|
1743
|
+
/**
|
|
1744
|
+
* get Instances
|
|
1745
|
+
*/
|
|
1746
|
+
async getInstanceData() {
|
|
1747
|
+
try {
|
|
1748
|
+
await this.createDPsForInstances();
|
|
1749
|
+
|
|
1750
|
+
const instanceAliveDP = await this.getForeignStatesAsync(`system.adapter.*.alive`);
|
|
1751
|
+
for (const [id] of Object.entries(instanceAliveDP)) {
|
|
1752
|
+
if (!(typeof id === 'string' && id.startsWith(`system.adapter.`))) continue;
|
|
1753
|
+
|
|
1754
|
+
// get instance name
|
|
1755
|
+
const instanceName = await this.getInstanceName(id);
|
|
1756
|
+
|
|
1757
|
+
// get instance connected to host data
|
|
1758
|
+
const instanceConnectedHostDP = `system.adapter.${instanceName}.connected`;
|
|
1759
|
+
const instanceConnectedHostVal = await this.getInitValue(instanceConnectedHostDP);
|
|
1760
|
+
|
|
1761
|
+
// get instance connected to device data
|
|
1762
|
+
const instanceConnectedDeviceDP = `${instanceName}.info.connection`;
|
|
1763
|
+
let instanceConnectedDeviceVal;
|
|
1764
|
+
if (instanceConnectedDeviceDP !== undefined && typeof instanceConnectedDeviceDP === 'boolean') {
|
|
1765
|
+
instanceConnectedDeviceVal = await this.getInitValue(instanceConnectedDeviceDP);
|
|
1766
|
+
} else {
|
|
1767
|
+
instanceConnectedDeviceVal = 'N/A';
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
// get adapter version
|
|
1771
|
+
const instanceObjectPath = `system.adapter.${instanceName}`;
|
|
1772
|
+
let adapterName;
|
|
1773
|
+
let adapterVersion;
|
|
1774
|
+
let instanceMode;
|
|
1775
|
+
let scheduleTime = 'N/A';
|
|
1776
|
+
const instanceObjectData = await this.getForeignObjectAsync(instanceObjectPath);
|
|
1777
|
+
if (instanceObjectData) {
|
|
1778
|
+
// @ts-ignore
|
|
1779
|
+
adapterName = this.capitalize(instanceObjectData.common.name);
|
|
1780
|
+
adapterVersion = instanceObjectData.common.version;
|
|
1781
|
+
instanceMode = instanceObjectData.common.mode;
|
|
1782
|
+
|
|
1783
|
+
if (instanceMode === 'schedule') {
|
|
1784
|
+
scheduleTime = instanceObjectData.common.schedule;
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
//const adapterVersionVal = await this.getInitValue(adapterVersionDP);
|
|
1789
|
+
const instanceStatusRaw = await this.setInstanceStatus(instanceMode, scheduleTime, id, instanceAliveDP[id].val, instanceConnectedHostVal, instanceConnectedDeviceVal);
|
|
1790
|
+
const isAlive = instanceStatusRaw[1];
|
|
1791
|
+
const instanceStatus = instanceStatusRaw[0];
|
|
1792
|
+
const isHealthy = instanceStatusRaw[2];
|
|
1793
|
+
|
|
1794
|
+
//subscribe to statechanges
|
|
1795
|
+
this.subscribeForeignStatesAsync(id);
|
|
1796
|
+
this.subscribeForeignStatesAsync(instanceConnectedHostDP);
|
|
1797
|
+
this.subscribeForeignStatesAsync(instanceConnectedDeviceDP);
|
|
1798
|
+
//this.subscribeForeignObjectsAsync(instanceObjectPath);
|
|
1799
|
+
|
|
1800
|
+
// create raw list
|
|
1801
|
+
this.listInstanceRaw.push({
|
|
1802
|
+
Adapter: adapterName,
|
|
1803
|
+
InstanceName: instanceName,
|
|
1804
|
+
instanceObjectPath: instanceObjectPath,
|
|
1805
|
+
instanceAlivePath: id,
|
|
1806
|
+
instanceMode: instanceMode,
|
|
1807
|
+
schedule: scheduleTime,
|
|
1808
|
+
adapterVersion: adapterVersion,
|
|
1809
|
+
isAlive: isAlive,
|
|
1810
|
+
isHealthy: isHealthy,
|
|
1811
|
+
connectedHostPath: instanceConnectedHostDP,
|
|
1812
|
+
isConnectedHost: instanceConnectedHostVal,
|
|
1813
|
+
connectedDevicePath: instanceConnectedDeviceDP,
|
|
1814
|
+
isConnectedDevice: instanceConnectedDeviceVal,
|
|
1815
|
+
status: instanceStatus,
|
|
1816
|
+
});
|
|
1817
|
+
}
|
|
1818
|
+
await this.createInstanceList();
|
|
1819
|
+
await this.writeInstanceDPs();
|
|
1820
|
+
} catch (error) {
|
|
1821
|
+
this.errorReporting('[getInstance]', error);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
/**
|
|
1826
|
+
* get Instances
|
|
1827
|
+
* @param {string} id - Path of alive datapoint
|
|
1828
|
+
*/
|
|
1829
|
+
async getInstanceName(id) {
|
|
1830
|
+
let instance = id;
|
|
1831
|
+
instance = instance.slice(15); // remove "system.adapter."
|
|
1832
|
+
instance = instance.slice(0, instance.lastIndexOf('.') + 1 - 1); // remove ".alive"
|
|
1833
|
+
return instance;
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
/**
|
|
1837
|
+
* set status for instance
|
|
1838
|
+
* @param {object} instanceMode
|
|
1839
|
+
* @param {object} scheduleTime
|
|
1840
|
+
* @param {object} instanceAlivePath
|
|
1841
|
+
* @param {object} isAliveVal
|
|
1842
|
+
* @param {object} connectedHostVal
|
|
1843
|
+
* @param {object} connectedDeviceVal
|
|
1844
|
+
*/
|
|
1845
|
+
async setInstanceStatus(instanceMode, scheduleTime, instanceAlivePath, isAliveVal, connectedHostVal, connectedDeviceVal) {
|
|
1846
|
+
let instanceStatusString = 'not enabled';
|
|
1847
|
+
let lastUpdate;
|
|
1848
|
+
let lastCronRun;
|
|
1849
|
+
let diff;
|
|
1850
|
+
let previousCronRun = null;
|
|
1851
|
+
let isAlive = false;
|
|
1852
|
+
let isHealthy = false;
|
|
1853
|
+
let dpValue;
|
|
1854
|
+
switch (instanceMode) {
|
|
1855
|
+
case 'schedule':
|
|
1856
|
+
dpValue = await this.getForeignStateAsync(instanceAlivePath);
|
|
1857
|
+
if (dpValue) {
|
|
1858
|
+
lastUpdate = Math.round((Date.now() - dpValue.lc) / 1000); // Last state change in seconds
|
|
1859
|
+
previousCronRun = await this.getPreviousCronRun(scheduleTime); // When was the last cron run
|
|
1860
|
+
if (previousCronRun) {
|
|
1861
|
+
lastCronRun = Math.round(previousCronRun / 1000); // change distance to last run in seconds
|
|
1862
|
+
diff = lastCronRun - lastUpdate;
|
|
1863
|
+
if (diff > -300) {
|
|
1864
|
+
// if 5 minutes difference exceeded, instance is not alive
|
|
1865
|
+
isAlive = true;
|
|
1866
|
+
isHealthy = true;
|
|
1867
|
+
instanceStatusString = 'Instance okay';
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
break;
|
|
1872
|
+
case 'daemon':
|
|
1873
|
+
if (!isAliveVal) return ['Instance deactivated', false, null]; // if instance is turned off
|
|
1874
|
+
|
|
1875
|
+
// In case of (re)start, connection may take some time. We take 3 attempts.
|
|
1876
|
+
// Attempt 1/3 - immediately
|
|
1877
|
+
if (connectedHostVal && connectedDeviceVal) {
|
|
1878
|
+
isAlive = true;
|
|
1879
|
+
isHealthy = true;
|
|
1880
|
+
instanceStatusString = 'Instance okay';
|
|
1881
|
+
} else {
|
|
1882
|
+
// Attempt 2/3 - after 10 seconds
|
|
1883
|
+
await this.wait(10000);
|
|
1884
|
+
if (connectedHostVal && connectedDeviceVal) {
|
|
1885
|
+
isAlive = true;
|
|
1886
|
+
isHealthy = true;
|
|
1887
|
+
instanceStatusString = 'Instance okay';
|
|
1888
|
+
} else {
|
|
1889
|
+
// Attempt 3/3 - after 20 seconds in total
|
|
1890
|
+
await this.wait(10000);
|
|
1891
|
+
if (connectedHostVal && connectedDeviceVal) {
|
|
1892
|
+
isAlive = true;
|
|
1893
|
+
isHealthy = true;
|
|
1894
|
+
instanceStatusString = 'Instance okay';
|
|
1895
|
+
} else {
|
|
1896
|
+
if (!connectedDeviceVal) {
|
|
1897
|
+
instanceStatusString = 'not connected to Device';
|
|
1898
|
+
isAlive = true;
|
|
1899
|
+
isHealthy = false;
|
|
1900
|
+
} else if (!connectedHostVal) {
|
|
1901
|
+
instanceStatusString = 'not connected to host';
|
|
1902
|
+
isAlive = true;
|
|
1903
|
+
isHealthy = false;
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
break;
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
return [instanceStatusString, isAlive, isHealthy];
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
async createAdapterUpdateData() {
|
|
1915
|
+
const adapterUpdateListDP = `admin.*.info.updatesJson`;
|
|
1916
|
+
const adapterUpdatesListVal = await this.getForeignStatesAsync(adapterUpdateListDP);
|
|
1917
|
+
|
|
1918
|
+
// subscribe to datapoint
|
|
1919
|
+
this.subscribeForeignStates(adapterUpdateListDP);
|
|
1920
|
+
let adapterJsonList;
|
|
1921
|
+
|
|
1922
|
+
for (const [id] of Object.entries(adapterUpdatesListVal)) {
|
|
1923
|
+
adapterJsonList = await this.parseData(adapterUpdatesListVal[id].val);
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
for (const [id] of Object.entries(adapterJsonList)) {
|
|
1927
|
+
this.adapterUpdatesJsonRaw.push({
|
|
1928
|
+
Path: adapterUpdateListDP,
|
|
1929
|
+
Adapter: this.capitalize(id),
|
|
1930
|
+
newVersion: adapterJsonList[id].availableVersion,
|
|
1931
|
+
oldVersion: adapterJsonList[id].installedVersion,
|
|
1932
|
+
});
|
|
1933
|
+
}
|
|
1934
|
+
await this.createAdapterUpdateList();
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
/**
|
|
1938
|
+
* create instanceList
|
|
1939
|
+
*/
|
|
1940
|
+
async createAdapterUpdateList() {
|
|
1941
|
+
this.listAdapterUpdates = [];
|
|
1942
|
+
this.countAdapterUpdates = 0;
|
|
1943
|
+
|
|
1944
|
+
for (const adapter of this.adapterUpdatesJsonRaw) {
|
|
1945
|
+
this.listAdapterUpdates.push({
|
|
1946
|
+
Adapter: adapter.Adapter,
|
|
1947
|
+
'Available Version': adapter.newVersion,
|
|
1948
|
+
'Installed Version': adapter.oldVersion,
|
|
1949
|
+
});
|
|
1950
|
+
}
|
|
1951
|
+
this.countAdapterUpdates = this.listAdapterUpdates.length;
|
|
1952
|
+
await this.writeAdapterUpdatesDPs();
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
/**
|
|
1956
|
+
* write datapoints for adapter with updates
|
|
1957
|
+
*/
|
|
1958
|
+
async writeAdapterUpdatesDPs() {
|
|
1959
|
+
// Write Datapoints for counts
|
|
1960
|
+
await this.setStateAsync(`adapterAndInstances.countAdapterUpdates`, { val: this.countAdapterUpdates, ack: true });
|
|
1961
|
+
|
|
1962
|
+
// list deactivated instances
|
|
1963
|
+
if (this.countAdapterUpdates === 0) {
|
|
1964
|
+
this.listAdapterUpdates = [{ Adapter: '--none--', 'Available Version': '', 'Installed Version': '' }];
|
|
1965
|
+
}
|
|
1966
|
+
await this.setStateAsync(`adapterAndInstances.listAdapterUpdates`, { val: JSON.stringify(this.listAdapterUpdates), ack: true });
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
/**
|
|
1970
|
+
* create instanceList
|
|
1971
|
+
*/
|
|
1972
|
+
async createInstanceList() {
|
|
1973
|
+
this.listAllInstances = [];
|
|
1974
|
+
this.listDeactivatedInstances = [];
|
|
1975
|
+
this.listErrorInstanceRaw = [];
|
|
1976
|
+
this.listErrorInstance = [];
|
|
1977
|
+
|
|
1978
|
+
for (const instance of this.listInstanceRaw) {
|
|
1979
|
+
// fill raw list
|
|
1980
|
+
if (instance.isAlive && !instance.isHealthy) {
|
|
1981
|
+
this.listErrorInstanceRaw.push({
|
|
1982
|
+
Adapter: instance.Adapter,
|
|
1983
|
+
Instance: instance.InstanceName,
|
|
1984
|
+
Mode: instance.instanceMode,
|
|
1985
|
+
Status: instance.status,
|
|
1986
|
+
});
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
if (this.blacklistInstancesLists.includes(instance.instanceAlivePath)) continue;
|
|
1990
|
+
this.listAllInstances.push({
|
|
1991
|
+
Adapter: instance.Adapter,
|
|
1992
|
+
Instance: instance.InstanceName,
|
|
1993
|
+
Mode: instance.instanceMode,
|
|
1994
|
+
Schedule: instance.schedule,
|
|
1995
|
+
Version: instance.adapterVersion,
|
|
1996
|
+
Status: instance.status,
|
|
1997
|
+
});
|
|
1998
|
+
if (!instance.isAlive) {
|
|
1999
|
+
this.listDeactivatedInstances.push({
|
|
2000
|
+
Adapter: instance.Adapter,
|
|
2001
|
+
Instance: instance.InstanceName,
|
|
2002
|
+
Status: instance.status,
|
|
2003
|
+
});
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
// fill List for User
|
|
2007
|
+
if (instance.isAlive && !instance.isHealthy) {
|
|
2008
|
+
this.listErrorInstance.push({
|
|
2009
|
+
Adapter: instance.Adapter,
|
|
2010
|
+
Instance: instance.InstanceName,
|
|
2011
|
+
Mode: instance.instanceMode,
|
|
2012
|
+
Status: instance.status,
|
|
2013
|
+
});
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
await this.countInstances();
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
/**
|
|
2020
|
+
* count instanceList
|
|
2021
|
+
*/
|
|
2022
|
+
async countInstances() {
|
|
2023
|
+
this.countAllInstances = 0;
|
|
2024
|
+
this.countDeactivatedInstances = 0;
|
|
2025
|
+
this.countErrorInstance = 0;
|
|
2026
|
+
|
|
2027
|
+
this.countAllInstances = this.listAllInstances.length;
|
|
2028
|
+
this.countDeactivatedInstances = this.listDeactivatedInstances.length;
|
|
2029
|
+
this.countErrorInstance = this.listErrorInstance.length;
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
/**
|
|
2033
|
+
* write datapoints for instances list and counts
|
|
2034
|
+
*/
|
|
2035
|
+
async writeInstanceDPs() {
|
|
2036
|
+
// Write Datapoints for counts
|
|
2037
|
+
await this.setStateAsync(`adapterAndInstances.countAllInstances`, { val: this.countAllInstances, ack: true });
|
|
2038
|
+
await this.setStateAsync(`adapterAndInstances.countDeactivatedInstances`, { val: this.countDeactivatedInstances, ack: true });
|
|
2039
|
+
|
|
2040
|
+
// List all instances
|
|
2041
|
+
await this.setStateAsync(`adapterAndInstances.listAllInstances`, { val: JSON.stringify(this.listAllInstances), ack: true });
|
|
2042
|
+
|
|
2043
|
+
// list deactivated instances
|
|
2044
|
+
if (this.countDeactivatedInstances === 0) {
|
|
2045
|
+
this.listDeactivatedInstances = [{ Instance: '--none--', Version: '', Status: '' }];
|
|
2046
|
+
}
|
|
2047
|
+
await this.setStateAsync(`adapterAndInstances.listDeactivatedInstances`, { val: JSON.stringify(this.listDeactivatedInstances), ack: true });
|
|
2048
|
+
await this.setStateAsync(`adapterAndInstances.countDeactivatedInstances`, { val: this.countDeactivatedInstances, ack: true });
|
|
2049
|
+
|
|
2050
|
+
// list error instances
|
|
2051
|
+
if (this.countErrorInstance === 0) {
|
|
2052
|
+
this.listErrorInstance = [{ Instance: '--none--', Mode: '', Status: '' }];
|
|
2053
|
+
}
|
|
2054
|
+
await this.setStateAsync(`adapterAndInstances.listInstancesError`, { val: JSON.stringify(this.listErrorInstance), ack: true });
|
|
2055
|
+
await this.setStateAsync(`adapterAndInstances.countInstancesError`, { val: this.countErrorInstance, ack: true });
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
/**
|
|
2059
|
+
* create Datapoints for Instances
|
|
2060
|
+
*/
|
|
2061
|
+
async createDPsForInstances() {
|
|
2062
|
+
await this.setObjectNotExistsAsync(`adapterAndInstances`, {
|
|
2063
|
+
type: 'channel',
|
|
2064
|
+
common: {
|
|
2065
|
+
name: {
|
|
2066
|
+
en: 'Adapter and Instances',
|
|
2067
|
+
de: 'Adapter und Instanzen',
|
|
2068
|
+
ru: 'Адаптер и Instances',
|
|
2069
|
+
pt: 'Adaptador e instâncias',
|
|
2070
|
+
nl: 'Adapter en Instance',
|
|
2071
|
+
fr: 'Adaptateur et instances',
|
|
2072
|
+
it: 'Adattatore e istanze',
|
|
2073
|
+
es: 'Adaptador e instalaciones',
|
|
2074
|
+
pl: 'Adapter and Instances',
|
|
2075
|
+
uk: 'Адаптер та інстанції',
|
|
2076
|
+
'zh-cn': '道歉和案',
|
|
2077
|
+
},
|
|
2078
|
+
},
|
|
2079
|
+
native: {},
|
|
2080
|
+
});
|
|
2081
|
+
|
|
2082
|
+
// Instances
|
|
2083
|
+
await this.setObjectNotExistsAsync(`adapterAndInstances.listAllInstances`, {
|
|
2084
|
+
type: 'state',
|
|
2085
|
+
common: {
|
|
2086
|
+
name: {
|
|
2087
|
+
en: 'JSON List of all instances',
|
|
2088
|
+
de: 'JSON Liste aller Instanzen',
|
|
2089
|
+
ru: 'ДЖСОН Список всех инстанций',
|
|
2090
|
+
pt: 'J. Lista de todas as instâncias',
|
|
2091
|
+
nl: 'JSON List van alle instanties',
|
|
2092
|
+
fr: 'JSON Liste de tous les cas',
|
|
2093
|
+
it: 'JSON Elenco di tutte le istanze',
|
|
2094
|
+
es: 'JSON Lista de todos los casos',
|
|
2095
|
+
pl: 'JSON Lista wszystkich instancji',
|
|
2096
|
+
uk: 'Сонце Список всіх екземплярів',
|
|
2097
|
+
'zh-cn': '附 件 所有事例一览表',
|
|
2098
|
+
},
|
|
2099
|
+
type: 'array',
|
|
2100
|
+
role: 'json',
|
|
2101
|
+
read: true,
|
|
2102
|
+
write: false,
|
|
2103
|
+
},
|
|
2104
|
+
native: {},
|
|
2105
|
+
});
|
|
2106
|
+
await this.setObjectNotExistsAsync(`adapterAndInstances.countAllInstances`, {
|
|
2107
|
+
type: 'state',
|
|
2108
|
+
common: {
|
|
2109
|
+
name: {
|
|
2110
|
+
en: 'Number of all instances',
|
|
2111
|
+
de: 'Anzahl aller Instanzen',
|
|
2112
|
+
ru: 'Количество всех инстанций',
|
|
2113
|
+
pt: 'Número de todas as instâncias',
|
|
2114
|
+
nl: 'Nummer van alle gevallen',
|
|
2115
|
+
fr: 'Nombre de cas',
|
|
2116
|
+
it: 'Numero di tutte le istanze',
|
|
2117
|
+
es: 'Número de casos',
|
|
2118
|
+
pl: 'Liczba wszystkich instancji',
|
|
2119
|
+
uk: 'Кількість всіх екземплярів',
|
|
2120
|
+
'zh-cn': '各类案件数目',
|
|
2121
|
+
},
|
|
2122
|
+
type: 'number',
|
|
2123
|
+
role: 'value',
|
|
2124
|
+
read: true,
|
|
2125
|
+
write: false,
|
|
2126
|
+
},
|
|
2127
|
+
native: {},
|
|
2128
|
+
});
|
|
2129
|
+
await this.setObjectNotExistsAsync(`adapterAndInstances.listDeactivatedInstances`, {
|
|
2130
|
+
type: 'state',
|
|
2131
|
+
common: {
|
|
2132
|
+
name: {
|
|
2133
|
+
en: 'JSON List of deactivated instances',
|
|
2134
|
+
de: 'JSON Liste der deaktivierten Instanzen',
|
|
2135
|
+
ru: 'ДЖСОН Список деактивированных инстанций',
|
|
2136
|
+
pt: 'J. Lista de instâncias desativadas',
|
|
2137
|
+
nl: 'JSON List van gedeactiveerde instanties',
|
|
2138
|
+
fr: 'JSON Liste des cas désactivés',
|
|
2139
|
+
it: 'JSON Elenco delle istanze disattivate',
|
|
2140
|
+
es: 'JSON Lista de casos desactivados',
|
|
2141
|
+
pl: 'JSON Lista przypadków deaktywowanych',
|
|
2142
|
+
uk: 'Сонце Перелік деактивованих екземплярів',
|
|
2143
|
+
'zh-cn': '附 件 被动事例清单',
|
|
2144
|
+
},
|
|
2145
|
+
type: 'array',
|
|
2146
|
+
role: 'json',
|
|
2147
|
+
read: true,
|
|
2148
|
+
write: false,
|
|
2149
|
+
},
|
|
2150
|
+
native: {},
|
|
2151
|
+
});
|
|
2152
|
+
await this.setObjectNotExistsAsync(`adapterAndInstances.countDeactivatedInstances`, {
|
|
2153
|
+
type: 'state',
|
|
2154
|
+
common: {
|
|
2155
|
+
name: {
|
|
2156
|
+
en: 'Number of deactivated instances',
|
|
2157
|
+
de: 'Anzahl deaktivierter Instanzen',
|
|
2158
|
+
ru: 'Количество деактивированных инстанций',
|
|
2159
|
+
pt: 'Número de instâncias desativadas',
|
|
2160
|
+
nl: 'Nummer van gedeactiveerde instanties',
|
|
2161
|
+
fr: 'Nombre de cas désactivés',
|
|
2162
|
+
it: 'Numero di istanze disattivate',
|
|
2163
|
+
es: 'Número de casos desactivados',
|
|
2164
|
+
pl: 'Liczba deaktywowanych instancji',
|
|
2165
|
+
uk: 'Кількість деактивованих екземплярів',
|
|
2166
|
+
'zh-cn': 'A. 递解事件的数目',
|
|
2167
|
+
},
|
|
2168
|
+
type: 'number',
|
|
2169
|
+
role: 'value',
|
|
2170
|
+
read: true,
|
|
2171
|
+
write: false,
|
|
2172
|
+
},
|
|
2173
|
+
native: {},
|
|
2174
|
+
});
|
|
2175
|
+
await this.setObjectNotExistsAsync(`adapterAndInstances.listInstancesError`, {
|
|
2176
|
+
type: 'state',
|
|
2177
|
+
common: {
|
|
2178
|
+
name: {
|
|
2179
|
+
en: 'JSON list of instances with error',
|
|
2180
|
+
de: 'JSON-Liste von Instanzen mit Fehler',
|
|
2181
|
+
ru: 'JSON список инстанций с ошибкой',
|
|
2182
|
+
pt: 'Lista de instâncias JSON com erro',
|
|
2183
|
+
nl: 'JSON lijst met fouten',
|
|
2184
|
+
fr: 'Liste des instances avec erreur',
|
|
2185
|
+
it: 'Elenco JSON delle istanze con errore',
|
|
2186
|
+
es: 'JSON lista de casos con error',
|
|
2187
|
+
pl: 'Lista błędów JSON',
|
|
2188
|
+
uk: 'JSON список екземплярів з помилкою',
|
|
2189
|
+
'zh-cn': '联合工作组办公室错误事件清单',
|
|
2190
|
+
},
|
|
2191
|
+
type: 'array',
|
|
2192
|
+
role: 'json',
|
|
2193
|
+
read: true,
|
|
2194
|
+
write: false,
|
|
2195
|
+
},
|
|
2196
|
+
native: {},
|
|
2197
|
+
});
|
|
2198
|
+
await this.setObjectNotExistsAsync(`adapterAndInstances.countInstancesError`, {
|
|
2199
|
+
type: 'state',
|
|
2200
|
+
common: {
|
|
2201
|
+
name: {
|
|
2202
|
+
en: 'Count of instances with error',
|
|
2203
|
+
de: 'Anzahl der Instanzen mit Fehler',
|
|
2204
|
+
ru: 'Количество инстанций с ошибкой',
|
|
2205
|
+
pt: 'Contagem de instâncias com erro',
|
|
2206
|
+
nl: 'Graaf van instoringen met fouten',
|
|
2207
|
+
fr: 'Nombre de cas avec erreur',
|
|
2208
|
+
it: 'Conteggio di istanze con errore',
|
|
2209
|
+
es: 'Cuenta de casos con error',
|
|
2210
|
+
pl: 'Liczba przykładów w przypadku błędów',
|
|
2211
|
+
uk: 'Кількість екземплярів з помилкою',
|
|
2212
|
+
'zh-cn': '发生错误的情况',
|
|
2213
|
+
},
|
|
2214
|
+
type: 'number',
|
|
2215
|
+
role: 'value',
|
|
2216
|
+
read: true,
|
|
2217
|
+
write: false,
|
|
2218
|
+
},
|
|
2219
|
+
native: {},
|
|
2220
|
+
});
|
|
2221
|
+
|
|
2222
|
+
// Adapter
|
|
2223
|
+
await this.setObjectNotExistsAsync(`adapterAndInstances.listAdapterUpdates`, {
|
|
2224
|
+
type: 'state',
|
|
2225
|
+
common: {
|
|
2226
|
+
name: {
|
|
2227
|
+
en: 'JSON list of adapters with available updates',
|
|
2228
|
+
de: 'JSON-Liste der Adapter mit verfügbaren Updates',
|
|
2229
|
+
ru: 'JSON список адаптеров с доступными обновлениями',
|
|
2230
|
+
pt: 'Lista de adaptadores JSON com atualizações disponíveis',
|
|
2231
|
+
nl: 'JSON lijst met beschikbare updates',
|
|
2232
|
+
fr: 'Liste JSON des adaptateurs avec mises à jour disponibles',
|
|
2233
|
+
it: 'Elenco di adattatori JSON con aggiornamenti disponibili',
|
|
2234
|
+
es: 'JSON lista de adaptadores con actualizaciones disponibles',
|
|
2235
|
+
pl: 'JSON lista adapterów z dostępnymi aktualizacjami',
|
|
2236
|
+
uk: 'JSON список адаптерів з доступними оновленнями',
|
|
2237
|
+
'zh-cn': '附录A',
|
|
2238
|
+
},
|
|
2239
|
+
type: 'array',
|
|
2240
|
+
role: 'json',
|
|
2241
|
+
read: true,
|
|
2242
|
+
write: false,
|
|
2243
|
+
},
|
|
2244
|
+
native: {},
|
|
2245
|
+
});
|
|
2246
|
+
await this.setObjectNotExistsAsync(`adapterAndInstances.countAdapterUpdates`, {
|
|
2247
|
+
type: 'state',
|
|
2248
|
+
common: {
|
|
2249
|
+
name: {
|
|
2250
|
+
en: 'Number of adapters with available updates',
|
|
2251
|
+
de: 'Anzahl der Adapter mit verfügbaren Updates',
|
|
2252
|
+
ru: 'Количество адаптеров с доступными обновлениями',
|
|
2253
|
+
pt: 'Número de adaptadores com atualizações disponíveis',
|
|
2254
|
+
nl: 'Nummer van adapters met beschikbare updates',
|
|
2255
|
+
fr: "Nombre d'adaptateurs avec mises à jour disponibles",
|
|
2256
|
+
it: 'Numero di adattatori con aggiornamenti disponibili',
|
|
2257
|
+
es: 'Número de adaptadores con actualizaciones disponibles',
|
|
2258
|
+
pl: 'Liczba adapterów z dostępną aktualizacją',
|
|
2259
|
+
uk: 'Кількість адаптерів з доступними оновленнями',
|
|
2260
|
+
'zh-cn': '更新的适应者人数',
|
|
2261
|
+
},
|
|
2262
|
+
type: 'number',
|
|
2263
|
+
role: 'value',
|
|
2264
|
+
read: true,
|
|
2265
|
+
write: false,
|
|
2266
|
+
},
|
|
2267
|
+
native: {},
|
|
2268
|
+
});
|
|
2269
|
+
}
|
|
2270
|
+
|
|
1575
2271
|
/*=============================================
|
|
1576
2272
|
= functions to send notifications =
|
|
1577
2273
|
=============================================*/
|
|
@@ -1722,6 +2418,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1722
2418
|
}
|
|
1723
2419
|
} // <-- End of sendNotification function
|
|
1724
2420
|
|
|
2421
|
+
/*---------- Battery notifications ----------*/
|
|
1725
2422
|
/**
|
|
1726
2423
|
* send shedule message for low battery devices
|
|
1727
2424
|
*/
|
|
@@ -1805,6 +2502,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1805
2502
|
this.log.debug(`Finished the function: ${this.sendLowBatNoticiation.name}`);
|
|
1806
2503
|
}
|
|
1807
2504
|
|
|
2505
|
+
/*---------- Offline/Online notifications ----------*/
|
|
1808
2506
|
/**
|
|
1809
2507
|
* send message if an device is offline
|
|
1810
2508
|
* @param {string} deviceName
|
|
@@ -1896,6 +2594,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1896
2594
|
}
|
|
1897
2595
|
} //<--End of daily offline notification
|
|
1898
2596
|
|
|
2597
|
+
/*---------- Device Updates notifications ----------*/
|
|
1899
2598
|
/**
|
|
1900
2599
|
* check if device updates are available and send notification
|
|
1901
2600
|
* @param {string} deviceName
|
|
@@ -1928,7 +2627,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1928
2627
|
/**
|
|
1929
2628
|
* send shedule message with offline devices
|
|
1930
2629
|
*/
|
|
1931
|
-
async
|
|
2630
|
+
async sendDeviceUpdateNotificationsShedule() {
|
|
1932
2631
|
const time = this.config.checkSendUpgradeTime.split(':');
|
|
1933
2632
|
|
|
1934
2633
|
const checkDays = []; // list of selected days
|
|
@@ -1950,6 +2649,91 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1950
2649
|
return; // cancel function if no day is selected
|
|
1951
2650
|
}
|
|
1952
2651
|
|
|
2652
|
+
if (!isUnloaded) {
|
|
2653
|
+
const cron = '10 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
|
|
2654
|
+
schedule.scheduleJob(cron, () => {
|
|
2655
|
+
try {
|
|
2656
|
+
let deviceList = '';
|
|
2657
|
+
|
|
2658
|
+
for (const id of this.upgradableDevicesRaw) {
|
|
2659
|
+
if (!this.blacklistNotify.includes(id.Path)) {
|
|
2660
|
+
if (!this.config.showAdapterNameinMsg) {
|
|
2661
|
+
deviceList = `${deviceList}\n${id.Device}`;
|
|
2662
|
+
} else {
|
|
2663
|
+
deviceList = `${deviceList}\n${id.Adapter}: ${id.Device}`;
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
if (deviceList.length > 0) {
|
|
2668
|
+
this.log.info(`Geräte Upgrade: ${deviceList}`);
|
|
2669
|
+
this.setStateAsync('lastNotification', `Geräte Upgrade: ${deviceList}`, true);
|
|
2670
|
+
|
|
2671
|
+
this.sendNotification(`Geräte Upgrade:\n${deviceList}`);
|
|
2672
|
+
}
|
|
2673
|
+
} catch (error) {
|
|
2674
|
+
this.errorReporting('[sendUpgradeNotificationsShedule]', error);
|
|
2675
|
+
}
|
|
2676
|
+
});
|
|
2677
|
+
}
|
|
2678
|
+
} //<--End of daily device updates notification
|
|
2679
|
+
|
|
2680
|
+
/*---------- Adapter Updates notifications ----------*/
|
|
2681
|
+
/**
|
|
2682
|
+
* check if adapter updates are available and send notification
|
|
2683
|
+
* @param {string} id
|
|
2684
|
+
* @param {ioBroker.State | null | undefined} state
|
|
2685
|
+
*/
|
|
2686
|
+
async sendAdapterUpdatesNotification(id, state) {
|
|
2687
|
+
this.log.debug(`Start the function: ${this.sendAdapterUpdatesNotification.name}`);
|
|
2688
|
+
|
|
2689
|
+
try {
|
|
2690
|
+
if (state && state !== undefined) {
|
|
2691
|
+
const list = await this.parseData(state.val);
|
|
2692
|
+
let msg = '';
|
|
2693
|
+
let adapterList = '';
|
|
2694
|
+
|
|
2695
|
+
for (const [id] of Object.entries(list)) {
|
|
2696
|
+
adapterList = `${adapterList}\n${this.capitalize(id)} - Version: ${list[id].availableVersion}`;
|
|
2697
|
+
}
|
|
2698
|
+
if (adapterList.length !== 0) {
|
|
2699
|
+
msg = `Neue Adapter Updates vorhanden: \n`;
|
|
2700
|
+
|
|
2701
|
+
this.log.info(msg + adapterList);
|
|
2702
|
+
await this.setStateAsync('lastNotification', msg + adapterList, true);
|
|
2703
|
+
await this.sendNotification(msg + adapterList);
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
} catch (error) {
|
|
2707
|
+
this.errorReporting('[sendAdapterUpdatesNotification]', error);
|
|
2708
|
+
}
|
|
2709
|
+
this.log.debug(`Finished the function: ${this.sendAdapterUpdatesNotification.name}`);
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2712
|
+
/**
|
|
2713
|
+
* send shedule message with list of updatable adapters
|
|
2714
|
+
*/
|
|
2715
|
+
async sendAdapterUpdatesNotificatioShedule() {
|
|
2716
|
+
const time = this.config.checkSendAdapterUpdateTime.split(':');
|
|
2717
|
+
|
|
2718
|
+
const checkDays = []; // list of selected days
|
|
2719
|
+
|
|
2720
|
+
// push the selected days in list
|
|
2721
|
+
if (this.config.checkAdapterUpdateMonday) checkDays.push(1);
|
|
2722
|
+
if (this.config.checkAdapterUpdateTuesday) checkDays.push(2);
|
|
2723
|
+
if (this.config.checkAdapterUpdateWednesday) checkDays.push(3);
|
|
2724
|
+
if (this.config.checkAdapterUpdateThursday) checkDays.push(4);
|
|
2725
|
+
if (this.config.checkAdapterUpdateFriday) checkDays.push(5);
|
|
2726
|
+
if (this.config.checkAdapterUpdateSaturday) checkDays.push(6);
|
|
2727
|
+
if (this.config.checkAdapterUpdateSunday) checkDays.push(0);
|
|
2728
|
+
|
|
2729
|
+
if (checkDays.length >= 1) {
|
|
2730
|
+
// check if an day is selected
|
|
2731
|
+
this.log.debug(`Number of selected days for daily adapter update message: ${checkDays.length}. Send Message on: ${checkDays.join(', ')} ...`);
|
|
2732
|
+
} else {
|
|
2733
|
+
this.log.warn(`No days selected for daily adapter update message. Please check the instance configuration!`);
|
|
2734
|
+
return; // cancel function if no day is selected
|
|
2735
|
+
}
|
|
2736
|
+
|
|
1953
2737
|
if (!isUnloaded) {
|
|
1954
2738
|
const cron = '10 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
|
|
1955
2739
|
schedule.scheduleJob(cron, () => {
|
|
@@ -1978,6 +2762,81 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1978
2762
|
}
|
|
1979
2763
|
} //<--End of daily offline notification
|
|
1980
2764
|
|
|
2765
|
+
/*---------- Instance error notifications ----------*/
|
|
2766
|
+
/**
|
|
2767
|
+
* check if device updates are available and send notification
|
|
2768
|
+
* @param {string} instanceName
|
|
2769
|
+
* @param {string} error
|
|
2770
|
+
**/
|
|
2771
|
+
async sendInstanceErrorNotification(instanceName, error) {
|
|
2772
|
+
this.log.debug(`Start the function: ${this.sendInstanceErrorNotification.name}`);
|
|
2773
|
+
|
|
2774
|
+
try {
|
|
2775
|
+
let msg = '';
|
|
2776
|
+
let instanceList = '';
|
|
2777
|
+
|
|
2778
|
+
instanceList = `${instanceList}\n${instanceName}: ${error}`;
|
|
2779
|
+
|
|
2780
|
+
msg = `Fehler einer Instanz entdeckt: \n`;
|
|
2781
|
+
|
|
2782
|
+
this.log.info(msg + instanceList);
|
|
2783
|
+
await this.setStateAsync('lastNotification', msg + instanceList, true);
|
|
2784
|
+
await this.sendNotification(msg + instanceList);
|
|
2785
|
+
} catch (error) {
|
|
2786
|
+
this.errorReporting('[sendInstanceErrorNotification]', error);
|
|
2787
|
+
}
|
|
2788
|
+
this.log.debug(`Finished the function: ${this.sendInstanceErrorNotification.name}`);
|
|
2789
|
+
}
|
|
2790
|
+
|
|
2791
|
+
/**
|
|
2792
|
+
* send shedule message with offline devices
|
|
2793
|
+
*/
|
|
2794
|
+
async sendInstanceErrorNotificationShedule() {
|
|
2795
|
+
const time = this.config.checkSendInstanceFailedTime.split(':');
|
|
2796
|
+
|
|
2797
|
+
const checkDays = []; // list of selected days
|
|
2798
|
+
|
|
2799
|
+
// push the selected days in list
|
|
2800
|
+
if (this.config.checkFailedInstancesMonday) checkDays.push(1);
|
|
2801
|
+
if (this.config.checkFailedInstancesTuesday) checkDays.push(2);
|
|
2802
|
+
if (this.config.checkFailedInstancesWednesday) checkDays.push(3);
|
|
2803
|
+
if (this.config.checkFailedInstancesThursday) checkDays.push(4);
|
|
2804
|
+
if (this.config.checkFailedInstancesFriday) checkDays.push(5);
|
|
2805
|
+
if (this.config.checkFailedInstancesSaturday) checkDays.push(6);
|
|
2806
|
+
if (this.config.checkFailedInstancesSunday) checkDays.push(0);
|
|
2807
|
+
|
|
2808
|
+
if (checkDays.length >= 1) {
|
|
2809
|
+
// check if an day is selected
|
|
2810
|
+
this.log.debug(`Number of selected days for daily instance error message: ${checkDays.length}. Send Message on: ${checkDays.join(', ')} ...`);
|
|
2811
|
+
} else {
|
|
2812
|
+
this.log.warn(`No days selected for daily instance error message. Please check the instance configuration!`);
|
|
2813
|
+
return; // cancel function if no day is selected
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
if (!isUnloaded) {
|
|
2817
|
+
const cron = '10 ' + time[1] + ' ' + time[0] + ' * * ' + checkDays;
|
|
2818
|
+
schedule.scheduleJob(cron, () => {
|
|
2819
|
+
try {
|
|
2820
|
+
let instanceList = '';
|
|
2821
|
+
|
|
2822
|
+
for (const id of this.listErrorInstanceRaw) {
|
|
2823
|
+
if (!this.blacklistInstancesNotify.includes(id.instanceAlivePath)) {
|
|
2824
|
+
instanceList = `${instanceList}\n${id.Instance}: ${id.Status}`;
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
if (instanceList.length > 0) {
|
|
2828
|
+
this.log.info(`Instanz Fehler: ${instanceList}`);
|
|
2829
|
+
this.setStateAsync('lastNotification', `Instanz Fehler: ${instanceList}`, true);
|
|
2830
|
+
|
|
2831
|
+
this.sendNotification(`Instanz Fehler:\n${instanceList}`);
|
|
2832
|
+
}
|
|
2833
|
+
} catch (error) {
|
|
2834
|
+
this.errorReporting('[sendInstanceErrorNotificationShedule]', error);
|
|
2835
|
+
}
|
|
2836
|
+
});
|
|
2837
|
+
}
|
|
2838
|
+
} //<--End of daily device updates notification
|
|
2839
|
+
|
|
1981
2840
|
/*=============================================
|
|
1982
2841
|
= functions to create html lists =
|
|
1983
2842
|
=============================================*/
|
|
@@ -2103,7 +2962,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2103
2962
|
* @param {object} adptName - Adaptername of devices
|
|
2104
2963
|
*/
|
|
2105
2964
|
async createDPsForEachAdapter(adptName) {
|
|
2106
|
-
await this.setObjectNotExistsAsync(
|
|
2965
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}`, {
|
|
2107
2966
|
type: 'channel',
|
|
2108
2967
|
common: {
|
|
2109
2968
|
name: adptName,
|
|
@@ -2111,7 +2970,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2111
2970
|
native: {},
|
|
2112
2971
|
});
|
|
2113
2972
|
|
|
2114
|
-
await this.setObjectNotExistsAsync(
|
|
2973
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.offlineCount`, {
|
|
2115
2974
|
type: 'state',
|
|
2116
2975
|
common: {
|
|
2117
2976
|
name: {
|
|
@@ -2134,7 +2993,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2134
2993
|
native: {},
|
|
2135
2994
|
});
|
|
2136
2995
|
|
|
2137
|
-
await this.setObjectNotExistsAsync(
|
|
2996
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.offlineList`, {
|
|
2138
2997
|
type: 'state',
|
|
2139
2998
|
common: {
|
|
2140
2999
|
name: {
|
|
@@ -2157,7 +3016,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2157
3016
|
native: {},
|
|
2158
3017
|
});
|
|
2159
3018
|
|
|
2160
|
-
await this.setObjectNotExistsAsync(
|
|
3019
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.oneDeviceOffline`, {
|
|
2161
3020
|
type: 'state',
|
|
2162
3021
|
common: {
|
|
2163
3022
|
name: {
|
|
@@ -2182,7 +3041,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2182
3041
|
native: {},
|
|
2183
3042
|
});
|
|
2184
3043
|
|
|
2185
|
-
await this.setObjectNotExistsAsync(
|
|
3044
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.listAll`, {
|
|
2186
3045
|
type: 'state',
|
|
2187
3046
|
common: {
|
|
2188
3047
|
name: {
|
|
@@ -2205,7 +3064,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2205
3064
|
native: {},
|
|
2206
3065
|
});
|
|
2207
3066
|
|
|
2208
|
-
await this.setObjectNotExistsAsync(
|
|
3067
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.linkQualityList`, {
|
|
2209
3068
|
type: 'state',
|
|
2210
3069
|
common: {
|
|
2211
3070
|
name: {
|
|
@@ -2228,7 +3087,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2228
3087
|
native: {},
|
|
2229
3088
|
});
|
|
2230
3089
|
|
|
2231
|
-
await this.setObjectNotExistsAsync(
|
|
3090
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.countAll`, {
|
|
2232
3091
|
type: 'state',
|
|
2233
3092
|
common: {
|
|
2234
3093
|
name: {
|
|
@@ -2251,7 +3110,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2251
3110
|
native: {},
|
|
2252
3111
|
});
|
|
2253
3112
|
|
|
2254
|
-
await this.setObjectNotExistsAsync(
|
|
3113
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.batteryList`, {
|
|
2255
3114
|
type: 'state',
|
|
2256
3115
|
common: {
|
|
2257
3116
|
name: {
|
|
@@ -2274,7 +3133,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2274
3133
|
native: {},
|
|
2275
3134
|
});
|
|
2276
3135
|
|
|
2277
|
-
await this.setObjectNotExistsAsync(
|
|
3136
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.lowBatteryList`, {
|
|
2278
3137
|
type: 'state',
|
|
2279
3138
|
common: {
|
|
2280
3139
|
name: {
|
|
@@ -2297,7 +3156,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2297
3156
|
native: {},
|
|
2298
3157
|
});
|
|
2299
3158
|
|
|
2300
|
-
await this.setObjectNotExistsAsync(
|
|
3159
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.lowBatteryCount`, {
|
|
2301
3160
|
type: 'state',
|
|
2302
3161
|
common: {
|
|
2303
3162
|
name: {
|
|
@@ -2320,7 +3179,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2320
3179
|
native: {},
|
|
2321
3180
|
});
|
|
2322
3181
|
|
|
2323
|
-
await this.setObjectNotExistsAsync(
|
|
3182
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.oneDeviceLowBat`, {
|
|
2324
3183
|
type: 'state',
|
|
2325
3184
|
common: {
|
|
2326
3185
|
name: {
|
|
@@ -2345,7 +3204,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2345
3204
|
native: {},
|
|
2346
3205
|
});
|
|
2347
3206
|
|
|
2348
|
-
await this.setObjectNotExistsAsync(
|
|
3207
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.batteryCount`, {
|
|
2349
3208
|
type: 'state',
|
|
2350
3209
|
common: {
|
|
2351
3210
|
name: {
|
|
@@ -2368,7 +3227,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2368
3227
|
native: {},
|
|
2369
3228
|
});
|
|
2370
3229
|
|
|
2371
|
-
await this.setObjectNotExistsAsync(
|
|
3230
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.upgradableCount`, {
|
|
2372
3231
|
type: 'state',
|
|
2373
3232
|
common: {
|
|
2374
3233
|
name: {
|
|
@@ -2392,7 +3251,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2392
3251
|
native: {},
|
|
2393
3252
|
});
|
|
2394
3253
|
|
|
2395
|
-
await this.setObjectNotExistsAsync(
|
|
3254
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.upgradableList`, {
|
|
2396
3255
|
type: 'state',
|
|
2397
3256
|
common: {
|
|
2398
3257
|
name: {
|
|
@@ -2416,7 +3275,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2416
3275
|
native: {},
|
|
2417
3276
|
});
|
|
2418
3277
|
|
|
2419
|
-
await this.setObjectNotExistsAsync(
|
|
3278
|
+
await this.setObjectNotExistsAsync(`devices.${adptName}.oneDeviceUpdatable`, {
|
|
2420
3279
|
type: 'state',
|
|
2421
3280
|
common: {
|
|
2422
3281
|
name: {
|
|
@@ -2454,7 +3313,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2454
3313
|
dpSubFolder = '';
|
|
2455
3314
|
}
|
|
2456
3315
|
|
|
2457
|
-
await this.setObjectNotExistsAsync(
|
|
3316
|
+
await this.setObjectNotExistsAsync(`devices.${dpSubFolder}offlineListHTML`, {
|
|
2458
3317
|
type: 'state',
|
|
2459
3318
|
common: {
|
|
2460
3319
|
name: {
|
|
@@ -2477,7 +3336,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2477
3336
|
native: {},
|
|
2478
3337
|
});
|
|
2479
3338
|
|
|
2480
|
-
await this.setObjectNotExistsAsync(
|
|
3339
|
+
await this.setObjectNotExistsAsync(`devices.${dpSubFolder}linkQualityListHTML`, {
|
|
2481
3340
|
type: 'state',
|
|
2482
3341
|
common: {
|
|
2483
3342
|
name: {
|
|
@@ -2500,7 +3359,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2500
3359
|
native: {},
|
|
2501
3360
|
});
|
|
2502
3361
|
|
|
2503
|
-
await this.setObjectNotExistsAsync(
|
|
3362
|
+
await this.setObjectNotExistsAsync(`devices.${dpSubFolder}batteryListHTML`, {
|
|
2504
3363
|
type: 'state',
|
|
2505
3364
|
common: {
|
|
2506
3365
|
name: {
|
|
@@ -2523,7 +3382,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2523
3382
|
native: {},
|
|
2524
3383
|
});
|
|
2525
3384
|
|
|
2526
|
-
await this.setObjectNotExistsAsync(
|
|
3385
|
+
await this.setObjectNotExistsAsync(`devices.${dpSubFolder}lowBatteryListHTML`, {
|
|
2527
3386
|
type: 'state',
|
|
2528
3387
|
common: {
|
|
2529
3388
|
name: {
|
|
@@ -2567,6 +3426,18 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2567
3426
|
return (dpValue = Math.round((time.getTime() - dpValue) / 1000 / 60));
|
|
2568
3427
|
}
|
|
2569
3428
|
|
|
3429
|
+
/**
|
|
3430
|
+
* @param {string} dp - get Time of this datapoint
|
|
3431
|
+
*/
|
|
3432
|
+
async getTimestampConnectionDP(dp) {
|
|
3433
|
+
const time = new Date();
|
|
3434
|
+
const dpValue = await this.getForeignStateAsync(dp);
|
|
3435
|
+
if (dpValue !== null && dpValue !== undefined) {
|
|
3436
|
+
const dpLastStateChange = Math.round((time.getTime() - dpValue.lc) / 1000);
|
|
3437
|
+
return dpLastStateChange;
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
|
|
2570
3441
|
/**
|
|
2571
3442
|
* @param {object} obj - State of datapoint
|
|
2572
3443
|
*/
|
|
@@ -2595,6 +3466,32 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2595
3466
|
return {};
|
|
2596
3467
|
}
|
|
2597
3468
|
|
|
3469
|
+
/**
|
|
3470
|
+
* @param {number} time
|
|
3471
|
+
*/
|
|
3472
|
+
async wait(time) {
|
|
3473
|
+
return new Promise((resolve) => {
|
|
3474
|
+
setTimeout(resolve, time);
|
|
3475
|
+
});
|
|
3476
|
+
}
|
|
3477
|
+
|
|
3478
|
+
/**
|
|
3479
|
+
* Get previous run of cron job schedule
|
|
3480
|
+
* Requires cron-parser!
|
|
3481
|
+
* Inspired by https://stackoverflow.com/questions/68134104/
|
|
3482
|
+
* @param {string} lastCronRun
|
|
3483
|
+
*/
|
|
3484
|
+
async getPreviousCronRun(lastCronRun) {
|
|
3485
|
+
try {
|
|
3486
|
+
const interval = cronParser.parseExpression(lastCronRun);
|
|
3487
|
+
const previous = interval.prev();
|
|
3488
|
+
return Math.floor(Date.now() - previous.getTime()); // in ms
|
|
3489
|
+
} catch (error) {
|
|
3490
|
+
this.log.warn(error);
|
|
3491
|
+
return;
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
|
|
2598
3495
|
/**
|
|
2599
3496
|
* @param {string} codePart - Message Prefix
|
|
2600
3497
|
* @param {object} error - Sentry message
|