iobroker.device-watcher 2.15.11 → 2.15.12

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 CHANGED
@@ -191,6 +191,9 @@ 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.12 (2026-05-06)
195
+ * (arteck) fix hueExtended battery check
196
+
194
197
  ### 2.15.11 (2026-05-06)
195
198
  * (arteck)
196
199
 
@@ -204,10 +207,6 @@ This adapter would not have been possible without the great work of Christian Be
204
207
  ### 2.15.8 (2026-04-18)
205
208
  * (arteck) fix cronParserLib.parseExpression message
206
209
 
207
- ### 2.15.7 (2026-04-18)
208
- * (arteck) fix matter
209
- * (arteck) fix cronParserLib.parseExpression message
210
-
211
210
  ## License
212
211
 
213
212
  MIT License
package/io-package.json CHANGED
@@ -1,86 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "device-watcher",
4
- "version": "2.15.11",
4
+ "version": "2.15.12",
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为单位的固定组"
6
+ "2.15.12": {
7
+ "en": "fix hueExtended battery check",
8
+ "de": "hueExtended Akku Check",
9
+ "ru": "проверка батареи Extended battery check",
10
+ "pt": "corrigir matizExtended verificação da bateria",
11
+ "nl": "fix hueExtended batterijcontrole",
12
+ "fr": "fix hueVérification étendue de la batterie",
13
+ "it": "correggere il controllo della batteria estesa",
14
+ "es": "hue de fijaciónComprobar la batería",
15
+ "pl": "fix hueExtended kontrola baterii",
16
+ "uk": "fix hueExtended перевірка батареї",
17
+ "zh-cn": "修复 hue 扩展电池检查"
83
18
  },
19
+ "2.15.11": {
20
+ "en": "fix",
21
+ "de": "fix",
22
+ "ru": "fix",
23
+ "pt": "fix",
24
+ "nl": "fix",
25
+ "fr": "fix",
26
+ "it": "fix",
27
+ "es": "fix",
28
+ "pl": "fix",
29
+ "uk": "fix",
30
+ "zh-cn": "fix"
31
+ },
84
32
  "2.15.5": {
85
33
  "en": "fix admin",
86
34
  "de": "admin",
package/lib/crud.js CHANGED
@@ -1204,18 +1204,28 @@ async function createData(adaptr, i) {
1204
1204
  deviceBatteryState = await tools.getInitValue(adaptr, deviceBatteryStateDP);
1205
1205
  }
1206
1206
  break;
1207
- case 'hueExt':
1208
- case 'mihomeVacuum':
1209
- case 'mqttNuki':
1210
- case 'loqedSmartLock':
1211
- deviceBatteryStateDP = shortCurrDeviceString + adaptr.selAdapter[i].battery;
1207
+ case 'hueExt':
1208
+ // hue-extended: battery is at currDeviceString level (e.g. hue-extended.0.lights.1.config.battery)
1209
+ // NOT shortCurrDeviceString (which is the lights/sensors folder, e.g. hue-extended.0.lights)
1210
+ deviceBatteryStateDP = currDeviceString + adaptr.selAdapter[i].battery;
1211
+ deviceBatteryState = await tools.getInitValue(adaptr, deviceBatteryStateDP);
1212
+
1213
+ if (deviceBatteryState === undefined) {
1214
+ deviceBatteryStateDP = currDeviceString + adaptr.selAdapter[i].battery2;
1212
1215
  deviceBatteryState = await tools.getInitValue(adaptr, deviceBatteryStateDP);
1213
-
1214
- if (deviceBatteryState === undefined) {
1215
- deviceBatteryStateDP = shortCurrDeviceString + adaptr.selAdapter[i].battery2;
1216
- deviceBatteryState = await tools.getInitValue(adaptr, deviceBatteryStateDP);
1217
- }
1218
- break;
1216
+ }
1217
+ break;
1218
+ case 'mihomeVacuum':
1219
+ case 'mqttNuki':
1220
+ case 'loqedSmartLock':
1221
+ deviceBatteryStateDP = shortCurrDeviceString + adaptr.selAdapter[i].battery;
1222
+ deviceBatteryState = await tools.getInitValue(adaptr, deviceBatteryStateDP);
1223
+
1224
+ if (deviceBatteryState === undefined) {
1225
+ deviceBatteryStateDP = shortCurrDeviceString + adaptr.selAdapter[i].battery2;
1226
+ deviceBatteryState = await tools.getInitValue(adaptr, deviceBatteryStateDP);
1227
+ }
1228
+ break;
1219
1229
  case 'homee': // only battery devices, structure problem like homee.0.*.BatteryLevel-964
1220
1230
  const devicePrefix = `${currDeviceString}.BatteryLevel-`;
1221
1231
  const listeDP = await adaptr.getObjectViewAsync('system', 'state', {
package/main.js CHANGED
@@ -1085,76 +1085,113 @@ class DeviceWatcher extends utils.Adapter {
1085
1085
  async theLists(device) {
1086
1086
  // Raw List with all devices for user
1087
1087
  if (device.Status !== 'disabled') {
1088
- this.listAllDevicesUserRaw.push({
1089
- Device: device.Device,
1090
- Adapter: device.Adapter,
1091
- Instance: device.instance,
1092
- 'Instance connected': device.instanceDeviceConnected,
1093
- isBatteryDevice: device.isBatteryDevice,
1094
- Battery: device.Battery,
1095
- BatteryRaw: device.BatteryRaw,
1096
- BatteryUnitRaw: device.BatteryUnitRaw,
1097
- isLowBat: device.LowBat,
1098
- 'Signal strength': device.SignalStrength,
1099
- 'Signal strength Raw': device.SignalStrengthRaw,
1100
- 'Last contact': device.LastContact,
1101
- 'Update Available': device.Upgradable,
1102
- Status: device.Status,
1103
- });
1088
+ // Deduplication: some adapters (e.g. hmrpc with multiple channels, hue-extended with
1089
+ // devices appearing under both lights and sensors) create multiple Map entries for the
1090
+ // same physical device. Use Path as unique key to prevent duplicate list entries.
1091
+ const lang = this.config.userSelectedLanguage;
1092
+ const alreadyInUserRaw = this.listAllDevicesUserRaw.some((d) => d.Device === device.Device && d.Adapter === device.Adapter);
1093
+ if (!alreadyInUserRaw) {
1094
+ this.listAllDevicesUserRaw.push({
1095
+ Device: device.Device,
1096
+ Adapter: device.Adapter,
1097
+ Instance: device.instance,
1098
+ 'Instance connected': device.instanceDeviceConnected,
1099
+ isBatteryDevice: device.isBatteryDevice,
1100
+ Battery: device.Battery,
1101
+ BatteryRaw: device.BatteryRaw,
1102
+ BatteryUnitRaw: device.BatteryUnitRaw,
1103
+ isLowBat: device.LowBat,
1104
+ 'Signal strength': device.SignalStrength,
1105
+ 'Signal strength Raw': device.SignalStrengthRaw,
1106
+ 'Last contact': device.LastContact,
1107
+ 'Update Available': device.Upgradable,
1108
+ Status: device.Status,
1109
+ });
1110
+ }
1104
1111
 
1105
1112
  // List with all devices
1106
- this.listAllDevices.push({
1107
- [translations.Device[this.config.userSelectedLanguage]]: device.Device,
1108
- [translations.Adapter[this.config.userSelectedLanguage]]: device.Adapter,
1109
- [translations.Battery[this.config.userSelectedLanguage]]: device.Battery,
1110
- [translations.Signal_strength[this.config.userSelectedLanguage]]: device.SignalStrength,
1111
- [translations.Last_Contact[this.config.userSelectedLanguage]]: device.LastContact,
1112
- [translations.Status[this.config.userSelectedLanguage]]: device.Status,
1113
- });
1113
+ const alreadyInAll = this.listAllDevices.some(
1114
+ (d) => d[translations.Device[lang]] === device.Device && d[translations.Adapter[lang]] === device.Adapter,
1115
+ );
1116
+ if (!alreadyInAll) {
1117
+ this.listAllDevices.push({
1118
+ [translations.Device[lang]]: device.Device,
1119
+ [translations.Adapter[lang]]: device.Adapter,
1120
+ [translations.Battery[lang]]: device.Battery,
1121
+ [translations.Signal_strength[lang]]: device.SignalStrength,
1122
+ [translations.Last_Contact[lang]]: device.LastContact,
1123
+ [translations.Status[lang]]: device.Status,
1124
+ });
1125
+ }
1114
1126
 
1115
1127
  // LinkQuality lists
1116
1128
  if (device.SignalStrength !== ' - ') {
1117
- this.linkQualityDevices.push({
1118
- [translations.Device[this.config.userSelectedLanguage]]: device.Device,
1119
- [translations.Adapter[this.config.userSelectedLanguage]]: device.Adapter,
1120
- [translations.Signal_strength[this.config.userSelectedLanguage]]: device.SignalStrength,
1121
- });
1129
+ const alreadyInLQ = this.linkQualityDevices.some(
1130
+ (d) => d[translations.Device[lang]] === device.Device && d[translations.Adapter[lang]] === device.Adapter,
1131
+ );
1132
+ if (!alreadyInLQ) {
1133
+ this.linkQualityDevices.push({
1134
+ [translations.Device[lang]]: device.Device,
1135
+ [translations.Adapter[lang]]: device.Adapter,
1136
+ [translations.Signal_strength[lang]]: device.SignalStrength,
1137
+ });
1138
+ }
1122
1139
  }
1123
1140
 
1124
1141
  // Battery lists
1125
1142
  if (device.isBatteryDevice) {
1126
- this.batteryPowered.push({
1127
- [translations.Device[this.config.userSelectedLanguage]]: device.Device,
1128
- [translations.Adapter[this.config.userSelectedLanguage]]: device.Adapter,
1129
- [translations.Battery[this.config.userSelectedLanguage]]: device.Battery,
1130
- [translations.Status[this.config.userSelectedLanguage]]: device.Status,
1131
- });
1143
+ const alreadyInBat = this.batteryPowered.some(
1144
+ (d) => d[translations.Device[lang]] === device.Device && d[translations.Adapter[lang]] === device.Adapter,
1145
+ );
1146
+ if (!alreadyInBat) {
1147
+ this.batteryPowered.push({
1148
+ [translations.Device[lang]]: device.Device,
1149
+ [translations.Adapter[lang]]: device.Adapter,
1150
+ [translations.Battery[lang]]: device.Battery,
1151
+ [translations.Status[lang]]: device.Status,
1152
+ });
1153
+ }
1132
1154
  }
1133
1155
 
1134
1156
  // Low Bat lists
1135
1157
  if (device.LowBat && device.Status !== 'Offline') {
1136
- this.batteryLowPowered.push({
1137
- [translations.Device[this.config.userSelectedLanguage]]: device.Device,
1138
- [translations.Adapter[this.config.userSelectedLanguage]]: device.Adapter,
1139
- [translations.Battery[this.config.userSelectedLanguage]]: device.Battery,
1140
- });
1158
+ const alreadyInLowBat = this.batteryLowPowered.some(
1159
+ (d) => d[translations.Device[lang]] === device.Device && d[translations.Adapter[lang]] === device.Adapter,
1160
+ );
1161
+ if (!alreadyInLowBat) {
1162
+ this.batteryLowPowered.push({
1163
+ [translations.Device[lang]]: device.Device,
1164
+ [translations.Adapter[lang]]: device.Adapter,
1165
+ [translations.Battery[lang]]: device.Battery,
1166
+ });
1167
+ }
1141
1168
  }
1142
1169
 
1143
1170
  // Offline List
1144
1171
  if (device.Status === 'Offline') {
1145
- this.offlineDevices.push({
1146
- [translations.Device[this.config.userSelectedLanguage]]: device.Device,
1147
- [translations.Adapter[this.config.userSelectedLanguage]]: device.Adapter,
1148
- [translations.Last_Contact[this.config.userSelectedLanguage]]: device.LastContact,
1149
- });
1172
+ const alreadyOffline = this.offlineDevices.some(
1173
+ (d) => d[translations.Device[lang]] === device.Device && d[translations.Adapter[lang]] === device.Adapter,
1174
+ );
1175
+ if (!alreadyOffline) {
1176
+ this.offlineDevices.push({
1177
+ [translations.Device[lang]]: device.Device,
1178
+ [translations.Adapter[lang]]: device.Adapter,
1179
+ [translations.Last_Contact[lang]]: device.LastContact,
1180
+ });
1181
+ }
1150
1182
  }
1151
1183
 
1152
1184
  // Device update List
1153
1185
  if (device.Upgradable === true || device.Upgradable === 1) {
1154
- this.upgradableList.push({
1155
- [translations.Device[this.config.userSelectedLanguage]]: device.Device,
1156
- [translations.Adapter[this.config.userSelectedLanguage]]: device.Adapter,
1157
- });
1186
+ const alreadyUpgradable = this.upgradableList.some(
1187
+ (d) => d[translations.Device[lang]] === device.Device && d[translations.Adapter[lang]] === device.Adapter,
1188
+ );
1189
+ if (!alreadyUpgradable) {
1190
+ this.upgradableList.push({
1191
+ [translations.Device[lang]]: device.Device,
1192
+ [translations.Adapter[lang]]: device.Adapter,
1193
+ });
1194
+ }
1158
1195
  }
1159
1196
  }
1160
1197
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.device-watcher",
3
- "version": "2.15.11",
3
+ "version": "2.15.12",
4
4
  "description": "Watchdog for devices",
5
5
  "author": "Christian Behrends <mail@christian-behrends.de>",
6
6
  "contributors": [
@@ -38,9 +38,9 @@
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.12.0",
41
+ "@types/node": "^24.12.2",
42
42
  "@types/node-schedule": "^2.1.8",
43
- "typescript": "~6.0.2"
43
+ "typescript": "~6.0.3"
44
44
  },
45
45
  "main": "main.js",
46
46
  "files": [