iobroker.zigbee2mqtt 3.2.2 → 3.2.4

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
@@ -17,11 +17,29 @@
17
17
 
18
18
  This adapter allows to control the data points of the devices of a Zigbee2MQTT instance in ioBroker.
19
19
 
20
+ ## Troubleshooting
21
+ if you see in Log a message with Caught by controller[1]: /opt/iobroker/node_modules/iobroker.zigbee2mqtt/node_modules/sharp/lib/sharp.js
22
+ check you VM Settings
23
+
24
+ <img width="619" height="238" alt="grafik" src="https://github.com/user-attachments/assets/83879925-96f8-4c33-a6cd-2b68e4b41780" />
25
+ <img width="618" height="216" alt="grafik" src="https://github.com/user-attachments/assets/30c33952-b055-4d6f-99d9-f7cc49831db3" />
26
+ <img width="711" height="497" alt="grafik" src="https://github.com/user-attachments/assets/803340a6-f000-4e64-b53f-8e80f2a13127" />
27
+
20
28
  ## Adapter Documentation
21
29
 
22
30
  [Adapter Documentation](https://github.com/arteck/ioBroker.zigbee2mqtt/blob/main/docs/wiki.md)
23
31
 
24
32
  ## Changelog
33
+ ### 3.2.4 (2026-06-26)
34
+ * (arteck) Dependencies have been updated
35
+ *
36
+
37
+ ### 3.2.3 (2026-06-25)
38
+ * (arteck) typo
39
+ * (arteck) fix some warnings
40
+ * (arteck) fix internal mqtt
41
+ * (arteck) fix languages
42
+
25
43
  ### 3.2.2 (2026-05-26)
26
44
  * (arteck) Dependencies have been updated
27
45
 
@@ -34,12 +52,6 @@ This adapter allows to control the data points of the devices of a Zigbee2MQTT i
34
52
  ### 3.2.0 (2026-04-26)
35
53
  * (arteck) del deprectated setStateAsync
36
54
 
37
- ### 3.1.9 (2026-04-26)
38
- * (arteck) fix WS close
39
-
40
- ### 3.1.8 (2026-04-26)
41
- * (arteck) back to old dependency aedes
42
-
43
55
  ## License
44
56
 
45
57
  MIT License
@@ -48,6 +48,16 @@
48
48
  "More information": "Mehr Informationen",
49
49
  "Expert Settings. Please only use if you know what you're doing": "Expert Einstellungen. Bitte nur verwenden, wenn Du weisst was du machst",
50
50
  "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System" : "Aktualisiert immer den Status für die Bewegung, wenn eine Nachricht vom zigbee2mqtt-Server eintrifft (nur bei true). Erhöht die Last auf dem ioBroker",
51
- "Always update available state when message included last_seen status": "Aktualisiert immer den available Status, wenn die Nachricht last_seen Status enthält"
52
-
51
+ "Always update available state when message included last_seen status": "Aktualisiert immer den available Status, wenn die Nachricht last_seen Status enthält",
52
+ "WS": "WS",
53
+ "WS (SSL)": "WS (SSL)",
54
+ "HTTP": "HTTP",
55
+ "HTTPS": "HTTPS",
56
+ "Main Settings": "Haupteinstellungen",
57
+ "Welcome to Zigbee2MQTT Adapter": "Willkommen beim Zigbee2MQTT-Adapter",
58
+ "Device image configurations": "Gerätebild-Konfigurationen",
59
+ "Size of the object icons in pixels": "Größe der Objekt-Symbole in Pixeln",
60
+ "Expert configurations": "Experteneinstellungen",
61
+ "coming soon": "kommt bald",
62
+ "Delete old / unused states": "Alte / ungenutzte Zustände löschen"
53
63
  }
@@ -10,11 +10,11 @@
10
10
  "Configure your Zigbee2MQTT connection": "Configure your Zigbee2MQTT connection",
11
11
  "Websocket IP-Address": "Websocket IP-Address",
12
12
  "Websocket Port": "Websocket Port",
13
- "Use Auth-Token": "Use Auth-Token",
14
- "Auth-Token (special characters are not supported)": "Auth-Token (special characters are not supported)",
15
- "Create a dummy MQTT-Server for Zigbee2MQTT": "Create a dummy MQTT-Server for Zigbee2MQTT",
16
- "Base MQTT topic": "Base MQTT topic",
17
- "External MQTT-Server IP-Address": "External MQTT-Server IP-Address",
13
+ "Use Auth-Token": "Use Auth-Token",
14
+ "Auth-Token (special characters are not supported)": "Auth-Token (special characters are not supported)",
15
+ "Create a dummy MQTT-Server for Zigbee2MQTT": "Create a dummy MQTT-Server for Zigbee2MQTT",
16
+ "Base MQTT topic": "Base MQTT topic",
17
+ "External MQTT-Server IP-Address": "External MQTT-Server IP-Address",
18
18
  "External MQTT-Server Port": "External MQTT-Server Port",
19
19
  "MQTT-Server IP-Address bind": "MQTT-Server IP-Address bind",
20
20
  "MQTT-Server Port": "MQTT-Server Port",
@@ -48,5 +48,16 @@
48
48
  "More information": "More information",
49
49
  "Expert Settings. Please only use if you know what you're doing": "Expert Settings. Please only use if you know what you're doing",
50
50
  "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System" : "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System",
51
- "Always update available state when message included last_seen status": "Always update available state when message included last_seen status"
51
+ "Always update available state when message included last_seen status": "Always update available state when message included last_seen status",
52
+ "Main Settings": "Main Settings",
53
+ "Welcome to Zigbee2MQTT Adapter": "Welcome to Zigbee2MQTT Adapter",
54
+ "WS": "WS",
55
+ "WS (SSL)": "WS (SSL)",
56
+ "HTTP": "HTTP",
57
+ "HTTPS": "HTTPS",
58
+ "Device image configurations" : "Device image configurations",
59
+ "Size of the object icons in pixels": "Size of the object icons in pixels",
60
+ "Expert configurations": "Expert configurations",
61
+ "coming soon": "coming soon ",
62
+ "Delete old / unused states": "Delete old / unused states"
52
63
  }
@@ -45,5 +45,19 @@
45
45
  "Automatic check for missing routers in the coordinator memory.": "Comprobación automática de enrutadores faltantes en la memoria del coordinador.",
46
46
  "With which log level should a negative search be logged?": "¿Con qué nivel de registro se debe registrar una búsqueda negativa?",
47
47
  "Time of the automatic check": "Hora del control automático",
48
- "More information": "Más información"
48
+ "More information": "Más información",
49
+ "Expert Settings. Please only use if you know what you're doing": "Expert Settings. Please only use if you know what you're doing",
50
+ "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System": "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System",
51
+ "Always update available state when message included last_seen status": "Siempre actualizar el estado disponible cuando el mensaje incluya el estado last_seen",
52
+ "WS": "WS",
53
+ "WS (SSL)": "WS (SSL)",
54
+ "HTTP": "HTTP",
55
+ "HTTPS": "HTTPS",
56
+ "Main Settings": "Configuración principal",
57
+ "Welcome to Zigbee2MQTT Adapter": "Bienvenido al adaptador Zigbee2MQTT",
58
+ "Device image configurations": "Configuración de imágenes de dispositivos",
59
+ "Size of the object icons in pixels": "Tamaño de los iconos de objetos en píxeles",
60
+ "Expert configurations": "Configuraciones avanzadas",
61
+ "coming soon": "próximamente",
62
+ "Delete old / unused states": "Eliminar estados antiguos / no utilizados"
49
63
  }
@@ -46,5 +46,18 @@
46
46
  "With which log level should a negative search be logged?": "Avec quel niveau de journalisation une recherche négative doit-elle être enregistrée ?",
47
47
  "Time of the automatic check": "Heure du contrôle automatique",
48
48
  "More information": "Plus d'information",
49
- "Always update available state when message included last_seen status": "Mettre à jour l'état disponible lorsque le message inclut le statut last_seen"
49
+ "Expert Settings. Please only use if you know what you're doing": "Expert Settings. Please only use if you know what you're doing",
50
+ "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System": "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System",
51
+ "Always update available state when message included last_seen status": "Mettre à jour l'état disponible lorsque le message inclut le statut last_seen",
52
+ "WS": "WS",
53
+ "WS (SSL)": "WS (SSL)",
54
+ "HTTP": "HTTP",
55
+ "HTTPS": "HTTPS",
56
+ "Main Settings": "Paramètres principaux",
57
+ "Welcome to Zigbee2MQTT Adapter": "Bienvenue dans l'adaptateur Zigbee2MQTT",
58
+ "Device image configurations": "Configuration des images des appareils",
59
+ "Size of the object icons in pixels": "Taille des icônes d'objet en pixels",
60
+ "Expert configurations": "Configurations avancées",
61
+ "coming soon": "bientôt disponible",
62
+ "Delete old / unused states": "Supprimer les états anciens / inutilisés"
50
63
  }
@@ -46,5 +46,18 @@
46
46
  "With which log level should a negative search be logged?": "Con quale livello di registro deve essere registrata una ricerca negativa?",
47
47
  "Time of the automatic check": "Orario del controllo automatico",
48
48
  "More information": "Maggiori informazioni",
49
- "Always update available state when message included last_seen status": "Aggiorna sempre lo stato disponibile quando il messaggio include lo stato last_seen"
49
+ "Expert Settings. Please only use if you know what you're doing": "Expert Settings. Please only use if you know what you're doing",
50
+ "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System": "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System",
51
+ "Always update available state when message included last_seen status": "Aggiorna sempre lo stato disponibile quando il messaggio include lo stato last_seen",
52
+ "WS": "WS",
53
+ "WS (SSL)": "WS (SSL)",
54
+ "HTTP": "HTTP",
55
+ "HTTPS": "HTTPS",
56
+ "Main Settings": "Impostazioni principali",
57
+ "Welcome to Zigbee2MQTT Adapter": "Benvenuto nell'adattatore Zigbee2MQTT",
58
+ "Device image configurations": "Configurazioni delle immagini dei dispositivi",
59
+ "Size of the object icons in pixels": "Dimensione delle icone degli oggetti in pixel",
60
+ "Expert configurations": "Configurazioni avanzate",
61
+ "coming soon": "prossimamente",
62
+ "Delete old / unused states": "Elimina stati vecchi / inutilizzati"
50
63
  }
@@ -46,5 +46,18 @@
46
46
  "With which log level should a negative search be logged?": "Met welk logniveau moet een negatieve zoekopdracht worden geregistreerd?",
47
47
  "Time of the automatic check": "Tijdstip van de automatische controle",
48
48
  "More information": "Meer informatie",
49
- "Always update available state when message included last_seen status": "Altijd de beschikbare status bijwerken wanneer het bericht de last_seen-status bevat"
49
+ "Expert Settings. Please only use if you know what you're doing": "Expert Settings. Please only use if you know what you're doing",
50
+ "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System": "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System",
51
+ "Always update available state when message included last_seen status": "Altijd de beschikbare status bijwerken wanneer het bericht de last_seen-status bevat",
52
+ "WS": "WS",
53
+ "WS (SSL)": "WS (SSL)",
54
+ "HTTP": "HTTP",
55
+ "HTTPS": "HTTPS",
56
+ "Main Settings": "Hoofdinstellingen",
57
+ "Welcome to Zigbee2MQTT Adapter": "Welkom bij de Zigbee2MQTT-adapter",
58
+ "Device image configurations": "Configuratie van apparaatafbeeldingen",
59
+ "Size of the object icons in pixels": "Grootte van de objectpictogrammen in pixels",
60
+ "Expert configurations": "Geavanceerde configuraties",
61
+ "coming soon": "binnenkort beschikbaar",
62
+ "Delete old / unused states": "Oude / ongebruikte statussen verwijderen"
50
63
  }
@@ -46,5 +46,18 @@
46
46
  "With which log level should a negative search be logged?": "Na jakim poziomie rejestrowania należy rejestrować wyszukiwanie wykluczające?",
47
47
  "Time of the automatic check": "Czas automatycznego sprawdzenia",
48
48
  "More information": "Więcej informacji",
49
- "Always update available state when message included last_seen status": "Zawsze aktualizuj available stan, gdy wiadomość zawiera status last_seen"
49
+ "Expert Settings. Please only use if you know what you're doing": "Expert Settings. Please only use if you know what you're doing",
50
+ "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System": "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System",
51
+ "Always update available state when message included last_seen status": "Zawsze aktualizuj available stan, gdy wiadomość zawiera status last_seen",
52
+ "WS": "WS",
53
+ "WS (SSL)": "WS (SSL)",
54
+ "HTTP": "HTTP",
55
+ "HTTPS": "HTTPS",
56
+ "Main Settings": "Ustawienia główne",
57
+ "Welcome to Zigbee2MQTT Adapter": "Witamy w adapterze Zigbee2MQTT",
58
+ "Device image configurations": "Konfiguracja obrazów urządzeń",
59
+ "Size of the object icons in pixels": "Rozmiar ikon obiektów w pikselach",
60
+ "Expert configurations": "Konfiguracje zaawansowane",
61
+ "coming soon": "wkrótce dostępne",
62
+ "Delete old / unused states": "Usuń stare / nieużywane stany"
50
63
  }
@@ -46,5 +46,18 @@
46
46
  "With which log level should a negative search be logged?": "Com qual nível de log uma pesquisa negativa deve ser registrada?",
47
47
  "Time of the automatic check": "Hora da verificação automática",
48
48
  "More information": "Mais Informações",
49
- "Always update available state when message included last_seen status": "Sempre atualize o estado disponível quando a mensagem incluir o status last_seen"
49
+ "Expert Settings. Please only use if you know what you're doing": "Expert Settings. Please only use if you know what you're doing",
50
+ "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System": "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System",
51
+ "Always update available state when message included last_seen status": "Sempre atualize o estado disponível quando a mensagem incluir o status last_seen",
52
+ "WS": "WS",
53
+ "WS (SSL)": "WS (SSL)",
54
+ "HTTP": "HTTP",
55
+ "HTTPS": "HTTPS",
56
+ "Main Settings": "Configurações principais",
57
+ "Welcome to Zigbee2MQTT Adapter": "Bem-vindo ao adaptador Zigbee2MQTT",
58
+ "Device image configurations": "Configurações de imagens dos dispositivos",
59
+ "Size of the object icons in pixels": "Tamanho dos ícones dos objetos em pixels",
60
+ "Expert configurations": "Configurações avançadas",
61
+ "coming soon": "em breve",
62
+ "Delete old / unused states": "Excluir estados antigos / não utilizados"
50
63
  }
@@ -46,5 +46,18 @@
46
46
  "With which log level should a negative search be logged?": "На каком уровне журнала следует регистрировать отрицательный поиск?",
47
47
  "Time of the automatic check": "Время автоматической проверки",
48
48
  "More information": "Больше информации",
49
- "Always update available state when message included last_seen status": "Всегда обновляйте доступное состояние, когда сообщение включает статус last_seen"
49
+ "Expert Settings. Please only use if you know what you're doing": "Expert Settings. Please only use if you know what you're doing",
50
+ "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System": "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System",
51
+ "Always update available state when message included last_seen status": "Всегда обновляйте доступное состояние, когда сообщение включает статус last_seen",
52
+ "WS": "WS",
53
+ "WS (SSL)": "WS (SSL)",
54
+ "HTTP": "HTTP",
55
+ "HTTPS": "HTTPS",
56
+ "Main Settings": "Основные настройки",
57
+ "Welcome to Zigbee2MQTT Adapter": "Добро пожаловать в адаптер Zigbee2MQTT",
58
+ "Device image configurations": "Настройки изображений устройств",
59
+ "Size of the object icons in pixels": "Размер значков объектов в пикселях",
60
+ "Expert configurations": "Расширенные настройки",
61
+ "coming soon": "скоро будет доступно",
62
+ "Delete old / unused states": "Удалить старые / неиспользуемые состояния"
50
63
  }
@@ -46,5 +46,18 @@
46
46
  "With which log level should a negative search be logged?": "На якому рівні журналу слід реєструвати негативний пошук?",
47
47
  "Time of the automatic check": "Час автоматичної перевірки",
48
48
  "More information": "Більше інформації",
49
- "Always update available state when message included last_seen status": "Завжди оновлюйте доступний стан, коли повідомлення містить статус last_seen"
49
+ "Expert Settings. Please only use if you know what you're doing": "Expert Settings. Please only use if you know what you're doing",
50
+ "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System": "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System",
51
+ "Always update available state when message included last_seen status": "Завжди оновлюйте доступний стан, коли повідомлення містить статус last_seen",
52
+ "WS": "WS",
53
+ "WS (SSL)": "WS (SSL)",
54
+ "HTTP": "HTTP",
55
+ "HTTPS": "HTTPS",
56
+ "Main Settings": "Основні налаштування",
57
+ "Welcome to Zigbee2MQTT Adapter": "Ласкаво просимо до адаптера Zigbee2MQTT",
58
+ "Device image configurations": "Налаштування зображень пристроїв",
59
+ "Size of the object icons in pixels": "Розмір значків об'єктів у пікселях",
60
+ "Expert configurations": "Розширені налаштування",
61
+ "coming soon": "незабаром",
62
+ "Delete old / unused states": "Видалити старі / невикористовувані стани"
50
63
  }
@@ -48,5 +48,16 @@
48
48
  "More information": "更多信息",
49
49
  "Expert Settings. Please only use if you know what you're doing": "专家设置。请仅在您清楚操作的情况下使用",
50
50
  "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System": "当来自 zigbee2mqtt 服务器的消息到达时始终更新占用状态(仅限为 true 的状态)。会增加 ioBroker 系统负载",
51
- "Always update available state when message included last_seen status": "当消息包含 last_seen 状态时始终更新可用状态"
51
+ "Always update available state when message included last_seen status": "当消息包含 last_seen 状态时始终更新可用状态",
52
+ "WS": "WS",
53
+ "WS (SSL)": "WS (SSL)",
54
+ "HTTP": "HTTP",
55
+ "HTTPS": "HTTPS",
56
+ "Main Settings": "主要设置",
57
+ "Welcome to Zigbee2MQTT Adapter": "欢迎使用 Zigbee2MQTT 适配器",
58
+ "Device image configurations": "设备图片配置",
59
+ "Size of the object icons in pixels": "对象图标大小(像素)",
60
+ "Expert configurations": "高级配置",
61
+ "coming soon": "即将推出",
62
+ "Delete old / unused states": "删除旧的/未使用的状态"
52
63
  }
@@ -112,7 +112,7 @@
112
112
  "value": "ws"
113
113
  },
114
114
  {
115
- "label": "WSS (SSL)",
115
+ "label": "WS (SSL)",
116
116
  "value": "wss"
117
117
  }
118
118
  ],
@@ -546,7 +546,7 @@
546
546
  "hidden": "data.coordinatorCheck != true"
547
547
  },
548
548
 
549
- "allwaysUpdateOccupancyState": {
549
+ "alwaysUpdateOccupancyState": {
550
550
  "type": "checkbox",
551
551
  "label": "Always update state for occupancy when message arrives from zigbee2mqtt server (Only for true state). Increases load on ioBroker System",
552
552
  "xs": 12,
@@ -556,7 +556,7 @@
556
556
  "xl": 12,
557
557
  "newLine": true
558
558
  },
559
- "allwaysUpdateAvailableState": {
559
+ "alwaysUpdateAvailableState": {
560
560
  "type": "checkbox",
561
561
  "label": "Always update available state when message included last_seen status",
562
562
  "xs": 12,
@@ -578,7 +578,7 @@
578
578
  },
579
579
  "headerDeleteStates": {
580
580
  "type": "header",
581
- "text": "coming soon ",
581
+ "text": "coming soon",
582
582
  "size": 4,
583
583
  "newLine": true
584
584
  },
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "zigbee2mqtt",
4
- "version": "3.2.2",
4
+ "version": "3.2.4",
5
5
  "news": {
6
+ "3.2.4": {
7
+ "en": "Dependencies have been updated\n",
8
+ "de": "Die Abhängigkeiten wurden aktualisiert.\n",
9
+ "ru": "Зависимости обновлены.\n",
10
+ "pt": "As dependências foram atualizadas.\n",
11
+ "nl": "Afhankelijkheden zijn bijgewerkt.\n",
12
+ "fr": "Les dépendances ont été mises à jour\n",
13
+ "it": "Le dipendenze sono state aggiornate\n",
14
+ "es": "Se han actualizado las dependencias.\n",
15
+ "pl": "Zaktualizowano zależności\n",
16
+ "uk": "Залежності оновлено\n",
17
+ "zh-cn": "依赖项已更新\n"
18
+ },
19
+ "3.2.3": {
20
+ "en": "typo\nfix some warnings\nfix internal mqtt\nfix languages",
21
+ "de": "Tippfehler\nEinige Warnungen beheben\nInternes MQTT reparieren\nSprachen korrigieren",
22
+ "ru": "опечатка\nИсправлены некоторые предупреждения\nисправление внутреннего MQTT\nисправить языки",
23
+ "pt": "erro de digitação\nCorrigir alguns avisos\ncorrigir MQTT interno\ncorrigir idiomas",
24
+ "nl": "typfout\nEnkele waarschuwingen verhelpen\ninterne MQTT-problemen oplossen\ntalen corrigeren",
25
+ "fr": "faute de frappe\nCorrection de certains avertissements\ncorrection du MQTT interne\ncorriger les langues",
26
+ "it": "errore di battitura\ncorreggere alcuni avvisi\ncorrezione interna MQTT\nlinguaggi corretti",
27
+ "es": "error de tipografía\ncorregir algunas advertencias\ncorregir mqtt interno\ncorregir idiomas",
28
+ "pl": "literówka\nnapraw niektóre ostrzeżenia\nnapraw wewnętrzny MQTT\nnaprawić języki",
29
+ "uk": "друкарська помилка\nвиправити деякі попередження\nвиправити внутрішній mqtt\nвиправити мови",
30
+ "zh-cn": "拼写错误\n修复一些警告\n修复内部 MQTT\n修复语言"
31
+ },
6
32
  "3.2.2": {
7
33
  "en": "Dependencies have been updated",
8
34
  "de": "Abhängigkeiten wurden aktualisiert",
@@ -170,7 +196,8 @@
170
196
  "it": "Zigbee2MQTT",
171
197
  "es": "Zigbee2MQTT",
172
198
  "pl": "Zigbee2MQTT",
173
- "zh-cn": "Zigbee2MQTT"
199
+ "zh-cn": "Zigbee2MQTT",
200
+ "uk": "Zigbee2MQTT"
174
201
  },
175
202
  "link": "%webUIScheme%://%webUIServer%:%webUIPort%"
176
203
  },
@@ -224,8 +251,8 @@
224
251
  "coordinatorCheck": false,
225
252
  "coordinatorCheckLogLvl": "info",
226
253
  "coordinatorCheckCron": "0 3 * * *",
227
- "allwaysUpdateOccupancyState": false,
228
- "allwaysUpdateAvailableState": false
254
+ "alwaysUpdateOccupancyState": false,
255
+ "alwaysUpdateAvailableState": false
229
256
  },
230
257
  "protectedNative": [
231
258
  "externalMqttServerPassword",
@@ -6,19 +6,6 @@ const rgb = require('./rgb.js');
6
6
  const ImageController = require('./imageController').ImageController;
7
7
  const dmUtils = require('@iobroker/dm-utils');
8
8
 
9
- /**
10
- * Prüft ob eine ieee_address in der kommaseparierten debugDevices-Liste enthalten ist.
11
- * String.includes() würde Substring-Matches liefern (z.B. "0x12" trifft "0x1234").
12
- *
13
- * @param {string} debugDevices
14
- * @param {string} address
15
- * @returns {boolean}
16
- */
17
- function isDebugDevice(debugDevices, address) {
18
- if (!debugDevices || !address) { return false; }
19
- return String(debugDevices).split(',').map((s) => s.trim()).includes(address);
20
- }
21
-
22
9
  /**
23
10
  * Verwaltet das Erstellen und Aktualisieren von Geräte- und Gruppenobjekten in ioBroker
24
11
  * basierend auf den Zigbee2MQTT-Exposes.
@@ -43,6 +30,31 @@ class DeviceController extends dmUtils.DeviceManagement {
43
30
  this.logCustomizations = logCustomizations;
44
31
  this.createCache = createCache;
45
32
  this.imageController = new ImageController(adapter);
33
+
34
+ // Debug-Device Cache - wird lazy befüllt (siehe isDebugDevice)
35
+ this._debugDeviceCache = null;
36
+ }
37
+
38
+ /**
39
+ * Checks if the given device is a debug device.
40
+ * Der CSV-String wird einmalig geparst und in einem Set gecached (O(1) Lookup).
41
+ * Case-insensitive Vergleich.
42
+ *
43
+ * @param {string} ieeeAddr - IEEE address of the device
44
+ * @returns {boolean}
45
+ */
46
+ isDebugDevice(ieeeAddr) {
47
+ if (!ieeeAddr) { return false; }
48
+ if (this._debugDeviceCache === null) {
49
+ const debugDeviceList = this.logCustomizations.debugDevices || '';
50
+ this._debugDeviceCache = new Set(
51
+ debugDeviceList
52
+ .split(',')
53
+ .map(s => s.trim().toLowerCase())
54
+ .filter(s => s.length > 0)
55
+ );
56
+ }
57
+ return this._debugDeviceCache.has(ieeeAddr.toLowerCase());
46
58
  }
47
59
 
48
60
  /**
@@ -63,7 +75,7 @@ class DeviceController extends dmUtils.DeviceManagement {
63
75
  continue;
64
76
  }
65
77
 
66
- if (isDebugDevice(this.logCustomizations.debugDevices, devicesMessag.ieee_address)) {
78
+ if (this.isDebugDevice(devicesMessag.ieee_address)) {
67
79
  this.adapter.log.warn(
68
80
  `--->>> fromZ2M -> ${devicesMessag.ieee_address} exposes: ${JSON.stringify(devicesMessag)}`
69
81
  );
@@ -76,7 +88,11 @@ class DeviceController extends dmUtils.DeviceManagement {
76
88
  if (Array.isArray(devicesMessag.definition.exposes)) {
77
89
  try {
78
90
  const newDevice = await createDeviceFromExposes(devicesMessag, this.adapter);
79
- newDevice.icon = await this.imageController.getDeviceIcon(devicesMessag);
91
+ try {
92
+ newDevice.icon = await this.imageController.getDeviceIcon(devicesMessag);
93
+ } catch (e) {
94
+ this.adapter.log.warn(`[deviceController] Could not load icon for device ${newDevice.common?.name || 'unknown'}: ${e.message}`);
95
+ }
80
96
  newDevice.manufacturer = devicesMessag.definition.vendor || '';
81
97
  newDevice.model = devicesMessag.definition.model || '';
82
98
  newDevice.modelDescription = devicesMessag.definition.description || '';
@@ -297,7 +313,7 @@ class DeviceController extends dmUtils.DeviceManagement {
297
313
  if (!groupMessage || groupMessage.id == null || !groupMessage.friendly_name) {
298
314
  continue;
299
315
  }
300
- if (isDebugDevice(this.logCustomizations.debugDevices, String(groupMessage.id))) {
316
+ if (this.isDebugDevice(String(groupMessage.id))) {
301
317
  this.adapter.log.warn(`--->>> fromZ2M -> ${groupMessage.id} exposes: ${JSON.stringify(groupMessage)}`);
302
318
  }
303
319
  this.defineGroupDevice(groupMessage.friendly_name, `group_${groupMessage.id}`, groupMessage.scenes || []);
@@ -765,11 +781,9 @@ class DeviceController extends dmUtils.DeviceManagement {
765
781
  const detailItems = device._detailItems || {};
766
782
  const hasDetails = Object.keys(detailItems).length > 0;
767
783
 
768
- /** @type {Record<string, any>} */
769
784
  const data = {};
770
785
 
771
786
  // ── Tab 1: Gerät ─────────────────────────────────────────────────────
772
- /** @type {Record<string, any>} */
773
787
  const infoItems = {};
774
788
  infoItems['_h1'] = { type: 'header', text: 'Device Identity', size: 4, newLine: true };
775
789
  infoItems['_d1'] = { type: 'divider', color: 'primary' };
@@ -781,7 +795,6 @@ class DeviceController extends dmUtils.DeviceManagement {
781
795
  infoItems['pwr'] = { type: 'staticInfo', label: 'Power Source', data: device.powerSource || '—', size: 16, addColon: true, newLine: true };
782
796
 
783
797
  // ── Tab 2: Verbindung ─────────────────────────────────────────────────
784
- /** @type {Record<string, any>} */
785
798
  const connItems = {};
786
799
  connItems['_h1'] = { type: 'header', text: 'Zigbee Connection', size: 4, newLine: true };
787
800
  connItems['_d1'] = { type: 'divider', color: 'primary' };
@@ -793,7 +806,6 @@ class DeviceController extends dmUtils.DeviceManagement {
793
806
  }
794
807
 
795
808
  // ── Tab 3: Technisch ──────────────────────────────────────────────────
796
- /** @type {Record<string, any>} */
797
809
  const techItems = {};
798
810
  techItems['_h1'] = { type: 'header', text: 'Zigbee Status', size: 4, newLine: true };
799
811
  techItems['_d1'] = { type: 'divider', color: 'primary' };
@@ -806,7 +818,6 @@ class DeviceController extends dmUtils.DeviceManagement {
806
818
  data.disabled = !!device.disabled;
807
819
 
808
820
  // ── Tabs zusammenbauen ────────────────────────────────────────────────
809
- /** @type {Record<string, any>} */
810
821
  const tabs = {
811
822
  _tab_info: { type: 'panel', label: 'Device', items: infoItems },
812
823
  _tab_conn: { type: 'panel', label: 'Connection', items: connItems },
package/lib/exposes.js CHANGED
@@ -111,6 +111,7 @@ function genState(expose, role, name, desc) {
111
111
  states: {},
112
112
  };
113
113
 
114
+ state.type = 'string';
114
115
  for (const val of expose.values) {
115
116
  // if a definition of a button (eg. Aqara presence detector FP1)
116
117
  if (val === '') {
@@ -118,7 +119,6 @@ function genState(expose, role, name, desc) {
118
119
  } else {
119
120
  state.states[val] = val;
120
121
  }
121
- state.type = typeof val;
122
122
  }
123
123
  // Fix 4: wenn values leer → type bleibt undefined → Fallback auf 'string'
124
124
  if (!state.type) {
@@ -153,6 +153,7 @@ function genState(expose, role, name, desc) {
153
153
  break;
154
154
 
155
155
  default:
156
+ console.warn(`[genState] Unknown expose type: ${expose.type}`);
156
157
  break;
157
158
  }
158
159
 
@@ -203,13 +204,12 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
203
204
  state = Object.assign({}, state);
204
205
 
205
206
  if (access === undefined) {access = z2mAccess.ALL;}
206
- state.readable = (access & z2mAccess.STATE) > 0;
207
- state.writable = (access & z2mAccess.SET) > 0;
207
+ state.read = (access & z2mAccess.STATE) > 0;
208
+ state.write = (access & z2mAccess.SET) > 0;
208
209
  const stateExists = states.findIndex((x, _index, _array) => x.id === state.id);
209
210
 
210
211
  if (stateExists < 0) {
211
- state.write = state.writable;
212
- if (!state.writable) {
212
+ if (!state.write) {
213
213
  if (state.hasOwnProperty('setter')) {
214
214
  delete state.setter;
215
215
  }
@@ -219,7 +219,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
219
219
  }
220
220
  }
221
221
 
222
- if (!state.readable) {
222
+ if (!state.read) {
223
223
  if (state.hasOwnProperty('getter')) {
224
224
  //to awid some worning on unprocessed data
225
225
  state.getter = (_payload) => undefined;
@@ -228,7 +228,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
228
228
 
229
229
  return states.push(state);
230
230
  }
231
- if (state.readable && !states[stateExists].readable) {
231
+ if (state.read && !states[stateExists].read) {
232
232
  states[stateExists].read = state.read;
233
233
  // as state is readable, it can't be button or event
234
234
  if (states[stateExists].role === 'button') {
@@ -259,11 +259,11 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
259
259
  } else if (state.hasOwnProperty('prop')) {
260
260
  states[stateExists].prop = state.prop;
261
261
  }
262
- states[stateExists].readable = true;
262
+ states[stateExists].read = true;
263
263
  }
264
264
 
265
- if (state.writable && !states[stateExists].writable) {
266
- states[stateExists].write = state.writable;
265
+ if (state.write && !states[stateExists].write) {
266
+ states[stateExists].write = state.write;
267
267
  // use new state `setter`
268
268
  if (state.hasOwnProperty('setter')) {
269
269
  states[stateExists].setter = state.setter;
@@ -303,7 +303,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
303
303
  if (state.hasOwnProperty('epname')) {
304
304
  states[stateExists].epname = state.epname;
305
305
  }
306
- states[stateExists].writable = true;
306
+ states[stateExists].write = true;
307
307
  }
308
308
 
309
309
  return states.length;
@@ -1289,9 +1289,8 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1289
1289
  return !isNaN(payload[expose.property][prop.property])
1290
1290
  ? payload[expose.property][prop.property]
1291
1291
  : undefined;
1292
- }
1293
- return undefined;
1294
-
1292
+ }
1293
+ return undefined;
1295
1294
  };
1296
1295
  } else {
1297
1296
  state.getter = (payload) => {
@@ -106,7 +106,7 @@ class ImageController {
106
106
  return '';
107
107
  }
108
108
 
109
- const imageSize = this.adapter.config.deviceIconsSize;
109
+ const imageSize = this.adapter.config.deviceIconsSize || 120;
110
110
  const z2mModel = device.definition.model || '';
111
111
  const z2mIconFileNameJPG = `${this.sanitizeZ2MDeviceName(z2mModel)}.jpg`;
112
112
  const z2mIconFileNamePNG = `${this.sanitizeZ2MDeviceName(z2mModel)}.png`;
@@ -2,6 +2,7 @@
2
2
 
3
3
  const Aedes = require('aedes');
4
4
  const net = require('node:net');
5
+ const MemoryPersistence = require('aedes-persistence');
5
6
 
6
7
  /**
7
8
  * Verwaltet den internen oder Dummy-MQTT-Server (Aedes) für den Zigbee2MQTT-Adapter.
@@ -58,10 +59,9 @@ class MqttServerController {
58
59
  */
59
60
  async createMQTTServer() {
60
61
  if (!this._checkConfig()) {
61
- return;
62
+ return false;
62
63
  }
63
64
  try {
64
- const MemoryPersistence = require('aedes-persistence');
65
65
  const db = MemoryPersistence();
66
66
  const aedes = Aedes({ persistence: db });
67
67
  this.aedesBroker = aedes;
@@ -82,10 +82,20 @@ class MqttServerController {
82
82
  }
83
83
  );
84
84
  });
85
+ return true;
85
86
  } catch (err) {
86
- this.adapter.log.error(`createMQTTServer error: ${err && err.message ? err.message : String(err)}`);
87
+ const code = err && err.code ? err.code : '';
88
+ if (code === 'EACCES' || code === 'EADDRINUSE') {
89
+ this.adapter.log.error(
90
+ `Port ${this.adapter.config.mqttServerPort} is already in use or requires admin privileges. ` +
91
+ `Please change the port in the adapter settings or stop the other service.`
92
+ );
93
+ } else {
94
+ this.adapter.log.error(`createMQTTServer error: ${err && err.message ? err.message : String(err)}`);
95
+ }
87
96
  // Sicherstellen dass kein halboffener Server übrig bleibt
88
97
  this.closeServer();
98
+ return false;
89
99
  }
90
100
  }
91
101
 
@@ -95,7 +105,7 @@ class MqttServerController {
95
105
  */
96
106
  async createDummyMQTTServer() {
97
107
  if (!this._checkConfig()) {
98
- return;
108
+ return false;
99
109
  }
100
110
  try {
101
111
  const aedes = Aedes();
@@ -117,9 +127,19 @@ class MqttServerController {
117
127
  }
118
128
  );
119
129
  });
130
+ return true;
120
131
  } catch (err) {
121
- this.adapter.log.error(`createDummyMQTTServer error: ${err && err.message ? err.message : String(err)}`);
132
+ const code = err && err.code ? err.code : '';
133
+ if (code === 'EACCES' || code === 'EADDRINUSE') {
134
+ this.adapter.log.error(
135
+ `Port ${this.adapter.config.mqttServerPort} is already in use or requires admin privileges. ` +
136
+ `Please change the port in the adapter settings or stop the other service.`
137
+ );
138
+ } else {
139
+ this.adapter.log.error(`createDummyMQTTServer error: ${err && err.message ? err.message : String(err)}`);
140
+ }
122
141
  this.closeServer();
142
+ return false;
123
143
  }
124
144
  }
125
145
 
package/lib/rgb.js CHANGED
@@ -152,6 +152,11 @@ function rgb_to_cie(red, green, blue) {
152
152
  * @param v
153
153
  */
154
154
  function hsvToRGB(h, s, v) {
155
+ if (arguments.length === 1) {
156
+ s = h.s;
157
+ v = h.v;
158
+ h = h.h;
159
+ }
155
160
  h = (h % 360) / 360;
156
161
  s = s / 100;
157
162
  v = v / 100;
@@ -159,11 +164,6 @@ function hsvToRGB(h, s, v) {
159
164
  let r;
160
165
  let g;
161
166
  let b;
162
- if (arguments.length === 1) {
163
- s = h.s;
164
- v = h.v;
165
- h = h.h;
166
- }
167
167
  const i = Math.floor(h * 6);
168
168
  const f = h * 6 - i;
169
169
  const p = v * (1 - s);
package/lib/states.js CHANGED
@@ -37,6 +37,17 @@ const nameLookup = {
37
37
  Hz: 'frequency',
38
38
  pf: 'power_factor',
39
39
  lx: 'illuminance_lux',
40
+ '°C': 'temperature_celsius',
41
+ '°F': 'temperature_fahrenheit',
42
+ mA: 'milliampere',
43
+ mV: 'millivolt',
44
+ 'μg/m³': 'microgram_per_cubic_meter',
45
+ dB: 'decibel',
46
+ '%rH': 'percent_rh',
47
+ 'km/h': 'kilometer_per_hour',
48
+ 'm/s': 'meter_per_second',
49
+ 'mg/m³': 'milligram_per_cubic_meter',
50
+ K: 'kelvin',
40
51
  };
41
52
 
42
53
  const unitLookup = {
@@ -53,6 +64,17 @@ const unitLookup = {
53
64
  frequency: 'Hz',
54
65
  power_factor: 'pf',
55
66
  illuminance_lux: 'lx',
67
+ temperature_celsius: '°C',
68
+ temperature_fahrenheit: '°F',
69
+ milliampere: 'mA',
70
+ millivolt: 'mV',
71
+ microgram_per_cubic_meter: 'μg/m³',
72
+ decibel: 'dB',
73
+ percent_rh: '%rH',
74
+ kilometer_per_hour: 'km/h',
75
+ meter_per_second: 'm/s',
76
+ milligram_per_cubic_meter: 'mg/m³',
77
+ kelvin: 'K',
56
78
  };
57
79
 
58
80
  const states = {
@@ -116,6 +116,30 @@ class StatesController {
116
116
  return;
117
117
  }
118
118
 
119
+ // Fix 3: Vorab prüfen, ob überhaupt ein State des Devices existiert.
120
+ // Nur wenn KEIN EINZIGER State existiert → requeue.
121
+ // Wenn mindestens einer existiert → verarbeite vorhandene, ignoriere fehlende.
122
+ let hasAnyExistingState = false;
123
+ for (const key of Object.keys(messageObj.payload)) {
124
+ if (hasAnyExistingState) { break; }
125
+ let states = device.states.filter(state => state.prop && state.prop === key);
126
+ if (states.length === 0) { states = device.states.filter(x => x.id === key); }
127
+ for (const state of states) {
128
+ if (this.createCache[device.ieee_address]
129
+ && this.createCache[device.ieee_address][state.id]
130
+ && this.createCache[device.ieee_address][state.id].created === true) {
131
+ hasAnyExistingState = true;
132
+ break;
133
+ }
134
+ }
135
+ }
136
+
137
+ if (!hasAnyExistingState) {
138
+ // Kein einziger State existiert → Nachricht in Queue stellen
139
+ pushToQueue(messageObj);
140
+ return;
141
+ }
142
+
119
143
  for (let [key, value] of Object.entries(messageObj.payload)) {
120
144
  if (value === undefined || value === null) {
121
145
  continue;
@@ -166,15 +190,15 @@ class StatesController {
166
190
  const stateName = `${device.ieee_address}.${state.id}`;
167
191
 
168
192
  // set available status if last_seen is set
169
- if (state.id === 'last_seen' && this.adapter.config.allwaysUpdateAvailableState === true) {
193
+ if (state.id === 'last_seen' && this.adapter.config.alwaysUpdateAvailableState === true) {
170
194
  await this.setStateSafelyAsync(`${device.ieee_address}.available`, true);
171
195
  }
172
196
 
173
- // State noch nicht erstellt? → einmal in Queue legen und weiter
197
+ // State noch nicht erstellt? → überspringen (Requeue erfolgt nur,
198
+ // wenn GAR KEIN State des Devices existiert – siehe Pre-Check oben)
174
199
  if (!this.createCache[device.ieee_address]
175
200
  || !this.createCache[device.ieee_address][state.id]
176
201
  || this.createCache[device.ieee_address][state.id].created !== true) {
177
- pushToQueue(messageObj);
178
202
  continue;
179
203
  }
180
204
 
@@ -183,7 +207,7 @@ class StatesController {
183
207
  if (state.prop && state.prop === 'action') {
184
208
  actionStates.push(state);
185
209
  }
186
- else if (this.adapter.config.allwaysUpdateOccupancyState === true && state.id === 'occupancy' && value === true) {
210
+ else if (this.adapter.config.alwaysUpdateOccupancyState === true && state.id === 'occupancy' && value === true) {
187
211
  await this.setStateSafelyAsync(stateName, value);
188
212
  }
189
213
  else {
@@ -264,22 +288,33 @@ class StatesController {
264
288
  return;
265
289
  }
266
290
 
267
- this.adapter.setState(stateName, value, true);
291
+ // Prüfen, ob bereits ein Timer läuft (State ist dann schon auf true)
292
+ const wasAlreadyTrue = !!this.timeOutCache[stateName];
268
293
 
269
- // Auto-Reset (false → nichts tun, true → nach timeout zurücksetzen)
270
- // Wenn value=false (z.B. Stop-Aktion im simpleMoveStopState-Modus),
271
- // soll der State dauerhaft false bleiben und NICHT nach timeout auf true springen.
294
+ // Timer immer clearen, wenn vorhanden
272
295
  if (this.timeOutCache[stateName]) {
273
296
  this.adapter.clearTimeout(this.timeOutCache[stateName]);
274
297
  delete this.timeOutCache[stateName];
275
298
  }
299
+
276
300
  if (value === true) {
301
+ // Nur setState aufrufen, wenn der State NICHT bereits auf true war.
302
+ // Bei Dauerfeuer (value=true→true schneller als timeout) spart das
303
+ // den unnötigen setState-Call und verhindert, dass der Timer
304
+ // nie ausgelöst wird (Timer-Leak).
305
+ if (!wasAlreadyTrue) {
306
+ await this.setStateSafelyAsync(stateName, true);
307
+ }
308
+ // Neuen Timer für Auto-Reset setzen
277
309
  this.timeOutCache[stateName] = this.adapter.setTimeout(() => {
278
310
  delete this.timeOutCache[stateName];
279
311
  this.adapter.setState(stateName, false, true).catch((err) => {
280
312
  this.adapter.log.debug(`setStateWithTimeout reset error for ${stateName}: ${err}`);
281
313
  });
282
314
  }, timeout);
315
+ } else {
316
+ // value === false: State setzen, Timer bereits gelöscht
317
+ await this.setStateSafelyAsync(stateName, false);
283
318
  }
284
319
  }
285
320
 
@@ -105,7 +105,15 @@ class Z2mController {
105
105
  for (const option of deviceState.options) {
106
106
  // Fix: "in"-Prüfung statt === undefined, damit null als gültiger gecachter Wert behandelt wird
107
107
  if (!(option in device.optionsValues)) {
108
- const optState = await this.adapter.getStateAsync(`${splitedID[0]}.${splitedID[1]}.${splitedID[2]}.${option}`);
108
+ let optState;
109
+ try {
110
+ optState = await this.adapter.getStateAsync(`${splitedID[0]}.${splitedID[1]}.${splitedID[2]}.${option}`);
111
+ } catch (e) {
112
+ this.adapter.log.warn(
113
+ `Cannot read state for option "${option}": ${e.message}`
114
+ );
115
+ optState = null;
116
+ }
109
117
  device.optionsValues[option] = optState ? optState.val : null;
110
118
  }
111
119
 
package/main.js CHANGED
@@ -40,6 +40,7 @@ class Zigbee2mqtt extends core.Adapter {
40
40
  this.websocketController = null;
41
41
  this.mqttServerController = null;
42
42
  this.messageParseMutex = Promise.resolve();
43
+ this.mqttReconnectAttempts = 0;
43
44
 
44
45
  this.on('ready', () => {
45
46
  this.onReady().catch((e) => this.log.error(`onReady error: ${e}`));
@@ -124,7 +125,12 @@ class Zigbee2mqtt extends core.Adapter {
124
125
  } else {
125
126
  // Internal MQTT-Server
126
127
  this.mqttServerController = new MqttServerController(this);
127
- await this.mqttServerController.createMQTTServer();
128
+ const serverStarted = await this.mqttServerController.createMQTTServer();
129
+ if (!serverStarted) {
130
+ this.log.error('Internal MQTT server could not be started. The adapter cannot connect to Zigbee2MQTT.');
131
+ this.setState('info.connection', false, true);
132
+ return;
133
+ }
128
134
  // Kurze Pause damit der OS-Socket tatsächlich bereit ist (createMQTTServer wartet bereits auf listen)
129
135
  await this.delay(200);
130
136
  this.mqttClient = mqtt.connect(`mqtt://${this.config.mqttServerIPBind}:${this.config.mqttServerPort}`, {
@@ -137,6 +143,7 @@ class Zigbee2mqtt extends core.Adapter {
137
143
 
138
144
  // MQTT Client Events
139
145
  this.mqttClient.on('connect', () => {
146
+ this.mqttReconnectAttempts = 0;
140
147
  this.log.info(
141
148
  `Connect to Zigbee2MQTT over ${this.config.connectionType === 'exmqtt' ? 'external mqtt' : 'internal mqtt'} connection.`
142
149
  );
@@ -155,7 +162,20 @@ class Zigbee2mqtt extends core.Adapter {
155
162
  });
156
163
 
157
164
  this.mqttClient.on('reconnect', () => {
158
- this.log.info('MQTT client reconnecting to Zigbee2MQTT...');
165
+ this.mqttReconnectAttempts++;
166
+ if (this.mqttReconnectAttempts > 20) {
167
+ this.log.error(
168
+ `MQTT client gave up after ${this.mqttReconnectAttempts} reconnect attempts (10 seconds). ` +
169
+ `Please check whether Zigbee2MQTT is running and the MQTT connection settings are correct.`
170
+ );
171
+ if (this.mqttClient) {
172
+ this.mqttClient.end(true);
173
+ }
174
+ return;
175
+ }
176
+ this.log.info(
177
+ `MQTT client reconnecting to Zigbee2MQTT... (attempt ${this.mqttReconnectAttempts}/20)`
178
+ );
159
179
  });
160
180
 
161
181
  this.mqttClient.on('offline', async () => {
@@ -214,7 +234,12 @@ class Zigbee2mqtt extends core.Adapter {
214
234
 
215
235
  if (this.config.dummyMqtt === true) {
216
236
  this.mqttServerController = new MqttServerController(this);
217
- await this.mqttServerController.createDummyMQTTServer();
237
+ const serverStarted = await this.mqttServerController.createDummyMQTTServer();
238
+ if (!serverStarted) {
239
+ this.log.error('Dummy MQTT server could not be started – WebSocket mode cannot continue.');
240
+ this.setState('info.connection', false, true);
241
+ return;
242
+ }
218
243
  await this.delay(200);
219
244
  }
220
245
 
@@ -527,7 +552,7 @@ class Zigbee2mqtt extends core.Adapter {
527
552
  this.mqttClient.removeAllListeners();
528
553
  this.mqttClient.end(true);
529
554
  } catch (e) {
530
- this.log.error(e);
555
+ this.log.error(`[onUnload] Fehler beim Schließen des MQTT-Clients: ${e.message}`);
531
556
  }
532
557
  }
533
558
  }
@@ -537,15 +562,16 @@ class Zigbee2mqtt extends core.Adapter {
537
562
  this.mqttServerController.closeServer();
538
563
  }
539
564
  } catch (e) {
540
- this.log.error(e);
565
+ this.log.error(`[onUnload] Fehler beim Schließen des MQTT-Servers: ${e.message}`);
541
566
  }
542
- } else if (this.config.connectionType === 'ws') {
567
+ }
568
+ if (this.config.connectionType === 'ws') {
543
569
  try {
544
570
  if (this.websocketController) {
545
571
  this.websocketController.closeConnection();
546
572
  }
547
573
  } catch (e) {
548
- this.log.error(e);
574
+ this.log.error(`[onUnload] Fehler beim Schließen der WebSocket-Verbindung: ${e.message}`);
549
575
  }
550
576
  }
551
577
  try {
@@ -553,21 +579,21 @@ class Zigbee2mqtt extends core.Adapter {
553
579
  await this.statesController.setAllAvailableToFalse();
554
580
  }
555
581
  } catch (e) {
556
- this.log.error(e);
582
+ this.log.error(`[onUnload] Fehler beim Setzen aller States auf false: ${e.message}`);
557
583
  }
558
584
  try {
559
585
  if (this.websocketController) {
560
586
  this.websocketController.allTimerClear();
561
587
  }
562
588
  } catch (e) {
563
- this.log.error(e);
589
+ this.log.error(`[onUnload] Fehler beim Zurücksetzen der WebSocket-Timer: ${e.message}`);
564
590
  }
565
591
  try {
566
592
  if (this.statesController) {
567
593
  this.statesController.allTimerClear();
568
594
  }
569
595
  } catch (e) {
570
- this.log.error(e);
596
+ this.log.error(`[onUnload] Fehler beim Zurücksetzen der States-Timer: ${e.message}`);
571
597
  }
572
598
 
573
599
  this.setState('info.connection', false, true);
@@ -595,14 +621,14 @@ class Zigbee2mqtt extends core.Adapter {
595
621
  if (state && state.ack === false) {
596
622
  if (id.endsWith('info.debugmessages')) {
597
623
  this.logCustomizations.debugDevices = state.val != null ? String(state.val) : '';
598
- this.setState(id, state.val, true);
624
+ await this.setState(id, state.val, true).catch(e => this.log.error(`[stateChange] Fehler beim Setzen von ${id}: ${e.message}`));
599
625
  return;
600
626
  }
601
627
  if (id.endsWith('info.logfilter')) {
602
628
  this.logCustomizations.logfilter = state.val != null
603
629
  ? String(state.val).split(';').filter((x) => x)
604
630
  : [];
605
- this.setState(id, state.val, true);
631
+ await this.setState(id, state.val, true).catch(e => this.log.error(`[stateChange] Fehler beim Setzen von ${id}: ${e.message}`));
606
632
  return;
607
633
  }
608
634
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.zigbee2mqtt",
3
- "version": "3.2.2",
3
+ "version": "3.2.4",
4
4
  "description": "Zigbee2MQTT adapter for ioBroker",
5
5
  "author": {
6
6
  "name": "Dennis Rathjen and Arthur Rupp",
@@ -24,27 +24,27 @@
24
24
  "node": ">= 22"
25
25
  },
26
26
  "dependencies": {
27
- "@iobroker/adapter-core": "^3.3.2",
27
+ "@iobroker/adapter-core": "^3.4.1",
28
28
  "@iobroker/dm-utils": "^3.0.17",
29
29
  "aedes": "^0.51.3",
30
30
  "aedes-persistence": "^9.1.2",
31
- "axios": "^1.16.0",
31
+ "axios": "^1.17.0",
32
32
  "mqtt": "^5.15.1",
33
33
  "net": "^1.0.2",
34
34
  "node-schedule": "^2.1.1",
35
35
  "sharp": "^0.34.5",
36
- "ws": "^8.20.0"
36
+ "ws": "^8.21.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@alcalzone/release-script": "^5.2.0",
39
+ "@alcalzone/release-script": "^5.2.1",
40
40
  "@alcalzone/release-script-plugin-iobroker": "^5.2.0",
41
41
  "@alcalzone/release-script-plugin-license": "^5.2.0",
42
42
  "@alcalzone/release-script-plugin-manual-review": "^5.2.0",
43
43
  "@iobroker/adapter-dev": "^1.5.0",
44
44
  "@iobroker/eslint-config": "^2.3.4",
45
- "@iobroker/testing": "^5.1.1",
46
- "@tsconfig/node14": "^14.1.8",
47
- "@types/node": "^25.6.2",
45
+ "@iobroker/testing": "^5.2.2",
46
+ "@tsconfig/node22": "^22.0.5",
47
+ "@types/node": "^25.9.3",
48
48
  "@types/node-schedule": "^2.1.8",
49
49
  "typescript": "~6.0.3"
50
50
  },