Compare commits

...
158 Commits
Author SHA1 Message Date
Koen Kanters f2e39af12c 1.18.3 2021-05-01 14:52:07 +02:00
Koen Kanters 111d4d70bd Undev 2021-05-01 14:52:01 +02:00
github-actions[bot]andKoenkk fae2e4851c Update zigbee-herdsman-converters to 14.0.131 (#7276)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-05-01 14:15:31 +02:00
43ff2daebe Update zigbee-herdsman-converters to 14.0.129 (#7275)
* Update zigbee-herdsman-converters to 14.0.129

* Update homeassistant.test.js

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-05-01 13:56:44 +02:00
github-actions[bot]andnurikk 19373d815f Update zigbee2mqtt-frontend to 0.4.0 (#7271)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-05-01 11:35:36 +08:00
Koen Kanters e9a5ec1a58 Revert "Home Assistant: remove attributes from discovered entities. https://github.com/Koenkk/zigbee2mqtt/discussions/7249"
This reverts commit 54ab0a3f98.
2021-04-30 16:41:18 +02:00
Koen Kanters ec97931ee4 Home Assistant: don't counter action: null payload. 2021-04-30 16:41:00 +02:00
github-actions[bot]andnurikk 20c0712aba Update zigbee2mqtt-frontend to 0.3.121 (#7247)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-04-30 09:15:36 +08:00
github-actions[bot]andKoenkk 2e5e5beb83 Update zigbee-herdsman-converters to 14.0.128 (#7251)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-29 20:03:24 +02:00
Koen Kanters 54ab0a3f98 Home Assistant: remove attributes from discovered entities. https://github.com/Koenkk/zigbee2mqtt/discussions/7249 2021-04-29 19:43:54 +02:00
Koen Kanters d61d6e28f2 Only attempt to configure end device when message is received from it. (#7242) 2021-04-29 18:18:51 +02:00
ssierglandKoen Kanters 1d8b37eee0 Properly handle SIGTERM and other kernel events (#7230)
* Properly handle SIGTERM and other kernel events

see

https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md#handling-kernel-signals

* Update Dockerfile

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-04-29 18:13:41 +02:00
github-actions[bot]andKoenkk 2b488ccff4 Update zigbee-herdsman-converters to 14.0.127 (#7241)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-28 20:06:27 +02:00
cedbd1fd4c Update zigbee-herdsman-converters to 14.0.126 (#7240)
* Update zigbee-herdsman-converters to 14.0.126

* Update bind.js

* Update networkMap.test.js

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-04-28 19:48:08 +02:00
Koen Kanters f27e5efe0f Fix Home Assistant "KeyError: 'color_mode'" for brightness only lights. https://github.com/Koenkk/zigbee2mqtt/issues/7220 2021-04-28 19:10:39 +02:00
github-actions[bot]andKoenkk 7eeaeafbd0 Update zigbee-herdsman-converters to 14.0.125 (#7221)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-27 16:27:58 +02:00
github-actions[bot]andKoenkk e4d868652a Update zigbee-herdsman-converters to 14.0.124 (#7216)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-26 21:42:48 +02:00
71d77ac27c Update zigbee-herdsman-converters to 14.0.121 (#7213)
* Update zigbee-herdsman-converters to 14.0.121

* Update bridge.test.js

* Update bridge.test.js

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-04-26 16:34:08 +02:00
github-actions[bot]andKoenkk 1f80a05477 Update zigbee-herdsman to 0.13.92 (#7211)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-26 11:35:25 +02:00
github-actions[bot]andKoenkk a02c8d242a Update zigbee-herdsman-converters to 14.0.120 (#7205)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-25 19:26:15 +02:00
daxy01andKoen Kanters edc18e3376 Add log_symlink_current option (#7166)
* Update logger.js

Adding a symlink from "log/<timestamp>" to "log/current" to be able to always view the last logfile using "log/current/log.txt".

* Update logger.js

* Update logger.js

Create directory first to prevent startup failure

* Update logger.js

Fixing check on startup

* Update settings.js

* Update logger.js

* Update settings.schema.json

* Update bridge.test.js

* Update logger.test.js

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-04-25 19:21:38 +02:00
github-actions[bot]andKoenkk 1f797e5e3a Update zigbee-herdsman-converters to 14.0.119 (#7204)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-25 18:55:26 +02:00
Koen Kanters aee4e96619 Attempt to fix https://github.com/Koenkk/zigbee2mqtt/issues/7198 2021-04-25 15:27:40 +02:00
Koen Kanters 7631c191c5 Home Assistant discovery: add color_mode for lights (#7057)
* Home Assistant add color_mode.

* Fix tests

* Fix coverage
2021-04-25 14:56:59 +02:00
github-actions[bot]andKoenkk 8802354ca9 Update dependencies (#7199)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-25 14:30:39 +02:00
github-actions[bot]andKoenkk 627b94e5ab Update zigbee-herdsman-converters to 14.0.118 (#7192)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-24 18:56:42 +02:00
github-actions[bot]andnurikk 8ed842603c Update zigbee2mqtt-frontend to 0.3.120 (#7190)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-04-24 21:58:41 +08:00
github-actions[bot]andKoenkk 6904020f7d Update zigbee-herdsman-converters to 14.0.117 (#7182)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-23 20:44:47 +02:00
d3fd3bcacc Update zigbee-herdsman-converters to 14.0.116 (#7169)
* Fix state of members from group incorrect when toZigbee converter reads a member state. #7038

* Update zigbee-herdsman-converters to 14.0.116

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-22 20:34:13 +02:00
Koen Kanters 366c5fcb4d Fix state of members from group incorrect when toZigbee converter reads a member state. #7038 2021-04-22 20:28:54 +02:00
Koen Kanters 2c44f4ede9 Test case for #7106 2021-04-22 19:20:03 +02:00
Koen Kanters 3f0ef8e08f Improve utils.getObjectProperty() 2021-04-22 19:19:17 +02:00
github-actions[bot]andKoenkk 01af249e95 Update zigbee-herdsman-converters to 14.0.115 (#7162)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-21 19:56:15 +02:00
github-actions[bot]andKoenkk a1e6439a5c Update zigbee-herdsman-converters to 14.0.114 (#7148)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-20 18:42:49 +02:00
github-actions[bot]andKoenkk ba305ad18b Update zigbee-herdsman-converters to 14.0.113 (#7134)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-19 20:17:37 +02:00
pklokke 95dd6c485c Support binding of server clusters towards clients (#7127)
This allows binding of devices such as sleepy temperature sensors to heating actuators
2021-04-19 20:16:31 +02:00
github-actions[bot]andKoenkk dbfdbcba4a Update zigbee-herdsman to 0.13.91 (#7122)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-18 20:43:42 +02:00
github-actions[bot]andKoenkk 14cc33cd44 Update zigbee-herdsman-converters to 14.0.112 (#7121)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-18 20:32:21 +02:00
xyzroeandKoen Kanters 9a53b954f8 Add wifi endpoint name (#7103)
* Update utils.js

added endpointNames wifi, ds, bme
wifi for future devices
ds and bme are using in DIYRuZ_Flower

* Update utils.js

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-04-18 20:25:18 +02:00
github-actions[bot]andKoenkk 615026984c Update dependencies (#7110)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-18 19:40:27 +02:00
github-actions[bot]andKoenkk bd660dee82 Update zigbee-herdsman-converters to 14.0.111 (#7105)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-17 16:13:09 +02:00
HeddaandKoen Kanters 75dc72550f Add 57600 as another common baud rate speed example (#7094)
* Add 57600 as another common board date example

Add 57600 as another common board date example to avoid confusions like in https://github.com/Koenkk/zigbee-herdsman/issues/319

* Spelling and grammar

Spelling and grammar

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-04-17 14:45:48 +02:00
github-actions[bot]andKoenkk c7443191ff Update zigbee-herdsman-converters to 14.0.110 (#7089)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-15 17:27:08 +02:00
Koen Kanters dff4af94f5 Home Assistant: fix device_automation not published when homeassistant is in device options. https://github.com/Koenkk/zigbee2mqtt/issues/7074 2021-04-14 20:22:26 +02:00
github-actions[bot]andKoenkk a1fc606d99 Update zigbee-herdsman to 0.13.90 (#7076)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-14 16:48:24 +02:00
github-actions[bot]andKoenkk 89ceaac3d1 Update zigbee-herdsman-converters to 14.0.109 (#7072)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-13 21:05:43 +02:00
Koen Kanters 8df8ef629e Fix state of group not changing when state of specific endpoint is changed. https://github.com/Koenkk/zigbee2mqtt/issues/6905 2021-04-13 20:20:44 +02:00
Koen Kanters 07262bd62f Fix device option set to null instead of removed when sending null. https://github.com/nurikk/z2m-frontend/issues/430 2021-04-12 19:49:21 +02:00
Koen Kanters 5963f3b7f4 Home Assistant: set unknown values to null (#7032) 2021-04-12 16:59:41 +02:00
github-actions[bot]andKoenkk 7e861aa3bb Update zigbee-herdsman-converters to 14.0.108 (#7047)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-11 17:54:23 +02:00
github-actions[bot]andKoenkk a4da036266 Update dependencies (#7040)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-11 13:04:15 +02:00
Koen Kanters 487ab0648d Improve logging 2021-04-10 18:51:13 +02:00
github-actions[bot]andKoenkk e91a23b3ed Update zigbee-herdsman-converters to 14.0.107 (#7022)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-09 22:33:05 +02:00
ptvoandptvoinfo d5d16d1616 Update schema with the Icon device property. (#7018)
* Device-specific icon

* Updated tests.

* Updated test

* Updated tests

* Updated tests.

* Updated tests

* Update schema with the Icon device property.

* Fix

Co-authored-by: ptvoinfo <xagga@ya.ru>
2021-04-09 20:52:41 +08:00
ptvoandptvoinfo e81ac11466 Allow to redefine device icon (#7013)
* Device-specific icon

* Updated tests.

* Updated test

* Updated tests

* Updated tests.

* Updated tests

Co-authored-by: ptvoinfo <xagga@ya.ru>
2021-04-09 19:35:44 +08:00
github-actions[bot]andKoenkk 93c0a8a7ba Update zigbee-herdsman-converters to 14.0.106 (#7003)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-08 21:00:02 +02:00
John Doe 42a4596be6 Add device icon from converter definition (#7001) 2021-04-08 22:57:55 +08:00
github-actions[bot]andnurikk 53772e5536 Update zigbee2mqtt-frontend to 0.3.119 (#6998)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-04-08 21:57:42 +08:00
github-actions[bot]andKoenkk 2446e173b6 Update zigbee-herdsman-converters to 14.0.105 (#6990)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-07 19:28:18 +02:00
Koen Kanters 30efb3e824 Fix "Cannot read property 'ID' of undefined". https://github.com/Koenkk/zigbee2mqtt/issues/6981 2021-04-07 18:39:54 +02:00
ab0ae8ce91 Update zigbee-herdsman-converters to 14.0.104 (#6975)
* Update zigbee-herdsman-converters to 14.0.104

* Update bridge.test.js

* Update otaUpdate.test.js

* Update zigbeeHerdsman.js

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-04-06 22:24:30 +02:00
github-actions[bot]andKoenkk 172689976e Update zigbee-herdsman-converters to 14.0.103 (#6968)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-05 21:06:24 +02:00
Koen Kanters bf47282ea7 Fix optimistic group state property not postfixed with endpoint name when necessary. https://github.com/Koenkk/zigbee2mqtt/issues/6905 2021-04-04 21:00:24 +02:00
github-actions[bot]andnurikk ec8348854b Update zigbee2mqtt-frontend to 0.3.118 (#6952)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-04-04 17:24:22 +08:00
github-actions[bot]andKoenkk 348c562f97 Update zigbee-herdsman to 0.13.89 (#6953)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-04 10:45:20 +02:00
github-actions[bot]andKoenkk 92bd2166e3 Update dependencies (#6948)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-04-04 10:35:29 +02:00
github-actions[bot]andnurikk d6a1d2deb5 Update zigbee2mqtt-frontend to 0.3.115 (#6938)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-04-03 15:54:29 +08:00
Koen Kanters f98d71ba6e Promote to dev 2021-04-01 09:08:03 +02:00
Koen Kanters abd8a09264 1.18.2 2021-04-01 09:07:24 +02:00
Koen Kanters 9bfbd25bd8 Remove -dev 2021-04-01 09:07:21 +02:00
Koen Kanters afc2b2ea95 Merge branch 'dev' 2021-04-01 09:06:39 +02:00
6bf27b9976 Update zigbee-herdsman-converters to 14.0.102 (#6903)
* Update zigbee-herdsman-converters to 14.0.102

* Update publish.test.js

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-03-31 18:30:08 +02:00
github-actions[bot]andKoenkk 29c8a179e3 Update zigbee-herdsman-converters to 14.0.101 (#6888)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-30 19:36:23 +02:00
github-actions[bot]andKoenkk be906fec76 Update zigbee-herdsman to 0.13.88 (#6882)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-30 17:52:09 +02:00
github-actions[bot]andnurikk 9aacf32ac7 Update zigbee2mqtt-frontend to 0.3.114 (#6880)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-30 16:36:00 +08:00
github-actions[bot]andKoenkk 010a140835 Update zigbee-herdsman-converters to 14.0.100 (#6875)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-29 21:17:29 +02:00
Koen Kanters 0b72de7056 Log FAQ on failed to start Zigbee 2021-03-29 20:15:47 +02:00
github-actions[bot]andKoenkk ddbfa02d5c Update zigbee-herdsman-converters to 14.0.99 (#6860)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-28 13:45:45 +02:00
github-actions[bot]andKoenkk cd563bffd5 Update dependencies (#6857)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-28 13:13:00 +02:00
github-actions[bot]andKoenkk 306e1b6391 Update zigbee-herdsman-converters to 14.0.98 (#6855)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-27 20:09:50 +01:00
github-actions[bot]andKoenkk f8f79d3d18 Update zigbee-herdsman to 0.13.87 (#6850)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-26 21:56:11 +01:00
github-actions[bot]andKoenkk 58bc53683d Update zigbee-herdsman-converters to 14.0.97 (#6846)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-26 21:21:51 +01:00
github-actions[bot]andKoenkk 41a4dea208 Update zigbee-herdsman to 0.13.86 (#6843)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-26 18:50:42 +01:00
github-actions[bot]andKoenkk e56f6b602e Update zigbee-herdsman-converters to 14.0.96 (#6830)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-25 19:42:32 +01:00
github-actions[bot]andKoenkk fda0270343 Update zigbee-herdsman-converters to 14.0.95 (#6821)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-24 19:23:13 +01:00
0493cf60da Fix no transaction in group and bind responses (#6810)
* Fix no transaction property in /group/members response

* Update groups.js

* Update group.test.js

* Update bind.js

* Update bind.test.js

Co-authored-by: Guillaume COURTOIS <guillaume.courtois@victeon.fr>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-03-24 19:17:49 +01:00
github-actions[bot]andKoenkk 98b98ddf8f Update zigbee-herdsman to 0.13.85 (#6820)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-24 19:16:36 +01:00
github-actions[bot]andnurikk 171e87d6ba Update zigbee2mqtt-frontend to 0.3.113 (#6819)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-24 15:56:21 +00:00
github-actions[bot]andnurikk 6d19579a70 Update zigbee2mqtt-frontend to 0.3.111 (#6795)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-23 22:42:14 +00:00
766ab452cc Update zigbee-herdsman-converters to 14.0.94 (#6806)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-03-23 19:13:16 +01:00
github-actions[bot]andKoenkk add5179fc8 Update zigbee-herdsman to 0.13.84 (#6805)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-23 19:08:29 +01:00
github-actions[bot]andKoenkk e66e2cbc04 Update zigbee-herdsman-converters to 14.0.93 (#6792)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-23 16:25:34 +01:00
github-actions[bot]andKoenkk 9c6ed20d6c Update zigbee-herdsman to 0.13.83 (#6791)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-22 20:30:40 +01:00
Koen Kanters b6085fceae Add buymeacoffee 2021-03-22 20:28:15 +01:00
Koen Kanters 326823ee00 Add permit_join_timeout to bridge/info 2021-03-22 17:03:01 +01:00
github-actions[bot]andKoenkk 4d2eaa882b Update zigbee-herdsman to 0.13.82 (#6787)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-22 17:02:06 +01:00
github-actions[bot]andKoenkk f6e7bec357 Update zigbee-herdsman-converters to 14.0.92 (#6782)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-21 21:23:16 +01:00
github-actions[bot]andKoenkk 9b1772824b Update dependencies (#6773)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-21 13:17:38 +01:00
github-actions[bot]andKoenkk 840e97edd9 Update zigbee-herdsman-converters to 14.0.91 (#6771)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-20 19:21:51 +01:00
github-actions[bot]andnurikk a2f847e370 Update zigbee2mqtt-frontend to 0.3.110 (#6768)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-20 15:13:38 +08:00
github-actions[bot]andnurikk c255625131 Update zigbee2mqtt-frontend to 0.3.109 (#6767)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-20 13:52:12 +08:00
github-actions[bot]andnurikk 5df8d1c4c0 Update zigbee2mqtt-frontend to 0.3.108 (#6766)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-20 11:40:58 +08:00
github-actions[bot]andKoenkk 04ebe253bb Update zigbee-herdsman-converters to 14.0.90 (#6764)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-19 19:36:39 +01:00
Jorge Schrauwen 3541db891d groups: also publish color_mode (#6756) 2021-03-19 17:48:56 +01:00
github-actions[bot]andKoenkk fb4f88295c Update zigbee-herdsman-converters to 14.0.89 (#6754)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-18 18:20:41 +01:00
github-actions[bot]andnurikk 8c6bb7383c Update zigbee2mqtt-frontend to 0.3.107 (#6752)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-18 23:51:39 +08:00
5a37400408 Update zigbee-herdsman-converters to 14.0.88 (#6745)
* Update zigbee-herdsman-converters to 14.0.88

* Update group.test.js

* Update publish.test.js

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-03-17 22:19:26 +01:00
Koen Kanters 1acccc002a Only publish changed properties for groups and its members. #6718 2021-03-17 21:44:29 +01:00
github-actions[bot]andKoenkk 144fdb43da Update zigbee-herdsman to 0.13.81 (#6744)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-17 20:14:06 +01:00
Franck Nijhof a17f3b1c5a Fix use of deprecated values in HA Cover platform discovery (#6544) 2021-03-17 16:48:50 +01:00
github-actions[bot]andKoenkk a9b5d5ea58 Update zigbee-herdsman-converters to 14.0.87 (#6735)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-16 20:32:33 +01:00
b85825ba4a Update zigbee-herdsman-converters to 14.0.86 (#6711)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-03-14 17:11:53 +01:00
Koen Kanters 06a14c5b20 Prepare for https://github.com/Koenkk/zigbee2mqtt/pull/6711 2021-03-14 17:09:43 +01:00
github-actions[bot]andKoenkk 1f09b853d2 Update zigbee-herdsman to 0.13.80 (#6710)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-14 16:55:02 +01:00
github-actions[bot]andKoenkk 953e0e7f12 Update dependencies (#6700)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-14 16:33:35 +01:00
github-actions[bot]andnurikk 7b54d188f4 Update zigbee2mqtt-frontend to 0.3.85 (#6703)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-14 16:33:50 +08:00
John Doe 39239d1416 Revert "Add additionalProperties to device schema (#6687)" (#6692)
This reverts commit eb930ac544.
2021-03-13 20:59:44 +08:00
github-actions[bot]andnurikk 036aab2e2e Update zigbee2mqtt-frontend to 0.3.84 (#6688)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-13 18:48:08 +08:00
John Doe eb930ac544 Add additionalProperties to device schema (#6687) 2021-03-13 11:22:23 +01:00
29343f8e9c Update zigbee-herdsman-converters to 14.0.85 (#6680)
* Update zigbee-herdsman-converters to 14.0.85

* Update bridge.test.js

* Update zigbeeHerdsman.js

* Update otaUpdate.test.js

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-03-13 10:28:48 +01:00
github-actions[bot]andnurikk 0a2466e55b Update zigbee2mqtt-frontend to 0.3.82 (#6682)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-13 16:40:25 +08:00
github-actions[bot]andnurikk 07c02f94da Update zigbee2mqtt-frontend to 0.3.81 (#6681)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-13 11:38:35 +08:00
github-actions[bot]andKoenkk f70e1b343d Update zigbee-herdsman to 0.13.79 (#6679)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-12 20:16:59 +01:00
Koen Kanters 26d4f3d70b Changes for https://github.com/Koenkk/zigbee2mqtt/pull/6669. 2021-03-11 20:11:34 +01:00
github-actions[bot]andKoenkk 581145eae2 Update zigbee-herdsman-converters to 14.0.84 (#6669)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-11 20:11:17 +01:00
github-actions[bot]andKoenkk 50cbc85da6 Update zigbee-herdsman to 0.13.78 (#6668)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-11 20:00:36 +01:00
df670a872e Update zigbee-herdsman-converters to 14.0.83 (#6659)
* Update zigbee-herdsman-converters to 14.0.83

* Update bridge.test.js

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2021-03-10 23:04:53 +01:00
github-actions[bot]andKoenkk 6163265323 Update zigbee-herdsman to 0.13.77 (#6658)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-10 22:43:47 +01:00
github-actions[bot]andKoenkk 20e60ba812 Update zigbee-herdsman-converters to 14.0.81 (#6639)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-09 20:34:58 +01:00
Koen Kanters 00c2894bb4 Reread settings on restart. https://github.com/Koenkk/zigbee2mqtt/discussions/6628 2021-03-09 19:50:05 +01:00
github-actions[bot]andKoenkk f10b0e3070 Update zigbee-herdsman-converters to 14.0.80 (#6627)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-08 19:30:33 +01:00
github-actions[bot]andnurikk ece9e03fba Update zigbee2mqtt-frontend to 0.3.80 (#6624)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-08 12:34:08 +08:00
github-actions[bot]andKoenkk 87f0408bd5 Update zigbee-herdsman-converters to 14.0.79 (#6619)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-07 17:43:30 +01:00
github-actions[bot]andKoenkk 46848cb5c9 Update dependencies (#6610)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-07 17:25:17 +01:00
John Doe 0ca834cc70 Add timer api to extensions sandbox (#6604) 2021-03-06 17:41:11 +01:00
github-actions[bot]andKoenkk 0d60ae2f58 Update zigbee-herdsman to 0.13.76 (#6605)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-06 17:40:46 +01:00
github-actions[bot]andKoenkk 2712d98871 Update zigbee-herdsman-converters to 14.0.78 (#6603)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-06 17:27:01 +01:00
Koen Kanters 377356b9c1 Fix no attribute property in configured_reportings when attribute is manufacturer specific. #6580 2021-03-06 14:51:07 +01:00
github-actions[bot]andnurikk 6fa5f75510 Update zigbee2mqtt-frontend to 0.3.79 (#6592)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-06 15:34:03 +08:00
github-actions[bot]andKoenkk 199d970947 Update zigbee-herdsman-converters to 14.0.77 (#6566)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-04 17:56:49 +01:00
Koen Kanters 42f2bd496d Merge branch 'master' into dev
# Conflicts:
#	npm-shrinkwrap.json
#	package.json
2021-03-04 17:28:52 +01:00
github-actions[bot]andKoenkk 5508b6cc60 Update zigbee-herdsman-converters to 14.0.76 (#6557)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-04 17:14:22 +01:00
github-actions[bot]andKoenkk 92a374e63c Update zigbee-herdsman to 0.13.75 (#6553)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-03 17:17:53 +01:00
Jorge Schrauwen e5a9c947aa Home Assistant does not support 'sleep' as system_mode (#6549)
But 'sleep' is a valid ZCL system_mode, so far only the Viessmann TRV supports it.
We simply drop the exposed system_mode value to not confuse homeassistent.
2021-03-03 16:59:03 +01:00
github-actions[bot]andnurikk c97fce71f7 Update zigbee2mqtt-frontend to 0.3.78 (#6546)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-03 21:25:38 +08:00
github-actions[bot]andnurikk 1a266637c5 Update zigbee2mqtt-frontend to 0.3.77 (#6545)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2021-03-03 21:14:55 +08:00
Koen Kanters a43d1f3917 1.18.1 2021-03-02 21:42:12 +01:00
Koen Kanters 8b9dfb3ee3 Fix not starting with CC2652RB. https://github.com/Koenkk/zigbee2mqtt/issues/6517 2021-03-02 21:42:02 +01:00
github-actions[bot]andKoenkk b9c69f96fd Update zigbee-herdsman to 0.13.74 (#6534)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-02 21:03:43 +01:00
Koen Kanters 5ed30eb005 Promote to dev 2021-03-02 20:42:24 +01:00
Koen Kanters 7e52087c73 Merge branch 'master' into dev 2021-03-02 20:41:40 +01:00
Koen Kanters 4100ebb670 Update update_check_interval in settings.schema.json. https://github.com/Koenkk/zigbee2mqtt/commit/fb2ab44e3e28a242ae12bbaf78864f470910dc62 2021-03-02 20:24:27 +01:00
Koen Kanters 52b8022173 Revert "Update update_check_interval in settings.schema.json. https://github.com/Koenkk/zigbee2mqtt/commit/fb2ab44e3e28a242ae12bbaf78864f470910dc62"
This reverts commit e552b76b04.
2021-03-02 20:24:10 +01:00
Ilya Kirov d77231b99f Added "ezsp" adapter to schema (#6532) 2021-03-02 19:41:56 +01:00
github-actions[bot]andKoenkk 1341973f07 Update zigbee-herdsman to 0.13.73 (#6533)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-02 19:41:38 +01:00
Koen Kanters e552b76b04 Update update_check_interval in settings.schema.json. https://github.com/Koenkk/zigbee2mqtt/commit/fb2ab44e3e28a242ae12bbaf78864f470910dc62 2021-03-02 19:31:21 +01:00
John Doe fb2ab44e3e Set default update_check_interval to 1 day (#6523) 2021-03-02 19:22:39 +01:00
github-actions[bot]andKoenkk 827f9cdcdf Update zigbee-herdsman-converters to 14.0.75 (#6510)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2021-03-01 18:58:49 +01:00
41 changed files with 1511 additions and 1012 deletions
+3 -1
View File
@@ -1,2 +1,4 @@
github: [koenkk]
custom: https://www.paypal.me/koenkk
custom:
- https://www.paypal.me/koenkk
- https://www.buymeacoffee.com/koenkk
+2 -2
View File
@@ -1,7 +1,7 @@
FROM node:14-alpine3.12 as base
WORKDIR /app
RUN apk add --no-cache tzdata eudev
RUN apk add --no-cache tzdata eudev tini
COPY package.json ./
@@ -30,4 +30,4 @@ ARG COMMIT
RUN echo "{\"hash\": \"$COMMIT\"}" > .hash.json
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["npm", "start"]
CMD [ "/sbin/tini", "--", "node", "index.js"]
+1
View File
@@ -24,6 +24,7 @@ async function start() {
// Validate settings
const settings = require('./lib/util/settings');
settings.reRead();
const errors = settings.validate();
if (errors.length > 0) {
console.log(`\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`);
+9 -5
View File
@@ -4,7 +4,6 @@ const EventBus = require('./eventBus');
const State = require('./state');
const logger = require('./util/logger');
const settings = require('./util/settings');
const objectAssignDeep = require('object-assign-deep');
const utils = require('./util/utils');
const stringify = require('json-stable-stringify-without-jsonify');
const assert = require('assert');
@@ -108,6 +107,8 @@ class Controller {
this.zigbee.on('adapterDisconnected', this.onZigbeeAdapterDisconnected);
} catch (error) {
logger.error('Failed to start zigbee');
// eslint-disable-next-line
logger.error('Check https://www.zigbee2mqtt.io/information/FAQ.html#help-zigbee2mqtt-fails-to-start for possible solutions');
logger.error('Exiting...');
logger.error(error.stack);
this.exitCallback(1);
@@ -279,12 +280,9 @@ class Controller {
}
let messagePayload = {...payload};
const currentState = this.state.exists(resolvedEntity.settings.ID) ?
this.state.get(resolvedEntity.settings.ID) : {};
const newState = objectAssignDeep.noMutate(currentState, payload);
// Update state cache with new state.
this.state.set(resolvedEntity.settings.ID, newState, stateChangeReason);
const newState = this.state.set(resolvedEntity.settings.ID, payload, stateChangeReason);
if (settings.get().advanced.cache_state) {
// Add cached state to payload
@@ -332,6 +330,12 @@ class Controller {
resolvedEntity.settings.filtered_attributes.forEach((a) => delete messagePayload[a]);
}
for (const extension of this.extensions) {
if (extension.adjustMessagePayloadBeforePublish) {
extension.adjustMessagePayloadBeforePublish(resolvedEntity, messagePayload);
}
}
if (Object.entries(messagePayload).length) {
const output = settings.get().experimental.output;
if (output === 'attribute_and_json' || output === 'json') {
Regular → Executable
+18 -5
View File
@@ -8,9 +8,10 @@ const stringify = require('json-stable-stringify-without-jsonify');
const debounce = require('debounce');
const zigbeeHersdman = require('zigbee-herdsman');
const clusterCandidates = ['genScenes', 'genOnOff', 'genLevelCtrl', 'lightingColorCtrl', 'closuresWindowCovering'];
const clusterCandidates = ['genScenes', 'genOnOff', 'genLevelCtrl', 'lightingColorCtrl', 'closuresWindowCovering',
'hvacThermostat', 'msTemperatureMeasurement'];
// See zigbee-herdsman-converters devices.js
// See zigbee-herdsman-converters
const defaultBindGroup = {type: 'group_number', ID: 901};
const defaultReportConfiguration = {
@@ -146,6 +147,7 @@ class Bind extends Extension {
async onMQTTMessage(topic, message) {
const {type, sourceKey, targetKey, clusters} = this.parseMQTTMessage(topic, message);
if (!type) return null;
message = utils.parseJSON(message, message);
let error = null;
const source = this.zigbee.resolveEntity(sourceKey);
@@ -172,11 +174,22 @@ class Bind extends Extension {
// Groups are assumed to support all clusters.
for (const cluster of clusterCandidates) {
if (clusters && !clusters.includes(cluster)) continue;
let matchingClusters = false;
const targetValid = target.type === 'group' || target.type === 'group_number' ||
target.device.type === 'Coordinator' || target.endpoint.supportsInputCluster(cluster);
const anyClusterValid = target.type === 'group' || target.type === 'group_number' ||
target.device.type === 'Coordinator';
if (source.endpoint.supportsOutputCluster(cluster) && targetValid) {
if (!anyClusterValid) {
matchingClusters = ((target.endpoint.supportsInputCluster(cluster) &&
source.endpoint.supportsOutputCluster(cluster)) ||
(source.endpoint.supportsInputCluster(cluster) &&
target.endpoint.supportsOutputCluster(cluster)) );
}
const sourceValid = source.endpoint.supportsInputCluster(cluster) ||
source.endpoint.supportsOutputCluster(cluster);
if ( sourceValid && (anyClusterValid || matchingClusters)) {
logger.debug(`${type}ing cluster '${cluster}' from '${sourceName}' to '${targetName}'`);
attemptedClusters.push(cluster);
+23 -5
View File
@@ -116,7 +116,7 @@ class Bridge extends Extension {
if (data.status === 'successful') {
const definition = resolvedEntity.definition;
payload.supported = !!definition;
payload.definition = this.getDefinitionPayload(definition);
payload.definition = this.getDefinitionPayload(definition, resolvedEntity);
}
} else if (type === 'deviceAnnounce') {
payload = {
@@ -559,7 +559,8 @@ class Bridge extends Extension {
coordinator: this.coordinatorVersion,
network: utils.toSnakeCase(await this.zigbee.getNetworkParameters()),
log_level: logger.getLevel(),
permit_join: await this.zigbee.getPermitJoin(),
permit_join: this.zigbee.getPermitJoin(),
permit_join_timeout: this.zigbee.getPermitJoinTimeout(),
restart_required: this.restartRequired,
config,
config_schema: settings.schema,
@@ -601,7 +602,7 @@ class Bridge extends Extension {
for (const configuredReporting of endpoint.configuredReportings) {
data.configured_reportings.push({
cluster: configuredReporting.cluster.name,
attribute: configuredReporting.attribute.name,
attribute: configuredReporting.attribute.name || configuredReporting.attribute.ID,
minimum_report_interval: configuredReporting.minimumReportInterval,
maximum_report_interval: configuredReporting.maximumReportInterval,
reportable_change: configuredReporting.reportableChange,
@@ -617,7 +618,7 @@ class Bridge extends Extension {
network_address: device.networkAddress,
supported: !!definition,
friendly_name: resolved.name,
definition: this.getDefinitionPayload(definition),
definition: this.getDefinitionPayload(definition, resolved),
power_source: device.powerSource,
software_build_id: device.softwareBuildID,
date_code: device.dateCode,
@@ -651,14 +652,31 @@ class Bridge extends Extension {
'bridge/groups', stringify(groups), {retain: true, qos: 0}, settings.get().mqtt.base_topic, true);
}
getDefinitionPayload(definition) {
getDefinitionPayload(definition, resolvedDevice) {
if (definition) {
let icon = null;
if (resolvedDevice && resolvedDevice.hasOwnProperty('settings')) {
icon = resolvedDevice.settings.icon;
}
if (!icon) {
icon = definition.icon;
}
if (icon) {
let zigbeeModel = '';
/* istanbul ignore else */
if (resolvedDevice && resolvedDevice.hasOwnProperty('device')) {
zigbeeModel = resolvedDevice.device.modelID;
}
icon = icon.replace('${zigbeeModel}', utils.sanitizeImageParameter(zigbeeModel));
icon = icon.replace('${model}', utils.sanitizeImageParameter(definition.model));
}
return {
model: definition.model,
vendor: definition.vendor,
description: definition.description,
exposes: definition.exposes,
supports_ota: !!definition.ota,
icon,
};
} else {
return null;
+9 -4
View File
@@ -31,11 +31,11 @@ class Configure extends Extension {
}
if (this.shouldConfigure(resolvedEntity)) {
this.configure(resolvedEntity);
this.configure(resolvedEntity, 'reporting_disabled');
}
}
shouldConfigure(resolvedEntity) {
shouldConfigure(resolvedEntity, event) {
if (!resolvedEntity || !resolvedEntity.definition || !resolvedEntity.definition.configure) {
return false;
}
@@ -50,6 +50,11 @@ class Configure extends Extension {
return false;
}
// Only configure end devices when a message is received, otherwise it will likely fails as they are sleeping.
if (resolvedEntity.device.type === 'EndDevice' && event !== 'message_received') {
return false;
}
return true;
}
@@ -95,7 +100,7 @@ class Configure extends Extension {
for (const device of this.zigbee.getClients()) {
const resolvedEntity = this.zigbee.resolveEntity(device);
if (this.shouldConfigure(resolvedEntity)) {
if (this.shouldConfigure(resolvedEntity, 'started')) {
await this.configure(resolvedEntity);
}
}
@@ -109,7 +114,7 @@ class Configure extends Extension {
device.save();
}
if (this.shouldConfigure(resolvedEntity)) {
if (this.shouldConfigure(resolvedEntity, 'message_received')) {
this.configure(resolvedEntity);
}
}
+24 -7
View File
@@ -82,17 +82,24 @@ class Groups extends Extension {
return;
}
const properties = ['state', 'brightness', 'color_temp', 'color'];
const properties = ['state', 'brightness', 'color_temp', 'color', 'color_mode'];
const payload = {};
properties.forEach((prop) => {
if (data.to.hasOwnProperty(prop)) {
payload[prop] = data.to[prop];
let endpointName;
for (let [prop, value] of Object.entries(data.update)) {
const endpointNameMatch = utils.getEndpointNames().find((n) => prop.endsWith(`_${n}`));
if (endpointNameMatch) {
prop = prop.substring(0, prop.length - endpointNameMatch.length - 1);
endpointName = endpointNameMatch;
}
});
if (properties.includes(prop)) {
payload[prop] = value;
}
}
if (Object.keys(payload).length) {
const resolvedEntity = this.zigbee.resolveEntity(data.ID);
const resolvedEntity = this.zigbee.resolveEntity(`${data.ID}${endpointName ? `/${endpointName}` : ''}`);
const zigbeeGroups = this.zigbee.getGroups().filter((zigbeeGroup) => {
const settingsGroup = settings.getGroup(zigbeeGroup.groupID);
return settingsGroup && settingsGroup.optimistic;
@@ -114,7 +121,16 @@ class Groups extends Extension {
const groupIDsToPublish = new Set();
for (const member of resolvedEntity.group.members) {
await this.publishEntityState(member.getDevice().ieeeAddr, payload, reason);
const memberPayload = {...payload};
const endpointName = this.zigbee.resolveEntity(member).endpointName;
if (endpointName) {
Object.keys(memberPayload).forEach((key) => {
memberPayload[`${key}_${endpointName}`] = memberPayload[key];
delete memberPayload[key];
});
}
await this.publishEntityState(member.getDevice().ieeeAddr, memberPayload, reason);
for (const zigbeeGroup of zigbeeGroups) {
if (zigbeeGroup.hasMember(member)) {
if (!payload || payload.state !== 'OFF' || this.areAllMembersOff(zigbeeGroup)) {
@@ -237,6 +253,7 @@ class Groups extends Extension {
groupKey, deviceKey,
} = this.parseMQTTMessage(topic, message);
if (!type) return;
message = utils.parseJSON(message, message);
const responseData = {device: deviceKey};
if (groupKey) {
+55 -15
View File
@@ -16,6 +16,7 @@ const sensorClick = {
},
};
const ACCESS_STATE = 1;
const defaultStatusTopic = 'homeassistant/status';
/**
@@ -81,17 +82,16 @@ class HomeAssistant extends Extension {
let discoveryEntry = null;
/* istanbul ignore else */
if (expose.type === 'light') {
const supportsXY = !!expose.features.find((e) => e.name === 'color_xy');
const supportsHS = !!expose.features.find((e) => e.name === 'color_hs');
const colorXY = expose.features.find((e) => e.name === 'color_xy');
const colorHS = expose.features.find((e) => e.name === 'color_hs');
const brightness = expose.features.find((e) => e.name === 'brightness');
const colorTemp = expose.features.find((e) => e.name === 'color_temp');
discoveryEntry = {
type: 'light',
object_id: expose.endpoint ? `light_${expose.endpoint}` : 'light',
discovery_payload: {
brightness: !!expose.features.find((e) => e.name === 'brightness'),
color_temp: !!colorTemp,
xy: supportsXY,
hs: !supportsXY && supportsHS,
brightness: !!brightness,
schema: 'json',
command_topic: true,
brightness_scale: 254,
@@ -100,6 +100,18 @@ class HomeAssistant extends Extension {
},
};
const colorModes = [
colorXY ? 'xy' : null,
!colorXY && colorHS ? 'hs' : null,
colorTemp ? 'color_temp' : null,
].filter((c) => c);
if (colorModes.length) {
discoveryEntry.discovery_payload.color_mode = true;
discoveryEntry.discovery_payload.supported_color_modes = colorModes;
}
if (colorTemp) {
discoveryEntry.discovery_payload.max_mireds = colorTemp.value_max;
discoveryEntry.discovery_payload.min_mireds = colorTemp.value_min;
@@ -162,6 +174,12 @@ class HomeAssistant extends Extension {
const mode = expose.features.find((f) => f.name === 'system_mode');
if (mode) {
if (mode.values.includes('sleep')) {
// 'sleep' is not supported by homeassistent, but is valid according to ZCL
// TRV that support sleep (e.g. Viessmann) will have it removed from here,
// this allows other expose consumers to still use it, e.g. the frontend.
mode.values.splice(mode.values.indexOf('sleep'), 1);
}
discoveryEntry.discovery_payload.mode_state_topic = true;
discoveryEntry.discovery_payload.mode_state_template = `{{ value_json.${mode.property} }}`;
discoveryEntry.discovery_payload.modes = mode.values;
@@ -245,8 +263,8 @@ class HomeAssistant extends Extension {
// deprecated: child_lock is messy, but changing is breaking
discoveryEntry.discovery_payload.payload_lock = state.value_on;
discoveryEntry.discovery_payload.payload_unlock = state.value_off;
discoveryEntry.discovery_payload.state_locked = 'LOCKED';
discoveryEntry.discovery_payload.state_unlocked = 'UNLOCKED';
discoveryEntry.discovery_payload.state_locked = 'LOCK';
discoveryEntry.discovery_payload.state_unlocked = 'UNLOCK';
discoveryEntry.discovery_payload.state_topic = true;
discoveryEntry.object_id = 'child_lock';
} else {
@@ -277,7 +295,7 @@ class HomeAssistant extends Extension {
if (hasPosition) {
discoveryEntry.discovery_payload = {...discoveryEntry.discovery_payload,
value_template: '{{ value_json.position }}',
position_template: '{{ value_json.position }}',
set_position_template: '{ "position": {{ position }} }',
set_position_topic: true,
position_topic: true,
@@ -380,7 +398,6 @@ class HomeAssistant extends Extension {
},
};
} else if (expose.type === 'enum' || expose.type === 'text' || expose.type === 'composite') {
const ACCESS_STATE = 1;
if (expose.access & ACCESS_STATE) {
const lookup = {
action: {icon: 'mdi:gesture-double-tap'},
@@ -457,8 +474,7 @@ class HomeAssistant extends Extension {
* https://github.com/Koenkk/zigbee2mqtt/issues/959#issuecomment-480341347
*/
if (settings.get().advanced.homeassistant_legacy_triggers) {
const keys = ['action', 'click'].filter((k) =>
data.messagePayload.hasOwnProperty(k) && data.messagePayload[k] !== '');
const keys = ['action', 'click'].filter((k) => data.messagePayload[k]);
for (const key of keys) {
this.publishEntityState(data.entity.device.ieeeAddr, {[key]: ''});
}
@@ -471,7 +487,7 @@ class HomeAssistant extends Extension {
* and republish it to zigbee2mqtt/my_devic/action
*/
if (data.entity.definition) {
const keys = ['action', 'click'].filter((k) => data.messagePayload[k] && data.messagePayload[k] !== '');
const keys = ['action', 'click'].filter((k) => data.messagePayload[k]);
for (const key of keys) {
const value = data.messagePayload[key].toString();
await this.publishDeviceTriggerDiscover(data.entity, key, value);
@@ -871,13 +887,37 @@ class HomeAssistant extends Extension {
};
}
adjustMessagePayloadBeforePublish(resolvedEntity, messagePayload) {
// Set missing values of state to 'null': https://github.com/Koenkk/zigbee2mqtt/issues/6987
if (!resolvedEntity || !resolvedEntity.definition) return null;
const add = (expose) => {
if (!messagePayload.hasOwnProperty(expose.property) && expose.access & ACCESS_STATE) {
messagePayload[expose.property] = null;
}
};
for (const expose of resolvedEntity.definition.exposes) {
if (expose.hasOwnProperty('features')) {
for (const feature of expose.features) {
if (feature.name === 'state') {
add(feature);
}
}
} else {
add(expose);
}
}
}
getDiscoveryTopic(config, device) {
return `${config.type}/${device.ieeeAddr}/${config.object_id}/config`;
}
async publishDeviceTriggerDiscover(entity, key, value, force=false) {
if (entity.settings.hasOwnProperty('homeassistant') &&
(entity.settings.homeassistant == null || entity.settings.homeassistant.device_automation == null)) {
const haConfig = entity.settings.homeassistant;
if (entity.settings.hasOwnProperty('homeassistant') && (haConfig == null ||
(haConfig.hasOwnProperty('device_automation') && haConfig.device_automation == null))) {
return;
}
+1 -1
View File
@@ -382,7 +382,7 @@ class BridgeLegacy extends Extension {
coordinator,
network: await this.zigbee.getNetworkParameters(),
log_level: logger.getLevel(),
permit_join: await this.zigbee.getPermitJoin(),
permit_join: this.zigbee.getPermitJoin(),
};
await this.mqtt.publish(topic, stringify(payload), {retain: true, qos: 0});
+1 -1
View File
@@ -42,7 +42,7 @@ class OTAUpdate extends Extension {
if (supportsOTA) {
// When a device does a next image request, it will usually do it a few times after each other
// with only 10 - 60 seconds inbetween. It doesn't make sense to check for a new update
// each time, so this interval can be set by the user. The default is 10 minutes.
// each time, so this interval can be set by the user. The default is 1,440 minutes (one day).
const updateCheckInterval = settings.get().ota.update_check_interval * 1000 * 60;
const check = this.lastChecked.hasOwnProperty(data.device.ieeeAddr) ?
(Date.now() - this.lastChecked[data.device.ieeeAddr]) > updateCheckInterval : true;
+6 -6
View File
@@ -75,8 +75,10 @@ class State {
return this.state[ID];
}
set(ID, state, reason=null) {
const toState = objectAssignDeep.noMutate(state);
set(ID, update, reason=null) {
const fromState = this.state[ID] || {};
const toState = objectAssignDeep.noMutate(fromState, update);
const result = {...toState};
for (const property of Object.keys(toState)) {
if (dontCacheProperties.find((p) => property.match(p))) {
@@ -84,11 +86,9 @@ class State {
}
}
const fromState = this.state[ID];
this.state[ID] = toState;
this.eventBus.emit('stateChange', {ID, from: fromState, to: state, reason});
this.eventBus.emit('stateChange', {ID, from: fromState, to: toState, reason, update});
return result;
}
removeKey(ID, path) {
+9
View File
@@ -19,6 +19,15 @@ const logFilename = settings.get().advanced.log_file.replace('%TIMESTAMP%', time
// Make sure that log directoy exsists when not logging to stdout only
if (output.includes('file')) {
fx.mkdirSync(directory);
if (settings.get().advanced.log_symlink_current) {
const current = settings.get().advanced.log_directory.replace('%TIMESTAMP%', 'current');
const actual = './' + timestamp;
if (fs.existsSync(current)) {
fs.unlinkSync(current);
}
fs.symlinkSync(actual, current);
}
}
const z2mToWinstonLevel = (level) => level === 'warn' ? 'warning' : level;
+8 -5
View File
@@ -57,6 +57,7 @@ const defaults = {
advanced: {
legacy_api: true,
log_rotation: true,
log_symlink_current: false,
log_output: ['console', 'file'],
log_directory: path.join(data.getPath(), 'log', '%TIMESTAMP%'),
log_file: 'log.txt',
@@ -141,7 +142,7 @@ const defaults = {
/**
* Minimal time delta in minutes between polling third party server for potential firmware updates
*/
update_check_interval: 10,
update_check_interval: 24 * 60,
/**
* Completely disallow Zigbee devices to initiate a search for a potential firmware update.
* If set to true, only a user-initiated update search will be possible.
@@ -635,8 +636,10 @@ function changeEntityOptions(IDorName, newOptions) {
delete newOptions.devices;
if (getDevice(IDorName)) {
objectAssignDeep(settings.devices[getDevice(IDorName).ID], newOptions);
utils.removeNullPropertiesFromObject(settings.devices[getDevice(IDorName).ID]);
} else if (getGroup(IDorName)) {
objectAssignDeep(settings.groups[getGroup(IDorName).ID], newOptions);
utils.removeNullPropertiesFromObject(settings.groups[getGroup(IDorName).ID]);
} else {
throw new Error(`Device or group '${IDorName}' does not exist`);
}
@@ -683,15 +686,15 @@ module.exports = {
changeEntityOptions,
changeFriendlyName,
schema,
// For tests only
_write: write,
_reRead: () => {
reRead: () => {
_settings = null;
get();
_settingsWithDefaults = null;
getWithDefaults();
},
// For tests only
_write: write,
_clear: () => {
_settings = null;
_settingsWithDefaults = null;
+17 -5
View File
@@ -144,7 +144,7 @@
},
"adapter": {
"type": ["string", "null"],
"enum": ["deconz", "zstack", "zigate"],
"enum": ["deconz", "zstack", "zigate", "ezsp"],
"title": "Adapter",
"requiresRestart": true,
"description": "Adapter type, not needed unless you are experiencing problems"
@@ -274,6 +274,13 @@
"description": "Log rotation",
"default": true
},
"log_symlink_current": {
"type": "boolean",
"title": "Log symlink current",
"requiresRestart": true,
"description": "Create symlink to current logs in the log directory",
"default": false
},
"log_level": {
"type": "string",
"enum": ["info", "warn", "error", "debug"],
@@ -310,8 +317,8 @@
"type": "number",
"title": "Baudrate",
"requiresRestart": true,
"description": "Baudrate for serial port, default: 115200 for Z-Stack, 38400 for Deconz",
"examples": [38400, 115200]
"description": "Baud rate speed for serial port, this can be anything firmware support but default is 115200 for Z-Stack and EZSP, 38400 for Deconz, however note that some EZSP firmware need 57600",
"examples": [38400, 57600, 115200]
},
"rtscts": {
"type": "boolean",
@@ -589,8 +596,8 @@
"update_check_interval": {
"type": "number",
"title": "Update check interval",
"description": "Your device may request a check for a new firmware update. This value determines how frequently third party servers may actually be contacted to look for firmware updates. The value is set in minutes, and the default is 10.",
"default": 10
"description": "Your device may request a check for a new firmware update. This value determines how frequently third party servers may actually be contacted to look for firmware updates. The value is set in minutes, and the default is 1 day.",
"default": 1440
},
"disable_automatic_update_check": {
"type": "boolean",
@@ -702,6 +709,11 @@
"examples": ["temperature", "battery", "action"],
"title": "Filtered attributes",
"description": "Allows to prevent certain attributes from being published"
},
"icon": {
"type": "string",
"title": "Icon",
"description": "The user-defined device icon for the frontend. It can be a link to an image (not a path to a file) or base64 encoded data URL like: image/svg+xml;base64,PHN2ZyB3aW....R0aD"
}
},
"required": ["friendly_name"]
+39 -2
View File
@@ -42,7 +42,7 @@ const endpointNames = [
'button_11', 'button_12', 'button_13', 'button_14', 'button_15',
'button_16', 'button_17', 'button_18', 'button_19', 'button_20',
'button_light', 'button_fan_high', 'button_fan_med', 'button_fan_low',
'heat', 'cool', 'water', 'meter',
'heat', 'cool', 'water', 'meter', 'wifi',
];
function capitalize(s) {
@@ -126,7 +126,7 @@ function equalsPartial(object, expected) {
}
function getObjectProperty(object, key, defaultValue) {
return object.hasOwnProperty(key) ? object[key] : defaultValue;
return object && object.hasOwnProperty(key) ? object[key] : defaultValue;
}
function getResponse(request, data, error) {
@@ -152,6 +152,12 @@ function loadModuleFromText(moduleCode) {
require: require,
module: {},
console,
setTimeout,
clearTimeout,
setInterval,
clearInterval,
setImmediate,
clearImmediate,
};
vm.runInNewContext(moduleCode, sandbox, moduleFakePath);
return sandbox.module.exports;
@@ -184,6 +190,27 @@ function* getExternalConvertersDefinitions(settings) {
}
}
function removeNullPropertiesFromObject(obj) {
for (const key of Object.keys(obj)) {
const value = obj[key];
if (value == null) {
delete obj[key];
} else if (typeof value === 'object') {
removeNullPropertiesFromObject(value);
}
}
}
function getKey(object, value, fallback, convertTo) {
for (const key in object) {
if (object[key]===value) {
return convertTo ? convertTo(key) : key;
}
}
return fallback;
}
function toSnakeCase(value) {
if (typeof value === 'object') {
value = {...value};
@@ -227,6 +254,13 @@ function sleep(seconds) {
return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
}
function sanitizeImageParameter(parameter) {
const replaceByDash = [/\?/g, /&/g, /[^a-z\d\- _./:]/gi];
let sanitized = parameter;
replaceByDash.forEach((r) => sanitized = sanitized.replace(r, '-'));
return sanitized;
}
module.exports = {
millisecondsToSeconds: (milliseconds) => milliseconds / 1000,
secondsToMilliseconds: (seconds) => seconds * 1000,
@@ -251,4 +285,7 @@ module.exports = {
validateFriendlyName,
loadModuleFromFile,
loadModuleFromText,
getKey,
sanitizeImageParameter,
removeNullPropertiesFromObject,
};
+37 -16
View File
@@ -125,8 +125,9 @@ class Zigbee extends events.EventEmitter {
}
async stop() {
logger.info('Stopping zigbee-herdsman...');
await this.herdsman.stop();
logger.info('zigbee-herdsman stopped');
logger.info('Stopped zigbee-herdsman');
}
async permitJoin(permit, resolvedEntity, time=undefined) {
@@ -141,10 +142,14 @@ class Zigbee extends events.EventEmitter {
}
}
async getPermitJoin() {
getPermitJoin() {
return this.herdsman.getPermitJoin();
}
getPermitJoinTimeout() {
return this.herdsman.getPermitJoinTimeout();
}
getClients() {
return this.herdsman.getDevices().filter((device) => device.type !== 'Coordinator');
}
@@ -179,10 +184,16 @@ class Zigbee extends events.EventEmitter {
resolveEntity(key) {
assert(
typeof key === 'string' || typeof key === 'number' ||
key.constructor.name === 'Device' || key.constructor.name === 'Group',
key.constructor.name === 'Device' || key.constructor.name === 'Group' ||
key.constructor.name === 'Endpoint',
`Wrong type '${typeof key}'`,
);
const getEndpointName = (endpointNames, endpoint) => {
return endpoint ?
utils.getKey(endpointNames, endpoint.ID, null, ((v) => v === 'default' ? null : v)) : null;
};
const deviceOptions = settings.get().device_options;
if (typeof key === 'string' || typeof key === 'number') {
if (typeof key === 'number') {
@@ -197,6 +208,7 @@ class Zigbee extends events.EventEmitter {
endpoint: coordinator.getEndpoint(1),
settings: {friendlyName: 'Coordinator'},
name: 'Coordinator',
endpointName: null,
};
}
@@ -219,20 +231,21 @@ class Zigbee extends events.EventEmitter {
}
const definition = zigbeeHerdsmanConverters.findByDevice(device);
const endpoints = definition && definition.endpoint ? definition.endpoint(device) : null;
const endpointNames = definition && definition.endpoint ? definition.endpoint(device) : null;
let endpoint;
if (endpointKey) {
if (endpointByNumber) {
endpoint = device.getEndpoint(endpointKey);
} else {
assert(definition != null, `Endpoint name '${endpointKey}' is given but device is unsupported`);
assert(endpoints != null, `Endpoint name '${endpointKey}' is given but no endpoints defined`);
const endpointID = endpoints[endpointKey];
assert(endpointNames != null,
`Endpoint name '${endpointKey}' is given but no endpoints defined`);
const endpointID = endpointNames[endpointKey];
assert(endpointID, `Endpoint name '${endpointKey}' is given but device has no such endpoint`);
endpoint = device.getEndpoint(endpointID);
}
} else if (endpoints && endpoints['default']) {
endpoint = device.getEndpoint(endpoints['default']);
} else if (endpointNames && endpointNames['default']) {
endpoint = device.getEndpoint(endpointNames['default']);
} else {
endpoint = device.endpoints[0];
}
@@ -240,21 +253,29 @@ class Zigbee extends events.EventEmitter {
return {
type: 'device', device, endpoint, settings: {...deviceOptions, ...entity},
name: entity.friendlyName, definition,
endpointName: getEndpointName(endpointNames, endpoint),
};
} else {
let group = this.getGroupByID(entity.ID);
if (!group) group = this.createGroup(entity.ID);
return {type: 'group', group, settings: {...deviceOptions, ...entity}, name: entity.friendlyName};
}
} else if (key.constructor.name === 'Device') {
const setting = settings.getEntity(key.ieeeAddr);
} else if (key.constructor.name === 'Device' || key.constructor.name === 'Endpoint') {
const device = key.constructor.name === 'Endpoint' ? key.getDevice() : key;
const setting = settings.getEntity(device.ieeeAddr);
const definition = zigbeeHerdsmanConverters.findByDevice(device);
const name = setting ? setting.friendlyName :
(device.type === 'Coordinator' ? 'Coordinator' : device.ieeeAddr);
const endpointNames = definition && definition.endpoint ? definition.endpoint(device) : null;
let endpoint;
if (key.constructor.name === 'Endpoint') endpoint = key;
else if (endpointNames && endpointNames['default']) endpoint = device.getEndpoint(endpointNames['default']);
else endpoint = device.endpoints[0];
return {
type: 'device',
device: key,
endpoint: key.endpoints[0],
settings: {...deviceOptions, ...(setting || {})},
name: setting ? setting.friendlyName : (key.type === 'Coordinator' ? 'Coordinator' : key.ieeeAddr),
definition: zigbeeHerdsmanConverters.findByDevice(key),
type: 'device', definition, name, device, endpoint, settings: {...deviceOptions, ...(setting || {})},
endpointName: getEndpointName(endpointNames, endpoint),
};
} else { // Group
const setting = settings.getEntity(key.groupID);
+894 -812
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "zigbee2mqtt",
"version": "1.18.0",
"version": "1.18.3",
"description": "Zigbee to MQTT bridge using Zigbee-herdsman",
"main": "index.js",
"repository": {
@@ -52,9 +52,9 @@
"winston": "^3.3.3",
"winston-syslog": "^2.4.4",
"ws": "^7.3.1",
"zigbee-herdsman": "0.13.72",
"zigbee-herdsman-converters": "14.0.74",
"zigbee2mqtt-frontend": "0.3.76"
"zigbee-herdsman": "0.13.92",
"zigbee-herdsman-converters": "14.0.131",
"zigbee2mqtt-frontend": "0.4.0"
},
"devDependencies": {
"eslint": "*",
+1 -1
View File
@@ -25,7 +25,7 @@ describe('Availability', () => {
beforeEach(async () => {
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
data.writeEmptyState();
jest.useFakeTimers();
settings.set(['advanced', 'availability_timeout'], 10);
+19 -3
View File
@@ -25,7 +25,7 @@ describe('Bind', () => {
beforeEach(async () => {
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
data.writeEmptyState();
zigbeeHerdsman.groups.group_1.members = [];
zigbeeHerdsman.devices.bulb_color.getEndpoint(1).configureReporting.mockClear();
@@ -53,7 +53,7 @@ describe('Bind', () => {
mockClear(device);
target.configureReporting.mockImplementationOnce(() => {throw new Error("timeout")});
MQTT.events.message('zigbee2mqtt/bridge/request/device/bind', stringify({from: 'remote', to: 'bulb_color'}));
MQTT.events.message('zigbee2mqtt/bridge/request/device/bind', stringify({transaction: "1234", from: 'remote', to: 'bulb_color'}));
await flushPromises();
expect(target.read).toHaveBeenCalledWith('lightingColorCtrl', [ 'colorCapabilities' ]);
expect(endpoint.bind).toHaveBeenCalledTimes(4);
@@ -67,7 +67,7 @@ describe('Bind', () => {
expect(target.configureReporting).toHaveBeenCalledWith("lightingColorCtrl",[{"attribute":"colorTemperature","minimumReportInterval":5,"maximumReportInterval":3600,"reportableChange":1},{"attribute":"currentX","minimumReportInterval":5,"maximumReportInterval":3600,"reportableChange":1},{"attribute":"currentY","minimumReportInterval":5,"maximumReportInterval":3600,"reportableChange":1}]);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bridge/response/device/bind',
stringify({"data":{"from":"remote","to":"bulb_color","clusters":["genScenes","genOnOff","genLevelCtrl", "lightingColorCtrl"],"failed":[]},"status":"ok"}),
stringify({"transaction": "1234","data":{"from":"remote","to":"bulb_color","clusters":["genScenes","genOnOff","genLevelCtrl", "lightingColorCtrl"],"failed":[]},"status":"ok"}),
{retain: false, qos: 0}, expect.any(Function)
);
@@ -279,6 +279,22 @@ describe('Bind', () => {
);
});
it('Should bind server clusters to client clusters', async () => {
const device = zigbeeHerdsman.devices.temperature_sensor;
const target = zigbeeHerdsman.devices.heating_actuator.getEndpoint(1);
const endpoint = device.getEndpoint(1);
mockClear(device);
MQTT.events.message('zigbee2mqtt/bridge/request/device/bind', stringify({from: 'temperature_sensor', to: 'heating_actuator'}));
await flushPromises();
expect(endpoint.bind).toHaveBeenCalledTimes(1);
expect(endpoint.bind).toHaveBeenCalledWith("msTemperatureMeasurement", target);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bridge/response/device/bind',
stringify({"data":{"from":"temperature_sensor","to":"heating_actuator","clusters":["msTemperatureMeasurement"],"failed":[]},"status":"ok"}),
{retain: false, qos: 0}, expect.any(Function)
);
});
it('Should bind to default endpoint returned by endpoints()', async () => {
const device = zigbeeHerdsman.devices.remote;
const target = zigbeeHerdsman.devices.QBKG04LM.getEndpoint(2);
+66 -4
View File
File diff suppressed because one or more lines are too long
+35 -16
View File
@@ -26,6 +26,22 @@ describe('Configure', () => {
expect(device.meta.configured).toBe(1);
}
expectBulbConfigured = () => {
const device = zigbeeHerdsman.devices.bulb;
const endpoint1 = device.getEndpoint(1);
console.log(endpoint1.read.mock.calls);
expect(endpoint1.read).toHaveBeenCalledTimes(2);
expect(endpoint1.read).toHaveBeenCalledWith('lightingColorCtrl', ['colorCapabilities']);
expect(endpoint1.read).toHaveBeenCalledWith('lightingColorCtrl', [ 'colorTempPhysicalMin', 'colorTempPhysicalMax' ]);
}
expectBulbNotConfigured = () => {
const device = zigbeeHerdsman.devices.bulb;
const endpoint1 = device.getEndpoint(1);
console.log(endpoint1.read.mock.calls);
expect(endpoint1.read).toHaveBeenCalledTimes(0);
}
expectRemoteNotConfigured = () => {
const device = zigbeeHerdsman.devices.remote;
const endpoint1 = device.getEndpoint(1);
@@ -44,7 +60,7 @@ describe('Configure', () => {
beforeEach(async () => {
jest.useRealTimers();
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
data.writeEmptyState();
controller = new Controller(jest.fn(), jest.fn());
await controller.start();
@@ -53,56 +69,59 @@ describe('Configure', () => {
this.coordinatorEndoint = zigbeeHerdsman.devices.coordinator.getEndpoint(1);
});
it('Should configure on startup', async () => {
expectRemoteConfigured();
it('Should configure Router on startup', async () => {
expectBulbConfigured();
});
it('Should not configure EndDevice on startup', async () => {
expectRemoteNotConfigured();
});
it('Should re-configure when device rejoins', async () => {
expectRemoteConfigured();
const device = zigbeeHerdsman.devices.remote;
expectBulbConfigured();
const device = zigbeeHerdsman.devices.bulb;
const endpoint = device.getEndpoint(1);
await flushPromises();
mockClear(device);
const payload = {device};
zigbeeHerdsman.events.deviceJoined(payload);
await flushPromises();
expectRemoteConfigured();
expectBulbConfigured();
});
it('Should reconfigure reporting on reportingDisabled event', async () => {
expectRemoteConfigured();
const device = zigbeeHerdsman.devices.remote;
expectBulbConfigured();
const device = zigbeeHerdsman.devices.bulb;
mockClear(device);
expectRemoteNotConfigured();
expectBulbNotConfigured();
controller.eventBus.emit('reportingDisabled', {device})
await flushPromises();
expectRemoteConfigured();
expectBulbConfigured();
});
it('Should not configure twice', async () => {
expectRemoteConfigured();
const device = zigbeeHerdsman.devices.remote;
expectBulbConfigured();
const device = zigbeeHerdsman.devices.bulb;
const endpoint = device.getEndpoint(1);
mockClear(device);
const payload = {data: {zclVersion: 1}, cluster: 'genBasic', device, endpoint, type: 'attributeReport', linkquality: 10};
await zigbeeHerdsman.events.message(payload);
await flushPromises();
expect(endpoint.bind).toHaveBeenCalledTimes(0);
expectBulbNotConfigured();
});
it('Should configure on zigbee message when not configured yet', async () => {
const device = zigbeeHerdsman.devices.remote;
const device = zigbeeHerdsman.devices.bulb;
delete device.meta.configured;
const endpoint = device.getEndpoint(1);
mockClear(device);
const payload = {data: {zclVersion: 1}, cluster: 'genBasic', device, endpoint, type: 'attributeReport', linkquality: 10};
await zigbeeHerdsman.events.message(payload);
await flushPromises();
expectRemoteConfigured();
expectBulbConfigured();
});
it('Should allow to configure via MQTT', async () => {
expectRemoteConfigured();
mockClear(zigbeeHerdsman.devices.remote);
expectRemoteNotConfigured();
await MQTT.events.message('zigbee2mqtt/bridge/request/device/configure', 'remote');
+1 -1
View File
@@ -26,7 +26,7 @@ describe('Controller', () => {
controller = new Controller(jest.fn(), mockExit);
mocksClear.forEach((m) => m.mockClear());
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
data.writeDefaultState();
});
+1 -1
View File
@@ -47,7 +47,7 @@ describe('Loads external converters', () => {
mocksClear.forEach((m) => m.mockClear());
data.writeDefaultConfiguration();
data.writeEmptyState();
settings._reRead();
settings.reRead();
});
it('Does not load external converters', async () => {
+1 -1
View File
@@ -28,7 +28,7 @@ describe('User extensions', () => {
controller = new Controller(jest.fn(), mockExit);
mocksClear.forEach((m) => m.mockClear());
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
data.writeDefaultState();
});
afterEach(() => {
+3 -3
View File
@@ -74,7 +74,7 @@ describe('Frontend', () => {
mockWS.implementation.clients = [];
data.writeDefaultConfiguration();
data.writeDefaultState();
settings._reRead();
settings.reRead();
settings.set(['frontend'], {port: 8081, host: "127.0.0.1"});
settings.set(['homeassistant'], true);
zigbeeHerdsman.devices.bulb.linkquality = 10;
@@ -130,7 +130,7 @@ describe('Frontend', () => {
expect(MQTT.publish).toHaveBeenCalledTimes(4);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bulb_color',
stringify({state: 'ON'}),
stringify({state: 'ON', linkquality: null}),
{ retain: false, qos: 0 },
expect.any(Function)
);
@@ -141,7 +141,7 @@ describe('Frontend', () => {
// Received message on socket
expect(mockWSClient.implementation.send).toHaveBeenCalledTimes(4);
expect(mockWSClient.implementation.send).toHaveBeenCalledWith(stringify({topic: 'bulb_color', payload: {state: 'ON'}}));
expect(mockWSClient.implementation.send).toHaveBeenCalledWith(stringify({topic: 'bulb_color', payload: {state: 'ON', linkquality: null}}));
// Shouldnt set when not ready
mockWSClient.implementation.send.mockClear();
+62 -3
View File
@@ -9,6 +9,7 @@ zigbeeHerdsman.returnDevices.push('0x000b57fffec6a5b2');
zigbeeHerdsman.returnDevices.push('0x0017880104e45542');
zigbeeHerdsman.returnDevices.push('0x000b57fffec6a5b4');
zigbeeHerdsman.returnDevices.push('0x000b57fffec6a5b7');
zigbeeHerdsman.returnDevices.push('0x0017880104e45724');
const MQTT = require('./stub/mqtt');
const Controller = require('../lib/controller');
@@ -23,8 +24,9 @@ describe('Groups', () => {
controller = new Controller(jest.fn(), jest.fn());
Object.values(zigbeeHerdsman.groups).forEach((g) => g.members = []);
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
MQTT.publish.mockClear();
zigbeeHerdsman.groups.gledopto_group.command.mockClear();
zigbeeHerdsmanConverters.toZigbeeConverters.__clearStore__();
})
@@ -371,6 +373,35 @@ describe('Groups', () => {
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/group_1", stringify({"state":"ON"}), {"retain": false, qos: 0}, expect.any(Function));
});
it('Should publish state of device with endpoint name', async () => {
const group = zigbeeHerdsman.groups.gledopto_group;
await controller.start();
await flushPromises();
MQTT.publish.mockClear();
await MQTT.events.message('zigbee2mqtt/gledopto_group/set', stringify({state: 'ON'}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(2);
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/GLEDOPTO_2ID", stringify({"state_cct":"ON"}), {"retain": false, qos: 0}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/gledopto_group", stringify({"state":"ON"}), {"retain": false, qos: 0}, expect.any(Function));
expect(group.command).toHaveBeenCalledTimes(1);
expect(group.command).toHaveBeenCalledWith("genOnOff", "on", {}, {});
});
it('Should publish state of group when specific state of specific endpoint is changed', async () => {
const group = zigbeeHerdsman.groups.gledopto_group;
await controller.start();
await flushPromises();
MQTT.publish.mockClear();
await MQTT.events.message('zigbee2mqtt/GLEDOPTO_2ID/set', stringify({state_cct: 'ON'}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(2);
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/GLEDOPTO_2ID", stringify({"state_cct":"ON"}), {"retain": false, qos: 0}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/gledopto_group", stringify({"state":"ON"}), {"retain": false, qos: 0}, expect.any(Function));
expect(group.command).toHaveBeenCalledTimes(0);
});
it('Should publish state change of all members when a group changes its state, filtered', async () => {
const device = zigbeeHerdsman.devices.bulb_color;
const endpoint = device.getEndpoint(1);
@@ -505,6 +536,34 @@ describe('Groups', () => {
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/group_1", stringify({"state":"OFF"}), {"retain": false, qos: 0}, expect.any(Function));
});
it('Should only update group state with changed properties', async () => {
const device_1 = zigbeeHerdsman.devices.bulb_color;
const device_2 = zigbeeHerdsman.devices.bulb;
const endpoint_1 = device_1.getEndpoint(1);
const endpoint_2 = device_2.getEndpoint(1);
const group = zigbeeHerdsman.groups.group_1;
group.members.push(endpoint_1);
group.members.push(endpoint_2);
settings.set(['groups'], {
'1': {friendly_name: 'group_1', devices: [device_1.ieeeAddr, device_2.ieeeAddr], retain: false}
});
await controller.start();
await flushPromises();
MQTT.publish.mockClear();
await MQTT.events.message('zigbee2mqtt/bulb_color/set', stringify({state: 'OFF', color_temp: 200}));
await MQTT.events.message('zigbee2mqtt/bulb/set', stringify({state: 'ON', color_temp: 250}));
await flushPromises();
MQTT.publish.mockClear();
await MQTT.events.message('zigbee2mqtt/group_1/set', stringify({color_temp: 300}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(3);
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb_color", stringify({"color_mode": "color_temp", "color":{"x":0.415211980162654,"y":0.395434886759171},"color_temp":300,"state":"OFF"}), {"retain": false, qos: 0}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb", stringify({"color_mode": "color_temp", "color":{"x":0.415211980162654,"y":0.395434886759171},"color_temp":300,"state":"ON"}), {"retain": true, qos: 0}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/group_1", stringify({"color_mode": "color_temp", "color":{"x":0.415211980162654,"y":0.395434886759171},"color_temp":300,"state":"ON"}), {"retain": false, qos: 0}, expect.any(Function));
});
it('Should publish state change off even when missing current state', async () => {
const device_1 = zigbeeHerdsman.devices.bulb_color;
const device_2 = zigbeeHerdsman.devices.bulb;
@@ -541,14 +600,14 @@ describe('Groups', () => {
await controller.start();
await flushPromises();
MQTT.publish.mockClear();
MQTT.events.message('zigbee2mqtt/bridge/request/group/members/add', stringify({group: 'group_1', device: 'bulb_color'}));
MQTT.events.message('zigbee2mqtt/bridge/request/group/members/add', stringify({transaction: "123", group: 'group_1', device: 'bulb_color'}));
await flushPromises();
expect(group.members).toStrictEqual([endpoint]);
expect(settings.getGroup('group_1').devices).toStrictEqual([`${device.ieeeAddr}/1`]);
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/groups', expect.any(String), expect.any(Object), expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bridge/response/group/members/add',
stringify({"data":{"device":"bulb_color","group":"group_1"},"status":"ok"}),
stringify({"data":{"device":"bulb_color","group":"group_1"},"transaction": "123", "status":"ok"}),
{retain: false, qos: 0}, expect.any(Function)
);
});
+34 -17
View File
@@ -18,7 +18,7 @@ describe('HomeAssistant extension', () => {
this.version = `Zigbee2MQTT ${this.version.version}`;
jest.useRealTimers();
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
data.writeEmptyState();
MQTT.publish.mockClear();
settings.set(['homeassistant'], true);
@@ -248,7 +248,8 @@ describe('HomeAssistant extension', () => {
],
"brightness":true,
"brightness_scale":254,
"color_temp":true,
"color_mode": true,
"supported_color_modes": ["color_temp"],
"min_mireds": 250,
"max_mireds": 454,
"command_topic":"zigbee2mqtt/bulb/set",
@@ -270,13 +271,11 @@ describe('HomeAssistant extension', () => {
"finish_effect",
"stop_effect"
],
"hs":false,
"json_attributes_topic":"zigbee2mqtt/bulb",
"name":"bulb",
"schema":"json",
"state_topic":"zigbee2mqtt/bulb",
"unique_id":"0x000b57fffec6a5b2_light_zigbee2mqtt",
"xy":false
};
expect(MQTT.publish).toHaveBeenCalledWith(
@@ -603,8 +602,6 @@ describe('HomeAssistant extension', () => {
await flushPromises();
payload = {
"action_template":"{% set values = {'idle':'off','heat':'heating','cool':'cooling','fan only':'fan'} %}{{ values[value_json.running_state] }}",
"action_topic":"zigbee2mqtt/TS0601_thermostat",
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
"away_mode_command_topic":"zigbee2mqtt/TS0601_thermostat/set/away_mode",
"away_mode_state_template":"{{ value_json.away_mode }}",
@@ -669,7 +666,7 @@ describe('HomeAssistant extension', () => {
position_topic: 'zigbee2mqtt/smart vent',
set_position_topic: 'zigbee2mqtt/smart vent/set',
set_position_template: '{ "position": {{ position }} }',
value_template: '{{ value_json.position }}',
position_template: '{{ value_json.position }}',
json_attributes_topic: 'zigbee2mqtt/smart vent',
name: 'smart vent',
unique_id: '0x0017880104e45551_cover_zigbee2mqtt',
@@ -740,6 +737,26 @@ describe('HomeAssistant extension', () => {
expect(logger.warn).toHaveBeenCalledWith("In order for HomeAssistant integration to work properly set `cache_state: true");
});
it('Should set missing values to null', async () => {
// https://github.com/Koenkk/zigbee2mqtt/issues/6987
controller = new Controller(false);
await controller.start();
await flushPromises();
const device = zigbeeHerdsman.devices.WSDCGQ11LM;
const data = {measuredValue: -85}
const payload = {data, cluster: 'msTemperatureMeasurement', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10};
MQTT.publish.mockClear();
await zigbeeHerdsman.events.message(payload);
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(3);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/weather_sensor',
stringify({"battery":null,"humidity":null,"linkquality":null,"pressure":null,"temperature":-0.85,"voltage":null}),
{ retain: false, qos: 1 },
expect.any(Function),
);
});
it('Shouldt discover when already discovered', async () => {
controller = new Controller(false);
await controller.start();
@@ -823,7 +840,7 @@ describe('HomeAssistant extension', () => {
);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/remote',
stringify({"brightness":255,"update_available":false,"update":{"state":"idle"}}),
stringify({"action":null,"battery":null,"brightness":255,"linkquality":null,"update":{"state":"idle"},"update_available":false}),
{ retain: true, qos: 0 },
expect.any(Function)
);
@@ -849,7 +866,7 @@ describe('HomeAssistant extension', () => {
);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/remote',
stringify({"brightness":255,"update_available":false,"update":{"state":"idle"}}),
stringify({"action":null,"battery":null,"brightness":255,"linkquality":null,"update":{"state":"idle"},"update_available":false}),
{ retain: true, qos: 0 },
expect.any(Function)
);
@@ -1186,21 +1203,21 @@ describe('HomeAssistant extension', () => {
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/button',
stringify({action: "single", click: "single"}),
stringify({action: "single", click: "single", battery: null, linkquality: null, voltage: null}),
{ retain: false, qos: 0 },
expect.any(Function),
);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/button',
stringify({action: ""}),
stringify({action: "", battery: null, linkquality: null, voltage: null}),
{ retain: false, qos: 0 },
expect.any(Function),
);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/button',
stringify({click: ""}),
stringify({click: "", action: null, battery: null, linkquality: null, voltage: null}),
{ retain: false, qos: 0 },
expect.any(Function),
);
@@ -1349,7 +1366,7 @@ describe('HomeAssistant extension', () => {
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/button',
stringify({action: "single"}),
stringify({action: "single", "battery":null,"linkquality":null,"voltage":null}),
{ retain: false, qos: 0 },
expect.any(Function),
);
@@ -1365,9 +1382,9 @@ describe('HomeAssistant extension', () => {
await MQTT.events.message('zigbee2mqtt/U202DST600ZB/l2/set', stringify({state: 'ON', brightness: 20}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/U202DST600ZB', stringify({state_l2:"ON", brightness_l2:20}), {"qos": 0, "retain": false}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/U202DST600ZB', stringify({state_l2:"ON", brightness_l2:20, linkquality: null, state_l1: null}), {"qos": 0, "retain": false}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/U202DST600ZB/l2', stringify({state:"ON", brightness:20}), {"qos": 0, "retain": false}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/U202DST600ZB/l1', stringify({}), {"qos": 0, "retain": false}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/U202DST600ZB/l1', stringify({state: null}), {"qos": 0, "retain": false}, expect.any(Function));
});
it('Shouldnt crash in onPublishEntityState on group publish', async () => {
@@ -1395,10 +1412,10 @@ describe('HomeAssistant extension', () => {
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(4);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/button');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({action: 'single'});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({action: 'single', battery: null, linkquality: null, voltage: null});
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false});
expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/button');
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({action: ''});
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({action: '', battery: null, linkquality: null, voltage: null});
expect(MQTT.publish.mock.calls[1][2]).toStrictEqual({"qos": 0, "retain": false});
expect(MQTT.publish.mock.calls[2][0]).toStrictEqual('homeassistant/device_automation/0x0017880104e45520/action_single/config');
expect(MQTT.publish.mock.calls[3][0]).toStrictEqual('zigbee2mqtt/button/action');
+2 -2
View File
@@ -21,7 +21,7 @@ describe('Bridge legacy', () => {
beforeEach(() => {
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
data.writeDefaultState();
logger.info.mockClear();
logger.warn.mockClear();
@@ -188,7 +188,7 @@ describe('Bridge legacy', () => {
await flushPromises();
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bridge/log');
const payload = JSON.parse(MQTT.publish.mock.calls[0][1]);
expect(payload).toStrictEqual({"message":[{"ID":1,"devices":[],"friendly_name":"group_1","optimistic":true,"retain":false},{"ID":2,"devices":[],"friendly_name":"group_2","optimistic":true,"retain":false},{"ID":11,"devices":["bulb_2"],"friendly_name":"group_with_tradfri","optimistic":true,"retain":false},{"ID":12,"devices":["TS0601_thermostat"],"friendly_name":"thermostat_group","optimistic":true,"retain":false},{"ID":14,"devices":["power_plug"],"friendly_name":"switch_group","optimistic":true,"retain":false},{"ID":15071,"devices":["bulb_color_2","bulb_2"],"friendly_name":"group_tradfri_remote","optimistic":true,"retain":false}],"type":"groups"});
expect(payload).toStrictEqual({"message":[{"ID":1,"devices":[],"friendly_name":"group_1","optimistic":true,"retain":false},{"ID":2,"devices":[],"friendly_name":"group_2","optimistic":true,"retain":false},{"ID":11,"devices":["bulb_2"],"friendly_name":"group_with_tradfri","optimistic":true,"retain":false},{"ID":12,"devices":["TS0601_thermostat"],"friendly_name":"thermostat_group","optimistic":true,"retain":false},{"ID":14,"devices":["power_plug"],"friendly_name":"switch_group","optimistic":true,"retain":false},{"ID":21,"devices":["GLEDOPTO_2ID/cct"],"friendly_name":"gledopto_group","optimistic":true},{"ID":15071,"devices":["bulb_color_2","bulb_2"],"friendly_name":"group_tradfri_remote","optimistic":true,"retain":false}],"type":"groups"});
});
it('Should allow rename devices', async () => {
+1 -1
View File
@@ -71,7 +71,7 @@ describe('Report', () => {
beforeEach(async () => {
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
data.writeEmptyState();
settings.set(['advanced', 'report'], true);
for (const device of Object.values(zigbeeHerdsman.devices)) {
+11 -1
View File
@@ -14,7 +14,7 @@ describe('Logger', () => {
jest.resetModules();
settings = require('../lib/util/settings');
settings.set(['advanced', 'log_directory'], dir.name + '/%TIMESTAMP%');
settings._reRead();
settings.reRead();
stdOutWriteOriginal = console._stdout.write;
console._stdout.write = () => {};
});
@@ -138,4 +138,14 @@ describe('Logger', () => {
expect(pipes[1].tailable).toBeFalsy();
expect(pipes[1].maxsize).toBeNull();
});
it('Should allow to symlink logs to current directory', () => {
settings.set(['advanced', 'log_symlink_current'], true);
let logger = require('../lib/util/logger.js');
logger.logOutput();
expect(fs.readdirSync(dir.name).includes('current')).toBeTruthy()
jest.resetModules();
logger = require('../lib/util/logger.js');
});
});
+3 -3
View File
@@ -27,7 +27,7 @@ describe('Networkmap', () => {
beforeAll(async () => {
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
data.writeEmptyState();
fs.copyFileSync(path.join(__dirname, 'assets', 'mock-external-converter.js'), path.join(data.mockDir, 'mock-external-converter.js'));
settings.set(['external_converters'], ['mock-external-converter.js']);
@@ -97,7 +97,7 @@ describe('Networkmap', () => {
let call = MQTT.publish.mock.calls[0];
expect(call[0]).toStrictEqual('zigbee2mqtt/bridge/networkmap/raw');
const expected = {"links":[{"depth":1,"linkquality":120,"lqi":120,"relationship":2,"routes":[],"source":{"ieeeAddr":"0x000b57fffec6a5b3","networkAddress":40399},"sourceIeeeAddr":"0x000b57fffec6a5b3","sourceNwkAddr":40399,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":1,"linkquality":92,"lqi":92,"relationship":2,"routes":[{"destinationAddress":6540,"nextHop":40369,"status":"ACTIVE"}],"source":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"sourceIeeeAddr":"0x000b57fffec6a5b2","sourceNwkAddr":40369,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":1,"linkquality":92,"lqi":92,"relationship":2,"routes":[],"source":{"ieeeAddr":"0x0017880104e45511","networkAddress":1114},"sourceIeeeAddr":"0x0017880104e45511","sourceNwkAddr":1114,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":2,"linkquality":110,"lqi":110,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x000b57fffec6a5b3","networkAddress":40399},"sourceIeeeAddr":"0x000b57fffec6a5b3","sourceNwkAddr":40399,"target":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"targetIeeeAddr":"0x000b57fffec6a5b2"},{"depth":2,"linkquality":100,"lqi":100,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x0017880104e45559","networkAddress":6540},"sourceIeeeAddr":"0x0017880104e45559","sourceNwkAddr":6540,"target":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"targetIeeeAddr":"0x000b57fffec6a5b2"},{"depth":2,"linkquality":130,"lqi":130,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x0017880104e45521","networkAddress":6538},"sourceIeeeAddr":"0x0017880104e45521","sourceNwkAddr":6538,"target":{"ieeeAddr":"0x0017880104e45559","networkAddress":6540},"targetIeeeAddr":"0x0017880104e45559"}],"nodes":[{"definition":null,"failed":[],"friendlyName":"Coordinator","ieeeAddr":"0x00124b00120144ae","lastSeen":1000,"modelID":null,"networkAddress":0,"type":"Coordinator"},{"definition":{"description":"TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white","model":"LED1545G12","supports":"light (state, brightness, color_temp, color_temp_startup), effect, linkquality","vendor":"IKEA"},"failed":[],"friendlyName":"bulb","ieeeAddr":"0x000b57fffec6a5b2","lastSeen":1000,"modelID":"TRADFRI bulb E27 WS opal 980lm","networkAddress":40369,"type":"Router"},{"definition":{"description":"Hue Go","model":"7146060PH","supports":"light (state, brightness, color_temp, color_temp_startup, color_xy, color_hs), effect, linkquality","vendor":"Philips"},"failed":[],"friendlyName":"bulb_color","ieeeAddr":"0x000b57fffec6a5b3","lastSeen":1000,"modelID":"LLC020","networkAddress":40399,"type":"Router"},{"definition":{"description":"Aqara double key wireless wall switch (2016 model)","model":"WXKG02LM_rev1","supports":"battery, action, voltage, linkquality","vendor":"Xiaomi"},"friendlyName":"button_double_key","ieeeAddr":"0x0017880104e45521","lastSeen":1000,"modelID":"lumi.sensor_86sw2.es1","networkAddress":6538,"type":"EndDevice"},{"definition":null,"failed":["lqi","routingTable"],"friendlyName":"0x0017880104e45525","ieeeAddr":"0x0017880104e45525","lastSeen":1000,"manufacturerName":"Boef","modelID":"notSupportedModelID","networkAddress":6536,"type":"Router"},{"definition":{"description":"[CC2530 router](http://ptvo.info/cc2530-based-zigbee-coordinator-and-router-112/)","model":"CC2530.ROUTER","supports":"led, linkquality","vendor":"Custom devices (DiY)"},"failed":[],"friendlyName":"cc2530_router","ieeeAddr":"0x0017880104e45559","lastSeen":1000,"modelID":"lumi.router","networkAddress":6540,"type":"Router"},{"definition":{"description": "external","model":"external_converter_device","supports":"","vendor":"external"},"friendlyName":"0x0017880104e45511","ieeeAddr":"0x0017880104e45511","lastSeen":1000,"modelID":"external_converter_device","networkAddress":1114,"type":"EndDevice"}]};
const expected = {"links":[{"depth":1,"linkquality":120,"lqi":120,"relationship":2,"routes":[],"source":{"ieeeAddr":"0x000b57fffec6a5b3","networkAddress":40399},"sourceIeeeAddr":"0x000b57fffec6a5b3","sourceNwkAddr":40399,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":1,"linkquality":92,"lqi":92,"relationship":2,"routes":[{"destinationAddress":6540,"nextHop":40369,"status":"ACTIVE"}],"source":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"sourceIeeeAddr":"0x000b57fffec6a5b2","sourceNwkAddr":40369,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":1,"linkquality":92,"lqi":92,"relationship":2,"routes":[],"source":{"ieeeAddr":"0x0017880104e45511","networkAddress":1114},"sourceIeeeAddr":"0x0017880104e45511","sourceNwkAddr":1114,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":2,"linkquality":110,"lqi":110,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x000b57fffec6a5b3","networkAddress":40399},"sourceIeeeAddr":"0x000b57fffec6a5b3","sourceNwkAddr":40399,"target":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"targetIeeeAddr":"0x000b57fffec6a5b2"},{"depth":2,"linkquality":100,"lqi":100,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x0017880104e45559","networkAddress":6540},"sourceIeeeAddr":"0x0017880104e45559","sourceNwkAddr":6540,"target":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"targetIeeeAddr":"0x000b57fffec6a5b2"},{"depth":2,"linkquality":130,"lqi":130,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x0017880104e45521","networkAddress":6538},"sourceIeeeAddr":"0x0017880104e45521","sourceNwkAddr":6538,"target":{"ieeeAddr":"0x0017880104e45559","networkAddress":6540},"targetIeeeAddr":"0x0017880104e45559"}],"nodes":[{"definition":null,"failed":[],"friendlyName":"Coordinator","ieeeAddr":"0x00124b00120144ae","lastSeen":1000,"modelID":null,"networkAddress":0,"type":"Coordinator"},{"definition":{"description":"TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white","model":"LED1545G12","supports":"light (state, brightness, color_temp, color_temp_startup), effect, linkquality","vendor":"IKEA"},"failed":[],"friendlyName":"bulb","ieeeAddr":"0x000b57fffec6a5b2","lastSeen":1000,"modelID":"TRADFRI bulb E27 WS opal 980lm","networkAddress":40369,"type":"Router"},{"definition":{"description":"Hue Go","model":"7146060PH","supports":"light (state, brightness, color_temp, color_temp_startup, color_xy, color_hs), effect, linkquality","vendor":"Philips"},"failed":[],"friendlyName":"bulb_color","ieeeAddr":"0x000b57fffec6a5b3","lastSeen":1000,"modelID":"LLC020","networkAddress":40399,"type":"Router"},{"definition":{"description":"Aqara double key wireless wall switch (2016 model)","model":"WXKG02LM_rev1","supports":"battery, action, voltage, linkquality","vendor":"Xiaomi"},"friendlyName":"button_double_key","ieeeAddr":"0x0017880104e45521","lastSeen":1000,"modelID":"lumi.sensor_86sw2.es1","networkAddress":6538,"type":"EndDevice"},{"definition":null,"failed":["lqi","routingTable"],"friendlyName":"0x0017880104e45525","ieeeAddr":"0x0017880104e45525","lastSeen":1000,"manufacturerName":"Boef","modelID":"notSupportedModelID","networkAddress":6536,"type":"Router"},{"definition":{"description":"[CC2530 router](http://ptvo.info/cc2530-based-zigbee-coordinator-and-router-112/)","model":"CC2530.ROUTER","supports":"led, linkquality","vendor":"Custom devices (DiY)"},"failed":[],"friendlyName":"cc2530_router","ieeeAddr":"0x0017880104e45559","lastSeen":1000,"modelID":"lumi.router","networkAddress":6540,"type":"Router"},{"definition":{"description": "external","model":"external_converter_device","supports":"linkquality","vendor":"external"},"friendlyName":"0x0017880104e45511","ieeeAddr":"0x0017880104e45511","lastSeen":1000,"modelID":"external_converter_device","networkAddress":1114,"type":"EndDevice"}]};
expect(JSON.parse(call[1])).toStrictEqual(expected);
/**
@@ -271,7 +271,7 @@ describe('Networkmap', () => {
let call = MQTT.publish.mock.calls[0];
expect(call[0]).toStrictEqual('zigbee2mqtt/bridge/response/networkmap');
const expected = {"data":{"routes":true,"type":"raw","value":{"links":[{"depth":1,"linkquality":120,"lqi":120,"relationship":2,"routes":[],"source":{"ieeeAddr":"0x000b57fffec6a5b3","networkAddress":40399},"sourceIeeeAddr":"0x000b57fffec6a5b3","sourceNwkAddr":40399,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":1,"linkquality":92,"lqi":92,"relationship":2,"routes":[{"destinationAddress":6540,"nextHop":40369,"status":"ACTIVE"}],"source":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"sourceIeeeAddr":"0x000b57fffec6a5b2","sourceNwkAddr":40369,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":1,"linkquality":92,"lqi":92,"relationship":2,"routes":[],"source":{"ieeeAddr":"0x0017880104e45511","networkAddress":1114},"sourceIeeeAddr":"0x0017880104e45511","sourceNwkAddr":1114,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":2,"linkquality":110,"lqi":110,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x000b57fffec6a5b3","networkAddress":40399},"sourceIeeeAddr":"0x000b57fffec6a5b3","sourceNwkAddr":40399,"target":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"targetIeeeAddr":"0x000b57fffec6a5b2"},{"depth":2,"linkquality":100,"lqi":100,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x0017880104e45559","networkAddress":6540},"sourceIeeeAddr":"0x0017880104e45559","sourceNwkAddr":6540,"target":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"targetIeeeAddr":"0x000b57fffec6a5b2"},{"depth":2,"linkquality":130,"lqi":130,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x0017880104e45521","networkAddress":6538},"sourceIeeeAddr":"0x0017880104e45521","sourceNwkAddr":6538,"target":{"ieeeAddr":"0x0017880104e45559","networkAddress":6540},"targetIeeeAddr":"0x0017880104e45559"}],"nodes":[{"definition":null,"failed":[],"friendlyName":"Coordinator","ieeeAddr":"0x00124b00120144ae","lastSeen":1000,"modelID":null,"networkAddress":0,"type":"Coordinator"},{"definition":{"description":"TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white","model":"LED1545G12","supports":"light (state, brightness, color_temp, color_temp_startup), effect, linkquality","vendor":"IKEA"},"failed":[],"friendlyName":"bulb","ieeeAddr":"0x000b57fffec6a5b2","lastSeen":1000,"modelID":"TRADFRI bulb E27 WS opal 980lm","networkAddress":40369,"type":"Router"},{"definition":{"description":"Hue Go","model":"7146060PH","supports":"light (state, brightness, color_temp, color_temp_startup, color_xy, color_hs), effect, linkquality","vendor":"Philips"},"failed":[],"friendlyName":"bulb_color","ieeeAddr":"0x000b57fffec6a5b3","lastSeen":1000,"modelID":"LLC020","networkAddress":40399,"type":"Router"},{"definition":{"description":"Aqara double key wireless wall switch (2016 model)","model":"WXKG02LM_rev1","supports":"battery, action, voltage, linkquality","vendor":"Xiaomi"},"friendlyName":"button_double_key","ieeeAddr":"0x0017880104e45521","lastSeen":1000,"modelID":"lumi.sensor_86sw2.es1","networkAddress":6538,"type":"EndDevice"},{"definition":null,"failed":["lqi","routingTable"],"friendlyName":"0x0017880104e45525","ieeeAddr":"0x0017880104e45525","lastSeen":1000,"manufacturerName":"Boef","modelID":"notSupportedModelID","networkAddress":6536,"type":"Router"},{"definition":{"description":"[CC2530 router](http://ptvo.info/cc2530-based-zigbee-coordinator-and-router-112/)","model":"CC2530.ROUTER","supports":"led, linkquality","vendor":"Custom devices (DiY)"},"failed":[],"friendlyName":"cc2530_router","ieeeAddr":"0x0017880104e45559","lastSeen":1000,"modelID":"lumi.router","networkAddress":6540,"type":"Router"},{"definition":{"description":"external","model":"external_converter_device","supports":"","vendor":"external"},"friendlyName":"0x0017880104e45511","ieeeAddr":"0x0017880104e45511","lastSeen":1000,"modelID":"external_converter_device","networkAddress":1114,"type":"EndDevice"}]}},"status":"ok"};
const expected = {"data":{"routes":true,"type":"raw","value":{"links":[{"depth":1,"linkquality":120,"lqi":120,"relationship":2,"routes":[],"source":{"ieeeAddr":"0x000b57fffec6a5b3","networkAddress":40399},"sourceIeeeAddr":"0x000b57fffec6a5b3","sourceNwkAddr":40399,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":1,"linkquality":92,"lqi":92,"relationship":2,"routes":[{"destinationAddress":6540,"nextHop":40369,"status":"ACTIVE"}],"source":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"sourceIeeeAddr":"0x000b57fffec6a5b2","sourceNwkAddr":40369,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":1,"linkquality":92,"lqi":92,"relationship":2,"routes":[],"source":{"ieeeAddr":"0x0017880104e45511","networkAddress":1114},"sourceIeeeAddr":"0x0017880104e45511","sourceNwkAddr":1114,"target":{"ieeeAddr":"0x00124b00120144ae","networkAddress":0},"targetIeeeAddr":"0x00124b00120144ae"},{"depth":2,"linkquality":110,"lqi":110,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x000b57fffec6a5b3","networkAddress":40399},"sourceIeeeAddr":"0x000b57fffec6a5b3","sourceNwkAddr":40399,"target":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"targetIeeeAddr":"0x000b57fffec6a5b2"},{"depth":2,"linkquality":100,"lqi":100,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x0017880104e45559","networkAddress":6540},"sourceIeeeAddr":"0x0017880104e45559","sourceNwkAddr":6540,"target":{"ieeeAddr":"0x000b57fffec6a5b2","networkAddress":40369},"targetIeeeAddr":"0x000b57fffec6a5b2"},{"depth":2,"linkquality":130,"lqi":130,"relationship":1,"routes":[],"source":{"ieeeAddr":"0x0017880104e45521","networkAddress":6538},"sourceIeeeAddr":"0x0017880104e45521","sourceNwkAddr":6538,"target":{"ieeeAddr":"0x0017880104e45559","networkAddress":6540},"targetIeeeAddr":"0x0017880104e45559"}],"nodes":[{"definition":null,"failed":[],"friendlyName":"Coordinator","ieeeAddr":"0x00124b00120144ae","lastSeen":1000,"modelID":null,"networkAddress":0,"type":"Coordinator"},{"definition":{"description":"TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white","model":"LED1545G12","supports":"light (state, brightness, color_temp, color_temp_startup), effect, linkquality","vendor":"IKEA"},"failed":[],"friendlyName":"bulb","ieeeAddr":"0x000b57fffec6a5b2","lastSeen":1000,"modelID":"TRADFRI bulb E27 WS opal 980lm","networkAddress":40369,"type":"Router"},{"definition":{"description":"Hue Go","model":"7146060PH","supports":"light (state, brightness, color_temp, color_temp_startup, color_xy, color_hs), effect, linkquality","vendor":"Philips"},"failed":[],"friendlyName":"bulb_color","ieeeAddr":"0x000b57fffec6a5b3","lastSeen":1000,"modelID":"LLC020","networkAddress":40399,"type":"Router"},{"definition":{"description":"Aqara double key wireless wall switch (2016 model)","model":"WXKG02LM_rev1","supports":"battery, action, voltage, linkquality","vendor":"Xiaomi"},"friendlyName":"button_double_key","ieeeAddr":"0x0017880104e45521","lastSeen":1000,"modelID":"lumi.sensor_86sw2.es1","networkAddress":6538,"type":"EndDevice"},{"definition":null,"failed":["lqi","routingTable"],"friendlyName":"0x0017880104e45525","ieeeAddr":"0x0017880104e45525","lastSeen":1000,"manufacturerName":"Boef","modelID":"notSupportedModelID","networkAddress":6536,"type":"Router"},{"definition":{"description":"[CC2530 router](http://ptvo.info/cc2530-based-zigbee-coordinator-and-router-112/)","model":"CC2530.ROUTER","supports":"led, linkquality","vendor":"Custom devices (DiY)"},"failed":[],"friendlyName":"cc2530_router","ieeeAddr":"0x0017880104e45559","lastSeen":1000,"modelID":"lumi.router","networkAddress":6540,"type":"Router"},{"definition":{"description":"external","model":"external_converter_device","supports":"linkquality","vendor":"external"},"friendlyName":"0x0017880104e45511","ieeeAddr":"0x0017880104e45511","lastSeen":1000,"modelID":"external_converter_device","networkAddress":1114,"type":"EndDevice"}]}},"status":"ok"};
const actual = JSON.parse(call[1]);
expect(actual).toStrictEqual(expected);
});
+1 -1
View File
@@ -23,7 +23,7 @@ describe('On event', () => {
beforeEach(async () => {
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
data.writeEmptyState();
controller = new Controller(jest.fn(), jest.fn());
await controller.start();
+7 -7
View File
@@ -18,7 +18,7 @@ describe('OTA update', () => {
beforeEach(async () => {
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
settings.set(['advanced', 'ikea_ota_use_test_url'], true);
data.writeEmptyState();
controller = new Controller(jest.fn(), jest.fn());
@@ -166,11 +166,11 @@ describe('OTA update', () => {
});
it('Should not check for OTA when device does not support it', async () => {
MQTT.events.message('zigbee2mqtt/bridge/request/device/ota_update/check', "ZNLDP12LM");
MQTT.events.message('zigbee2mqtt/bridge/request/device/ota_update/check', "dimmer_wall_switch");
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bridge/response/device/ota_update/check',
stringify({"data":{"id": "ZNLDP12LM"},"status":"error","error": `Device 'ZNLDP12LM' does not support OTA updates`}),
stringify({"data":{"id": "dimmer_wall_switch"},"status":"error","error": `Device 'dimmer_wall_switch' does not support OTA updates`}),
{retain: false, qos: 0}, expect.any(Function)
);
});
@@ -265,7 +265,7 @@ describe('OTA update', () => {
});
it('Should respond with NO_IMAGE_AVAILABLE when not supporting OTA', async () => {
const device = zigbeeHerdsman.devices.QBKG04LM;
const device = zigbeeHerdsman.devices.HGZB04D;
const data = {imageType: 12382};
const payload = {data, cluster: 'genOta', device, endpoint: device.getEndpoint(1), type: 'commandQueryNextImageRequest', linkquality: 10};
await zigbeeHerdsman.events.message(payload);
@@ -275,7 +275,7 @@ describe('OTA update', () => {
});
it('Shouldnt respond with NO_IMAGE_AVAILABLE when not supporting OTA and device has no OTA endpoint', async () => {
const device = zigbeeHerdsman.devices.QBKG03LM;
const device = zigbeeHerdsman.devices.SV01;
const data = {imageType: 12382};
const payload = {data, cluster: 'genOta', device, endpoint: device.getEndpoint(1), type: 'commandQueryNextImageRequest', linkquality: 10};
logger.error.mockClear();
@@ -374,9 +374,9 @@ describe('OTA update', () => {
});
it('Legacy api: Should not check for OTA when device does not support it', async () => {
MQTT.events.message('zigbee2mqtt/bridge/ota_update/check', 'ZNLDP12LM');
MQTT.events.message('zigbee2mqtt/bridge/ota_update/check', 'dimmer_wall_switch');
await flushPromises();
expect(logger.error).toHaveBeenCalledWith(`Device 'ZNLDP12LM' does not support OTA updates`);
expect(logger.error).toHaveBeenCalledWith(`Device 'dimmer_wall_switch' does not support OTA updates`);
});
it('Legacy api: Shouldnt crash when read modelID after OTA update fails', async () => {
+50 -28
View File
@@ -38,7 +38,7 @@ describe('Publish', () => {
await flushPromises();
data.writeDefaultConfiguration();
controller.state.state = {};
settings._reRead();
settings.reRead();
mocksClear.forEach((m) => m.mockClear());
Object.values(zigbeeHerdsman.devices).forEach((d) => {
d.endpoints.forEach((e) => {
@@ -139,7 +139,7 @@ describe('Publish', () => {
expect(endpoint.command).toHaveBeenCalledWith("lightingColorCtrl", "moveToColorTemp", {colortemp: 222, transtime: 0}, {});
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_temp: 222, color: {x: 0.360786471097048, y: 0.363543544699483}});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_mode: 'color_temp', color_temp: 222, color: {x: 0.360786471097048, y: 0.363543544699483}});
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false});
});
@@ -152,7 +152,7 @@ describe('Publish', () => {
expect(endpoint.command).toHaveBeenCalledWith("lightingColorCtrl", "moveToColorTemp", {colortemp: 500, transtime: 0}, {});
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_temp: 500, color: {x: 0.526676280311873, y: 0.41329727450763}});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_mode: 'color_temp', color_temp: 500, color: {x: 0.526676280311873, y: 0.41329727450763}});
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false});
});
@@ -219,7 +219,7 @@ describe('Publish', () => {
expect(endpoint.command).toHaveBeenCalledWith("lightingColorCtrl", "moveToColor", {colorx: 6553500, colory: 3276750, transtime: 0}, {});
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_temp: 62, color: {x: 100, y: 50}});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_mode: 'xy', color_temp: 62, color: {x: 100, y: 50}});
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false});
});
@@ -236,7 +236,7 @@ describe('Publish', () => {
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({state: 'ON'});
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false});
expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({color: {x: 100, y: 50}, color_temp: 62, state: 'ON'});
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({color_mode: 'xy', color: {x: 100, y: 50}, color_temp: 62, state: 'ON'});
expect(MQTT.publish.mock.calls[1][2]).toStrictEqual({"qos": 0, "retain": false});
});
@@ -253,7 +253,7 @@ describe('Publish', () => {
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({state: 'ON', brightness: 20});
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false});
expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({color: {x: 100, y: 50}, state: 'ON', color_temp: 62, brightness: 20});
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({color_mode: 'xy', color: {x: 100, y: 50}, state: 'ON', color_temp: 62, brightness: 20});
expect(MQTT.publish.mock.calls[1][2]).toStrictEqual({"qos": 0, "retain": false});
});
@@ -270,7 +270,7 @@ describe('Publish', () => {
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({state: 'ON', brightness: 20});
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false});
expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({color: {x: 100, y: 50}, state: 'ON', color_temp: 62, brightness: 20});
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({color: {x: 100, y: 50}, state: 'ON', color_temp: 62, brightness: 20, color_mode: 'xy'});
expect(MQTT.publish.mock.calls[1][2]).toStrictEqual({"qos": 0, "retain": false});
});
@@ -284,10 +284,10 @@ describe('Publish', () => {
expect(endpoint.command).toHaveBeenNthCalledWith(2, "genOnOff", "off", {}, {});
expect(MQTT.publish).toHaveBeenCalledTimes(2);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color: {x: 100, y: 50}, color_temp: 62});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_mode: 'xy', color: {x: 100, y: 50}, color_temp: 62});
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false});
expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({color: {x: 100, y: 50}, color_temp: 62, state: 'OFF'});
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({color_mode: 'xy', color: {x: 100, y: 50}, color_temp: 62, state: 'OFF'});
expect(MQTT.publish.mock.calls[1][2]).toStrictEqual({"qos": 0, "retain": false});
});
@@ -300,7 +300,7 @@ describe('Publish', () => {
expect(endpoint.command).toHaveBeenCalledWith("lightingColorCtrl", "moveToColor", {colorx: 17721, colory: 43148, transtime: 0}, {});
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_temp: 157, color: {x: 0.2704, y: 0.6584}});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_temp: 157, color: {x: 0.2704, y: 0.6584}, color_mode: 'xy'});
});
it('Should publish messages to zigbee devices with color rgb', async () => {
@@ -312,7 +312,7 @@ describe('Publish', () => {
expect(endpoint.command).toHaveBeenCalledWith("lightingColorCtrl", "moveToColor", {colorx: 17721, colory: 43148, transtime: 0}, {});
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_temp: 157, color: {x: 0.2704, y: 0.6584}});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_temp: 157, color: {x: 0.2704, y: 0.6584}, color_mode: 'xy'});
});
it('Should publish messages to zigbee devices with color rgb', async () => {
@@ -343,10 +343,10 @@ describe('Publish', () => {
await MQTT.events.message('zigbee2mqtt/group_1/set', stringify({brightness_percent: 50}));
await flushPromises();
expect(group.command).toHaveBeenCalledTimes(1);
expect(group.command).toHaveBeenCalledWith("genLevelCtrl", "moveToLevelWithOnOff", {level: 127, transtime: 0}, {});
expect(group.command).toHaveBeenCalledWith("genLevelCtrl", "moveToLevelWithOnOff", {level: 128, transtime: 0}, {});
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/group_1');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({state: 'ON', brightness: 127});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({state: 'ON', brightness: 128});
});
it('Should publish messages to groups when converter is not in the default list but device in it supports it', async () => {
@@ -387,7 +387,7 @@ describe('Publish', () => {
expect(group.command).toHaveBeenCalledWith("lightingColorCtrl", "moveToColor", {colorx: 24248, colory: 18350, transtime: 0}, {});
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/group_1');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color: {x: 0.37, y: 0.28}, color_temp: 249});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color: {x: 0.37, y: 0.28}, color_temp: 249, color_mode: 'xy'});
});
it('Should publish messages to groups color temperature', async () => {
@@ -398,15 +398,15 @@ describe('Publish', () => {
expect(group.command).toHaveBeenCalledWith("lightingColorCtrl", "moveToColorTemp", {colortemp: 100, transtime: 0}, {});
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/group_1');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color: {x: 0.280632719756407, y: 0.288286029784579}, color_temp: 100});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color: {x: 0.280632719756407, y: 0.288286029784579}, color_temp: 100, color_mode: 'color_temp'});
});
it('Should create and publish to group which is in configuration.yaml but not in zigbee-herdsman', async () => {
delete zigbeeHerdsman.groups.group_2;
expect(Object.values(zigbeeHerdsman.groups).length).toBe(7);
expect(Object.values(zigbeeHerdsman.groups).length).toBe(8);
await MQTT.events.message('zigbee2mqtt/group_2/set', stringify({state: 'ON'}));
await flushPromises();
expect(Object.values(zigbeeHerdsman.groups).length).toBe(8);
expect(Object.values(zigbeeHerdsman.groups).length).toBe(9);
expect(zigbeeHerdsman.groups.group_2.command).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsman.groups.group_2.command).toHaveBeenCalledWith("genOnOff", "on", {}, {});
});
@@ -554,7 +554,7 @@ describe('Publish', () => {
expect(endpoint.command).toHaveBeenCalledWith("lightingColorCtrl", "moveToColor", {colorx: 17721, colory: 43148, transtime: 0}, {});
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_temp: 157, color: {x: 0.2704, y: 0.6584}});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color_temp: 157, color: {x: 0.2704, y: 0.6584}, color_mode: "xy"});
});
it('Should parse set with ieeeAddr topic', async () => {
@@ -910,10 +910,10 @@ describe('Publish', () => {
await MQTT.events.message('zigbee2mqtt/bulb_color/set', stringify(payload));
await flushPromises();
expect(endpoint.command).toHaveBeenCalledTimes(1);
expect(endpoint.command.mock.calls[0]).toEqual(["lightingColorCtrl", "enhancedMoveToHueAndSaturation", {"direction": 0, "enhancehue": 44891.475, "saturation": 199.21474, "transtime": 0,}, {}]);
expect(endpoint.command.mock.calls[0]).toEqual(["lightingColorCtrl", "enhancedMoveToHueAndSaturation", {"direction": 0, "enhancehue": 44891, "saturation": 199, "transtime": 0,}, {}]);
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({"color":{"hue":250,"saturation":50}});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({"color":{"hue":250,"saturation":50}, "color_mode": "hs"});
});
it('ZNCLDJ11LM open', async () => {
@@ -1064,6 +1064,7 @@ describe('Publish', () => {
it('Home Assistant: should not set state when color temperature is also set and device is already on', async () => {
settings.set(['homeassistant'], true);
const device = zigbeeHerdsman.devices.bulb_color;
controller.state.remove(device.ieeeAddr);
controller.state.set(device.ieeeAddr, {state: 'ON'})
const endpoint = device.getEndpoint(1);
const payload = {state: 'ON', color_temp: 100};
@@ -1073,12 +1074,13 @@ describe('Publish', () => {
expect(endpoint.command.mock.calls[0]).toEqual(["lightingColorCtrl", "moveToColorTemp", {colortemp: 100, transtime: 0}, {}]);
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({state: 'ON', color: {x: 0.280632719756407, y: 0.288286029784579}, color_temp: 100});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({state: 'ON', color: {x: 0.280632719756407, y: 0.288286029784579}, color_temp: 100, color_mode: 'color_temp'});
});
it('Home Assistant: should set state when color temperature is also set and device is off', async () => {
settings.set(['homeassistant'], true);
const device = zigbeeHerdsman.devices.bulb_color;
controller.state.remove(device.ieeeAddr);
controller.state.set(device.ieeeAddr, {state: 'OFF'})
const endpoint = device.getEndpoint(1);
const payload = {state: 'ON', color_temp: 100};
@@ -1091,12 +1093,13 @@ describe('Publish', () => {
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({state: 'ON'});
expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({state: 'ON', color: {x: 0.280632719756407, y: 0.288286029784579}, color_temp: 100});
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({state: 'ON', color: {x: 0.280632719756407, y: 0.288286029784579}, color_temp: 100, color_mode: 'color_temp'});
});
it('Home Assistant: should not set state when color is also set', async () => {
settings.set(['homeassistant'], true);
const device = zigbeeHerdsman.devices.bulb_color;
controller.state.remove(device.ieeeAddr);
controller.state.set(device.ieeeAddr, {state: 'ON'})
const endpoint = device.getEndpoint(1);
const payload = {state: 'ON', color: {x: 0.41, y: 0.25}};
@@ -1106,7 +1109,7 @@ describe('Publish', () => {
expect(endpoint.command.mock.calls[0]).toEqual(["lightingColorCtrl", "moveToColor", {colorx: 26869, colory: 16384, transtime: 0}, {}]);
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bulb_color');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color: {x: 0.41, y: 0.25}, color_temp: 150, state: 'ON'});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({color: {x: 0.41, y: 0.25}, color_temp: 150, state: 'ON', color_mode: 'xy'});
});
it('Should publish correct state on toggle command to zigbee bulb', async () => {
@@ -1282,6 +1285,25 @@ describe('Publish', () => {
expect(logger.error).toHaveBeenCalledWith("No converter available for 'get' 'brightness_move' (20)");
});
it('Should restore brightness when its turned on with transition, Z2M is restarted and turned on again', async () => {
// https://github.com/Koenkk/zigbee2mqtt/issues/7106
const device = zigbeeHerdsman.devices.bulb_color;
const endpoint = device.getEndpoint(1);
endpoint.command.mockClear();
await MQTT.events.message('zigbee2mqtt/bulb_color/set', stringify({state: 'ON', brightness: 20, transition: 0.0}));
await flushPromises();
zigbeeHerdsmanConverters.toZigbeeConverters.__clearStore__();
await MQTT.events.message('zigbee2mqtt/bulb_color/set', stringify({"state": "ON", "transition": 1.0}));
await flushPromises();
expect(endpoint.command).toHaveBeenCalledTimes(2);
expect(endpoint.command).toHaveBeenCalledWith('genLevelCtrl', 'moveToLevelWithOnOff', {level: 20, transtime: 0}, {});
expect(endpoint.command).toHaveBeenCalledWith('genLevelCtrl', 'moveToLevelWithOnOff', {level: 20, transtime: 10}, {});
});
it('Should restore brightness when its turned off without transition and is turned on with', async () => {
// https://github.com/Koenkk/zigbee-herdsman-converters/issues/1097
const device = zigbeeHerdsman.devices.bulb_color;
@@ -1362,27 +1384,27 @@ describe('Publish', () => {
expect(MQTT.publish).toHaveBeenCalledTimes(5);
expect(MQTT.publish).toHaveBeenNthCalledWith(1,
'zigbee2mqtt/group_tradfri_remote',
stringify({"brightness":50,"color":{"x":0.408707336668894,"y":0.39239142575868},"color_temp":290,"state":"ON"}),
stringify({"brightness":50,"color":{"x":0.408707336668894,"y":0.39239142575868},"color_temp":290,"state":"ON","color_mode": "color_temp"}),
{retain: false, qos: 0}, expect.any(Function)
);
expect(MQTT.publish).toHaveBeenNthCalledWith(2,
'zigbee2mqtt/bulb_color_2',
stringify({"brightness":50,"color":{"x":0.408707336668894,"y":0.39239142575868},"color_temp":290,"state":"ON"}),
stringify({"color_mode": "color_temp", "brightness":50,"color":{"x":0.408707336668894,"y":0.39239142575868},"color_temp":290,"state":"ON"}),
{retain: false, qos: 0}, expect.any(Function)
);
expect(MQTT.publish).toHaveBeenNthCalledWith(3,
'zigbee2mqtt/group_tradfri_remote',
stringify({"brightness":100,"color":{"x":0.408707336668894,"y":0.39239142575868},"color_temp":290,"state":"ON"}),
stringify({"brightness":100,"color":{"x":0.408707336668894,"y":0.39239142575868},"color_temp":290,"state":"ON","color_mode": "color_temp"}),
{retain: false, qos: 0}, expect.any(Function)
);
expect(MQTT.publish).toHaveBeenNthCalledWith(4,
'zigbee2mqtt/bulb_2',
stringify({"brightness":100,"color":{"x":0.408707336668894,"y":0.39239142575868},"color_temp":290,"state":"ON"}),
stringify({"brightness":100,"state":"ON"}),
{retain: false, qos: 0}, expect.any(Function)
);
expect(MQTT.publish).toHaveBeenNthCalledWith(5,
'zigbee2mqtt/group_with_tradfri',
stringify({"brightness":100,"color":{"x":0.408707336668894,"y":0.39239142575868},"color_temp":290,"state":"ON"}),
stringify({"brightness":100,"state":"ON"}),
{retain: false, qos: 0}, expect.any(Function)
);
});
+2 -2
View File
@@ -15,7 +15,7 @@ describe('Receive', () => {
beforeEach(async () => {
jest.useRealTimers();
data.writeDefaultConfiguration();
settings._reRead();
settings.reRead();
data.writeEmptyState();
controller = new Controller(jest.fn(), jest.fn());
await controller.start();
@@ -64,7 +64,7 @@ describe('Receive', () => {
const payload = {data, cluster: 'msTemperatureMeasurement', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10};
await zigbeeHerdsman.events.message(payload);
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish).toHaveBeenCalledTimes(3);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/weather_sensor');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({temperature: -0.85});
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 1, "retain": false});
+16 -16
View File
@@ -22,7 +22,7 @@ describe('Settings', () => {
const write = (file, json, reread=true) => {
fs.writeFileSync(file, yaml.safeDump(json))
if (reread) {
settings._reRead();
settings.reRead();
}
};
const read = (file) => yaml.safeLoad(fs.readFileSync(file, 'utf8'));
@@ -616,7 +616,7 @@ describe('Settings', () => {
advanced: {network_key: 'NOT_GENERATE'},
});
settings._reRead();
settings.reRead();
const error = `advanced.network_key: should be array or 'GENERATE' (is 'NOT_GENERATE')`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -628,7 +628,7 @@ describe('Settings', () => {
advanced: {pan_id: 'NOT_GENERATE'},
});
settings._reRead();
settings.reRead();
const error = `advanced.pan_id: should be number or 'GENERATE' (is 'NOT_GENERATE')`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -641,7 +641,7 @@ describe('Settings', () => {
devices: {'0x0017880104e45519': {friendly_name: 'tain', retention: 900}},
});
settings._reRead();
settings.reRead();
expect(settings.validate()).toEqual([]);
});
@@ -652,7 +652,7 @@ describe('Settings', () => {
devices: {'0x0017880104e45519': {friendly_name: 'tain', retention: 900}},
});
settings._reRead();
settings.reRead();
const error = 'MQTT retention requires protocol version 5';
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -665,7 +665,7 @@ describe('Settings', () => {
advanced: {availability_blocklist: ['0x0017880104e45519', 'non_existing']},
});
settings._reRead();
settings.reRead();
const error = `Non-existing entity 'non_existing' specified in 'availability_blocklist'`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -677,7 +677,7 @@ describe('Settings', () => {
advanced: null,
});
settings._reRead();
settings.reRead();
const error = `advanced should be object`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -723,7 +723,7 @@ describe('Settings', () => {
groups: {'1': {friendly_name: 'myname', retain: false}},
});
settings._reRead();
settings.reRead();
const error = `Duplicate friendly_name 'myname' found`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -735,7 +735,7 @@ describe('Settings', () => {
devices: {'0x0017880104e45519': {friendly_name: '', retain: false}},
});
settings._reRead();
settings.reRead();
const error = `friendly_name must be at least 1 char long`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -747,7 +747,7 @@ describe('Settings', () => {
devices: {'0x0017880104e45519': {friendly_name: 'blaa/', retain: false}},
});
settings._reRead();
settings.reRead();
const error = `friendly_name is not allowed to end or start with /`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -759,7 +759,7 @@ describe('Settings', () => {
devices: {'0x0017880104e45519': {friendly_name: 'blaa/blaa' + String.fromCharCode(0), retain: false}},
});
settings._reRead();
settings.reRead();
const error = `friendly_name is not allowed to contain null char`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -771,7 +771,7 @@ describe('Settings', () => {
devices: {'0x0017880104e45519': {friendly_name: 'myname/123', retain: false}},
});
settings._reRead();
settings.reRead();
const error = `Friendly name cannot end with a "/DIGIT" ('myname/123')`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -783,7 +783,7 @@ describe('Settings', () => {
devices: {'0x0017880104e45519': {friendly_name: 'myname#', retain: false}},
});
settings._reRead();
settings.reRead();
const error = `MQTT wildcard (+ and #) not allowed in friendly_name ('myname#')`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -795,7 +795,7 @@ describe('Settings', () => {
devices: {'0x0017880104e45519': {friendly_name: 'left', retain: false}},
});
settings._reRead();
settings.reRead();
const error = `Following friendly_name are not allowed: '${utils.getEndpointNames()}'`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
@@ -809,7 +809,7 @@ describe('Settings', () => {
},
});
settings._reRead();
settings.reRead();
expect(() => {
settings.changeFriendlyName('myname1', 'myname');
@@ -824,7 +824,7 @@ describe('Settings', () => {
},
});
settings._reRead();
settings.reRead();
expect(() => {
settings.removeDevice('myname33');
+13
View File
@@ -165,6 +165,15 @@ function writeDefaultConfiguration() {
'0x0017882194e45543': {
friendly_name: 'QS-Zigbee-D02-TRIAC-2C-LN',
},
'0x0017880104e45724': {
friendly_name: 'GLEDOPTO_2ID',
},
'0x0017880104e45561': {
friendly_name: 'temperature_sensor',
},
'0x0017880104e45562': {
friendly_name: 'heating_actuator',
}
},
groups: {
'1': {
@@ -194,6 +203,10 @@ function writeDefaultConfiguration() {
friendly_name: 'switch_group',
retain: false,
devices: ['power_plug'],
},
'21': {
friendly_name: 'gledopto_group',
devices: ['GLEDOPTO_2ID/cct'],
}
},
external_converters: [],
+15 -4
View File
@@ -26,10 +26,12 @@ const clusters = {
'genLevelCtrl': 8,
'lightingColorCtrl': 768,
'closuresWindowCovering': 258,
'hvacThermostat': 513,
'msTemperatureMeasurement': 1026,
}
class Endpoint {
constructor(ID, inputClusters, outputClusters, deviceIeeeAddress, binds=[], clusterValues={}, configuredReportings=[]) {
constructor(ID, inputClusters, outputClusters, deviceIeeeAddress, binds=[], clusterValues={}, configuredReportings=[], profileID=null, deviceID=null) {
this.deviceIeeeAddress = deviceIeeeAddress;
this.clusterValues = clusterValues;
this.ID = ID;
@@ -45,6 +47,8 @@ class Endpoint {
this.configureReporting = jest.fn();
this.meta = {};
this.binds = binds;
this.profileID = profileID;
this.deviceID = deviceID;
this.configuredReportings = configuredReportings;
this.getInputClusters = () => inputClusters.map((c) => {
return {ID: c, name: getKeyByValue(clusters, c)};
@@ -127,6 +131,7 @@ const bulb_color_2 = new Device('Router', '0x000b57fffec6a5b4', 401292, 4107, [n
const bulb_2 = new Device('Router', '0x000b57fffec6a5b7', 40369, 4476, [new Endpoint(1, [0,3,4,5,6,8,768,2821,4096], [5,25,32,4096], '0x000b57fffec6a5b7', [], {lightingColorCtrl: {colorCapabilities: 17}})], true, "Mains (single phase)", "TRADFRI bulb E27 WS opal 980lm");
const TS0601_thermostat = new Device('EndDevice', '0x0017882104a44559', 6544,4151, [new Endpoint(1, [], [], '0x0017882104a44559')], true, "Mains (single phase)", 'kud7u2l');
const ZNCZ02LM = new Device('Router', '0x0017880104e45524', 6540,4151, [new Endpoint(1, [0], [], '0x0017880104e45524')], true, "Mains (single phase)", "lumi.plug");
const GLEDOPTO_2ID = new Device('Router', '0x0017880104e45724', 6540,4151, [new Endpoint(11, [0,3,4,5,6,8,768], [], '0x0017880104e45724', [], {}, [], 49246, 528), new Endpoint(12, [0, 3, 4, 5, 6, 8, 768], [], '0x0017880104e45724', [], {}, [], 260, 258), new Endpoint(13, [4096], [4096], '0x0017880104e45724', [], {}, [], 49246, 57694), new Endpoint(15, [0, 3, 4, 5, 6, 8, 768], [], '0x0017880104e45724', [], {}, [], 49246, 256)], true, "Mains (single phase)", 'GL-C-007', false, 'GLEDOPTO');
const groups = {
'group_1': new Group(1, []),
@@ -135,6 +140,7 @@ const groups = {
'group_with_tradfri': new Group(11, [bulb_2.endpoints[0]]),
'thermostat_group': new Group(12, [TS0601_thermostat.endpoints[0]]),
'group_with_switch': new Group(14, [ZNCZ02LM.endpoints[0]]),
'gledopto_group': new Group(21, [GLEDOPTO_2ID.endpoints[3]]),
'default_bind_group': new Group(901, []),
}
@@ -149,7 +155,7 @@ const devices = {
'unsupported2': new Device('EndDevice', '0x0017880104e45529', 6536, 0, [new Endpoint(1, [0], [0,3,4,6,8,5])], true, "Battery", "notSupportedModelID"),
'interviewing': new Device('EndDevice', '0x0017880104e45530', 6536, 0, [new Endpoint(1, [0], [0,3,4,6,8,5])], true, "Battery", undefined, true),
'notInSettings': new Device('EndDevice', '0x0017880104e45519', 6537, 0, [new Endpoint(1, [0], [0,3,4,6,8,5])], true, "Battery", "lumi.sensor_switch.aq2"),
'WXKG11LM': new Device('EndDevice', '0x0017880104e45520', 6537,4151, [new Endpoint(1, [0], [0,3,4,6,8,5])], true, "Battery", "lumi.sensor_switch.aq2"),
'WXKG11LM': new Device('EndDevice', '0x0017880104e45520', 6537,4151, [new Endpoint(1, [0], [0,3,4,6,8,5], '0x0017880104e45520', [], {}, [{cluster: {name: 'genOnOff'}, attribute: {name: undefined, ID: 1337}, minimumReportInterval: 1, maximumReportInterval: 10, reportableChange: 20}])], true, "Battery", "lumi.sensor_switch.aq2"),
'WXKG02LM_rev1': new Device('EndDevice', '0x0017880104e45521', 6538,4151, [new Endpoint(1, [0], []), new Endpoint(2, [0], [])], true, "Battery", "lumi.sensor_86sw2.es1"),
'WSDCGQ11LM': new Device('EndDevice', '0x0017880104e45522', 6539,4151, [new Endpoint(1, [0], [])], true, "Battery", "lumi.weather"),
'RTCGQ11LM': new Device('EndDevice', '0x0017880104e45523', 6540,4151, [new Endpoint(1, [0], [])], true, "Battery", "lumi.sensor_motion.aq2"),
@@ -159,7 +165,8 @@ const devices = {
'QBKG03LM':new Device('Router', '0x0017880104e45542', 6540,4151, [new Endpoint(1, [0], [], '0x0017880104e45542'), new Endpoint(2, [0, 6], [], '0x0017880104e45542'), new Endpoint(3, [0, 6], [], '0x0017880104e45542')], true, "Mains (single phase)", 'lumi.ctrl_neutral2'),
'GLEDOPTO1112': new Device('Router', '0x0017880104e45543', 6540, 4151, [new Endpoint(11, [0], [], '0x0017880104e45543'), new Endpoint(13, [0], [], '0x0017880104e45543')], true, "Mains (single phase)", 'GL-C-008'),
'GLEDOPTO111213': new Device('Router', '0x0017880104e45544', 6540,4151, [new Endpoint(11, [0], []), new Endpoint(13, [0], []), new Endpoint(12, [0], [])], true, "Mains (single phase)", 'GL-C-008'),
'HGZB04D': new Device('Router', '0x0017880104e45545', 6540,4151, [new Endpoint(1, [0], [], '0x0017880104e45545')], true, "Mains (single phase)", 'FB56+ZSC05HG1.0'),
'GLEDOPTO_2ID': GLEDOPTO_2ID,
'HGZB04D': new Device('Router', '0x0017880104e45545', 6540,4151, [new Endpoint(1, [0], [25], '0x0017880104e45545')], true, "Mains (single phase)", 'FB56+ZSC05HG1.0'),
'ZNCLDJ11LM': new Device('Router', '0x0017880104e45547', 6540,4151, [new Endpoint(1, [0], []), new Endpoint(2, [0], [])], true, "Mains (single phase)", 'lumi.curtain'),
'HAMPTON99432': new Device('Router', '0x0017880104e45548', 6540,4151, [new Endpoint(1, [0], []), new Endpoint(2, [0], [])], true, "Mains (single phase)", 'HDC52EastwindFan'),
'HS2WD': new Device('Router', '0x0017880104e45549', 6540,4151, [new Endpoint(1, [0], [])], true, "Mains (single phase)", 'WarningDevice'),
@@ -182,8 +189,11 @@ const devices = {
'3157100': new Device('Router', '0x0017880104e44559', 6542,4151, [new Endpoint(1, [], [], '0x0017880104e44559')], true, "Mains (single phase)", '3157100'),
'J1': new Device('Router', '0x0017880104a44559', 6543,4151, [new Endpoint(1, [], [], '0x0017880104a44559')], true, "Mains (single phase)", 'J1 (5502)'),
'TS0601_thermostat': TS0601_thermostat,
'external_converter_device': new Device('EndDevice', '0x0017880104e45511', 1114, 'external', [], false, null, 'external_converter_device' ),
'external_converter_device': new Device('EndDevice', '0x0017880104e45511', 1114, 'external', [new Endpoint(1, [], [], '0x0017880104e45511')], false, null, 'external_converter_device' ),
'QS_Zigbee_D02_TRIAC_2C_LN':new Device('Router', '0x0017882194e45543', 6549,4151, [new Endpoint(1, [0], [], '0x0017882194e45543'), new Endpoint(2, [0, 6], [], '0x0017882194e45543')], true, "Mains (single phase)", 'TS110F', false, '_TYZB01_v8gtiaed'),
'unknown': new Device('Router', '0x0017980134e45545', 6540,4151, [], true, "Mains (single phase)"),
'temperature_sensor': new Device('EndDevice', '0x0017880104e45561', 6544,4151, [new Endpoint(1, [0,3,4,1026], [])], true, "Battery", "temperature.sensor"),
'heating_actuator': new Device('Router', '0x0017880104e45562', 6545,4151, [new Endpoint(1, [0,3,4,513], [1026])], true, "Mains (single phase)", "heating.actuator"),
}
const mock = {
@@ -221,6 +231,7 @@ const mock = {
return Object.values(groups).find((d) => d.groupID === groupID);
}),
getPermitJoin: jest.fn().mockReturnValue(false),
getPermitJoinTimeout: jest.fn().mockReturnValue(undefined),
reset: jest.fn(),
createGroup: jest.fn().mockImplementation((groupID) => {
const group = new Group(groupID, []);
+7 -1
View File
@@ -46,7 +46,7 @@ describe('Utils', () => {
var dependency = 'zigbee-herdsman';
expect(await utils.getDependencyVersion(dependency)).toStrictEqual({"version": versionHerdsman});
})
it('To local iso string', async () => {
var date = new Date('August 19, 1975 23:15:30 UTC+00:00');
var getTimezoneOffset = Date.prototype.getTimezoneOffset;
@@ -61,4 +61,10 @@ describe('Utils', () => {
var date = new Date('August 19, 1975 23:15:30 UTC+00:00');
expect(() => utils.formatDate(date, 'invalid', 1)).toThrowError("Unsupported type 'invalid'")
})
it('Get key', async () => {
expect(utils.getKey({'1': '1'}, '1', 2, null)).toBe('1');
expect(utils.getKey({'1': '1'}, '2', 2, null)).toBe(2);
expect(utils.getKey({'1': '1'}, '1', null, () => '3')).toBe('3');
})
});