iobroker.device-watcher 2.15.5 → 2.15.11
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 +12 -11
- package/io-package.json +80 -67
- package/lib/adapterArray.js +13 -10
- package/lib/crud.js +80 -5
- package/lib/tools.js +20 -4
- package/lib/translations.js +1 -1
- package/main.js +109 -44
- package/package.json +9 -11
package/README.md
CHANGED
|
@@ -191,21 +191,22 @@ This adapter would not have been possible without the great work of Christian Be
|
|
|
191
191
|
Placeholder for the next version (at the beginning of the line):
|
|
192
192
|
### **WORK IN PROGRESS**
|
|
193
193
|
-->
|
|
194
|
-
### 2.15.
|
|
195
|
-
* (arteck)
|
|
194
|
+
### 2.15.11 (2026-05-06)
|
|
195
|
+
* (arteck)
|
|
196
196
|
|
|
197
|
-
### 2.15.
|
|
198
|
-
|
|
197
|
+
### 2.15.10 (2026-05-06)
|
|
198
|
+
- (copilot) Adapter requires node.js >= 22 now
|
|
199
|
+
* (arteck) fix adapter crash after delete a device
|
|
199
200
|
|
|
200
|
-
### 2.15.
|
|
201
|
-
* (arteck)
|
|
201
|
+
### 2.15.9 (2026-04-22)
|
|
202
|
+
* (arteck) new xsense (v. 0.4.0) structure, plz update before
|
|
202
203
|
|
|
203
|
-
### 2.15.
|
|
204
|
-
* (arteck) fix
|
|
204
|
+
### 2.15.8 (2026-04-18)
|
|
205
|
+
* (arteck) fix cronParserLib.parseExpression message
|
|
205
206
|
|
|
206
|
-
### 2.15.
|
|
207
|
-
* (arteck) fix
|
|
208
|
-
* (arteck) fix
|
|
207
|
+
### 2.15.7 (2026-04-18)
|
|
208
|
+
* (arteck) fix matter
|
|
209
|
+
* (arteck) fix cronParserLib.parseExpression message
|
|
209
210
|
|
|
210
211
|
## License
|
|
211
212
|
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,86 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "device-watcher",
|
|
4
|
-
"version": "2.15.
|
|
4
|
+
"version": "2.15.11",
|
|
5
5
|
"news": {
|
|
6
|
+
"2.15.11": {
|
|
7
|
+
"en": "",
|
|
8
|
+
"de": "",
|
|
9
|
+
"ru": "",
|
|
10
|
+
"pt": "",
|
|
11
|
+
"nl": "",
|
|
12
|
+
"fr": "",
|
|
13
|
+
"it": "",
|
|
14
|
+
"es": "",
|
|
15
|
+
"pl": "",
|
|
16
|
+
"uk": "",
|
|
17
|
+
"zh-cn": ""
|
|
18
|
+
},
|
|
19
|
+
"2.15.10": {
|
|
20
|
+
"en": "Adapter requires node.js >= 22 now\nfix adapter crash after delete a device",
|
|
21
|
+
"de": "Adapter benötigt node.js >= 22 jetzt\nfix adapter crash nach dem löschen eines geräts",
|
|
22
|
+
"ru": "Адаптер требует node.js >= 22 сейчас\nисправить сбой адаптера после удаления устройства",
|
|
23
|
+
"pt": "Adaptador requer nod.js >= 22 agora\ncorrigir falha do adaptador após apagar um dispositivo",
|
|
24
|
+
"nl": "Voor de adapter zijn node.js < 22 nu nodig\nfix adapter crash na het verwijderen van een apparaat",
|
|
25
|
+
"fr": "Adaptateur nécessite node.js >= 22 maintenant\ncorrection du crash de l'adaptateur après suppression d'un périphérique",
|
|
26
|
+
"it": "Adattatore richiede node.js >= 22 ora\nfissare l'arresto dell'adattatore dopo eliminare un dispositivo",
|
|
27
|
+
"es": "Adaptador requiere node.js ю= 22 ahora\najuste de bloqueo del adaptador después de eliminar un dispositivo",
|
|
28
|
+
"pl": "Adapter wymaga node.js > = 22\nnaprawić awarię adaptera po usunięciu urządzenia",
|
|
29
|
+
"uk": "Адаптер вимагає node.js >= 22 тепер\nвиправлено аварійний перехід після видалення пристрою",
|
|
30
|
+
"zh-cn": "适配器需要节点.js 现在22\n删除设备后修复适配器崩溃"
|
|
31
|
+
},
|
|
32
|
+
"2.15.9": {
|
|
33
|
+
"en": "new xsense (v. 0.4.0) structure, plz update before",
|
|
34
|
+
"de": "neue xsense (v. 0.4.0) struktur, plz update vor",
|
|
35
|
+
"ru": "новая структура xsense (v. 0.4.0), обновление plz до",
|
|
36
|
+
"pt": "nova estrutura xsense (v. 0.4.0), atualização plz antes",
|
|
37
|
+
"nl": "nieuwe xsense (v. 0.4.0) structuur, plz update voor",
|
|
38
|
+
"fr": "nouvelle structure xsense (v. 0.4.0), mise à jour plz",
|
|
39
|
+
"it": "nuova struttura xsense (v. 0.4.0), aggiornamento plz prima",
|
|
40
|
+
"es": "nueva estructura xsense (v. 0.4.0)",
|
|
41
|
+
"pl": "nowa struktura xsense (v. 0.4.0), aktualizacja plz przed",
|
|
42
|
+
"uk": "новий xsense (v. 0.4.0) структура, оновлення plz перед",
|
|
43
|
+
"zh-cn": "新的 xsense (v. 04. 0) 结构, plz 更新前"
|
|
44
|
+
},
|
|
45
|
+
"2.15.8": {
|
|
46
|
+
"en": "fix cronParserLib.parseExpression message",
|
|
47
|
+
"de": "cronParserLib.parseExpressionsnachricht",
|
|
48
|
+
"ru": "исправить сообщение cronParserLib.parse",
|
|
49
|
+
"pt": "corrigir cronParserLib.parseExpression message",
|
|
50
|
+
"nl": "fix cronParserLib.parseExpressiebericht",
|
|
51
|
+
"fr": "correction du message cronParserLib.parseExpression",
|
|
52
|
+
"it": "correzione cronParserLib.parseExpression messaggio",
|
|
53
|
+
"es": "fijar cronParserLib.parse",
|
|
54
|
+
"pl": "naprawić wiadomość cronParserLib.parseExpression",
|
|
55
|
+
"uk": "виправлено cronParserLib.parseExpression повідомлення",
|
|
56
|
+
"zh-cn": "修补 cronParserLib.parsepression 信件"
|
|
57
|
+
},
|
|
58
|
+
"2.15.7": {
|
|
59
|
+
"en": "fix matter \n",
|
|
60
|
+
"de": "fixkosten\n",
|
|
61
|
+
"ru": "исправлять\n",
|
|
62
|
+
"pt": "corrigir a matéria\n",
|
|
63
|
+
"nl": "fix materie\n",
|
|
64
|
+
"fr": "fixer la matière\n",
|
|
65
|
+
"it": "risolvere la questione\n",
|
|
66
|
+
"es": "arregla la materia\n",
|
|
67
|
+
"pl": "materia stabilna\n",
|
|
68
|
+
"uk": "фіксувати матерію\n",
|
|
69
|
+
"zh-cn": "固定事项\n"
|
|
70
|
+
},
|
|
71
|
+
"2.15.6": {
|
|
72
|
+
"en": "Adapter requires admin >= 7.7.22 now\nfix instanz restart\nfix cronParserLib.parseExpression message\nfix group in zigbee2mqtt",
|
|
73
|
+
"de": "Adapter benötigt admin >= 7.7.22 jetzt\ninstanz restart\ncronParserLib.parseExpressionsnachricht\nfix group in zigbee2mqtt",
|
|
74
|
+
"ru": "Адаптер требует администратора >= 7.7.22\nвосстановление instanz\nисправить сообщение cronParserLib.parse\nфиксированная группа в zigbee2mqtt",
|
|
75
|
+
"pt": "Adaptador requer admin >= 7.7.22 agora\ncorrigir instanz reiniciar\ncorrigir cronParserLib.parseExpression message\ngrupo de correção em zigbee2mqtt",
|
|
76
|
+
"nl": "Adapter vereist admin < 7.7.22 nu\nfix instanz herstart\nfix cronParserLib.parseExpressiebericht\nfix groep in zigbee2mqtt",
|
|
77
|
+
"fr": "Adaptateur nécessite admin >= 7.7.22 maintenant\ncorrection du redémarrage de l'instanz\ncorrection du message cronParserLib.parseExpression\nfixer le groupe dans zigbee2mqtt",
|
|
78
|
+
"it": "Adattatore richiede admin >= 7.7.22 ora\nfix instanz riavvio\ncorrezione cronParserLib.parseExpression messaggio\ngruppo di correzione in zigbee2mqt",
|
|
79
|
+
"es": "El adaptador requiere administrador= 7.7.22 ahora\nfijación instanz restart\nfijar cronParserLib.parse\ngrupo de fijación en zigbee2mqt",
|
|
80
|
+
"pl": "Adapter wymaga admin > = 7.7.22\nfix instanz restart\nnaprawić wiadomość cronParserLib.parseExpression\nfix group in zigbee2mqtt",
|
|
81
|
+
"uk": "Адаптер вимагає адмін >= 7.7.22 тепер\nвиправити instanz перезавантаження\nвиправлено cronParserLib.parseExpression повідомлення\nфіксувати групу в zigbee2mqtt",
|
|
82
|
+
"zh-cn": "适任者需要管理员 \\ 7.7.22 现在\n修复即时状态重新启动\n修补 cronParserLib.parsepression 信件\n以zigbee2mqtt为单位的固定组"
|
|
83
|
+
},
|
|
6
84
|
"2.15.5": {
|
|
7
85
|
"en": "fix admin",
|
|
8
86
|
"de": "admin",
|
|
@@ -15,71 +93,6 @@
|
|
|
15
93
|
"pl": "fix admin",
|
|
16
94
|
"uk": "адмін",
|
|
17
95
|
"zh-cn": "固定管理员"
|
|
18
|
-
},
|
|
19
|
-
"2.15.4": {
|
|
20
|
-
"en": "define subscribe rules new",
|
|
21
|
-
"de": "anmelderegeln neu definieren",
|
|
22
|
-
"ru": "новые правила подписки",
|
|
23
|
-
"pt": "definir regras de subscrição novas",
|
|
24
|
-
"nl": "nieuwe ondertekenregels definiëren",
|
|
25
|
-
"fr": "définir des règles de souscription nouvelles",
|
|
26
|
-
"it": "definire le regole di abbonamento",
|
|
27
|
-
"es": "definir reglas de suscripción nuevas",
|
|
28
|
-
"pl": "nowe zasady subskrypcji",
|
|
29
|
-
"uk": "визначити правила підписки",
|
|
30
|
-
"zh-cn": "定义订阅规则新"
|
|
31
|
-
},
|
|
32
|
-
"2.15.3": {
|
|
33
|
-
"en": "fix ping adapter, fritzdec",
|
|
34
|
-
"de": "fixierpistole, fritzdec",
|
|
35
|
-
"ru": "адаптер для фиксации пингов, fritzdec",
|
|
36
|
-
"pt": "corrigir adaptador de ping, fritzdec",
|
|
37
|
-
"nl": "fix ping adapter, fritzdec",
|
|
38
|
-
"fr": "adaptateur de fixation de ping, fritzdec",
|
|
39
|
-
"it": "correzione adattatore ping, fritzdec",
|
|
40
|
-
"es": "adaptador de fijación, fritzdec",
|
|
41
|
-
"pl": "fix adapter ping, fritzdec",
|
|
42
|
-
"uk": "фіксатор ping, fritzdec",
|
|
43
|
-
"zh-cn": "修补 ping 适配器, fritzdec"
|
|
44
|
-
},
|
|
45
|
-
"2.15.2": {
|
|
46
|
-
"en": "fix cronjob response",
|
|
47
|
-
"de": "fix cronjob antwort",
|
|
48
|
-
"ru": "реакция cronjob",
|
|
49
|
-
"pt": "corrigir a resposta do cronjob",
|
|
50
|
-
"nl": "cronjob respons repareren",
|
|
51
|
-
"fr": "corriger la réponse cronjob",
|
|
52
|
-
"it": "correzione di cronjob risposta",
|
|
53
|
-
"es": "solución respuesta cronjob",
|
|
54
|
-
"pl": "naprawić odpowiedź cronjob",
|
|
55
|
-
"uk": "виправити cronjob відповідь",
|
|
56
|
-
"zh-cn": "固定 curonjob 响应"
|
|
57
|
-
},
|
|
58
|
-
"2.15.1": {
|
|
59
|
-
"en": "fix instance check\nfix admin json",
|
|
60
|
-
"de": "fehlerbehebung\nadmin json",
|
|
61
|
-
"ru": "установить проверку\nисполнитель: admin json",
|
|
62
|
-
"pt": "corrigir verificação de instância\ncorrigir o administrador json",
|
|
63
|
-
"nl": "fix instantiecontrole\nfix admin json",
|
|
64
|
-
"fr": "correction de la vérification de l'instance\nréparer admin json",
|
|
65
|
-
"it": "verifica dell'istanza di correzione\ncorrezione admin json",
|
|
66
|
-
"es": "control de instancia de fijación\nadmin json",
|
|
67
|
-
"pl": "fix instance check\nfix admin json",
|
|
68
|
-
"uk": "перевірка екземпляра\nвиправлено admin json",
|
|
69
|
-
"zh-cn": "修补实例检查\n固定管理员json"
|
|
70
|
-
},
|
|
71
|
-
"2.15.0": {
|
|
72
|
-
"en": "fixed device array\ndeleted zwave2mqtt Adapter\nadded zwavews Adapter\nDependencies have been updated\nadded zwave2mqtt Adapter\nfixed all count devices\ncorrected finder",
|
|
73
|
-
"de": "Geräteanordnung bereinigt\nzwave2mqt Adapter gelöscht\nzwavews Adapter hinzugefügt\nAbhängigkeiten wurden aktualisiert\nzwave2mqtt Adapter hinzugefügt\nalle Zählgeräte überarbeitet\nfinder korrigiert",
|
|
74
|
-
"ru": "фиксированный массив устройств\nудаленный zwave2mqtt Адаптер\nдобавить zwavews Адаптер\nЗависимости были обновлены\nдобавить zwave2mqtt Адаптер\nфиксированные все счетные устройства\nисправленный искатель",
|
|
75
|
-
"pt": "arranjo fixo do dispositivo\napagado zwave2mqtt Adaptador\nzwavews adicionados Adaptador\nAs dependências foram atualizadas\nadicionado zwave2mqtt Adaptador\nfixou todos os dispositivos de contagem\nlocalizador corrigido",
|
|
76
|
-
"nl": "vaste apparaatarray\nverwijderde zwave2mqtt Adapter\nzwavews toegevoegd Adapter\nAfhankelijkheden zijn bijgewerkt\nzwave2mqtt toegevoegd Adapter\nvaste alle telapparaten\ngecorrigeerde zoeker",
|
|
77
|
-
"fr": "tableau de périphériques fixes\nsupprimé zwave2mqtt Adaptateur\nzwavews ajoutés Adaptateur\nLes dépendances ont été actualisées\najouté zwave2mqtt Adaptateur\nfixe tous les appareils de comptage\ncorrecteur",
|
|
78
|
-
"it": "array di dispositivi fissi\ncancellato zwave2mqt Adattatore\naggiunto zwavews Adattatore\nLe dipendenze sono state aggiornate\naggiunto zwave2mqt Adattatore\nfissi tutti i dispositivi di conteggio\ncercatore corretto",
|
|
79
|
-
"es": "array de dispositivo fijo\nborrado zwave2mqt Adaptador\nañadido zwavews Adaptador\nSe han actualizado las dependencias\nzwave2mqt Adaptador\nfijo todos los dispositivos de cuenta\nbuscador corregido",
|
|
80
|
-
"pl": "stała tablica urządzeń\nusunięty zwave2mqtt Adapter\ndodane zwavews Adapter\nZaktualizowano zależności\ndodane zwave2mqtt Adapter\nwszystkie urządzenia liczące\npoprawiony wykrywacz",
|
|
81
|
-
"uk": "фіксований масив пристрою\nвидалено zwave2mqtt Адаптери\nдодано zwavews Адаптери\nЗалежність було оновлено\nдодано zwave2mqtt Адаптери\nфіксовані всі пристрої підрахунку\nвиправлений пошук",
|
|
82
|
-
"zh-cn": "固定设备阵列\n删除 zwave2mqtt 适配器\n添加z波长 适配器\n依赖关系已更新\n添加 zwave2mqtt 适配器\n固定所有计数设备\n更正的查找者"
|
|
83
96
|
}
|
|
84
97
|
},
|
|
85
98
|
"titleLang": {
|
|
@@ -163,7 +176,7 @@
|
|
|
163
176
|
],
|
|
164
177
|
"globalDependencies": [
|
|
165
178
|
{
|
|
166
|
-
"admin": ">=7.
|
|
179
|
+
"admin": ">=7.7.22"
|
|
167
180
|
}
|
|
168
181
|
],
|
|
169
182
|
"messages": [
|
package/lib/adapterArray.js
CHANGED
|
@@ -374,15 +374,18 @@ const adapterArray = {
|
|
|
374
374
|
},
|
|
375
375
|
matter: {
|
|
376
376
|
adapterKey: 'matterDevices',
|
|
377
|
-
|
|
377
|
+
// Selektor: matter.0.controller.<nodeId>.info.connection (boolean, true = online)
|
|
378
|
+
selektor: 'matter.*.controller.*.info.connection',
|
|
379
|
+
timeSelector: '.info.connection',
|
|
378
380
|
adapterID: 'matter',
|
|
379
|
-
adapter: '
|
|
381
|
+
adapter: 'Matter',
|
|
380
382
|
rssiState: 'none',
|
|
381
|
-
battery: '
|
|
382
|
-
|
|
383
|
-
|
|
383
|
+
battery: 'none',
|
|
384
|
+
battery2: 'none',
|
|
385
|
+
reach: '.info.connection',
|
|
386
|
+
isLowBat: 'none',
|
|
384
387
|
id: 'none',
|
|
385
|
-
upgrade: '
|
|
388
|
+
upgrade: '.info.updateAvailable',
|
|
386
389
|
},
|
|
387
390
|
maxcube: {
|
|
388
391
|
adapterKey: 'maxcubeDevices',
|
|
@@ -738,7 +741,7 @@ const adapterArray = {
|
|
|
738
741
|
},
|
|
739
742
|
xsense: {
|
|
740
743
|
adapterKey: 'xsenseDevices',
|
|
741
|
-
selektor: 'xsense
|
|
744
|
+
selektor: 'xsense.*.*.online',
|
|
742
745
|
timeSelector: '.online',
|
|
743
746
|
adapterID: 'xsense',
|
|
744
747
|
adapter: 'XSense',
|
|
@@ -773,8 +776,8 @@ const adapterArray = {
|
|
|
773
776
|
},
|
|
774
777
|
zigbee2MQTT: {
|
|
775
778
|
adapterKey: 'zigbee2mqttDevices',
|
|
776
|
-
selektor: 'zigbee2mqtt.*.
|
|
777
|
-
timeSelector: '.
|
|
779
|
+
selektor: 'zigbee2mqtt.*.available',
|
|
780
|
+
timeSelector: '.last_seen',
|
|
778
781
|
adapterID: 'zigbee2MQTT',
|
|
779
782
|
adapter: 'Zigbee2MQTT',
|
|
780
783
|
battery: '.battery',
|
|
@@ -794,7 +797,7 @@ const adapterArray = {
|
|
|
794
797
|
rssiState: 'none',
|
|
795
798
|
isLowBat: '.Battery.isLow',
|
|
796
799
|
},
|
|
797
|
-
|
|
800
|
+
zwavews: {
|
|
798
801
|
adapterKey: 'zwavewsDevices',
|
|
799
802
|
selektor: 'zwavews.*.ready',
|
|
800
803
|
timeSelector: '.status',
|
package/lib/crud.js
CHANGED
|
@@ -1071,6 +1071,44 @@ async function createData(adaptr, i) {
|
|
|
1071
1071
|
if (id.endsWith('.')) {
|
|
1072
1072
|
continue;
|
|
1073
1073
|
}
|
|
1074
|
+
|
|
1075
|
+
// matter: nur matter.<inst>.controller.<nodeId>.info.connection zulassen
|
|
1076
|
+
if (adapterID === 'matter') {
|
|
1077
|
+
const parts = id.split('.');
|
|
1078
|
+
if (parts.length !== 6 || parts[2] !== 'controller' || parts[4] !== 'info' || parts[5] !== 'connection') {
|
|
1079
|
+
continue;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// zigbee2MQTT: Bridge/Coordinator/System-Objekte ausfiltern (kein echter Gerätepfad)
|
|
1084
|
+
if (adapterID === 'zigbee2MQTT') {
|
|
1085
|
+
const parts = id.split('.');
|
|
1086
|
+
// Pfad muss mindestens 4 Teile haben: zigbee2mqtt.0.<device>.<state>
|
|
1087
|
+
if (parts.length < 4) {
|
|
1088
|
+
continue;
|
|
1089
|
+
}
|
|
1090
|
+
// Bridge und System-Objekte ausschließen
|
|
1091
|
+
const deviceSegment = parts[2].toLowerCase();
|
|
1092
|
+
if (deviceSegment === 'bridge' || deviceSegment === 'coordinator' || deviceSegment === 'info' || deviceSegment === 'groups') {
|
|
1093
|
+
continue;
|
|
1094
|
+
}
|
|
1095
|
+
// Zigbee2MQTT Gruppen ausschließen: Gruppen haben native.type === 'group'
|
|
1096
|
+
// Gruppen liegen direkt auf Instanz-Ebene z.B. zigbee2mqtt.0.büro
|
|
1097
|
+
const currDevStr = id.slice(0, id.lastIndexOf('.'));
|
|
1098
|
+
const deviceObj = await adaptr.getForeignObjectAsync(currDevStr);
|
|
1099
|
+
if (deviceObj && deviceObj.native && deviceObj.native.type === 'group') {
|
|
1100
|
+
adaptr.log.debug(`[createData zigbee2MQTT] Skipping group (native.type): ${currDevStr}`);
|
|
1101
|
+
continue;
|
|
1102
|
+
}
|
|
1103
|
+
// Fallback: Gruppen haben weder last_seen noch link_quality → kein echtes Gerät
|
|
1104
|
+
const hasLastSeen = await tools.getInitValue(adaptr, `${currDevStr}.last_seen`);
|
|
1105
|
+
const hasLinkQuality = await tools.getInitValue(adaptr, `${currDevStr}.link_quality`);
|
|
1106
|
+
if (hasLastSeen === undefined && hasLinkQuality === undefined) {
|
|
1107
|
+
adaptr.log.debug(`[createData zigbee2MQTT] Skipping group (no last_seen/link_quality): ${currDevStr}`);
|
|
1108
|
+
continue;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1074
1112
|
const mainSelector = id;
|
|
1075
1113
|
|
|
1076
1114
|
/*=============================================
|
|
@@ -1192,17 +1230,39 @@ async function createData(adaptr, i) {
|
|
|
1192
1230
|
deviceBatteryState = await tools.getInitValue(adaptr, deviceBatteryStateDP);
|
|
1193
1231
|
break;
|
|
1194
1232
|
|
|
1233
|
+
case 'matter': {
|
|
1234
|
+
// matter: Batterie liegt unter shortCurrDeviceString.PowerSource-N.BATTERY
|
|
1235
|
+
// N ist variabel -> dynamisch per getObjectViewAsync suchen
|
|
1236
|
+
const matterBattPrefix = `${shortCurrDeviceString}.PowerSource-`;
|
|
1237
|
+
const matterBattList = await adaptr.getObjectViewAsync('system', 'state', {
|
|
1238
|
+
startkey: `${matterBattPrefix}`,
|
|
1239
|
+
endkey: `${matterBattPrefix}\u9999`,
|
|
1240
|
+
});
|
|
1241
|
+
// ersten BATTERY-State nehmen
|
|
1242
|
+
const matterBattRow = matterBattList.rows.find((r) => r.id.endsWith('.BATTERY'));
|
|
1243
|
+
if (matterBattRow) {
|
|
1244
|
+
deviceBatteryStateDP = matterBattRow.id;
|
|
1245
|
+
deviceBatteryState = await tools.getInitValue(adaptr, deviceBatteryStateDP);
|
|
1246
|
+
}
|
|
1247
|
+
break;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1195
1250
|
default:
|
|
1196
1251
|
deviceBatteryStateDP = currDeviceString + adaptr.selAdapter[i].battery;
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1252
|
+
if (adaptr.selAdapter[i].battery === 'none') {
|
|
1253
|
+
// adapter has no battery percentage DP (e.g. hmiP) – skip lookups
|
|
1254
|
+
deviceBatteryState = undefined;
|
|
1255
|
+
} else {
|
|
1201
1256
|
deviceBatteryState = await tools.getInitValue(adaptr, deviceBatteryStateDP);
|
|
1202
1257
|
|
|
1203
1258
|
if (deviceBatteryState === undefined) {
|
|
1204
|
-
deviceBatteryStateDP = currDeviceString + adaptr.selAdapter[i].
|
|
1259
|
+
deviceBatteryStateDP = currDeviceString + adaptr.selAdapter[i].battery2;
|
|
1205
1260
|
deviceBatteryState = await tools.getInitValue(adaptr, deviceBatteryStateDP);
|
|
1261
|
+
|
|
1262
|
+
if (deviceBatteryState === undefined) {
|
|
1263
|
+
deviceBatteryStateDP = currDeviceString + adaptr.selAdapter[i].battery3;
|
|
1264
|
+
deviceBatteryState = await tools.getInitValue(adaptr, deviceBatteryStateDP);
|
|
1265
|
+
}
|
|
1206
1266
|
}
|
|
1207
1267
|
}
|
|
1208
1268
|
break;
|
|
@@ -1221,6 +1281,21 @@ async function createData(adaptr, i) {
|
|
|
1221
1281
|
deviceLowBatState = await tools.getInitValue(adaptr, isLowBatDP);
|
|
1222
1282
|
}
|
|
1223
1283
|
}
|
|
1284
|
+
|
|
1285
|
+
// matter: LOWBAT dynamisch über PowerSource-N.LOWBAT suchen
|
|
1286
|
+
if (adapterID === 'matter' && deviceLowBatState === undefined) {
|
|
1287
|
+
const matterLowBatPrefix = `${shortCurrDeviceString}.PowerSource-`;
|
|
1288
|
+
const matterLowBatList = await adaptr.getObjectViewAsync('system', 'state', {
|
|
1289
|
+
startkey: matterLowBatPrefix,
|
|
1290
|
+
endkey: `${matterLowBatPrefix}\u9999`,
|
|
1291
|
+
});
|
|
1292
|
+
const matterLowBatRow = matterLowBatList.rows.find((r) => r.id.endsWith('.LOWBAT'));
|
|
1293
|
+
if (matterLowBatRow) {
|
|
1294
|
+
isLowBatDP = matterLowBatRow.id;
|
|
1295
|
+
deviceLowBatState = await tools.getInitValue(adaptr, isLowBatDP);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1224
1299
|
if (deviceLowBatState === undefined) {
|
|
1225
1300
|
isLowBatDP = 'none';
|
|
1226
1301
|
}
|
package/lib/tools.js
CHANGED
|
@@ -11,7 +11,15 @@ async function isDisabledDevice(adaptr, treeDP) {
|
|
|
11
11
|
|
|
12
12
|
const device = await adaptr.getForeignObject(treeDP);
|
|
13
13
|
|
|
14
|
-
if (device
|
|
14
|
+
if (!device || !device.common) {
|
|
15
|
+
return isDisabled;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const desc = device.common.desc ?? '';
|
|
19
|
+
const descStr = typeof desc === 'object' ? JSON.stringify(desc) : String(desc);
|
|
20
|
+
const deviceRemoved = device.native && device.native.deviceRemoved === true;
|
|
21
|
+
|
|
22
|
+
if (deviceRemoved || descStr.includes('disabled') || descStr.includes('Deaktiviert')) {
|
|
15
23
|
isDisabled = true;
|
|
16
24
|
}
|
|
17
25
|
return isDisabled;
|
|
@@ -114,11 +122,19 @@ async function countDevices(adaptr) {
|
|
|
114
122
|
*/
|
|
115
123
|
async function checkLastContact(adaptr) {
|
|
116
124
|
for (const [deviceID, deviceData] of adaptr.listAllDevicesRaw.entries()) {
|
|
117
|
-
if (deviceData.instanceDeviceConnected !== false && deviceData.instanceDeviceConnected
|
|
118
|
-
deviceData.UnreachState = await
|
|
125
|
+
if (deviceData.instanceDeviceConnected !== false && deviceData.instanceDeviceConnected !== undefined) {
|
|
126
|
+
deviceData.UnreachState = await getInitValue(adaptr, deviceData.UnreachDP);
|
|
119
127
|
|
|
120
128
|
const gefundenerAdapter = Object.values(adapterArray).find((adapter) => adapter.adapterID === deviceData.adapterID);
|
|
129
|
+
if (!gefundenerAdapter) {
|
|
130
|
+
adaptr.log.warn(`[checkLastContact] - adapter not found for adapterID: ${deviceData.adapterID}, skipping device ${deviceID}`);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
121
133
|
const silentEnabled = Object.values(adaptr.config.tableDevices).find((adapter) => adapter.adapterKey === gefundenerAdapter.adapterKey);
|
|
134
|
+
if (!silentEnabled) {
|
|
135
|
+
adaptr.log.warn(`[checkLastContact] - device config not found for adapterKey: ${gefundenerAdapter.adapterKey}, skipping device ${deviceID}`);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
122
138
|
|
|
123
139
|
const oldContactState = deviceData.Status;
|
|
124
140
|
|
|
@@ -138,7 +154,7 @@ async function checkLastContact(adaptr) {
|
|
|
138
154
|
}
|
|
139
155
|
if (adaptr.config.checkSendOfflineMsg && oldContactState !== deviceData.Status && !adaptr.blacklistNotify.includes(deviceData.Path)) {
|
|
140
156
|
// check if the generally deviceData connected state is for a while true
|
|
141
|
-
if (await
|
|
157
|
+
if (await getTimestampConnectionDP(adaptr, deviceData.instanceDeviceConnectionDP, 50000)) {
|
|
142
158
|
await adaptr.sendStateNotifications('Devices', 'onlineStateDevice', deviceID, silentEnabled.telegramSilent);
|
|
143
159
|
}
|
|
144
160
|
}
|
package/lib/translations.js
CHANGED
package/main.js
CHANGED
|
@@ -118,7 +118,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
118
118
|
// create list with enabled adapters for monitor devices
|
|
119
119
|
for (const device of Object.values(this.config.tableDevices)) {
|
|
120
120
|
if (device.enabled) {
|
|
121
|
-
for (const [
|
|
121
|
+
for (const [_adapterName, adapter] of Object.entries(adapterArray)) {
|
|
122
122
|
if (String(adapter.adapterKey).toLowerCase() === String(device.adapterKey).toLowerCase()) {
|
|
123
123
|
this.selAdapter.push(adapter);
|
|
124
124
|
this.adapterSelected.push(adapter.adapterKey);
|
|
@@ -325,6 +325,14 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
325
325
|
if (this.listAllDevicesRaw.has(id)) {
|
|
326
326
|
this.listAllDevicesRaw.delete(id);
|
|
327
327
|
}
|
|
328
|
+
// also remove all child devices if a parent/adapter object was deleted
|
|
329
|
+
const idPrefix = `${id }.`;
|
|
330
|
+
for (const key of this.listAllDevicesRaw.keys()) {
|
|
331
|
+
if (key.startsWith(idPrefix)) {
|
|
332
|
+
this.log.debug(`[onObjectChange] removing child device from map: ${key}`);
|
|
333
|
+
this.listAllDevicesRaw.delete(key);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
328
336
|
|
|
329
337
|
//unsubscribe of Objects and states
|
|
330
338
|
this.unsubscribeForeignObjects(id);
|
|
@@ -450,6 +458,9 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
450
458
|
}
|
|
451
459
|
}
|
|
452
460
|
break;
|
|
461
|
+
default:
|
|
462
|
+
this.log.warn(`[onMessage] Unknown command: ${obj.command}`);
|
|
463
|
+
break;
|
|
453
464
|
}
|
|
454
465
|
}
|
|
455
466
|
|
|
@@ -531,6 +542,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
531
542
|
// Get ID with short currDeviceString from objectjson
|
|
532
543
|
case 'hueExt':
|
|
533
544
|
case 'hmrpc':
|
|
545
|
+
case 'matter':
|
|
534
546
|
case 'nukiExt':
|
|
535
547
|
case 'wled':
|
|
536
548
|
case 'mqttNuki':
|
|
@@ -740,10 +752,16 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
740
752
|
default:
|
|
741
753
|
if (deviceBatteryState === undefined) {
|
|
742
754
|
if (deviceLowBatState !== undefined) {
|
|
743
|
-
|
|
755
|
+
// Explicit OK states: false, 'NORMAL', 0 (some adapters use 0=ok)
|
|
756
|
+
if (
|
|
757
|
+
deviceLowBatState === false ||
|
|
758
|
+
deviceLowBatState === 'NORMAL' ||
|
|
759
|
+
deviceLowBatState === 0
|
|
760
|
+
) {
|
|
744
761
|
batteryHealth = 'ok';
|
|
745
762
|
isBatteryDevice = true;
|
|
746
|
-
} else
|
|
763
|
+
} else {
|
|
764
|
+
// true, 1, any other string != 'NORMAL' → low
|
|
747
765
|
batteryHealth = 'low';
|
|
748
766
|
isBatteryDevice = true;
|
|
749
767
|
}
|
|
@@ -790,11 +808,14 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
790
808
|
}
|
|
791
809
|
break;
|
|
792
810
|
default:
|
|
793
|
-
if (typeof deviceLowBatState === '
|
|
811
|
+
if (typeof deviceLowBatState === 'boolean' && deviceLowBatState === true) {
|
|
812
|
+
// true = low bat
|
|
794
813
|
lowBatIndicator = true;
|
|
795
814
|
} else if (typeof deviceLowBatState === 'string' && deviceLowBatState !== 'NORMAL') {
|
|
815
|
+
// any string other than 'NORMAL' = low bat
|
|
796
816
|
lowBatIndicator = true;
|
|
797
|
-
} else if (typeof deviceLowBatState === '
|
|
817
|
+
} else if (typeof deviceLowBatState === 'number' && deviceLowBatState === 1) {
|
|
818
|
+
// 1 = low bat (0 = ok), consistent with getBatteryData
|
|
798
819
|
lowBatIndicator = true;
|
|
799
820
|
}
|
|
800
821
|
}
|
|
@@ -813,20 +834,16 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
813
834
|
* @param {object} selector - Selector
|
|
814
835
|
*/
|
|
815
836
|
async getLastContact(selector) {
|
|
816
|
-
const lastContact = tools.getTimestamp(selector);
|
|
817
|
-
|
|
818
|
-
let lastContactString = `${this.formatDate(new Date(selector), 'hh:mm:ss')}`;
|
|
837
|
+
const lastContact = tools.getTimestamp(selector);
|
|
819
838
|
|
|
820
|
-
|
|
821
|
-
if (Math.round(lastContact) >= 0) {
|
|
822
|
-
lastContactString = `${Math.round(lastContact)} ${translations.secs[this.config.userSelectedLanguage]}`;
|
|
823
|
-
}
|
|
839
|
+
let lastContactString;
|
|
824
840
|
|
|
825
|
-
// Optional: Wenn du ab einem bestimmten Wert lieber Minuten oder Stunden willst
|
|
826
841
|
if (lastContact >= 3600) {
|
|
827
842
|
lastContactString = `${(lastContact / 3600).toFixed(1)} ${translations.hours[this.config.userSelectedLanguage]}`;
|
|
828
|
-
} else {
|
|
843
|
+
} else if (lastContact >= 60) {
|
|
829
844
|
lastContactString = `${Math.round(lastContact / 60)} ${translations.minits[this.config.userSelectedLanguage]}`;
|
|
845
|
+
} else {
|
|
846
|
+
lastContactString = `${Math.round(lastContact)} ${translations.secs[this.config.userSelectedLanguage]}`;
|
|
830
847
|
}
|
|
831
848
|
|
|
832
849
|
return lastContactString;
|
|
@@ -842,7 +859,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
842
859
|
const deviceTimeSelector = await this.getForeignStateAsync(timeSelector);
|
|
843
860
|
const deviceUnreachSelector = await this.getForeignStateAsync(treeDP);
|
|
844
861
|
|
|
845
|
-
const lastDeviceUnreachStateChange = deviceUnreachSelector !=
|
|
862
|
+
const lastDeviceUnreachStateChange = deviceUnreachSelector?.lc != null ? tools.getTimestamp(deviceUnreachSelector.lc) : tools.getTimestamp(deviceTimeSelector?.ts ?? Date.now());
|
|
846
863
|
|
|
847
864
|
// ignore disabled device from zigbee2MQTT
|
|
848
865
|
if (adapterID === 'zigbee2MQTT') {
|
|
@@ -875,7 +892,15 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
875
892
|
}
|
|
876
893
|
|
|
877
894
|
const gefundenerAdapter = Object.values(adapterArray).find((adapter) => adapter.adapterID === adapterID);
|
|
895
|
+
if (!gefundenerAdapter) {
|
|
896
|
+
this.log.warn(`[getOnlineState] - adapter not found in adapterArray for adapterID: ${adapterID}`);
|
|
897
|
+
return [lastContactString ?? ' - ', deviceState, linkQualitySet];
|
|
898
|
+
}
|
|
878
899
|
const device = Object.values(this.config.tableDevices).find((adapter) => adapter.adapterKey === gefundenerAdapter.adapterKey);
|
|
900
|
+
if (!device) {
|
|
901
|
+
this.log.warn(`[getOnlineState] - device config not found for adapterKey: ${gefundenerAdapter.adapterKey}`);
|
|
902
|
+
return [lastContactString ?? ' - ', deviceState, linkQualitySet];
|
|
903
|
+
}
|
|
879
904
|
const maxSecondDevicesOffline = device.maxSecondDevicesOffline;
|
|
880
905
|
|
|
881
906
|
switch (adapterID) {
|
|
@@ -931,6 +956,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
931
956
|
case 'apcups':
|
|
932
957
|
case 'hue':
|
|
933
958
|
case 'hueExt':
|
|
959
|
+
case 'matter':
|
|
934
960
|
case 'ping':
|
|
935
961
|
case 'deconz':
|
|
936
962
|
case 'shelly':
|
|
@@ -1087,7 +1113,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1087
1113
|
});
|
|
1088
1114
|
|
|
1089
1115
|
// LinkQuality lists
|
|
1090
|
-
if (device.SignalStrength
|
|
1116
|
+
if (device.SignalStrength !== ' - ') {
|
|
1091
1117
|
this.linkQualityDevices.push({
|
|
1092
1118
|
[translations.Device[this.config.userSelectedLanguage]]: device.Device,
|
|
1093
1119
|
[translations.Adapter[this.config.userSelectedLanguage]]: device.Adapter,
|
|
@@ -1138,7 +1164,6 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1138
1164
|
* @param {ioBroker.State} state
|
|
1139
1165
|
*/
|
|
1140
1166
|
async renewDeviceData(id, state) {
|
|
1141
|
-
const regex = /^([^.]+\.\d+\.[^.]+)/;
|
|
1142
1167
|
let batteryData;
|
|
1143
1168
|
let signalData;
|
|
1144
1169
|
let oldLowBatState;
|
|
@@ -1153,7 +1178,15 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1153
1178
|
|
|
1154
1179
|
if (deviceData) {
|
|
1155
1180
|
const gefundenerAdapter = Object.values(adapterArray).find((adapter) => adapter.adapterID === deviceData.adapterID);
|
|
1181
|
+
if (!gefundenerAdapter) {
|
|
1182
|
+
this.log.warn(`[renewDeviceData] - adapter not found for adapterID: ${deviceData.adapterID}`);
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1156
1185
|
const silentEnabled = Object.values(this.config.tableDevices).find((adapter) => adapter.adapterKey === gefundenerAdapter.adapterKey);
|
|
1186
|
+
if (!silentEnabled) {
|
|
1187
|
+
this.log.warn(`[renewDeviceData] - device config not found for adapterKey: ${gefundenerAdapter.adapterKey}`);
|
|
1188
|
+
return;
|
|
1189
|
+
}
|
|
1157
1190
|
|
|
1158
1191
|
// On statechange update available datapoint
|
|
1159
1192
|
switch (id) {
|
|
@@ -1188,7 +1221,8 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1188
1221
|
if (deviceData.isBatteryDevice) {
|
|
1189
1222
|
oldLowBatState = deviceData.LowBat;
|
|
1190
1223
|
if (state.val === 0 && deviceData.BatteryRaw >= 5) {
|
|
1191
|
-
|
|
1224
|
+
// Glitch-Filter: ignore single 0-value if battery was above 5 before
|
|
1225
|
+
break;
|
|
1192
1226
|
}
|
|
1193
1227
|
batteryData = await this.getBatteryData(state.val, oldLowBatState, deviceData.faultReport, deviceData.adapterID);
|
|
1194
1228
|
|
|
@@ -1264,7 +1298,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1264
1298
|
deviceData.rssiPeerSelectorHMRPC,
|
|
1265
1299
|
);
|
|
1266
1300
|
|
|
1267
|
-
if (contactData !== undefined
|
|
1301
|
+
if (contactData !== undefined && contactData !== null) {
|
|
1268
1302
|
deviceData.LastContact = contactData[0];
|
|
1269
1303
|
deviceData.Status = contactData[1];
|
|
1270
1304
|
deviceData.SignalStrength = contactData[2];
|
|
@@ -1323,7 +1357,7 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1323
1357
|
const devicesState = await this.getForeignStateAsync(instanceConnectedDeviceDP);
|
|
1324
1358
|
|
|
1325
1359
|
let instanceConnectedDeviceVal;
|
|
1326
|
-
if (
|
|
1360
|
+
if (devicesState !== null && typeof devicesState.val === 'boolean') {
|
|
1327
1361
|
instanceConnectedDeviceVal = await tools.getInitValue(this, instanceConnectedDeviceDP);
|
|
1328
1362
|
} else {
|
|
1329
1363
|
instanceConnectedDeviceVal = 'N/A';
|
|
@@ -1549,13 +1583,19 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1549
1583
|
await this.delay(instanceErrorTime);
|
|
1550
1584
|
const daemonIsAliveAfterSecondDelay = await this.checkDaemonIsHealthy(instanceID);
|
|
1551
1585
|
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1586
|
+
// nach allen Retries: Status übernehmen (egal ob erholt oder weiterhin fehlerhaft)
|
|
1587
|
+
isAlive = Boolean(daemonIsAliveAfterSecondDelay[0]);
|
|
1588
|
+
isHealthy = Boolean(daemonIsAliveAfterSecondDelay[1]);
|
|
1589
|
+
instanceStatusString = String(daemonIsAliveAfterSecondDelay[2]);
|
|
1590
|
+
connectedToHost = Boolean(daemonIsAliveAfterSecondDelay[3]);
|
|
1591
|
+
connectedToDevice = Boolean(daemonIsAliveAfterSecondDelay[4]);
|
|
1592
|
+
} else {
|
|
1593
|
+
// nach erstem Retry wieder gesund
|
|
1594
|
+
isAlive = Boolean(daemonIsAliveAfterDelay[0]);
|
|
1595
|
+
isHealthy = Boolean(daemonIsAliveAfterDelay[1]);
|
|
1596
|
+
instanceStatusString = String(daemonIsAliveAfterDelay[2]);
|
|
1597
|
+
connectedToHost = Boolean(daemonIsAliveAfterDelay[3]);
|
|
1598
|
+
connectedToDevice = Boolean(daemonIsAliveAfterDelay[4]);
|
|
1559
1599
|
}
|
|
1560
1600
|
} else {
|
|
1561
1601
|
daemonIsNotAlive = await this.checkDaemonIsAlive(instanceID, instanceDeactivationTime);
|
|
@@ -1580,14 +1620,17 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1580
1620
|
async getAdapterUpdateData(adapterUpdateListDP) {
|
|
1581
1621
|
// Clear the existing adapter updates data
|
|
1582
1622
|
let adapterUpdatesJsonRaw = [];
|
|
1583
|
-
let adapterJsonList;
|
|
1623
|
+
let adapterJsonList = {};
|
|
1584
1624
|
|
|
1585
1625
|
// Fetch the adapter updates list
|
|
1586
1626
|
const adapterUpdatesListVal = await this.getForeignStatesAsync(adapterUpdateListDP);
|
|
1587
1627
|
|
|
1588
|
-
// Extract adapter data from the list
|
|
1589
|
-
for (const [
|
|
1590
|
-
|
|
1628
|
+
// Extract adapter data from the list - merge all admin instances
|
|
1629
|
+
for (const [_id, value] of Object.entries(adapterUpdatesListVal)) {
|
|
1630
|
+
const parsed = tools.parseData(value.val);
|
|
1631
|
+
if (parsed && typeof parsed === 'object') {
|
|
1632
|
+
Object.assign(adapterJsonList, parsed);
|
|
1633
|
+
}
|
|
1591
1634
|
}
|
|
1592
1635
|
|
|
1593
1636
|
// Populate the adapter updates data
|
|
@@ -1817,8 +1860,24 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
1817
1860
|
// send message when instance was deactivated
|
|
1818
1861
|
if (this.config.checkSendInstanceDeactivatedMsg && !instanceData.isAlive) {
|
|
1819
1862
|
if (this.blacklistInstancesNotify.includes(instanceID)) {
|
|
1820
|
-
|
|
1863
|
+
break;
|
|
1821
1864
|
}
|
|
1865
|
+
// Restart-Erkennung: Toleranzzeit abwarten und prüfen ob Instanz schon wieder läuft
|
|
1866
|
+
const restartTolerance = this.userTimeInstancesList.has(instanceID)
|
|
1867
|
+
? this.userTimeInstancesList.get(instanceID).deactivationTime * 1000
|
|
1868
|
+
: this.config.offlineTimeInstances * 1000;
|
|
1869
|
+
|
|
1870
|
+
this.log.debug(`[renewInstanceData] Instance ${instanceID} went offline - waiting ${restartTolerance}ms to check for restart...`);
|
|
1871
|
+
await this.delay(restartTolerance);
|
|
1872
|
+
|
|
1873
|
+
const aliveAfterWait = await tools.getInitValue(this, `system.adapter.${instanceID}.alive`);
|
|
1874
|
+
if (aliveAfterWait) {
|
|
1875
|
+
// Instanz ist bereits wieder online → war nur ein Neustart
|
|
1876
|
+
this.log.debug(`[renewInstanceData] Instance ${instanceID} is back online after restart. No deactivation notification sent.`);
|
|
1877
|
+
await checkInstance(instanceID, instanceData);
|
|
1878
|
+
break;
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1822
1881
|
await this.sendStateNotifications('Instances', 'deactivatedInstance', instanceID);
|
|
1823
1882
|
}
|
|
1824
1883
|
}
|
|
@@ -2291,18 +2350,24 @@ class DeviceWatcher extends utils.Adapter {
|
|
|
2291
2350
|
}
|
|
2292
2351
|
}
|
|
2293
2352
|
async getPreviousCronRun(lastCronRun) {
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2353
|
+
try {
|
|
2354
|
+
let interval;
|
|
2355
|
+
// cron-parser v4: parseExpression() – v5: CronExpressionParser.parse()
|
|
2356
|
+
if (typeof cronParserLib.parseExpression === 'function') {
|
|
2357
|
+
interval = cronParserLib.parseExpression(lastCronRun);
|
|
2358
|
+
} else if (cronParserLib.CronExpressionParser && typeof cronParserLib.CronExpressionParser.parse === 'function') {
|
|
2359
|
+
interval = cronParserLib.CronExpressionParser.parse(lastCronRun);
|
|
2360
|
+
} else {
|
|
2361
|
+
throw new Error('cron-parser: no compatible API found (parseExpression / CronExpressionParser.parse)');
|
|
2362
|
+
}
|
|
2363
|
+
const previous = interval.prev();
|
|
2364
|
+
|
|
2365
|
+
// Differenz in ms seit dem vorherigen Cron-Zeitpunkt
|
|
2366
|
+
return Date.now() - previous.getTime();
|
|
2367
|
+
} catch (error) {
|
|
2368
|
+
this.log.error(`[getPreviousCronRun] - ${error}`);
|
|
2369
|
+
return null;
|
|
2370
|
+
}
|
|
2306
2371
|
}
|
|
2307
2372
|
|
|
2308
2373
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.device-watcher",
|
|
3
|
-
"version": "2.15.
|
|
3
|
+
"version": "2.15.11",
|
|
4
4
|
"description": "Watchdog for devices",
|
|
5
5
|
"author": "Christian Behrends <mail@christian-behrends.de>",
|
|
6
6
|
"contributors": [
|
|
@@ -23,26 +23,24 @@
|
|
|
23
23
|
"url": "https://github.com/iobroker-community-adapters/ioBroker.device-watcher"
|
|
24
24
|
},
|
|
25
25
|
"engines": {
|
|
26
|
-
"node": ">=
|
|
26
|
+
"node": ">=22"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@iobroker/adapter-core": "^3.3.2",
|
|
30
30
|
"node-schedule": "^2.1.1",
|
|
31
|
-
"cron-parser": "^
|
|
31
|
+
"cron-parser": "^5.5.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@alcalzone/release-script": "^5.
|
|
35
|
-
"@alcalzone/release-script-plugin-iobroker": "^
|
|
36
|
-
"@alcalzone/release-script-plugin-license": "^
|
|
37
|
-
"@alcalzone/release-script-plugin-manual-review": "^
|
|
34
|
+
"@alcalzone/release-script": "^5.1.1",
|
|
35
|
+
"@alcalzone/release-script-plugin-iobroker": "^5.1.2",
|
|
36
|
+
"@alcalzone/release-script-plugin-license": "^5.1.1",
|
|
37
|
+
"@alcalzone/release-script-plugin-manual-review": "^5.1.1",
|
|
38
38
|
"@iobroker/adapter-dev": "^1.5.0",
|
|
39
39
|
"@iobroker/eslint-config": "^2.1.0",
|
|
40
40
|
"@iobroker/testing": "^5.2.2",
|
|
41
|
-
"@types/node": "^24.
|
|
41
|
+
"@types/node": "^24.12.0",
|
|
42
42
|
"@types/node-schedule": "^2.1.8",
|
|
43
|
-
"
|
|
44
|
-
"@typescript-eslint/parser": "^8.48.1",
|
|
45
|
-
"typescript": "~5.9.3"
|
|
43
|
+
"typescript": "~6.0.2"
|
|
46
44
|
},
|
|
47
45
|
"main": "main.js",
|
|
48
46
|
"files": [
|