iobroker.zigbee 2.0.1 → 2.0.2
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 +13 -1
- package/docs/de/readme.md +21 -28
- package/io-package.json +16 -3
- package/lib/commands.js +9 -3
- package/lib/devices.js +14 -4
- package/lib/exposes.js +45 -45
- package/lib/localConfig.js +10 -4
- package/lib/ota.js +5 -4
- package/lib/statescontroller.js +45 -5
- package/lib/utils.js +4 -2
- package/lib/zbDeviceAvailability.js +1 -7
- package/lib/zbDeviceConfigure.js +55 -28
- package/lib/zigbeecontroller.js +38 -9
- package/main.js +39 -12
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
With the Zigbee-coordinator based on Texas Instruments SoC, deCONZ ConBee/RaspBee modules, Silicon Labs EZSP v8 or ZIGate USB-TTL it creates its own zigbee-network, into which zigbee-devices are connected.
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
|
|
19
18
|
By working directly with the coordinator, the driver allows you to manage devices without additional application / gateways / bridge from device manufacturers (Xiaomi / TRADFRI / Hue / Tuya). About the device Zigbee-network can be read [here (in English)](https://www.zigbee2mqtt.io/information/zigbee_network.html).
|
|
20
19
|
|
|
21
20
|
## Hardware
|
|
@@ -137,6 +136,19 @@ You can thank the authors by these links:
|
|
|
137
136
|
|
|
138
137
|
-----------------------------------------------------------------------------------------------------
|
|
139
138
|
## Changelog
|
|
139
|
+
### 2.0.2 (2025-03-02)
|
|
140
|
+
* fix expose generation with expose function requiring a device. (Issue #1842)
|
|
141
|
+
* fix failure to configure for devices needing multiple configurations (Issue #2375)
|
|
142
|
+
* fix hold/release and press/release action handling (Issue #2387)
|
|
143
|
+
* fix lib/legacy requirement for external converters (Issue #2376)
|
|
144
|
+
* improved external converter handling
|
|
145
|
+
* fix OTA bug
|
|
146
|
+
* improved message handling for devices which report values outside their defined ranges
|
|
147
|
+
* preparation for ZHC 22.x (model definition loaded on demand
|
|
148
|
+
* fix legacy definition for devices
|
|
149
|
+
* added action state for remotes.
|
|
150
|
+
*
|
|
151
|
+
|
|
140
152
|
### 2.0.1 (2025-02-25)
|
|
141
153
|
* BREAKING CHANGES
|
|
142
154
|
*
|
package/docs/de/readme.md
CHANGED
|
@@ -6,9 +6,8 @@ Für den Koordinator (siehe oben) ist eine zusätzliche Hardware erforderlich, w
|
|
|
6
6
|
|
|
7
7
|
- Aufsteckmodul für den RaspberryPi (wird nicht mehr verwendet da veraltet und keine Zigbee 3.0 Unterstützung)<br>
|
|
8
8
|
- USB-Stick ähnliche Hardware
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-

|
|
9
|
+
- Netzwerk Koordinatoren
|
|
10
|
+
|
|
12
11
|

|
|
13
12
|

|
|
14
13
|

|
|
@@ -25,6 +24,7 @@ Zunehmend beliebt kommt der "Sonoff ZIGBEE 3.0 USB-STICK CC2652P" zum Einsatz:
|
|
|
25
24
|
|
|
26
25
|
Die mit dem ZigBee-Netz verbundenen Geräte übermitteln dem Koordinator ihren Zustand und benachrichtigen über Ereignisse (Knopfdruck, Bewegungserkennung, Temperaturänderung, …). Diese Infos werden im Adapter unter den jeweiligen ioBroker-Objekten angezeigt und können so in ioBroker weiterverarbeitet werden. Außerdem ist es möglich Kommandos an das ZigBee-Gerät zu senden (Zustandsänderung Steckdosen und Lampen, Farb- und Helligkeitseinstellungen, …).
|
|
27
26
|
|
|
27
|
+
Eine weitergehende Aufstellung der verschiedenen Hardware-optionen für den Koordinator ist m [zigbee2mqtt.io Projekt](https://www.zigbee2mqtt.io/guide/adapters/) zu finden (Dokumentation ausschliesslich auf englisch)
|
|
28
28
|
|
|
29
29
|
## Die Software
|
|
30
30
|
|
|
@@ -45,14 +45,15 @@ Die Software wird unterteilt in "Konverter" und "Adapter".
|
|
|
45
45
|
2. Über z.B. PuTTY mit RaspberryPi verbinden.<br>
|
|
46
46
|
3. Eventuell vorhandene ZigBee-Backupdatei löschen. Andernfalls wird der ZigBee-Adapter in ioBroker nicht grün und im ioBroker Log steht, dass der Adapter falsch konfiguriert ist.<br>
|
|
47
47
|
sudo rm /opt/iobroker/iobroker-data/zigbee_0/nvbackup.json<br>
|
|
48
|
-
4. Pfad des Koordinators ermitteln
|
|
49
|
-
`ls -la /dev/serial/by-id/`
|
|
48
|
+
4. Pfad des Koordinators ermitteln. Auf Linux Systemen befindet sich dieser oft im Verzeichnis /dev/serial/by-id. Alternativ dazu werden /dev/ttyUSB*, /dev/ttyAM* (Linux), /dev/tty.usbserial-* (macOS) oder com* (windows) erwartet.<br>
|
|
49
|
+
Das folgende Beispiel zeigt eine Linux-Installation auf einem Raspberry PI. Der Befehl `ls -la /dev/serial/by-id/` erzeugt die im Bild erkennbare Ausgabe.
|
|
50
50
|

|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
6. ioBroker -> ZigBee-Adapter installieren, hier als Beispiel die Version 1.8.10 <br>  <br> Hiermit werden alle erforderlichen Softwareteile (Konverter und Adapter) installiert.
|
|
52
|
+
7. Konfiguration des Adapters öffnen. Das folgende Bild zeigt das Interface ab der Version 2.0.1.<br><br>
|
|
53
|
+
8. Port zum Koordinator eintragen. Im Fall von USB Koordinatoren ist das der zuvor ermittelte Device-Pfad. Im Fall von über das Netzwerk angesteuerten Koordinatoren muss an Stelle des Gerätepfades die Netzwerkaddresse samt port in der Form tcp://ip:port angegeben werden. Im Beispielbild ist als Port /dev/tty.usbserial-1410 eingetragen.<br> Es ist zu achten, dass am Ende kein Leerzeichen mit eingetragen wird.
|
|
54
|
+
8. Netzwerk-ID und Pan ID vergeben zur Unterscheidung von anderen ZigBee-Netzwerken in Funkreichweite, z.B. Wichtig: Sollte hier als erweiterte PanID die StandardID DDDDDDDDDDDDDDDD (Pan ID 6757) eingetragen sein so sollte diese **unbedingt** angepasst werden<br>
|
|
55
|
+
9. Geeigneten Zigbee-Kanal auswählen. Dabei ist zu beachten das Zigbee und 2.4GHz WLAN sich das gleiche Frequenzband teilen. Der optimale Kanal hängt also unter anderem auch von den in der Umgebung verwendeten WLan Kanälen ab. Dabei sind die Kanalbezeichnungen von Zigbee und WLan **nicht** identisch. Weiterhin ist es Sinnvoll sich bei der Auswahl auf die Zigbee Light Link Kanäle 11,15,20 und 25 zu beschränken. Sofern der Adapter erfolgreich gestartet wurde kann über die Konfiguration auch ein Scan der Netzwerkkanäle durchgeführt werden. Dabei ist zu beachten das dieses vor dem Anlernen der Geräte geschehen sollte - nach dem Wechsel des Kanals muss der Adapter angehalten und das Backup gelöscht werden. In der folge müssen alle Geräte neu angelernt werden.
|
|
56
|
+
10. Prüfen ob der Adapter in ioBroker grün wird. Das kann bis zu 60 Sekunden dauern. Sollzustand: <br>  <br> Andernfalls ist es notwendig die Meldungen im ioBroker Log zu lesen. Diese beinhalten Informationen darüber warum der Adapter nicht gestartet wurde, und können bei der Fehlersuche mit Hilfe des Forums bereits Lösungsansätze liefern.
|
|
56
57
|
|
|
57
58
|
## Pairing
|
|
58
59
|
Jedes ZigBee-Gerät (Schalter, Lampe, Sensor, …) muss mit dem Koordinator gekoppelt werden (Pairing): <br>
|
|
@@ -61,8 +62,8 @@ Jedes ZigBee-Gerät (Schalter, Lampe, Sensor, …) muss mit dem Koordinator geko
|
|
|
61
62
|
Jedes **ZigBee-Gerät** kann nur mit genau 1 ZigBee-Netzwerk verbunden sein. Hat das ZigBee-Gerät noch Pairing-Informationen zu einem fremden Koordinator (z.B. Philips Hue Bridge) gespeichert, dann muss es von diesem ZigBee-Netzwerk zuerst entkoppelt werden. Dieses Entkoppeln vom alten ZigBee-Netzwerk erfolgt vorzugsweise über die Bedienoberfläche des alten ZigBee-Netzwerkes (z.B. Philips Hue App). Alternativ kann man das ZigBee-Gerät auf Werkseinstellungen zurücksetzen. <br>
|
|
62
63
|
Um ein ZigBee-Gerät nun in den Pairing-Mode zu versetzen, gibt es typischerweise folgende Möglichkeiten: <br>
|
|
63
64
|
1. ZigBee-Gerät von einem ZigBee-Netzwerk entkoppeln
|
|
64
|
-
2. Pairing-Button am ZigBee-Gerät drücken
|
|
65
|
-
3. Versorgungsspannung des ZigBee-Gerätes aus- und dann wieder einschalten
|
|
65
|
+
2. Pairing-Button am ZigBee-Gerät drücken (ggf. mehrfach)
|
|
66
|
+
3. Versorgungsspannung des ZigBee-Gerätes aus- und dann wieder einschalten (ggf. mehrfach)
|
|
66
67
|
|
|
67
68
|
Danach ist das ZigBee-Gerät für typischerweise 60 Sekunden im Pairing-Mode. <br>
|
|
68
69
|
Ähnlich wie die Vorgehensweise zum Rücksetzen auf Werkseinstellungen ist auch das Aktivieren des Pairing-Mode abhängig vom jeweiligen Gerätetyp (ggf. Bedienungsanleitung des ZigBee-Gerätes lesen). <br>
|
|
@@ -71,19 +72,17 @@ Danach ist das ZigBee-Gerät für typischerweise 60 Sekunden im Pairing-Mode. <b
|
|
|
71
72
|
Grünen Knopf drücken, um den Koordinator für 60 Sekunden (oder die in den Adaptereinstellungen gewählte Zeit) in den Pairing-Mode zu versetzen. <br>
|
|
72
73
|

|
|
73
74
|
|
|
74
|
-
- Warten bis im Dialog
|
|
75
|
+
- Warten bis im Dialog `Interview Successful` erscheint:<br>
|
|
75
76
|

|
|
76
|
-
|
|
77
77
|
- Pairing überprüfen:
|
|
78
|
-
Das zu koppelnde Gerät muss vom ioBroker ZigBee-Adapter unterstützt werden. Im Gutfall wird im ZigBee-Adapter ein neues Gerät angezeigt (z.B. Philips Light Stripe) und entsprechende ioBroker-Objekte angelegt
|
|
78
|
+
Das zu koppelnde Gerät muss vom ioBroker ZigBee-Adapter unterstützt werden. Im Gutfall wird im ZigBee-Adapter ein neues Gerät angezeigt (z.B. Philips Light Stripe) mit dem Hinweis `"supported":true` und entsprechende ioBroker-Objekte angelegt:<br>
|
|
79
79
|
 
|
|
80
80
|
|
|
81
81
|
- Im Schlechtfall wird das ZigBee-Gerät aktuell noch nicht unterstützt. Im nächsten Abschnitt ist beschrieben, was zu tun ist, um dieses ZigBee-Gerät dennoch nutzen zu können.
|
|
82
82
|
|
|
83
83
|
## Pairing von bisher unbekannten ZigBee-Geräten
|
|
84
84
|
|
|
85
|
-
Bei bisher unbekannten ZigBee-Geräten erscheint beim Pairing der ZigBee-Name des ZigBee-Gerätes (z.B. HOMA1001) mit dem Zusatz "
|
|
86
|
-
 <br>
|
|
85
|
+
Bei bisher unbekannten ZigBee-Geräten erscheint beim Pairing der ZigBee-Name des ZigBee-Gerätes (z.B. HOMA1001) mit dem Zusatz `"supported": false` <br>
|
|
87
86
|
 <br>
|
|
88
87
|
|
|
89
88
|
Durch Drehen dieser Kachel erhält man Detailinformationen zu dem ZigBee-Gerät: <br>
|
|
@@ -93,18 +92,12 @@ Nach einer Registrierung bei [github.com](https://github.com/ioBroker/ioBroker.z
|
|
|
93
92
|
|
|
94
93
|
 <br>
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Nach Anpassung der relevanten Dateien muss der ZigBee-Adapter neu gestartet und dann das ZigBee-Gerät vom Koordinator entkoppelt werden (unpair):
|
|
99
|
-
Danach kann das Pairing wiederholt werden. Sollzustand nach dem Pairing: <br>
|
|
100
|
-
 <br>
|
|
101
|
-
|
|
102
|
-
Bei manchen ZigBee-Geräten ist es erforderlich alle Softwareschnittstellen ("exposes") des neuen ZigBee-Gerätes in den ioBroker-Objekten anzuzeigen, um alle Funktionen des ZigBee-Gerätes nutzen zu können. In solchen Fällen muss das neue ZigBee-Gerät in die "Ausschliessen"-Gruppe aufgenommen werden.
|
|
103
|
-
|
|
104
|
-
 <br>
|
|
95
|
+
Detailinformationen der Kachel (siehe oben) in dem Issue einfügen, erstelle eine kurze Dokumentation (vorzugweise auf Englisch) und absenden. Ein Entwickler wird sich daraufhin über den Issue melden.
|
|
105
96
|
|
|
106
|
-
|
|
107
|
-
|
|
97
|
+
Als Ergebnis kommt eine von zwei Möglichkeiten in Frage:
|
|
98
|
+
- Anpassung an den Zigbee-Herdsman-Converters. Dieses erfordert eine aktualiserte Version des Zigbee-Adapters, der zunächst getestet und dann im Latest Repository zur Verfügung gestellt wird
|
|
99
|
+
- Erstellung eines "externen Konverters" - einer Datei mit JS Code welche in das Datenverzeichnis des Zigbee-Adapters kopiert und in der Konfiguration des Adapters angegeben werden kann.
|
|
100
|
+
In Beiden Fällen ist es hinreichend den Adapter neu zu starten - die entsprechend angepassten Datenpunkte des Adapters werden angelegt. Sofern dabei Datenpunkte nicht weiter unterstützt werden so werden diese in orange eingefärbt und der Adapter zeigt die Schaltfläche zum löschen der verwaisten Datenpunkte an.
|
|
108
101
|
|
|
109
102
|
## Symbole im ZigBee-Adapter
|
|
110
103
|
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "zigbee",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.2",
|
|
5
5
|
"news": {
|
|
6
|
+
"2.0.2": {
|
|
7
|
+
"en": "fix expose generation with expose function requiring a device. (Issue #1842)\nfix failure to configure for devices needing multiple configurations (Issue #2375)\nfix hold/release and press/release action handling (Issue #2387)\nfix lib/legacy requirement for external converters (Issue #2376)\nimproved external converter handling\nfix OTA bug\nimproved message handling for devices which report values outside their defined ranges\npreparation for ZHC 22.x (model definition loaded on demand\nfix legacy definition for devices\nadded action state for remotes.\n",
|
|
8
|
+
"de": "fix exponieren Erzeugung mit exponierender Funktion, die ein Gerät benötigt. (Ausgabe #1842)\nfehler beim Konfigurieren von Geräten, die mehrere Konfigurationen benötigen (Issue #2375)\nfix Hold/Release und Presse/Release-Action-Handling (Issue #2387)\nfix lib/legacy Anforderung für externe Konverter (Issue #2376)\nverbesserte externe konverterhandhabung\noTA Fehler beheben\nverbesserte nachrichtenbehandlung für geräte, die werte außerhalb ihrer definierten bereiche melden\nvorbereitung auf ZHC 22.x (Modelldefinition geladen auf Anfrage\nfix legacy definition für geräte\nden aktionszustand für remotes hinzugefügt.\n",
|
|
9
|
+
"ru": "исправить генерацию экспозиции с функцией экспозиции, требующей устройства. (Выпуск #1842)\nисправление неисправности настройки для устройств, нуждающихся в нескольких конфигурациях (выпуск No 2375)\nфиксация удержания/выпуска и обработки нажатия/выпуска (выпуск No 2387)\nтребование к фиксации lib/legacy для внешних преобразователей (выпуск No 2376)\nулучшенная внешняя обработка конвертера\nисправить ошибку OTA\nулучшенная обработка сообщений для устройств, которые сообщают значения за пределами своих определенных диапазонов\nподготовка к ZHC 22.x (определение модели, загруженное по требованию)\nисправить устаревшее определение для устройств\nдобавлено состояние действия для пультов.\n",
|
|
10
|
+
"pt": "corrigir a geração de exposição com a função de exposição que requer um dispositivo. (Issue #1842)\ncorrigir a falha de configurar para dispositivos que precisam de múltiplas configurações (Issue #2375)\ncorrigir o manuseio de ação de espera/lançamento e press/lançamento (Issue #2387)\ncorreção lib/legacy exigência para conversores externos (Issue #2376)\nmelhor desempenho do conversor externo\ncorrigir o erro OTA\nmelhor manuseio de mensagens para dispositivos que relatam valores fora de suas gamas definidas\npreparação para ZHC 22.x (definição modelo carregada sob demanda\ncorrigir a definição de legado para dispositivos\nestado de ação adicionado para controles remotos.\n",
|
|
11
|
+
"nl": "fix ontmaskering generatie met ontmaskering functie vereist een apparaat. (Issue # 1842)\nvast te stellen fout bij het configureren van apparaten die meerdere configuraties nodig hebben (Issue #2375)\nfix hold/release and pers/release action handling (Issue #2387)\nfix lib/legacy eis voor externe converters (Issue #2376)\nverbeterde externe converterbehandeling\nfix OTA bug\nverbeterde berichtverwerking voor apparaten die waarden rapporteren buiten hun gedefinieerde bereik\nvoorbereiding voor ZHC 22.x (modeldefinitie op aanvraag geladen\nfix legacy definitie voor apparaten\ntoegevoegde actiestatus voor remotes.\n",
|
|
12
|
+
"fr": "fixer la génération d'exposition avec la fonction d'exposition nécessitant un dispositif. (Numéro 1842)\ncorrection de l'échec à configurer pour les appareils nécessitant plusieurs configurations (Numéro #2375)\nfixer la tenue/la sortie et la prise en charge par la presse/la sortie (numéro d'émission 2387)\nfixer lib / légataire exigence pour les convertisseurs externes (Émission #2376)\namélioration de la manipulation du convertisseur externe\ncorrection du bug OTA\namélioration du traitement des messages pour les appareils qui déclarent des valeurs en dehors de leurs plages définies\npréparation pour ZHC 22.x (définition du modèle chargé sur demande\nfixer la définition du passé pour les appareils\nétat d'action ajouté pour les télécommandes.\n",
|
|
13
|
+
"it": "risolvere esporre la generazione con la funzione di esporre che richiede un dispositivo. (Issue #1842)\ncorretto il mancato configurazione per i dispositivi che necessitano di più configurazioni (Essue #2375)\nfix hold/release e press/release action handling (Issue #2387)\nfix lib/legacy requisito per i convertitori esterni (Issue #2376)\nmigliore gestione del convertitore esterno\ncorrezione di bug OTA\nmigliore gestione dei messaggi per dispositivi che segnalano valori al di fuori dei loro intervalli definiti\npreparazione per ZHC 22.x (definizione modello caricata su richiesta\nfissare la definizione legacy per i dispositivi\nstato di azione aggiunto per i remoti.\n",
|
|
14
|
+
"es": "fijar la generación expuesta con función expuesta que requiere un dispositivo. (Isue #1842)\nfijar el fallo de configuración para dispositivos que necesitan múltiples configuraciones (Isue #2375)\nfijación de sujeción / liberación y prensa / manejo de acción de liberación (Isue #2387)\nfijar el requisito de lib/legacy para convertidores externos (Isue #2376)\nmejor manejo del convertidor externo\ncorrección de OTA\nmejorar el manejo de mensajes para dispositivos que reportan valores fuera de sus rangos definidos\npreparación para ZHC 22.x (definición modelo cargada a la demanda\nfijar la definición heredada para los dispositivos\nestado de acción añadido para los remotos.\n",
|
|
15
|
+
"pl": "naprawić generowanie ekspozycji z funkcją odsłaniania wymagającą urządzenia. (Wydanie # 1842)\nnaprawić awarię konfiguracji dla urządzeń wymagających wielu konfiguracji (wydanie # 2375)\nfix hold / release and press / release action handling (wydanie # 2387)\nfix lib / last requirement for external konwerters (issue # 2376)\nulepszona obsługa zewnętrznego konwertera\nnaprawić błąd OTA\nulepszona obsługa wiadomości dla urządzeń, które przekazują wartości poza określonymi zakresami\nprzygotowanie do ZHC 22.x (definicja modelu załadowana na żądanie\nnaprawić dotychczasową definicję urządzeń\ndodano stan działania pilotów.\n",
|
|
16
|
+
"uk": "фіксувати генерацію висадки з функцією вистоювання, що вимагає пристрою. (Issue #1842)\nвиправлена відмова налаштовувати для пристроїв, які потребують декількох конфігурацій (Issue #2375)\nфіксувати передачу/випуск та прес/випуск дії (Issue #2387)\nфіксувати вимогу lib/legacy для зовнішніх перетворювачів (Issue #2376)\nпокращений зовнішній конвертер\nвиправлення помилок OTA\nпокращена обробка повідомлень для пристроїв, які повідомляють значення поза визначеними діапазонами\nпідготовка до ZHC 22.x (модельне визначення, завантажене на попит\nфіксувати визначення спадщини для пристроїв\nдодано стан дії для пультів.\n",
|
|
17
|
+
"zh-cn": "固定需要设备的曝光函数的曝光生成。 (问题1842)\n为需要多个配置的设备设置固定失败( 问题 # 2375)\n固定持有/释放和按压/释放处理(第2387号问题)\n固定外部转换器的 lib/ legacy 要求(问题 # 2376)\n改进外部转换器处理\n修复OTA 错误\n改进对报告超出规定范围值的设备的信息处理\nzHC 22.x(按要求装入的模型定义)\n固定设备的遗留定义\n为远程添加动作状态 .\n"
|
|
18
|
+
},
|
|
6
19
|
"2.0.1": {
|
|
7
20
|
"en": "BREAKING CHANGES\n\nswitch to converters 21 changes the exposes for a large numbern of devices (mostly remotes)\nnew method for controlling color based on subchannels for rgb, hs and xy\nExposes as default for ALL devices. Use of old definition as option only\nRequires Node 20.x or newer\n\nFix Pairing\nchange ping\ndelay map generation until refresh is activated, map messages after generation\nremove bindings tab from zigbee tab\nreorder tabs in configuration\nremove binding tab from configuration\nremove map from configuration\nadd debug to zigbee tab\nHerdsman 3.2.5, Converters 21.30.0\nExposes as default, use of old device definitions as legacy optional\nUser specific images (model based, device based)\nImproved group editing - remove members from group card",
|
|
8
21
|
"de": "VERÄNDERUNGEN\n\nschalter auf konverter 21 ändert die belichtung für eine große anzahl von geräten (meist fernbedienungen)\nneue methode zur farbsteuerung auf basis von subkanälen für rgb, hs und xy\nExposes als Standard für ALL Geräte. Verwendung der alten Definition nur als Option\nErfordert Node 20.x oder neuer\n\nFeste Paarung\nänderung ping\nverzögerung der kartenerzeugung, bis das update aktiviert ist, kartennachrichten nach generation\nbinden tab aus zickbee tab entfernen\nreorder tabs in konfiguration\nbindelasche aus der konfiguration entfernen\nkarte aus der konfiguration entfernen\ndebug to zigbee tab hinzufügen\nHerdsman 3.2.5, Konverter 21.30.0\nExposes als Standard, Verwendung von alten Gerätedefinitionen als Vermächtnis optional\nBenutzerspezifische Bilder (modellbasierte, gerätebasierte)\nVerbesserte Gruppenbearbeitung - Mitglieder aus Gruppenkarte entfernen",
|
|
@@ -240,8 +253,8 @@
|
|
|
240
253
|
},
|
|
241
254
|
"native": {
|
|
242
255
|
"port": "",
|
|
243
|
-
"panID":
|
|
244
|
-
"extPanID": "
|
|
256
|
+
"panID": 0,
|
|
257
|
+
"extPanID": "",
|
|
245
258
|
"channel": 11,
|
|
246
259
|
"disableLed": false,
|
|
247
260
|
"precfgkey": "01030507090B0D0F00020406080A0C0D",
|
package/lib/commands.js
CHANGED
|
@@ -649,13 +649,19 @@ class Commands {
|
|
|
649
649
|
const entity = await this.zbController.resolveEntity(devid);
|
|
650
650
|
if (entity) {
|
|
651
651
|
try {
|
|
652
|
-
await this.zbController.callExtensionMethod(
|
|
652
|
+
const result = await this.zbController.callExtensionMethod(
|
|
653
653
|
'doConfigure',
|
|
654
654
|
[entity.device, entity.mapped],
|
|
655
655
|
);
|
|
656
|
-
this.
|
|
656
|
+
this.warn('do configure result is ' + JSON.stringify(result));
|
|
657
|
+
const msg = result.join(',');
|
|
658
|
+
if (msg.length > 5)
|
|
659
|
+
this.adapter.sendTo(from, command, {error: msg}, callback);
|
|
660
|
+
else
|
|
661
|
+
this.adapter.sendTo(from, command, {}, callback);
|
|
662
|
+
|
|
657
663
|
} catch (error) {
|
|
658
|
-
const errmsg = `Reconfigure failed ${entity.device.ieeeAddr} ${entity.device.modelID}, (${error.
|
|
664
|
+
const errmsg = `Reconfigure failed ${entity.device.ieeeAddr} ${entity.device.modelID}, (${error.message})`;
|
|
659
665
|
this.error(errmsg);
|
|
660
666
|
this.adapter.sendTo(from, command, {error: errmsg}, callback);
|
|
661
667
|
}
|
package/lib/devices.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const states = require('./states.js').states;
|
|
4
4
|
const utils = require('./utils.js');
|
|
5
5
|
const rgb = require('./rgb.js');
|
|
6
|
-
const applyExposes = require('./exposes.js')
|
|
6
|
+
const {applyExposes, applyExposeForDevice} = require('./exposes.js');
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
// return list of changing states when incoming state is changed
|
|
@@ -3094,11 +3094,19 @@ function getByModel() {
|
|
|
3094
3094
|
|
|
3095
3095
|
removeEmptyStates(devices);
|
|
3096
3096
|
|
|
3097
|
-
function fillStatesWithExposes() {
|
|
3098
|
-
//const byModel = getByModel();
|
|
3097
|
+
function fillStatesWithExposes(logger) {
|
|
3099
3098
|
if (DevicesByModel.size <1) getByModel();
|
|
3100
|
-
|
|
3099
|
+
return;
|
|
3100
|
+
// applyExposes(devices, DevicesByModel, logger);
|
|
3101
|
+
//removeEmptyStates(devices);
|
|
3102
|
+
}
|
|
3103
|
+
|
|
3104
|
+
async function addExposeToDevices(device, logger, model) {
|
|
3105
|
+
const s = DevicesByModel.size;
|
|
3106
|
+
if (s < 1) getByModel();
|
|
3107
|
+
await applyExposeForDevice(devices, DevicesByModel, device, logger, model);
|
|
3101
3108
|
removeEmptyStates(devices);
|
|
3109
|
+
return (DevicesByModel.size != s);
|
|
3102
3110
|
}
|
|
3103
3111
|
|
|
3104
3112
|
// remove empty states
|
|
@@ -3166,6 +3174,8 @@ module.exports = {
|
|
|
3166
3174
|
groupStates,
|
|
3167
3175
|
groupsState: states.groups,
|
|
3168
3176
|
fillStatesWithExposes,
|
|
3177
|
+
addExposeToDevices,
|
|
3178
|
+
getByModel,
|
|
3169
3179
|
findModel,
|
|
3170
3180
|
fillDevicesForLegacy,
|
|
3171
3181
|
pairedLegacyDevices,
|
package/lib/exposes.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
|
|
4
|
-
const statesDefs = require('./states
|
|
5
|
-
const rgb = require('./rgb
|
|
6
|
-
const utils = require('./utils
|
|
7
|
-
const colors = require('./colors
|
|
8
|
-
const ea = require('zigbee-herdsman-converters/lib/exposes
|
|
4
|
+
const statesDefs = require('./states').states;
|
|
5
|
+
const rgb = require('./rgb');
|
|
6
|
+
const utils = require('./utils');
|
|
7
|
+
const colors = require('./colors');
|
|
8
|
+
const ea = require('zigbee-herdsman-converters/lib/exposes').access;
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const __logger = undefined;
|
|
9
12
|
|
|
10
13
|
function genState(expose, role, name, desc) {
|
|
11
14
|
let state;
|
|
@@ -134,7 +137,7 @@ function genState(expose, role, name, desc) {
|
|
|
134
137
|
return state;
|
|
135
138
|
}
|
|
136
139
|
|
|
137
|
-
function createFromExposes(model, def) {
|
|
140
|
+
function createFromExposes(model, def, device, log) {
|
|
138
141
|
const states = [];
|
|
139
142
|
// make the different (set and get) part of state is updatable if different exposes is used for get and set
|
|
140
143
|
// as example:
|
|
@@ -253,15 +256,12 @@ function createFromExposes(model, def) {
|
|
|
253
256
|
if (typeof def.exposes == 'object') {
|
|
254
257
|
for (const expose of def.exposes) {
|
|
255
258
|
genStateFromExpose(expose);
|
|
256
|
-
|
|
257
|
-
|
|
258
259
|
}
|
|
259
260
|
}
|
|
260
261
|
|
|
261
262
|
// maybee here check manufacturerName for tuya devices
|
|
262
263
|
if (typeof def.exposes == 'function') {
|
|
263
|
-
const expFunction = def.exposes(
|
|
264
|
-
|
|
264
|
+
const expFunction = def.exposes(device, {}); // maybee here check manufacturerName for tuya devices
|
|
265
265
|
for (const expose of expFunction) {
|
|
266
266
|
genStateFromExpose(expose);
|
|
267
267
|
}
|
|
@@ -636,37 +636,30 @@ function createFromExposes(model, def) {
|
|
|
636
636
|
|
|
637
637
|
case 'action': {
|
|
638
638
|
// Ansatz:
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
639
|
+
//generate an 'action' state\
|
|
640
|
+
state = genState(expose);
|
|
641
|
+
state.isEvent = true;
|
|
642
|
+
pushToStates(state, expose.access);
|
|
643
643
|
|
|
644
644
|
if (!Array.isArray(expose.values)) break;
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
645
|
+
// identify hold/release pairs
|
|
646
|
+
// if pairs of (prefix)press(postfix) and (prefix)release(postfix) or
|
|
647
|
+
// (prefix)hold(postfix) and (prefix)release(postfix)
|
|
648
|
+
// exist, the release action will not get its own state. Instead, the
|
|
649
|
+
// respective press or hold state will not be an event and be cleared at release time
|
|
650
|
+
//
|
|
651
|
+
const phr = {};
|
|
652
|
+
const phc = expose.values.filter((actionName) => actionName.match(/hold|press/gm));
|
|
653
|
+
for (const actionName of phc) {
|
|
654
|
+
const releasestr = actionName.replace(/hold|press/gm, 'release');
|
|
655
|
+
const release = expose.values.find((actionName) => actionName == releasestr);
|
|
656
|
+
phr[actionName]=release;
|
|
657
|
+
if (release) phr[release]= 'IGNORE';
|
|
658
|
+
}
|
|
649
659
|
for (const actionName of expose.values) {
|
|
650
|
-
|
|
651
|
-
if (
|
|
652
|
-
//
|
|
653
|
-
if (hasHold && hasRelease && actionName.includes('hold')) {
|
|
654
|
-
const releaseActionName = actionName.replace('hold', 'release');
|
|
655
|
-
const releaseActionName2 = actionName.concat('_release');
|
|
656
|
-
state = {
|
|
657
|
-
id: actionName.replace(/\*/g, ''),
|
|
658
|
-
prop: 'action',
|
|
659
|
-
name: actionName,
|
|
660
|
-
icon: undefined,
|
|
661
|
-
role: 'button',
|
|
662
|
-
write: false,
|
|
663
|
-
read: true,
|
|
664
|
-
type: 'boolean',
|
|
665
|
-
getter: payload => payload.action === actionName ? true : (payload.action === releaseActionName || payload.action === releaseActionName2 ? false : undefined),
|
|
666
|
-
};
|
|
667
|
-
} else if (hasPress && hasPressRelease && actionName.includes('press')) {
|
|
668
|
-
let getterKey = actionName.concat('_release');
|
|
669
|
-
if (expose.values.indexOf(getterKey) < 0) getterKey = actionName;
|
|
660
|
+
const release = phr[actionName];
|
|
661
|
+
if (release === 'IGNORE') continue // a release message for which a press or hold exists.
|
|
662
|
+
if (release) { // a press or hold state with a matching release state
|
|
670
663
|
state = {
|
|
671
664
|
id: actionName.replace(/\*/g, ''),
|
|
672
665
|
prop: 'action',
|
|
@@ -676,11 +669,10 @@ function createFromExposes(model, def) {
|
|
|
676
669
|
write: false,
|
|
677
670
|
read: true,
|
|
678
671
|
type: 'boolean',
|
|
679
|
-
getter: payload => payload.action ===
|
|
680
|
-
isEvent: true,
|
|
672
|
+
getter: payload => payload.action === actionName ? true : (payload.action === release ? false : undefined),
|
|
681
673
|
};
|
|
682
674
|
} else {
|
|
683
|
-
|
|
675
|
+
state = {
|
|
684
676
|
id: actionName.replace(/\*/g, ''),
|
|
685
677
|
prop: 'action',
|
|
686
678
|
name: actionName,
|
|
@@ -874,6 +866,7 @@ function createFromExposes(model, def) {
|
|
|
874
866
|
}
|
|
875
867
|
|
|
876
868
|
}
|
|
869
|
+
|
|
877
870
|
function applyExposes(mappedDevices, byModel) {
|
|
878
871
|
// create or device from exposes
|
|
879
872
|
for (const deviceDef of zigbeeHerdsmanConverters.definitions) {
|
|
@@ -892,22 +885,29 @@ function applyExposes(mappedDevices, byModel) {
|
|
|
892
885
|
}
|
|
893
886
|
}
|
|
894
887
|
|
|
895
|
-
function
|
|
888
|
+
async function applyExposeForDevice(mappedDevices, byModel, device) {
|
|
889
|
+
const deviceDef = await zigbeeHerdsmanConverters.findByDevice(device);
|
|
890
|
+
if (!deviceDef) return false;
|
|
891
|
+
applyDeviceDef(mappedDevices, byModel, deviceDef, device);
|
|
892
|
+
return true;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
function applyDeviceDef(mappedDevices, byModel, deviceDef, device) {
|
|
896
896
|
const stripModel = utils.getModelRegEx(deviceDef.model);
|
|
897
897
|
const existsMap = byModel.get(stripModel);
|
|
898
|
-
|
|
899
898
|
if (deviceDef.hasOwnProperty('exposes') && (!existsMap || !existsMap.hasOwnProperty('states'))) {
|
|
900
899
|
try {
|
|
901
|
-
const newDevice = createFromExposes(stripModel, deviceDef);
|
|
900
|
+
const newDevice = createFromExposes(stripModel, deviceDef, device);
|
|
902
901
|
mappedDevices.push(newDevice);
|
|
903
902
|
byModel.set(stripModel, newDevice);
|
|
904
903
|
|
|
905
904
|
} catch (e) {
|
|
906
|
-
|
|
905
|
+
//this.debug('empty catch in exposes');
|
|
907
906
|
}
|
|
908
907
|
}
|
|
909
908
|
}
|
|
910
909
|
|
|
911
910
|
module.exports = {
|
|
912
911
|
applyExposes: applyExposes,
|
|
912
|
+
applyExposeForDevice: applyExposeForDevice,
|
|
913
913
|
};
|
package/lib/localConfig.js
CHANGED
|
@@ -179,13 +179,13 @@ class localConfig extends EventEmitter {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
getOverrideData(target, isGlobal) {
|
|
182
|
-
const base = (isGlobal ? this.localData.by_model : this.localData.
|
|
183
|
-
if (base.hasOwnProperty(target)) return base
|
|
182
|
+
const base = (isGlobal ? this.localData.by_model : this.localData.by_id);
|
|
183
|
+
if (base.hasOwnProperty(target)) return base[target];
|
|
184
184
|
return {};
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
setOverrideData(target, isGlobal, data) {
|
|
188
|
-
const base = (isGlobal ? this.localData.by_model : this.localData.
|
|
188
|
+
const base = (isGlobal ? this.localData.by_model : this.localData.by_id);
|
|
189
189
|
if (typeof target != 'string') {
|
|
190
190
|
this.error('illegal target for override data: '+JSON.stringify(target));
|
|
191
191
|
return;
|
|
@@ -203,7 +203,7 @@ class localConfig extends EventEmitter {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
getOverridesWithKey(key, isGlobal) {
|
|
206
|
-
const base = (isGlobal ? this.localData.by_model : this.localData.
|
|
206
|
+
const base = (isGlobal ? this.localData.by_model : this.localData.by_id);
|
|
207
207
|
const rv = [];
|
|
208
208
|
for(const prop in base) {
|
|
209
209
|
if (base[prop].hasOwnProperty(key)) {
|
|
@@ -213,6 +213,12 @@ class localConfig extends EventEmitter {
|
|
|
213
213
|
return rv;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
getOverrideWithKey(target, key, isGlobal) {
|
|
217
|
+
const targetdata = this.getOverrideData(target, isGlobal);
|
|
218
|
+
if (targetdata && targetdata.hasOwnProperty(key)) return targetdata[key];
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
|
|
216
222
|
async updateFromDeviceNames() {
|
|
217
223
|
this.warn('updateFromDeviceNames');
|
|
218
224
|
const fn = this.adapter.expandFileName('dev_names').replace('.', '_').concat('.json');
|
package/lib/ota.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const getZbId = require('./utils').getZbId;
|
|
4
|
+
const zhc_ota = require('zigbee-herdsman-converters').ota;
|
|
4
5
|
|
|
5
6
|
class Ota {
|
|
6
7
|
constructor(adapter) {
|
|
@@ -24,7 +25,7 @@ class Ota {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
warn(msg) {
|
|
27
|
-
this.adapter.log.
|
|
28
|
+
this.adapter.log.warn(msg);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
error(msg) {
|
|
@@ -94,10 +95,10 @@ class Ota {
|
|
|
94
95
|
this.debug(`Checking if firmware update is available for ${device.name}`);
|
|
95
96
|
|
|
96
97
|
if (device && device.mapped.ota) {
|
|
97
|
-
const available = await
|
|
98
|
+
const available = await zhc_ota.isUpdateAvailable(device.device, device.mapped.ota, undefined, false);
|
|
98
99
|
result.status = available.available ? 'available' : 'not_available';
|
|
99
100
|
if (available.currentFileVersion !== available.otaFileVersion) {
|
|
100
|
-
this.
|
|
101
|
+
this.debug(`current Firmware for ${device.name} is ${available.currentFileVersion} new is ${available.otaFileVersion}`);
|
|
101
102
|
}
|
|
102
103
|
} else {
|
|
103
104
|
result.status = 'not_supported';
|
|
@@ -155,7 +156,7 @@ class Ota {
|
|
|
155
156
|
};
|
|
156
157
|
|
|
157
158
|
const from_ = await this.readSoftwareBuildIDAndDateCode(device.device, false);
|
|
158
|
-
const fileVersion = await
|
|
159
|
+
const fileVersion = await zhc_ota.update(device.device, device.mapped.ota, false, onProgress)
|
|
159
160
|
const to = await this.readSoftwareBuildIDAndDateCode(device.device, true);
|
|
160
161
|
const [fromS, toS] = [JSON.stringify(from_), JSON.stringify(to)];
|
|
161
162
|
result.status = 'success';
|
package/lib/statescontroller.js
CHANGED
|
@@ -31,6 +31,7 @@ class StatesController extends EventEmitter {
|
|
|
31
31
|
this.timeoutHandleUpload = null;
|
|
32
32
|
this.ImagesToDownload = [];
|
|
33
33
|
this.stashedErrors = {};
|
|
34
|
+
this.stashedUnknownModels = [];
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
info(message, data) {
|
|
@@ -71,8 +72,31 @@ class StatesController extends EventEmitter {
|
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
getStashedErrors() {
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
const rv = [];
|
|
76
|
+
if (Object.keys(this.stashedErrors).length > 0)
|
|
77
|
+
{
|
|
78
|
+
rv.push('<p><b>Stashed Messages</b></p>')
|
|
79
|
+
rv.push(Object.values(this.stashedErrors).join('<br>'));
|
|
80
|
+
}
|
|
81
|
+
if (this.stashedUnknownModels.length > 0) {
|
|
82
|
+
rv.push('<p><b>Devices whithout Model definition</b></p>')
|
|
83
|
+
rv.push()
|
|
84
|
+
}
|
|
85
|
+
return rv;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async AddModelFromHerdsman(device, model) {
|
|
89
|
+
// this.warn('addModelFromHerdsman ' + JSON.stringify(model) + ' ' + JSON.stringify(this.localConfig.getOverrideWithKey(model, 'legacy', true)));
|
|
90
|
+
if (this.localConfig.getOverrideWithKey(model, 'legacy', true)) {
|
|
91
|
+
//this.warn('legacy for ' + model);
|
|
92
|
+
await this.addLegacyDevice(model);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const pre = statesMapping.devices.length;
|
|
96
|
+
await statesMapping.addExposeToDevices(device, this, model);
|
|
97
|
+
const post = statesMapping.devices.length;
|
|
98
|
+
//this.warn('expose for ' + model + ' '+ pre + '->'+post);
|
|
99
|
+
}
|
|
76
100
|
}
|
|
77
101
|
|
|
78
102
|
async getDebugDevices(callback) {
|
|
@@ -228,7 +252,13 @@ class StatesController extends EventEmitter {
|
|
|
228
252
|
} else {
|
|
229
253
|
stateModel = statesMapping.findModel(model);
|
|
230
254
|
if (!stateModel) {
|
|
231
|
-
|
|
255
|
+
// try to get the model from the exposes
|
|
256
|
+
if (!this.stashedErrors.hasOwnProperty(`${deviceId}.nomodel`))
|
|
257
|
+
{
|
|
258
|
+
this.warn(`Device ${deviceId} "${model}" not found.`);
|
|
259
|
+
this.stashedErrors[`${deviceId}.nomodel`] = `Device ${deviceId} "${model}" not found.`;
|
|
260
|
+
}
|
|
261
|
+
|
|
232
262
|
states = statesMapping.commonStates;
|
|
233
263
|
} else {
|
|
234
264
|
states = stateModel.states;
|
|
@@ -615,6 +645,11 @@ class StatesController extends EventEmitter {
|
|
|
615
645
|
//this.warn('devices are' + modelarr2.join(','));
|
|
616
646
|
}
|
|
617
647
|
|
|
648
|
+
async addLegacyDevice(model) {
|
|
649
|
+
statesMapping.setLegacyDevices([model]);
|
|
650
|
+
statesMapping.getByModel();
|
|
651
|
+
}
|
|
652
|
+
|
|
618
653
|
async getDefaultGroupIcon(id) {
|
|
619
654
|
const regexResult = id.match(new RegExp(/group_(\d+)/));
|
|
620
655
|
if (!regexResult) return '';
|
|
@@ -807,7 +842,12 @@ class StatesController extends EventEmitter {
|
|
|
807
842
|
async getExposes() {
|
|
808
843
|
await this.localConfig.init();
|
|
809
844
|
await this.applyLegacyDevices();
|
|
810
|
-
|
|
845
|
+
try {
|
|
846
|
+
statesMapping.fillStatesWithExposes(this);
|
|
847
|
+
}
|
|
848
|
+
catch (error) {
|
|
849
|
+
this.error(`Error applying exposes: ${error && error.message ? error.message : 'no error message'} ${error && error.stack ? error.stack : ''}`);
|
|
850
|
+
}
|
|
811
851
|
}
|
|
812
852
|
|
|
813
853
|
async elevatedMessage(device, message, isError) {
|
|
@@ -888,7 +928,7 @@ class StatesController extends EventEmitter {
|
|
|
888
928
|
|
|
889
929
|
// if needs to return value to back after timeout
|
|
890
930
|
if (statedesc.isEvent) {
|
|
891
|
-
this.updateStateWithTimeout(devId, statedesc.id, value, common, 300, !value);
|
|
931
|
+
this.updateStateWithTimeout(devId, statedesc.id, value, common, 300, (typeof value == typeof (!value) ? !value : ''));
|
|
892
932
|
} else {
|
|
893
933
|
if (statedesc.prepublish) {
|
|
894
934
|
this.collectOptions(devId, model, options =>
|
package/lib/utils.js
CHANGED
|
@@ -106,11 +106,13 @@ function flatten(arr) {
|
|
|
106
106
|
flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten), []);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
const forceEndDevice =
|
|
109
|
+
const forceEndDevice = ['QBKG03LM', 'QBKG04LM', 'ZNMS13LM', 'ZNMS12LM'];
|
|
110
|
+
|
|
111
|
+
/*flatten(
|
|
110
112
|
['QBKG03LM', 'QBKG04LM', 'ZNMS13LM', 'ZNMS12LM']
|
|
111
113
|
.map(model => zigbeeHerdsmanConverters.findByModel(model))
|
|
112
114
|
.map(mappedModel => mappedModel.zigbeeModel));
|
|
113
|
-
|
|
115
|
+
*/
|
|
114
116
|
// Xiaomi uses 4151 and 4447 (lumi.plug) as manufacturer ID.
|
|
115
117
|
const xiaomiManufacturerID = [4151, 4447];
|
|
116
118
|
const ikeaTradfriManufacturerID = [4476];
|
|
@@ -6,13 +6,7 @@ const utils = require('./utils');
|
|
|
6
6
|
|
|
7
7
|
// Some EndDevices should be pinged
|
|
8
8
|
// e.g. E11-G13 https://github.com/Koenkk/zigbee2mqtt/issues/775#issuecomment-453683846
|
|
9
|
-
const forcedPingable = [
|
|
10
|
-
zigbeeHerdsmanConverters.findByModel('E11-G13'),
|
|
11
|
-
zigbeeHerdsmanConverters.findByModel('53170161'),
|
|
12
|
-
zigbeeHerdsmanConverters.findByModel('V3-BTZB'),
|
|
13
|
-
zigbeeHerdsmanConverters.findByModel('SPZB0001'),
|
|
14
|
-
zigbeeHerdsmanConverters.findByModel('014G2461')
|
|
15
|
-
];
|
|
9
|
+
const forcedPingable = ['E11-G13','53170161','V3-BTZB','SPZB0001','014G2461'];
|
|
16
10
|
|
|
17
11
|
// asgothian: 29.12.2020: Removed color and color_temp from readable
|
|
18
12
|
// state candidates as most states do not provide a getter to ikea_transform
|
package/lib/zbDeviceConfigure.js
CHANGED
|
@@ -3,17 +3,14 @@
|
|
|
3
3
|
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
|
|
4
4
|
const BaseExtension = require('./zbBaseExtension');
|
|
5
5
|
|
|
6
|
-
const forcedConfigureOnEachStart = [
|
|
7
|
-
zigbeeHerdsmanConverters.findByModel('V3-BTZB'),
|
|
8
|
-
zigbeeHerdsmanConverters.findByModel('014G2461'),
|
|
9
|
-
zigbeeHerdsmanConverters.findByModel('SPZB0001'),
|
|
10
|
-
zigbeeHerdsmanConverters.findByModel('ZK03840')
|
|
11
|
-
];
|
|
6
|
+
const forcedConfigureOnEachStart = ['V3-BTZB','014G2461','SPZB0001','ZK03840'];
|
|
12
7
|
|
|
13
8
|
class DeviceConfigure extends BaseExtension {
|
|
14
9
|
constructor(zigbee, options) {
|
|
15
10
|
super(zigbee, options);
|
|
16
11
|
|
|
12
|
+
this.delayedConfigure = {};
|
|
13
|
+
|
|
17
14
|
this.configuring = new Set();
|
|
18
15
|
this.attempts = {};
|
|
19
16
|
this.name = 'DeviceConfigure';
|
|
@@ -35,9 +32,36 @@ class DeviceConfigure extends BaseExtension {
|
|
|
35
32
|
return false;
|
|
36
33
|
}
|
|
37
34
|
|
|
38
|
-
return device.interviewing !== true;
|
|
35
|
+
return (device.interviewing !== true && this.checkDelayedConfigure(device.ieeeAddr)>0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
checkDelayedConfigure(device, num) {
|
|
39
|
+
if (!this.delayedConfigure.hasOwnProperty(device.ieeeAddr)) {
|
|
40
|
+
if (num && num > 0) {
|
|
41
|
+
this.delayedConfigure[device.ieeeAddr] = { maxAttempts:num };
|
|
42
|
+
return num;
|
|
43
|
+
}
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
const dc = this.delayedConfigure[device.ieeeAddr];
|
|
47
|
+
dc.maxAttempts--;
|
|
48
|
+
if (dc.maxAttempts > 0) return dc.maxAttempts;
|
|
49
|
+
if (num && num > 0) {
|
|
50
|
+
dc.maxAttempts = num;
|
|
51
|
+
return num;
|
|
52
|
+
}
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
delayedConfigureAttempt(device, status) {
|
|
57
|
+
if (status) {
|
|
58
|
+
delete this.delayedConfigure[device.ieeeAddr];
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
return this.checkDelayedConfigure(device, 10);
|
|
39
62
|
}
|
|
40
63
|
|
|
64
|
+
|
|
41
65
|
async onZigbeeStarted() {
|
|
42
66
|
try {
|
|
43
67
|
this.coordinatorEndpoint = await this.zigbee.getDevicesByType('Coordinator')[0].endpoints[0];
|
|
@@ -58,7 +82,7 @@ class DeviceConfigure extends BaseExtension {
|
|
|
58
82
|
}
|
|
59
83
|
} catch (error) {
|
|
60
84
|
this.sendError(error);
|
|
61
|
-
this.error(`Failed to DeviceConfigure.onZigbeeStarted (${error.
|
|
85
|
+
this.error(`Failed to DeviceConfigure.onZigbeeStarted (${error && error.message ? error.message : 'no error message'})`);
|
|
62
86
|
}
|
|
63
87
|
}
|
|
64
88
|
|
|
@@ -70,7 +94,7 @@ class DeviceConfigure extends BaseExtension {
|
|
|
70
94
|
}
|
|
71
95
|
} catch (error) {
|
|
72
96
|
this.sendError(error);
|
|
73
|
-
this.error(`Failed to DeviceConfigure.onZigbeeEvent (${error.
|
|
97
|
+
this.error(`Failed to DeviceConfigure.onZigbeeEvent (${error && error.message ? error.message : 'no error message'})`);
|
|
74
98
|
}
|
|
75
99
|
}
|
|
76
100
|
|
|
@@ -85,7 +109,7 @@ class DeviceConfigure extends BaseExtension {
|
|
|
85
109
|
}
|
|
86
110
|
} catch (error) {
|
|
87
111
|
this.sendError(error);
|
|
88
|
-
this.error(`Failed to DeviceConfigure.onDeviceRemove (${error.
|
|
112
|
+
this.error(`Failed to DeviceConfigure.onDeviceRemove (${error && error.message ? error.message : 'no error message'})`);
|
|
89
113
|
}
|
|
90
114
|
}
|
|
91
115
|
|
|
@@ -100,23 +124,11 @@ class DeviceConfigure extends BaseExtension {
|
|
|
100
124
|
async configure(device, mappedDevice) {
|
|
101
125
|
try {
|
|
102
126
|
if (mappedDevice !== undefined && device !== undefined) {
|
|
103
|
-
if (this.configuring.has(device.ieeeAddr) || this.attempts[device.ieeeAddr] >= 5) {
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
this.configuring.add(device.ieeeAddr);
|
|
108
|
-
|
|
109
|
-
if (!this.attempts.hasOwnProperty(device.ieeeAddr)) {
|
|
110
|
-
this.attempts[device.ieeeAddr] = 0;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
127
|
try {
|
|
114
|
-
await this.doConfigure(device, mappedDevice)
|
|
115
|
-
// this.configuring.delete(device.ieeeAddr);
|
|
128
|
+
await this.doConfigure(device, mappedDevice)
|
|
116
129
|
} catch (error) {
|
|
117
130
|
this.sendError(error);
|
|
118
|
-
this.warn(`DeviceConfigure failed ${device.ieeeAddr} ${device.modelID}
|
|
119
|
-
this.attempts[device.ieeeAddr]++;
|
|
131
|
+
this.warn(`DeviceConfigure failed ${device.ieeeAddr} ${device.modelID}`);
|
|
120
132
|
}
|
|
121
133
|
}
|
|
122
134
|
} catch (error) {
|
|
@@ -130,23 +142,38 @@ class DeviceConfigure extends BaseExtension {
|
|
|
130
142
|
try {
|
|
131
143
|
if (mappedDevice) {
|
|
132
144
|
this.info(`-> Configuring ${device.ieeeAddr} ${device.modelID}`);
|
|
145
|
+
const promises = [];
|
|
146
|
+
promises.push(mappedDevice.configure);
|
|
147
|
+
await Promise.all(promises.map(callback => callback(device, coordinatorEndpoint, mappedDevice)))
|
|
133
148
|
|
|
134
|
-
await mappedDevice.configure(device, coordinatorEndpoint, this);
|
|
149
|
+
//await mappedDevice.configure(device, coordinatorEndpoint, this);
|
|
135
150
|
|
|
136
151
|
device.meta.configured = zigbeeHerdsmanConverters.getConfigureKey(mappedDevice);
|
|
137
152
|
device.save();
|
|
138
153
|
this.info(`DeviceConfigure successful ${device.ieeeAddr} ${device.modelID}`);
|
|
154
|
+
this.delayedConfigureAttempt(device, true);
|
|
155
|
+
return '';
|
|
139
156
|
}
|
|
140
157
|
} catch (error) {
|
|
141
158
|
// https://github.com/Koenkk/zigbee2mqtt/issues/14857
|
|
142
159
|
if (error.stack.includes('UNSUPPORTED_ATTRIBUTE')) {
|
|
143
160
|
// do nothing
|
|
144
161
|
} else {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
162
|
+
if (error && error.message && error.message.match(/(\d+)ms/gm)) {
|
|
163
|
+
// timeout message - we do want to start the configure chain
|
|
164
|
+
const num = this.delayedConfigureAttempt(device, false);
|
|
165
|
+
this.info(`Delayed configure for ${device.ieeeAddr} ${device.modelID}: ${num} attempts remaining`)
|
|
166
|
+
return `Delayed configure for ${device.ieeeAddr} ${device.modelID}: ${num} attempts remaining`;
|
|
167
|
+
} else {
|
|
168
|
+
this.sendError(error);
|
|
169
|
+
this.warn(`${device.ieeeAddr} ${device.modelID} Failed to configure. --> ${error && error.message ? error.message : ' no error message given'} `);
|
|
170
|
+
return `${device.ieeeAddr} ${device.modelID} Failed to configure. --> ${error && error.message ? error.message : ' no error message given'} `
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
148
174
|
}
|
|
149
175
|
}
|
|
176
|
+
return 'no return value specified';
|
|
150
177
|
}
|
|
151
178
|
}
|
|
152
179
|
|
package/lib/zigbeecontroller.js
CHANGED
|
@@ -73,6 +73,17 @@ class ZigbeeController extends EventEmitter {
|
|
|
73
73
|
new DelayedActionExt(this, {}),
|
|
74
74
|
];
|
|
75
75
|
this.herdsmanTimeoutRegexp = new RegExp(/(\d+)ms/);
|
|
76
|
+
this.herdsmanLogSettings = {}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
ByteArrayToString(data) {
|
|
81
|
+
return data.map(function (x) {
|
|
82
|
+
x = x + 0x100 + 1; // twos complement
|
|
83
|
+
x = x.toString(16); // to hex
|
|
84
|
+
x = ('00'+x).substr(-2); // zero-pad to 8-digits
|
|
85
|
+
return x
|
|
86
|
+
}).join('');
|
|
76
87
|
}
|
|
77
88
|
|
|
78
89
|
configure(options) {
|
|
@@ -110,8 +121,9 @@ class ZigbeeController extends EventEmitter {
|
|
|
110
121
|
}
|
|
111
122
|
this.disableLed = options.disableLed;
|
|
112
123
|
this.warnOnDeviceAnnouncement = options.warnOnDeviceAnnouncement;
|
|
113
|
-
|
|
114
|
-
this.
|
|
124
|
+
this.herdsmanLogSettings.panID = herdsmanSettings.network.panID;
|
|
125
|
+
this.herdsmanLogSettings.channel = herdsmanSettings.network.channelList[0];
|
|
126
|
+
this.herdsmanLogSettings.extendedPanID = this.ByteArrayToString(herdsmanSettings.network.extendedPanID);
|
|
115
127
|
this.herdsman = new ZigbeeHerdsman.Controller(herdsmanSettings, this.adapter.log);
|
|
116
128
|
this.callExtensionMethod('setOptions', [{
|
|
117
129
|
disableActivePing: options.disablePing,
|
|
@@ -136,11 +148,10 @@ class ZigbeeController extends EventEmitter {
|
|
|
136
148
|
this.herdsman.on('message', this.handleMessage.bind(this));
|
|
137
149
|
this.herdsman.on('permitJoinChanged', this.handlePermitJoinChanged.bind(this));
|
|
138
150
|
|
|
151
|
+
this.info('Starting Zigbee-Herdsman');
|
|
139
152
|
await this.herdsman.start();
|
|
140
|
-
|
|
141
|
-
this.debug('zigbee-herdsman started');
|
|
142
153
|
this.herdsmanStarted = true;
|
|
143
|
-
this.info(`Coordinator firmware version: ${JSON.stringify(await this.herdsman.getCoordinatorVersion())}`);
|
|
154
|
+
this.info(`Zigbee-Herdsman started successfully with Coordinator firmware version: ${JSON.stringify(await this.herdsman.getCoordinatorVersion())}`);
|
|
144
155
|
|
|
145
156
|
// debug info from herdsman getNetworkParameters
|
|
146
157
|
const debNetworkParam = JSON.parse(JSON.stringify(await this.herdsman.getNetworkParameters()));
|
|
@@ -152,14 +163,29 @@ class ZigbeeController extends EventEmitter {
|
|
|
152
163
|
extPanIDDebug += extendedPanIDDebug[i];
|
|
153
164
|
i--;
|
|
154
165
|
}
|
|
155
|
-
|
|
156
|
-
this.info(`Zigbee network parameters: panID=${debNetworkParam.panID} channel=${debNetworkParam.channel} extendedPanID=${extPanIDDebug}`);
|
|
166
|
+
this.debug(`Network parameters: panID=${debNetworkParam.panID} channel=${debNetworkParam.channel} extendedPanID=${extPanIDDebug}`);
|
|
157
167
|
} catch (e) {
|
|
168
|
+
try {
|
|
169
|
+
const debNetworkParam = JSON.parse(JSON.stringify(await this.herdsman.getNetworkParameters()));
|
|
170
|
+
const extendedPanIDDebug = typeof debNetworkParam.extendedPanID === 'string' ? debNetworkParam.extendedPanID.replace('0x', '') : debNetworkParam.extendedPanID;
|
|
171
|
+
|
|
172
|
+
let extPanIDDebug = '';
|
|
173
|
+
for (let i = extendedPanIDDebug.length - 1; i >= 0; i--) {
|
|
174
|
+
extPanIDDebug += extendedPanIDDebug[i - 1];
|
|
175
|
+
extPanIDDebug += extendedPanIDDebug[i];
|
|
176
|
+
i--;
|
|
177
|
+
}
|
|
178
|
+
this.warn(`Network parameters in Config : panID=${this.herdsmanLogSettings.panID} channel=${this.herdsmanLogSettings.channel} extendedPanID=${this.herdsmanLogSettings.extendedPanID}`)
|
|
179
|
+
this.warn(`Network parameters on Coordinator: panID=${debNetworkParam.panID} channel=${debNetworkParam.channel} extendedPanID=${extPanIDDebug}`);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
this.warn(`Unable to obtain herdsman settings`)
|
|
183
|
+
}
|
|
158
184
|
try {
|
|
159
185
|
await this.herdsman.stop();
|
|
160
186
|
}
|
|
161
187
|
catch (error) {
|
|
162
|
-
this.warn(
|
|
188
|
+
this.warn('unable to stop zigbee-herdsman after failed startup');
|
|
163
189
|
}
|
|
164
190
|
this.sendError(e);
|
|
165
191
|
this.error(`Starting zigbee-herdsman problem : ${(e && e.message ? e.message : 'no error message')}`);
|
|
@@ -207,18 +233,20 @@ class ZigbeeController extends EventEmitter {
|
|
|
207
233
|
}
|
|
208
234
|
|
|
209
235
|
// Call extensions
|
|
210
|
-
this.callExtensionMethod('onZigbeeStarted', []);
|
|
211
236
|
|
|
212
237
|
const deviceIterator = this.getClientIterator();
|
|
213
238
|
let deviceCount = 0;
|
|
214
239
|
try {
|
|
215
240
|
for (const device of deviceIterator) {
|
|
216
241
|
deviceCount++;
|
|
242
|
+
// get the model description for the known devices
|
|
217
243
|
const entity = await this.resolveEntity(device);
|
|
218
244
|
if (!entity) {
|
|
219
245
|
this.warn('failed to resolve Entity for ' + device.ieeeAddr);
|
|
220
246
|
continue;
|
|
221
247
|
}
|
|
248
|
+
//await this.adapter.stController.AddModelFromHerdsman(device, entity.mapped.model);
|
|
249
|
+
|
|
222
250
|
this.adapter.getObject(device.ieeeAddr.substr(2), (err, obj) => {
|
|
223
251
|
if (obj && obj.common && obj.common.deactivated) {
|
|
224
252
|
this.callExtensionMethod('deregisterDevicePing', [device, entity]);
|
|
@@ -248,6 +276,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
248
276
|
} else {
|
|
249
277
|
this.info(`Currently no devices.`);
|
|
250
278
|
}
|
|
279
|
+
this.callExtensionMethod('onZigbeeStarted', []);
|
|
251
280
|
}
|
|
252
281
|
catch (error) {
|
|
253
282
|
this.error('error iterating devices : '+ (error && error.message ? error.message: 'no reason given'));
|
package/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
*
|
|
3
3
|
* Zigbee devices adapter
|
|
4
|
-
*
|
|
4
|
+
*
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -304,6 +304,9 @@ class Zigbee extends utils.Adapter {
|
|
|
304
304
|
//fs.writeFileSync(mN+'.tmp3', modifiedCode)
|
|
305
305
|
converterLoaded &= this.SandboxRequire(sandbox,[...modifiedCode.matchAll(/import\s+\{(.+)\}\s+from\s+(\S+);/gm)]);
|
|
306
306
|
modifiedCode = modifiedCode.replace(/import\s+\{.+\}\s+from\s+\S+;/gm, '');
|
|
307
|
+
|
|
308
|
+
converterLoaded &= this.SandboxRequire(sandbox,[...modifiedCode.matchAll(/import\s+(.+)\s+from\s+(\S+);/gm)]);
|
|
309
|
+
modifiedCode = modifiedCode.replace(/import\s+.+\s+from\s+\S+;/gm, '');
|
|
307
310
|
//fs.writeFileSync(mN+'.tmp4', modifiedCode)
|
|
308
311
|
converterLoaded &= this.SandboxRequire(sandbox,[...modifiedCode.matchAll(/const\s+\{(.+)\}\s+=\s+require\((.+)\)/gm)]);
|
|
309
312
|
modifiedCode = modifiedCode.replace(/const\s+\{.+\}\s+=\s+require\(.+\)/gm, '');
|
|
@@ -312,7 +315,12 @@ class Zigbee extends utils.Adapter {
|
|
|
312
315
|
modifiedCode = modifiedCode.replace(/const\s+\S+\s+=\s+require\(.+\)/gm, '');
|
|
313
316
|
//fs.writeFileSync(mN+'.tmp6', modifiedCode)
|
|
314
317
|
|
|
315
|
-
|
|
318
|
+
for(const component of modifiedCode.matchAll(/const (.+):(.+)=/gm)) {
|
|
319
|
+
modifiedCode = modifiedCode.replace(component[0], `const ${component[1]} = `);
|
|
320
|
+
}
|
|
321
|
+
modifiedCode = modifiedCode.replace(/export .+;/gm, '');
|
|
322
|
+
|
|
323
|
+
fs.writeFileSync(mN+'.tmp', modifiedCode)
|
|
316
324
|
|
|
317
325
|
if (converterLoaded) {
|
|
318
326
|
try {
|
|
@@ -345,10 +353,27 @@ class Zigbee extends utils.Adapter {
|
|
|
345
353
|
const toAdd = {...definition};
|
|
346
354
|
delete toAdd['homeassistant'];
|
|
347
355
|
try {
|
|
348
|
-
zigbeeHerdsmanConverters.
|
|
356
|
+
if (zigbeeHerdsmanConverters.hasOwnProperty('addExternalDefinition')) {
|
|
357
|
+
zigbeeHerdsmanConverters.addExternalDefinition(toAdd);
|
|
358
|
+
this.log.info('added external converter using addExternalDefinition')
|
|
359
|
+
}
|
|
360
|
+
else if (zigbeeHerdsmanConverters.hasOwnProperty('addDefinition')) {
|
|
361
|
+
zigbeeHerdsmanConverters.addDefinition(toAdd);
|
|
362
|
+
this.log.info('added external converter using addDefinition')
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/*
|
|
366
|
+
for (const zigbeeModel of toAdd.zigbeeModel)
|
|
367
|
+
{
|
|
368
|
+
try {
|
|
369
|
+
zigbeeHerdsmanConverters.addToExternalDefinitionsLookup(zigbeeModel, toAdd.toAdd);
|
|
370
|
+
} catch (e) {
|
|
371
|
+
this.log.error(`unable to apply external converter ${JSON.stringify(toAdd)} for device ${zigbeeModel}: ${e && e.message ? e.message : 'no error message available'}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
*/
|
|
349
375
|
} catch (e) {
|
|
350
|
-
this.log.error(`unable to apply external converter ${JSON.stringify(toAdd)}`);
|
|
351
|
-
this.log.error(`${e}`);
|
|
376
|
+
this.log.error(`unable to apply external converter for ${JSON.stringify(toAdd.model)}: ${e && e.message ? e.message : 'no error message available'}`);
|
|
352
377
|
}
|
|
353
378
|
}
|
|
354
379
|
}
|
|
@@ -359,15 +384,15 @@ class Zigbee extends utils.Adapter {
|
|
|
359
384
|
const DebugIdentify = require('./debugidentify');
|
|
360
385
|
debugversion = DebugIdentify.ReportIdentifier();
|
|
361
386
|
} catch {
|
|
362
|
-
debugversion = '
|
|
387
|
+
debugversion = 'npm ...';
|
|
363
388
|
}
|
|
364
389
|
|
|
365
390
|
// installed version
|
|
366
391
|
let gitVers = '';
|
|
367
392
|
try {
|
|
368
|
-
this.log.info(`Starting
|
|
393
|
+
this.log.info(`Starting Adapter ${debugversion}`);
|
|
369
394
|
|
|
370
|
-
|
|
395
|
+
this.getForeignObject(`system.adapter.${this.namespace}`,async (err, obj) => {
|
|
371
396
|
if (!err && obj && obj.common.installedFrom && obj.common.installedFrom.includes('://')) {
|
|
372
397
|
const instFrom = obj.common.installedFrom;
|
|
373
398
|
gitVers = gitVers + instFrom.replace('tarball', 'commit');
|
|
@@ -375,9 +400,9 @@ class Zigbee extends utils.Adapter {
|
|
|
375
400
|
gitVers = obj.common.installedFrom;
|
|
376
401
|
}
|
|
377
402
|
this.log.info(`Installed Version: ${gitVers} (Converters ${zigbeeHerdsmanConvertersPackage.version} Herdsman ${zigbeeHerdsmanPackage.version})`);
|
|
403
|
+
await this.zbController.start();
|
|
378
404
|
});
|
|
379
405
|
|
|
380
|
-
await this.zbController.start();
|
|
381
406
|
} catch (error) {
|
|
382
407
|
this.setState('info.connection', false, true);
|
|
383
408
|
this.log.error(`Failed to start Zigbee`);
|
|
@@ -434,7 +459,7 @@ class Zigbee extends utils.Adapter {
|
|
|
434
459
|
const configExtPanId = this.config.extPanID ? `0x${this.config.extPanID.toLowerCase()}` : '0xdddddddddddddddd';
|
|
435
460
|
let networkExtPanId = (await this.zbController.herdsman.getNetworkParameters()).extendedPanID;
|
|
436
461
|
let needChange = false;
|
|
437
|
-
this.log.
|
|
462
|
+
this.log.info(`Config value ${configExtPanId} : Network value ${networkExtPanId}`);
|
|
438
463
|
const adapterType = this.config.adapterType || 'zstack';
|
|
439
464
|
if (adapterType === 'zstack') {
|
|
440
465
|
if (configExtPanId !== networkExtPanId) {
|
|
@@ -480,16 +505,17 @@ class Zigbee extends utils.Adapter {
|
|
|
480
505
|
}
|
|
481
506
|
|
|
482
507
|
await this.setState('info.connection', true, true);
|
|
483
|
-
|
|
484
|
-
const devicesFromDB = this.zbController.getClientIterator(false);
|
|
485
508
|
this.stController.CleanupRequired(false);
|
|
509
|
+
const devicesFromDB = this.zbController.getClientIterator(false);
|
|
486
510
|
for (const device of devicesFromDB) {
|
|
487
511
|
const entity = await this.zbController.resolveEntity(device);
|
|
488
512
|
if (entity) {
|
|
513
|
+
// this.log.warn('sync dev states for ' + (entity.mapped ? entity.mapped.model : entity.device.modelID));
|
|
489
514
|
const model = entity.mapped ? entity.mapped.model : entity.device.modelID;
|
|
490
515
|
this.stController.updateDev(device.ieeeAddr.substr(2), model, model, () =>
|
|
491
516
|
this.stController.syncDevStates(device, model));
|
|
492
517
|
}
|
|
518
|
+
else (this.log.warn('resolveEntity returned no entity'));
|
|
493
519
|
}
|
|
494
520
|
await this.callPluginMethod('start', [this.zbController, this.stController]);
|
|
495
521
|
}
|
|
@@ -1023,6 +1049,7 @@ class Zigbee extends utils.Adapter {
|
|
|
1023
1049
|
|
|
1024
1050
|
newDevice(entity) {
|
|
1025
1051
|
this.log.debug(`New device event: ${safeJsonStringify(entity)}`);
|
|
1052
|
+
this.stController.AddModelFromHerdsman(entity.device, entity.mapped.model)
|
|
1026
1053
|
const dev = entity.device;
|
|
1027
1054
|
if (dev) {
|
|
1028
1055
|
this.getObject(dev.ieeeAddr.substr(2), (err, obj) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.zigbee",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Kirov Ilya",
|
|
6
6
|
"email": "kirovilya@gmail.com"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"ajv": "^8.17.1",
|
|
29
29
|
"uri-js": "^4.4.1",
|
|
30
30
|
"typescript": "^5.6.3",
|
|
31
|
-
"zigbee-herdsman": "3.2.
|
|
31
|
+
"zigbee-herdsman": "3.2.7",
|
|
32
32
|
"zigbee-herdsman-converters": "21.38.0"
|
|
33
33
|
},
|
|
34
34
|
"description": "Zigbee devices",
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
"chai-as-promised": "^7.1.1",
|
|
43
43
|
"eslint": "^9.19.0",
|
|
44
44
|
"eslint-config-prettier": "^9.1.0",
|
|
45
|
-
"eslint-plugin-prettier": "^5.2.
|
|
45
|
+
"eslint-plugin-prettier": "^5.2.3",
|
|
46
46
|
"gulp": "^4.0.2",
|
|
47
47
|
"gulp-jsdoc3": "^3.0.0",
|
|
48
48
|
"gulp-replace": "^1.1.4",
|
|
49
49
|
"mixin-deep": "^2.0.1",
|
|
50
|
-
"mocha": "^
|
|
50
|
+
"mocha": "^11.1.0"
|
|
51
51
|
},
|
|
52
52
|
"homepage": "https://github.com/ioBroker/ioBroker.zigbee",
|
|
53
53
|
"keywords": [
|