Compare commits

...
736 Commits
Author SHA1 Message Date
Koen Kanters cdf62ea560 1.30.2 2023-03-01 16:43:20 +01:00
Koen Kanters 5dcd3f67ed Undev 2023-03-01 16:43:06 +01:00
github-actions[bot]andKoenkk b013a7d8ef Update zigbee-herdsman-converters to 15.0.58 (#16860)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-03-01 15:28:46 +00:00
github-actions[bot]andKoenkk 8e6e38b968 Update zigbee-herdsman to 0.14.96 (#16851)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-28 16:00:34 +00:00
github-actions[bot]andKoenkk 8f20640008 Update zigbee-herdsman-converters to 15.0.57 (#16850)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-28 15:51:18 +00:00
github-actions[bot]andnurikk 57707cd9b9 Update zigbee2mqtt-frontend to 0.6.125 (#16844)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2023-02-27 22:28:55 +00:00
github-actions[bot]andKoenkk 911683ad13 Update zigbee-herdsman-converters to 15.0.56 (#16841)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-27 19:42:13 +00:00
github-actions[bot]andKoenkk 99204682b8 Update dependencies (#16819)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-26 08:57:31 +01:00
github-actions[bot]andKoenkk fec7fca89e Update zigbee-herdsman-converters to 15.0.55 (#16814)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-25 10:17:03 +00:00
github-actions[bot]andKoenkk 6bea88eeb6 Update zigbee-herdsman to 0.14.95 (#16813)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-25 10:09:26 +00:00
github-actions[bot]andKoenkk 6afcb97c0d Update zigbee-herdsman-converters to 15.0.54 (#16798)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-23 17:09:09 +00:00
github-actions[bot]andKoenkk 73d60396bc Update zigbee-herdsman-converters to 15.0.53 (#16788)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-22 20:09:37 +00:00
Koen Kanters 942faf412f Revert "Capitalize entity name in Home Assistant (#16702)"
This reverts commit f5cceb1719.
2023-02-22 20:34:39 +01:00
github-actions[bot]andKoenkk b62f65f045 Update zigbee-herdsman-converters to 15.0.52 (#16771)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-21 16:26:31 +00:00
Artem Draft f5cceb1719 Capitalize entity name in Home Assistant (#16702) 2023-02-21 17:18:15 +01:00
github-actions[bot]andKoenkk 0b6040dd25 Update zigbee-herdsman-converters to 15.0.51 (#16765)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-20 19:32:31 +00:00
github-actions[bot]andKoenkk 45fda8aefd Update zigbee-herdsman to 0.14.94 (#16764)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-20 19:14:42 +00:00
Andreas Fritiofson 85f32c039f Add entity_category to indicator_mode and led_enable for Home Assistant discovery (#16744)
These names are used by some TuYa and IKEA devices.
2023-02-20 19:53:22 +01:00
github-actions[bot]andKoenkk 7fa2b5fcc3 Update zigbee-herdsman-converters to 15.0.50 (#16742)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-19 09:32:01 +00:00
github-actions[bot]andKoenkk 08a0ace11a Update dependencies (#16738)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-19 09:36:47 +01:00
github-actions[bot]andKoenkk 7605e1ec06 Update zigbee-herdsman-converters to 15.0.49 (#16722)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-18 08:53:16 +00:00
Koen Kanters e934b0d94e Support Hue effects for groups. https://github.com/Koenkk/zigbee2mqtt/issues/15997 2023-02-16 18:20:08 +01:00
github-actions[bot]andKoenkk 4aa8e17214 Update zigbee-herdsman-converters to 15.0.48 (#16694)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-15 19:36:12 +00:00
github-actions[bot]andKoenkk a9f5f7c620 Update zigbee-herdsman-converters to 15.0.47 (#16679)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-14 19:11:35 +00:00
github-actions[bot]andKoenkk 6e193ca442 Update zigbee-herdsman-converters to 15.0.46 (#16661)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-13 18:48:16 +00:00
Tami 2eadf30199 Fix error when device is added when device: [] in configuration.yaml (#16629)
* fix for TypeError: The "path" argument must be of type string in writeDevicesOrGroups

* added test case that produces the error when running on old implementation

Summary of all failing tests
 FAIL  test/settings.test.js
  ● Settings › Should add devices even when devices exist empty

    TypeError: The "path" argument must be of type string. Received undefined

      275 |
      276 | jest.mock('../../lib/util/data', () => ({
    > 277 |     joinPath: (file) => require('path').join(mockDir, file),
          |                                         ^
      278 |     getPath: () => mockDir,
      279 | }));
      280 |

      at Object.join [as joinPath] (test/stub/data.js:277:41)
      at joinPath (lib/util/settings.ts:245:38)
      at writeDevicesOrGroups (lib/util/settings.ts:250:5)
      at Object.write [as addDevice] (lib/util/settings.ts:555:5)
      at Object.addDevice (test/settings.test.js:128:18)
2023-02-13 19:41:49 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 600e743941 Bump alpine from 3.17.1 to 3.17.2 in /docker (#16659)
Bumps alpine from 3.17.1 to 3.17.2.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-13 19:23:38 +01:00
github-actions[bot]andKoenkk 932541649e Update zigbee-herdsman to 0.14.93 (#16635)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-12 08:44:39 +00:00
Artem Draft 0217593c77 Improve checks in HA covers (#16614) 2023-02-12 09:28:57 +01:00
github-actions[bot]andKoenkk 10e65b5f26 Update dependencies (#16632)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-12 09:17:14 +01:00
github-actions[bot]andKoenkk e9a38353fa Update zigbee-herdsman to 0.14.92 (#16616)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-10 20:42:59 +00:00
68caf0260d Update zigbee-herdsman-converters to 15.0.45 (#16604)
* Update zigbee-herdsman-converters to 15.0.45

* Fix tests

---------

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2023-02-09 18:32:04 +01:00
github-actions[bot]andKoenkk 7d887adb7f Update zigbee-herdsman to 0.14.91 (#16603)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-09 18:04:15 +01:00
github-actions[bot]andKoenkk ec57d899e5 Update zigbee-herdsman-converters to 15.0.44 (#16576)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-07 19:41:16 +00:00
github-actions[bot]andKoenkk 61b1732ecb Update zigbee-herdsman-converters to 15.0.43 (#16558)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-06 16:58:21 +00:00
Koen Kanters a35705cd38 Merge branch 'master' into dev 2023-02-06 17:49:55 +01:00
Koen Kanters eb878d3d8e 1.30.1 2023-02-06 17:42:06 +01:00
Robert Kaussow 3420cf508b disable buildx provenance in the ci build command (#16495) 2023-02-06 17:39:51 +01:00
Koen Kanters d5a3bf626f Update zigbee-herdsman-converters to 15.0.38-hotfix.0 2023-02-06 17:39:10 +01:00
github-actions[bot]andKoenkk 0e1220ff24 Update zigbee-herdsman-converters to 15.0.42 (#16542)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-05 14:54:53 +00:00
github-actions[bot]andKoenkk 1496b95067 Update dependencies (#16534)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-05 13:29:02 +01:00
github-actions[bot]andKoenkk bd0694e164 Update zigbee-herdsman to 0.14.90 (#16523)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-04 14:23:17 +00:00
github-actions[bot]andKoenkk d580741dfe Update zigbee-herdsman-converters to 15.0.41 (#16522)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-04 14:11:41 +00:00
Robert Kaussow a24586bec3 disable buildx provenance in the ci build command (#16495) 2023-02-04 14:12:24 +01:00
github-actions[bot]andKoenkk 1e7a76139d Update zigbee-herdsman-converters to 15.0.40 (#16487)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-02 16:57:11 +00:00
github-actions[bot]andKoenkk ea0a9990b9 Update zigbee-herdsman-converters to 15.0.39 (#16459)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-01 17:20:38 +00:00
Koen Kanters 97af5a64e7 Promote to dev 2023-02-01 17:17:11 +01:00
Koen Kanters 8f781db93e 1.30.0 2023-02-01 17:14:40 +01:00
Koen Kanters 1a6ba18ec2 Undev 2023-02-01 17:14:22 +01:00
Koen Kanters d91e363d76 Merge branch 'dev' 2023-02-01 17:13:53 +01:00
github-actions[bot]andKoenkk f7e45b8284 Update zigbee-herdsman-converters to 15.0.38 (#16452)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-02-01 14:58:34 +00:00
github-actions[bot]andKoenkk bbbaaf4d89 Update zigbee-herdsman-converters to 15.0.37 (#16443)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-31 17:17:49 +00:00
github-actions[bot]andKoenkk c9076f8ce6 Update zigbee-herdsman to 0.14.89 (#16442)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-31 18:11:43 +01:00
github-actions[bot]andKoenkk 82fd062668 Update zigbee-herdsman-converters to 15.0.36 (#16429)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-30 17:22:52 +00:00
github-actions[bot]andKoenkk 769a1afd96 Update zigbee-herdsman-converters to 15.0.35 (#16416)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-29 18:28:16 +00:00
Koen Kanters f943619387 Always respond to OTA request. https://github.com/Koenkk/zigbee2mqtt/issues/16371 2023-01-29 19:16:03 +01:00
github-actions[bot]andKoenkk 43e204b7d1 Update zigbee-herdsman-converters to 15.0.34 (#16409)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-29 11:55:41 +00:00
Koen Kanters a3f1399489 Log device OTA request response. https://github.com/Koenkk/zigbee2mqtt/issues/16371 2023-01-29 11:23:21 +01:00
github-actions[bot]andKoenkk 4179d879d2 Update dependencies (#16400)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-29 10:27:14 +01:00
github-actions[bot]andKoenkk 6ce2d2e73f Update zigbee-herdsman-converters to 15.0.33 (#16374)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-26 16:54:37 +00:00
github-actions[bot]andKoenkk 981542827c Update zigbee-herdsman-converters to 15.0.32 (#16355)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-25 18:24:35 +00:00
github-actions[bot]andKoenkk 2f0a2cee6e Update zigbee-herdsman-converters to 15.0.31 (#16335)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-24 16:30:10 +00:00
Koen Kanters 0bc685a8e3 Sanatize manufacturerName. https://github.com/home-assistant/core/issues/85691 2023-01-24 17:19:56 +01:00
Artem Draft 02a99703a8 Fix motor_state and moving in HA covers (#16324) 2023-01-24 17:00:24 +01:00
github-actions[bot]andKoenkk 7639ce44a7 Update zigbee-herdsman-converters to 15.0.30 (#16322)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-23 19:26:59 +00:00
Koen Kanters b89a99fe0c Fix another Failed to call 'Frontend' 'stop' . https://github.com/Koenkk/zigbee2mqtt/issues/16317 2023-01-23 20:21:03 +01:00
mtdcr 06820d2220 Sane defaults for remote syslog (#16300)
The most commonly used transport for remote syslog is port 514/udp.
It also is the only defined method for BSD syslog (RFC 3164). RFCs
5424+5425 specify an additional TLS transport via 6514/tcp, which
does not seem to be supported by zigbee2mqtt, as evidenced by the
lack of TLS-related configuration options in this area. RFC 6587
describes legacy uses of syslog over TCP, recommending against them.

Port 123, the previous default, was probably used by accident and
is reserved for NTP.

| $ grep -w -e 123 -e 514 -e 601 -e 6514 /etc/services
| ntp		123/udp				# Network Time Protocol
| shell		514/tcp		cmd syslog	# no passwords used
| syslog	514/udp
| syslog-tls	6514/tcp			# Syslog over TLS [RFC5425]
2023-01-23 19:31:10 +01:00
Roland Ramthun 140213950d Disable provenance information in Docker images (#16297)
* Disable provenance information in Docker images

The new default of buildx to include provenance information to OCI images causes a series of infrastructure issues with current Docker versions. 

Disable generation of the new provenance information until all necessary infrastructure software components and registries have been fixed to support it properly.

* Correct docker/setup-buildx-action version number
2023-01-23 19:26:43 +01:00
github-actions[bot]andKoenkk f4f2c498b7 Update zigbee-herdsman-converters to 15.0.29 (#16295)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-22 08:45:14 +00:00
github-actions[bot]andKoenkk 31807c6c6b Update zigbee-herdsman to 0.14.88 (#16294)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-22 08:08:45 +00:00
github-actions[bot]andKoenkk 8ccad8ee53 Update dependencies (#16293)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-22 09:03:03 +01:00
github-actions[bot]andKoenkk a930539dc3 Update zigbee-herdsman-converters to 15.0.28 (#16284)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-21 09:37:42 +00:00
github-actions[bot]andnurikk b33db9397d Update zigbee2mqtt-frontend to 0.6.124 (#16277)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2023-01-20 15:19:13 +00:00
github-actions[bot]andKoenkk de4b7fb022 Update zigbee-herdsman-converters to 15.0.27 (#16264)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-19 16:58:25 +00:00
github-actions[bot]andKoenkk 9e85419f9e Update zigbee-herdsman-converters to 15.0.26 (#16254)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-18 20:28:00 +00:00
github-actions[bot]andKoenkk 80c464c951 Update zigbee-herdsman-converters to 15.0.25 (#16230)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-17 16:29:30 +00:00
github-actions[bot]andKoenkk e56dff4972 Update zigbee-herdsman-converters to 15.0.24 (#16215)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-16 18:46:18 +00:00
Koen Kanters d8501f04eb Fix Failed to call 'Frontend' 'stop' (TypeError: Cannot read properties of null (reading 'clients') error. https://github.com/Koenkk/zigbee2mqtt/issues/16207 2023-01-16 19:19:51 +01:00
github-actions[bot]andKoenkk c927b4b935 Update zigbee-herdsman-converters to 15.0.23 (#16177)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-15 13:26:50 +00:00
github-actions[bot]andKoenkk fb9872a4ff Update dependencies (#16172)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-15 10:05:39 +01:00
39b0964739 Update zigbee-herdsman-converters to 15.0.22 (#16159)
* Update zigbee-herdsman-converters to 15.0.22

* Fix tests

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2023-01-14 13:39:45 +00:00
Koen Kanters 2c509c0368 Promote to dev 2023-01-13 22:33:21 +01:00
Koen Kanters 49e1c68cac Merge branch 'master' into dev 2023-01-13 22:32:50 +01:00
Koen Kanters bb3e8f6d41 1.29.2 2023-01-13 22:28:52 +01:00
Koen Kanters 835a3288a0 Update zh to 0.14.83-hotfix.0 and zhc to 15.0.12-hotfix.1 2023-01-13 22:27:36 +01:00
Koen Kanters cddbb9a5e5 Fix f600066134 2023-01-13 16:59:20 +01:00
github-actions[bot]andnurikk 65366478e3 Update zigbee2mqtt-frontend to 0.6.123 (#16143)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2023-01-13 11:33:49 +00:00
1d8b19dce9 Update zigbee-herdsman-converters to 15.0.21 (#16123)
* Update zigbee-herdsman-converters to 15.0.21

* Fix tests

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2023-01-12 17:34:49 +00:00
Koen Kanters f600066134 Fix 328b9fbd60. https://github.com/Koenkk/zigbee2mqtt/issues/15958 2023-01-12 17:20:07 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 75533c20b8 Bump alpine from 3.17.0 to 3.17.1 in /docker (#16081)
Bumps alpine from 3.17.0 to 3.17.1.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-12 09:42:42 +01:00
Koen Kanters 0605a5e0e3 Attempt to improve Log when MQTT client is unavailable stability 2023-01-12 09:41:30 +01:00
cf9640bd59 Update zigbee-herdsman-converters to 15.0.20 (#16106)
* Update zigbee-herdsman-converters to 15.0.20

* Fix tests

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2023-01-12 08:37:17 +00:00
Koen Kanters 328b9fbd60 Remove state_class measurement when unit_of_measurement is not set. https://github.com/Koenkk/zigbee2mqtt/issues/15958 2023-01-11 18:23:13 +01:00
github-actions[bot]andnurikk bc6d1070c7 Update zigbee2mqtt-frontend to 0.6.122 (#16092)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2023-01-11 09:29:08 +00:00
github-actions[bot]andKoenkk bf339636b5 Update zigbee-herdsman to 0.14.87 (#16068)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-09 21:50:14 +00:00
github-actions[bot]andKoenkk d90dae5d9d Update zigbee-herdsman to 0.14.86 (#16066)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-09 21:00:50 +01:00
github-actions[bot]andKoenkk b34b0e866f Update zigbee-herdsman-converters to 15.0.19 (#16062)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-09 18:57:47 +00:00
Dan Klaffenbach 2288c0f1c2 Poll Busch-Jaeger devices for updates after binding-initiated changes (#16036)
The Busch-Jaeger devices don't support reporting and therefore their
state should be polled after being changed through a binding partner.
2023-01-09 19:18:13 +01:00
Miguel Cabral 9c4abb64c3 Expose cover moving state to Home Assistant (#16017) 2023-01-08 10:05:29 +01:00
github-actions[bot]andKoenkk 559f235e88 Update zigbee-herdsman-converters to 15.0.18 (#16023)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-08 09:01:56 +00:00
github-actions[bot]andKoenkk 30df0e25f9 Update zigbee-herdsman to 0.14.85 (#16020)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-08 08:44:31 +00:00
Koen Kanters e7735112e8 Fix Home Assistant Entity sensor.xxx (<class 'homeassistant.components.mqtt.sensor.MqttSensor'>) is using native unit of measurement '' which is not a valid unit for the device class ('illuminance') warning. https://github.com/Koenkk/zigbee2mqtt/issues/15958 2023-01-08 08:50:10 +01:00
github-actions[bot]andKoenkk b943feef29 Update dependencies (#16019)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-08 08:45:04 +01:00
Koen Kanters e92d3f4ede Promote to dev 2023-01-07 10:26:02 +01:00
Koen Kanters 044cd0b3a6 Merge branch 'master' into dev 2023-01-07 10:25:19 +01:00
github-actions[bot]andKoenkk 3351bc2f42 Update zigbee-herdsman to 0.14.84 (#15978)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-06 11:29:07 +01:00
github-actions[bot]andKoenkk 6a8d236b4d Update zigbee-herdsman-converters to 15.0.17 (#15977)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-06 10:26:52 +00:00
Koen Kanters 7d67ffc429 1.29.1 2023-01-06 11:07:47 +01:00
Koen Kanters f984734961 Update zigbee-herdsman-converters to v15.0.12-hotfix.0 2023-01-06 11:07:14 +01:00
Koen Kanters 217fbb284a Fix Home Assistant Template variable warning: 'dict object' has no attribute 'latest_version' when rendering '{{ value_json['update']['latest_version'] }}' error attempt 2. https://github.com/Koenkk/zigbee2mqtt/issues/15747 2023-01-06 10:41:43 +01:00
Koen Kanters 9fe48e2a88 Revert "Expose cover moving state to Home Assistant (#15555)"
This reverts commit 56f7f3e1bd.
2023-01-06 10:41:37 +01:00
Koen Kanters 1c7817ad77 Fix Home Assistant Template variable warning: 'dict object' has no attribute 'latest_version' when rendering '{{ value_json['update']['latest_version'] }}' error. https://github.com/Koenkk/zigbee2mqtt/issues/15747 2023-01-06 10:41:13 +01:00
github-actions[bot]andKoenkk cf801344f8 Update zigbee-herdsman-converters to 15.0.16 (#15947)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-04 19:00:11 +00:00
Koen Kanters 50bca161ce Fix Home Assistant Template variable warning: 'dict object' has no attribute 'latest_version' when rendering '{{ value_json['update']['latest_version'] }}' error attempt 2. https://github.com/Koenkk/zigbee2mqtt/issues/15747 2023-01-04 19:49:27 +01:00
github-actions[bot]andKoenkk 15ccf945c3 Update zigbee-herdsman-converters to 15.0.15 (#15906)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-03 10:27:14 +00:00
Koen Kanters d49f06f34d Revert "Expose cover moving state to Home Assistant (#15555)"
This reverts commit 56f7f3e1bd.
2023-01-03 10:59:20 +01:00
github-actions[bot]andKoenkk 826f03220d Update zigbee-herdsman-converters to 15.0.14 (#15876)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-02 09:12:10 +00:00
Koen Kanters cdb984f830 Fix Home Assistant Template variable warning: 'dict object' has no attribute 'latest_version' when rendering '{{ value_json['update']['latest_version'] }}' error. https://github.com/Koenkk/zigbee2mqtt/issues/15747 2023-01-02 09:18:36 +01:00
github-actions[bot]andKoenkk 4e40c8223f Update zigbee-herdsman-converters to 15.0.13 (#15852)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-01 10:27:09 +00:00
github-actions[bot]andKoenkk 02d86ab233 Update dependencies (#15848)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2023-01-01 11:13:54 +01:00
Koen Kanters a49079f560 Dev 2023-01-01 10:58:37 +01:00
Koen Kanters dddce571d3 1.29.0 2023-01-01 10:53:46 +01:00
Koen Kanters f1841377db Undev 2023-01-01 10:52:49 +01:00
Koen Kanters f3edfbf75b Update generateNewSupportedDevices.js 2023-01-01 10:52:02 +01:00
github-actions[bot]andnurikk d701d96bb2 Update zigbee2mqtt-frontend to 0.6.121 (#15845)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-12-31 19:11:30 +00:00
github-actions[bot]andKoenkk 3b9d6c5651 Update zigbee-herdsman-converters to 15.0.12 (#15837)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-31 09:36:55 +00:00
MattandKoen Kanters 19bd87de4a Keep cached device state until Zigbee2MQTT is stopped (#15770)
* Fix extension path to make debugginge easier in VScode

* Fix linting error

* Add setting "cache_state_persist_on_leave" (default false)

This setting does not remove a device from State if it leaves the network

* Merge from upstream kk/dev

* Re-define cache_state_persist_on_leave to be a timeout

Allows the config to specify how long the state should be held (and the device to re-join & maintain the state).

Remove all pending deletions if the system is stopped

* Add debug. Fix "time" test

* Disable esline warnings for long debug lines

* Simplify state maintenance for leave/join devices

* Restore default configuration.yaml

* Don't track device presence via events, but examine herdsman on system stop

* Update configuration.yaml

* Update state.ts

* Update state.ts

* Update controller.test.js

* Update eventBus.ts

* Update eventBus.ts

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-12-31 10:15:11 +01:00
github-actions[bot]andKoenkk af27e910d8 Update zigbee-herdsman-converters to 15.0.11 (#15816)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-30 08:22:39 +00:00
github-actions[bot]andKoenkk d8f1f3ef06 Update zigbee-herdsman-converters to 15.0.10 (#15797)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-29 09:50:01 +00:00
Koen Kanters 5b2756fef3 Build linux/386 Docker image. https://github.com/Koenkk/zigbee2mqtt/issues/15796 2022-12-29 10:44:15 +01:00
github-actions[bot]andKoenkk 75db8cf3f1 Update zigbee-herdsman-converters to 15.0.9 (#15775)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-28 08:28:49 +00:00
github-actions[bot]andKoenkk b4660417f8 Update zigbee-herdsman-converters to 15.0.8 (#15764)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-27 08:28:19 +00:00
github-actions[bot]andKoenkk 75e677608b Update zigbee-herdsman-converters to 15.0.7 (#15757)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-26 11:43:44 +00:00
Matt 05cb1406bb Fix extension path to make debugging easier in VS Code (#15741)
* Fix extension path to make debugginge easier in VScode

* Fix linting error
2022-12-25 16:57:48 +01:00
github-actions[bot]andKoenkk 10c6d1e4d9 Update dependencies (#15746)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-25 16:40:03 +01:00
Koen Kanters 6d08a2f0f6 Use Node.js 18 in CI 2022-12-24 09:50:32 +01:00
Koen Kanters 8d8c46ecae Reduce Docker image size 2022-12-24 09:45:15 +01:00
Koen Kanters 1f642d86e8 Add disabled option (#15589)
* Add disabled option

* Updates

* Tests

* Add restart required
2022-12-23 23:56:29 +01:00
github-actions[bot]andKoenkk 5afda96cf4 Update zigbee-herdsman-converters to 15.0.6 (#15722)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-23 19:39:13 +00:00
github-actions[bot]andnurikk 2550ca5978 Update zigbee2mqtt-frontend to 0.6.120 (#15717)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-12-23 16:55:52 +00:00
github-actions[bot]andKoenkk 566fc625cd Update zigbee-herdsman-converters to 15.0.4 (#15703)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-22 17:24:59 +00:00
github-actions[bot]andKoenkk 7f9de55b6c Update zigbee-herdsman-converters to 15.0.3 (#15689)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-21 19:18:48 +00:00
github-actions[bot]andKoenkk ccb5b49c80 Update zigbee-herdsman to 0.14.83 (#15688)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-21 19:13:08 +00:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> dea44579c3 Bump actions/stale from 6 to 7 (#15685)
Bumps [actions/stale](https://github.com/actions/stale) from 6 to 7.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-21 17:03:55 +01:00
github-actions[bot]andKoenkk 58445a2327 Update zigbee-herdsman to 0.14.82 (#15673)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-20 22:09:08 +00:00
github-actions[bot]andKoenkk 98cf8dbe5e Update zigbee-herdsman-converters to 15.0.2 (#15671)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-20 21:55:29 +00:00
github-actions[bot]andKoenkk 8fc83caac7 Update zigbee-herdsman-converters to 15.0.1 (#15651)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-19 20:07:35 +00:00
Miguel Cabral 56f7f3e1bd Expose cover moving state to Home Assistant (#15555) 2022-12-19 20:27:15 +01:00
Koen Kanters 01b46cf74e Use fileVersion for Home Assistant update sensor instead of softwareBuildID (#15630)
* Use fileVersion for Home Assistant update sensor instead of softwareBuildID. https://github.com/Koenkk/zigbee2mqtt/issues/15502

* Remove onlythis
2022-12-18 22:05:16 +01:00
github-actions[bot]andKoenkk 825c761c26 Update zigbee-herdsman-converters to 15.0.0 (#15631)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-18 21:04:48 +00:00
github-actions[bot]andKoenkk 443eb23a91 Update zigbee-herdsman-converters to 14.0.694 (#15624)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-18 13:01:34 +00:00
github-actions[bot]andKoenkk 9b78d85a46 Update dependencies (#15618)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-18 13:04:08 +01:00
6731c85981 Update zigbee-herdsman-converters to 14.0.693 (#15603)
* Update zigbee-herdsman-converters to 14.0.693

* fix tests

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-12-17 10:04:38 +00:00
github-actions[bot]andKoenkk da44667926 Update zigbee-herdsman-converters to 14.0.692 (#15573)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-15 20:02:58 +00:00
github-actions[bot]andKoenkk 3796084a27 Update zigbee-herdsman-converters to 14.0.691 (#15538)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-13 20:16:17 +00:00
Koen Kanters 4d32326a4f Fix failing configure blocking startup. https://github.com/Koenkk/zigbee2mqtt/issues/15299 2022-12-12 21:35:10 +01:00
github-actions[bot]andKoenkk 54d8002fd3 Update zigbee-herdsman-converters to 14.0.690 (#15517)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-12 20:31:55 +00:00
github-actions[bot]andKoenkk 21a30fc555 Update zigbee-herdsman-converters to 14.0.689 (#15490)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-11 09:44:07 +00:00
github-actions[bot]andKoenkk b90c0c4114 Update zigbee-herdsman to 0.14.81 (#15489)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-11 10:37:37 +01:00
github-actions[bot]andKoenkk e2deb23d77 Update dependencies (#15484)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-11 09:07:13 +01:00
github-actions[bot]andKoenkk b69d31d3ee Update zigbee-herdsman-converters to 14.0.688 (#15480)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-10 15:39:17 +00:00
github-actions[bot]andKoenkk 3481423810 Update zigbee-herdsman-converters to 14.0.687 (#15465)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-09 17:09:17 +00:00
github-actions[bot]andKoenkk d093200fec Update zigbee-herdsman to 0.14.80 (#15463)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-09 16:38:33 +00:00
eaf834a921 Update zigbee-herdsman to 0.14.79 (#15449)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-12-08 19:48:45 +01:00
github-actions[bot]andKoenkk 27377b0658 Update zigbee-herdsman-converters to 14.0.686 (#15448)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-08 18:40:40 +00:00
github-actions[bot]andKoenkk 2c53bc2c61 Update zigbee-herdsman-converters to 14.0.685 (#15430)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-07 19:15:23 +00:00
Gustav WestlingandKoen Kanters 83fae81724 docker: rebuild serialport from source (#15400)
* docker: rebuild serialport from source

* Update Dockerfile

* Update Dockerfile

* Update Dockerfile

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-12-07 17:54:24 +01:00
github-actions[bot]andKoenkk d075f0752e Update zigbee-herdsman-converters to 14.0.684 (#15399)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-06 17:21:51 +00:00
github-actions[bot]andKoenkk a29f90b441 Update zigbee-herdsman to 0.14.78 (#15398)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-06 17:11:48 +00:00
Koen Kanters 891392ff9a Revert "Fix Home Assistant installed_version error (#15369)" (#15396)
This reverts commit ba2d9aefe6.
2022-12-06 17:31:48 +01:00
Koen Kanters ba2d9aefe6 Fix Home Assistant installed_version error (#15369)
* Fix HA installed_version error

* add link
2022-12-05 16:52:11 +01:00
github-actions[bot]andKoenkk 586dda4d46 Update zigbee-herdsman-converters to 14.0.683 (#15356)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-04 20:09:14 +00:00
github-actions[bot]andKoenkk 1aa600ee59 Update zigbee-herdsman to 0.14.77 (#15355)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-04 19:56:20 +00:00
Pheel Tiandphil b0e352bfea Support HTTPS for frontend server (#15329)
* Adding 2 config params under 'frontend' : 'ssl_cert' and 'ssl_key' to contain file patch of certificate files to expose frontend in HTTPS.

* Taking all PR remarks in account.

Co-authored-by: phil <phil@8godsprod.com>
2022-12-04 19:33:04 +01:00
github-actions[bot]andKoenkk 959ca95219 Update dependencies (#15342)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-04 19:13:38 +01:00
github-actions[bot]andKoenkk 54bd9aa024 Update zigbee-herdsman-converters to 14.0.682 (#15320)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-02 16:55:00 +00:00
github-actions[bot]andKoenkk 0e4ea6a335 Update zigbee-herdsman-converters to 14.0.681 (#15287)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-01 19:18:59 +00:00
Koen Kanters ab1261385b Promote to dev 2022-12-01 19:59:17 +01:00
Koen Kanters 52e545f900 1.28.4 2022-12-01 19:58:42 +01:00
Koen Kanters 350abb354b Undev 2022-12-01 19:58:39 +01:00
Koen Kanters 87f253997c Update zhc to 14.0.681-hotfix.0 2022-12-01 19:56:37 +01:00
Koen Kanters 4e9b18fcbf Promote to dev 2022-12-01 17:38:11 +01:00
Koen Kanters e43c371d76 1.28.3 2022-12-01 17:35:02 +01:00
Koen Kanters a7e85a0bd9 Undev 2022-12-01 17:34:47 +01:00
Koen Kanters 7f6f6a69c7 Merge remote-tracking branch 'origin/master' into dev 2022-12-01 17:33:55 +01:00
github-actions[bot]andKoenkk 87667bdac7 Update zigbee-herdsman-converters to 14.0.680 (#15276)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-12-01 15:02:29 +00:00
github-actions[bot]andKoenkk bd8edd70bb Update zigbee-herdsman-converters to 14.0.679 (#15262)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-30 16:06:01 +00:00
github-actions[bot]andKoenkk 4a3e6b9561 Update zigbee-herdsman-converters to 14.0.678 (#15249)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-29 18:45:39 +00:00
Artem Draft f92134fc5f Disable by default update_available sensor in HA (#15237) 2022-11-29 19:18:33 +01:00
9dba2d7f11 Update zigbee-herdsman-converters to 14.0.677 (#15229)
* Update zigbee-herdsman-converters to 14.0.677

* Fix

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-11-28 18:49:34 +00:00
9289a26f11 Update dependencies (#15204)
* Update dependencies

* Fix diff

* fix

* update

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-11-27 14:52:47 +01:00
github-actions[bot]andKoenkk 17054627e9 Update zigbee-herdsman-converters to 14.0.676 (#15207)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-27 09:38:39 +00:00
github-actions[bot]andKoenkk 66c4ca072e Update zigbee-herdsman-converters to 14.0.675 (#15190)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-26 09:32:55 +00:00
github-actions[bot]andKoenkk 3b221d4fb0 Update zigbee-herdsman-converters to 14.0.674 (#15168)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-24 16:40:12 +00:00
github-actions[bot]andKoenkk 4464554f90 Update zigbee-herdsman to 0.14.76 (#15167)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-24 16:32:05 +00:00
b15cd433c4 Update zigbee-herdsman-converters to 14.0.673 (#15150)
* Update zigbee-herdsman-converters to 14.0.673

* Update homeassistant.test.js

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-11-23 17:56:32 +00:00
github-actions[bot]andKoenkk 4b5a03c6c5 Update zigbee-herdsman to 0.14.75 (#15149)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-23 16:10:46 +00:00
github-actions[bot]andKoenkk ca4badca4d Update zigbee-herdsman-converters to 14.0.672 (#15133)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-22 19:03:36 +00:00
DJTerentjevandAlex 1b3dd7540b Add polling when bounded for Trust and Gledopto (#15126)
* GitHub Workflows security hardening (#14799)

* build: harden update_frontend.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* build: harden update_zhc.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* build: harden ghcr_cleanup.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* build: harden update_zh.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* Add bound polling by manufacturerNames

Based on:
#7825

* Add bound polling by manufacturerNames

Based on:
#7825

Signed-off-by: Alex <aleksandrosansan@gmail.com>
Co-authored-by: Alex <aleksandrosansan@gmail.com>
2022-11-22 19:35:15 +01:00
Koen Kanters c7183ca080 Update external converter tester. 2022-11-22 19:16:25 +01:00
Koen Kanters 119531e9e2 Add external converter tester 2022-11-22 19:12:03 +01:00
85be7d28d5 Update zigbee-herdsman-converters to 14.0.671 (#15123)
* Update zigbee-herdsman-converters to 14.0.671

* Update homeassistant.ts

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-11-21 19:35:37 +00:00
github-actions[bot]andnurikk 6c147dae6c Update zigbee2mqtt-frontend to 0.6.119 (#15109)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-11-20 20:48:42 +00:00
github-actions[bot]andKoenkk 1fe138c34c Update zigbee-herdsman-converters to 14.0.670 (#15107)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-20 18:26:44 +00:00
github-actions[bot]andKoenkk 1258aee464 Update zigbee-herdsman to 0.14.74 (#15105)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-20 16:35:01 +00:00
github-actions[bot]andnurikk fbb0ed0e67 Update zigbee2mqtt-frontend to 0.6.118 (#15083)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-11-19 11:16:56 +00:00
github-actions[bot]andKoenkk 8510e99010 Update zigbee-herdsman-converters to 14.0.669 (#15053)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-17 17:07:37 +00:00
Koen Kanters 342955666a Fix 'dict object' has no attribute 'installed_version'. https://github.com/Koenkk/zigbee2mqtt/discussions/15039 2022-11-17 17:52:59 +01:00
github-actions[bot]andKoenkk 50cb421f64 Update zigbee-herdsman-converters to 14.0.668 (#15007)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-15 19:38:26 +00:00
github-actions[bot]andnurikk 16398b7810 Update zigbee2mqtt-frontend to 0.6.117 (#14995)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-11-15 11:36:57 +00:00
github-actions[bot]andKoenkk f3b5aee173 Update zigbee-herdsman-converters to 14.0.667 (#14983)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-14 20:16:38 +00:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> e8f85b35c1 Bump actions/dependency-review-action from 2 to 3 (#14978)
Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 2 to 3.
- [Release notes](https://github.com/actions/dependency-review-action/releases)
- [Commits](https://github.com/actions/dependency-review-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/dependency-review-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-14 18:13:49 +01:00
github-actions[bot]andKoenkk dd8f13aa8d Update zigbee-herdsman to 0.14.73 (#14979)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-14 17:07:35 +00:00
dreed47 ced2ba7344 small clarification to the description for adding a user-defined device icon (#14960)
* small clarification to the description for adding a user-defined device icon

* small wording change
2022-11-14 17:49:18 +01:00
Jakub Jirutka a2f8534823 Allow to specify full file name in value reference '!' (#14955)
* Extract parsing of value reference '!' in settings into a function

* Allow to specify full file name in value reference '!'

This `network_key: '!secret network_key'` is really confusing because
it looks like a YAML tag named 'secret' and a value "network_key".
When we write `network_key: '!secret.yaml network_key'` instead, it's
a little clearer what's going on. Also, it's more consistent with file
references in 'devices' and 'groups'.
2022-11-13 15:17:59 +01:00
github-actions[bot]andKoenkk d05ef70901 Update zigbee-herdsman to 0.14.72 (#14958)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-13 09:26:45 +00:00
Jakub JirutkaandKoen Kanters 4bc0c3ed6b Use path.resolve instead of path.join in data.joinPath (#14953)
This allows specifying a path outside of the data directory using an
absolute path (e.g. /path/to/devices.yaml) or a path relative to the data
directory (e.g. devices.yaml, foo/devices.yaml, ../../devices.yaml, ...).
This change is backward compatible because file names and nested paths are
just a special case of a relative path.

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-11-13 09:24:47 +01:00
Koen Kanters 489d1de756 Fix Cannot set properties of undefined (setting 'installed_version'). https://github.com/Koenkk/zigbee2mqtt/issues/14917 2022-11-13 09:21:27 +01:00
github-actions[bot]andKoenkk 499b993410 Update zigbee-herdsman to 0.14.71 (#14946)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-12 15:20:46 +00:00
github-actions[bot]andKoenkk 9f0b16291a Update zigbee-herdsman-converters to 14.0.666 (#14930)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-11 16:16:51 +00:00
github-actions[bot]andKoenkk 98a6a2dfe8 Update zigbee-herdsman-converters to 14.0.665 (#14916)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-10 17:05:54 +00:00
Koen Kanters fb14ba20ca Update Docker image to use node:18-alpine3.16 (#14915) 2022-11-10 17:48:17 +01:00
Koen Kanters b68b984de6 Log Zigbee2MQTT started! on startup. https://github.com/Koenkk/zigbee2mqtt/issues/14283 2022-11-10 17:45:48 +01:00
Koen Kanters 1d36dfd932 Support Home Assistant MQTT update #14748 (#14905) 2022-11-09 21:01:30 +01:00
github-actions[bot]andKoenkk 672da64913 Update zigbee-herdsman-converters to 14.0.664 (#14900)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-09 18:53:08 +00:00
github-actions[bot]andKoenkk cb29e164f8 Update zigbee-herdsman-converters to 14.0.663 (#14889)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-08 18:20:43 +00:00
Vincenzo Mantova 1e6a457190 more Home Assistant icons (#14865)
* add missing icons and classes for BRT-100-TRV (and possibly others)

* use high/low thermometer icons for max/min temperatures
2022-11-08 16:24:19 +01:00
github-actions[bot]andKoenkk cd22dafc89 Update zigbee-herdsman-converters to 14.0.662 (#14860)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-07 17:34:17 +00:00
github-actions[bot]andKoenkk 83d8a0e6a2 Update zigbee-herdsman to 0.14.70 (#14858)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-07 17:06:27 +00:00
Vincenzo Mantova e0b765ba88 Revert "Respect climate system_mode ACCESS_SET bit in Home Assistant (#14715)" (#14842)
This reverts commit 58c800181a.
2022-11-07 17:38:30 +01:00
5e2df18b75 Update zigbee-herdsman-converters to 14.0.661 (#14839)
* Update zigbee-herdsman-converters to 14.0.661

* Fix tests

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-11-06 14:42:08 +00:00
github-actions[bot]andKoenkk 9b48334e0e Update zigbee-herdsman to 0.14.69 (#14838)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-06 12:51:48 +00:00
github-actions[bot]andKoenkk c8ae15e92d Update dependencies (#14834)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-06 13:37:56 +01:00
John DoeandAinur Timerbaev f88ac154a2 Mark node v19 as supported (#14837)
* Mark node19 as supported

* Fix condition

* Fix tests

Co-authored-by: Ainur Timerbaev <ainur.timerbaev@superawesome.com>
2022-11-06 12:28:59 +00:00
Alex e66fe8534e GitHub Workflows security hardening (#14799)
* build: harden update_frontend.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* build: harden update_zhc.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* build: harden ghcr_cleanup.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* build: harden update_zh.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

Signed-off-by: Alex <aleksandrosansan@gmail.com>
2022-11-05 14:21:55 +01:00
Jakub Jirutka c2e95bdb6a Remove core-js polyfills (#14788)
According to engines.node in package.json, the minimal supported version
of Node.js is 14.

* `Object.fromEntries()` is supported by Node.js since 12.0.0
* `Array.prototype.flat()` is supported by Node.js since 11.0.0

These polyfills were added in #9085, but the minimum supported Node.js
version has since been raised to 14.
2022-11-05 14:17:53 +01:00
github-actions[bot]andnurikk 7c5ef8a3d6 Update zigbee2mqtt-frontend to 0.6.115 (#14816)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-11-05 09:59:34 +00:00
Koen Kanters 4a2190f969 Add back fsevents 2022-11-04 19:35:14 +01:00
github-actions[bot]andKoenkk a3ed236524 Update dependencies (#14810)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-04 17:08:56 +01:00
Koen Kanters f4d8e6f4c5 Merge branch 'master' into dev 2022-11-04 17:05:54 +01:00
Koen Kanters 360a777a4e 1.28.2 2022-11-04 16:53:33 +01:00
Koen Kanters 5ed8b36cf2 Bump zigbee-herdsman-converters to 14.0.657-hotfix.0 2022-11-04 16:52:53 +01:00
github-actions[bot]andKoenkk 9540b6c182 Update zigbee-herdsman-converters to 14.0.660 (#14792)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-03 18:43:32 +00:00
Koen Kanters 31f002294e Update README.md 2022-11-02 22:00:25 +01:00
ecfc7e8906 Update zigbee-herdsman-converters to 14.0.659 (#14780)
* Update zigbee-herdsman-converters to 14.0.659

* Fix tests

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-11-02 20:56:54 +00:00
Koen Kanters 60bf855e74 Fix starting via cli.js. https://github.com/Koenkk/zigbee2mqtt/pull/14396 2022-11-02 20:01:06 +01:00
Koen Kanters c3f6e793fa Promote to dev 2022-11-01 19:59:25 +01:00
Koen Kanters 48117fddfa 1.28.1 2022-11-01 19:58:47 +01:00
Koen Kanters 7e70a5984f Undev 2022-11-01 19:58:44 +01:00
github-actions[bot]andKoenkk 4589c9f691 Update zigbee-herdsman-converters to 14.0.657 (#14753)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-01 18:51:21 +00:00
github-actions[bot]andKoenkk d81c15b5af Update zigbee-herdsman to 0.14.68 (#14754)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-01 16:44:28 +00:00
github-actions[bot]andKoenkk 043ae738d2 Update zigbee-herdsman to 0.14.67 (#14752)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-11-01 16:07:35 +00:00
github-actions[bot]andKoenkk 68184d669e Update zigbee-herdsman-converters to 14.0.655 (#14734)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-31 18:20:01 +00:00
github-actions[bot]andKoenkk fb3ee70c7a Update zigbee-herdsman-converters to 14.0.654 (#14727)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-30 19:07:00 +00:00
github-actions[bot]andKoenkk c5697e6c2b Update dependencies (#14718)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-30 19:23:11 +01:00
Vincenzo Mantova 58c800181a Respect climate system_mode ACCESS_SET bit in Home Assistant (#14715) 2022-10-30 19:16:32 +01:00
github-actions[bot]andKoenkk fd023268c5 Update zigbee-herdsman-converters to 14.0.652 (#14708)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-29 15:50:52 +00:00
github-actions[bot]andKoenkk 9dc93c7d27 Update zigbee-herdsman-converters to 14.0.651 (#14700)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-29 08:21:29 +00:00
Koen Kanters c943992e49 Fix 60de5b7676 2022-10-27 21:49:25 +02:00
github-actions[bot]andKoenkk dd9e92f81f Update zigbee-herdsman-converters to 14.0.650 (#14677)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-27 21:46:16 +02:00
Koen Kanters 60de5b7676 Respond with NO_IMAGE_AVAILABLE when device requests OTA. https://github.com/Koenkk/zigbee2mqtt/issues/13396 2022-10-27 20:39:44 +02:00
github-actions[bot]andKoenkk 6c0430b6e2 Update zigbee-herdsman-converters to 14.0.649 (#14660)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-26 16:57:24 +00:00
github-actions[bot]andKoenkk ddc4345f01 Update zigbee-herdsman-converters to 14.0.648 (#14633)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-24 17:49:52 +00:00
Koen Kanters 41053aa024 Set NODE_ENV to PRODUTION in Docker container. https://github.com/Koenkk/zigbee2mqtt/discussions/14625 2022-10-24 19:30:40 +02:00
github-actions[bot]andKoenkk 08ceae235e Update dependencies (#14602)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-23 09:09:56 +02:00
github-actions[bot]andKoenkk 599380dd63 Update zigbee-herdsman-converters to 14.0.647 (#14592)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-22 15:58:08 +00:00
github-actions[bot]andKoenkk a426ee1041 Update zigbee-herdsman-converters to 14.0.646 (#14576)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-21 14:44:53 +00:00
github-actions[bot]andKoenkk 939fdf0496 Update zigbee-herdsman-converters to 14.0.645 (#14553)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-19 15:59:22 +00:00
github-actions[bot]andKoenkk 3cffc2fdd8 Update zigbee-herdsman to 0.14.66 (#14549)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-19 15:26:35 +00:00
github-actions[bot]andKoenkk 22d2170d41 Update zigbee-herdsman-converters to 14.0.644 (#14540)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-18 18:16:04 +00:00
Vladyslav Pavlov 50a9de4e2b Expose step size of local_temperature_calibration Home Assistant sensor (#14502) 2022-10-18 17:59:32 +02:00
github-actions[bot]andKoenkk 2c12cbaf18 Update zigbee-herdsman to 0.14.65 (#14538)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-18 15:50:13 +00:00
github-actions[bot]andKoenkk ef6826f263 Update dependencies (#14503)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-18 17:38:26 +02:00
github-actions[bot]andKoenkk ceeaabafbc Update zigbee-herdsman-converters to 14.0.643 (#14458)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-12 19:47:13 +00:00
github-actions[bot]andKoenkk c49f5b157d Update zigbee-herdsman-converters to 14.0.642 (#14444)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-11 18:52:33 +00:00
github-actions[bot]andKoenkk 0a71e39253 Update zigbee-herdsman-converters to 14.0.641 (#14426)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-10 15:20:46 +00:00
github-actions[bot]andKoenkk 52a0f68c87 Update zigbee-herdsman-converters to 14.0.640 (#14416)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-09 18:19:11 +00:00
github-actions[bot]andKoenkk 457fc9da7c Update dependencies (#14411)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-09 09:01:32 +02:00
github-actions[bot]andKoenkk 5b39884c13 Update zigbee-herdsman-converters to 14.0.639 (#14403)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-08 12:18:16 +00:00
Matt 4d7b1a6c03 Allow Zigbee2MQTT to be installed as a module (#14396)
* Fix mnodule resolution

Allows the correct module path to be found if installed as a package

* Correct signature to avoid TS error

* Allow module to be included in another module

Only create hash ot auto-start if it is the main module, otherwise export the `start` function
2022-10-08 10:48:15 +02:00
Koen Kanters 50b5c67dde Support effects for Home Assistant light groups. #13438 2022-10-08 10:22:26 +02:00
Ben Windsor 005ada0237 Make temperature sensor selection for thermostats appear as a config item in HA (#14376) 2022-10-07 16:58:06 +02:00
github-actions[bot]andKoenkk e9b1080734 Update zigbee-herdsman-converters to 14.0.638 (#14374)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-06 16:12:23 +00:00
Ben Windsor 56cc1432e9 Mark min_temperature_limit as a config variable for HA (#14358) 2022-10-06 17:31:48 +02:00
github-actions[bot]andKoenkk e3dcc7b0a6 Update zigbee-herdsman-converters to 14.0.637 (#14353)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-05 19:08:45 +00:00
github-actions[bot]andKoenkk 37aea8df8f Update zigbee-herdsman to 0.14.64 (#14348)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-05 14:30:54 +00:00
github-actions[bot]andKoenkk f8d64b67ad Update zigbee-herdsman-converters to 14.0.636 (#14331)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-04 17:30:49 +00:00
github-actions[bot]andKoenkk 77fc3a9308 Update dependencies (#14279)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-04 19:26:54 +02:00
Ben Windsor db3730ea44 Expose value_step to home assistant if it has been set on a numeric type (#14313) 2022-10-04 18:02:35 +02:00
github-actions[bot]andnurikk 98ceaa04bb Update zigbee2mqtt-frontend to 0.6.114 (#14290)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-10-02 16:51:48 +00:00
github-actions[bot]andnurikk e3e4a0a440 Update zigbee2mqtt-frontend to 0.6.113 (#14271)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-10-01 09:41:07 +00:00
github-actions[bot]andKoenkk 52150b7257 Update zigbee-herdsman to 0.14.63 (#14270)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-01 08:53:48 +00:00
Koen Kanters 5727fe3a49 Dev 2022-10-01 09:40:35 +02:00
Koen Kanters 03ba647dc6 1.28.0 2022-10-01 09:39:09 +02:00
Koen Kanters be1e9b4421 Undev 2022-10-01 09:38:55 +02:00
github-actions[bot]andKoenkk 57ce1e98a7 Update zigbee-herdsman-converters to 14.0.635 (#14268)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-10-01 07:33:47 +00:00
github-actions[bot]andKoenkk 3d2d4fd298 Update zigbee-herdsman-converters to 14.0.633 (#14262)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-30 18:58:14 +00:00
github-actions[bot]andKoenkk 2258ed1dfa Update zigbee-herdsman to 0.14.62 (#14259)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-30 18:02:25 +00:00
github-actions[bot]andKoenkk 2d750f8b9a Update zigbee-herdsman-converters to 14.0.632 (#14254)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-29 20:31:02 +00:00
b54e29917e Update zigbee-herdsman to 0.14.61 (#14238)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-09-28 18:28:27 +00:00
Markus WegmannandKoen Kanters 3b60a8e02a Fix cover state publishing of multi-endpoint devices (#14200)
* Fix cover state publishing of multi-endpoint devices

* WIP testing

* WIP test for multiEndpoint cover device

* WIP zigfred plus test

* WIP zigfred plus test

* Remove zigfred plus meta testing flag

* Working zigfred plus integration into bridge test

* Working integration of zigfred plus in tests

* WIP zigfred plus testing

* Add working test for multi-cover devices. Working cover state for multi-cover + multi-light devices.

* Fix republishing of cover state

* Fix cover position and tilt readout with postfix topic

* Fix homeassistant.test.js for zigfred plus cover

* Fix cover value template to support multi-cover devices

* Update homeassistant.ts

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-09-28 20:21:30 +02:00
github-actions[bot]andKoenkk a95d47fef9 Update zigbee-herdsman-converters to 14.0.631 (#14232)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-28 15:14:56 +00:00
github-actions[bot]andKoenkk d385d6c1af Update zigbee-herdsman to 0.14.60 (#14231)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-28 15:12:36 +00:00
github-actions[bot]andnurikk 3453585fd0 Update zigbee2mqtt-frontend to 0.6.112 (#14216)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-09-27 15:55:09 +00:00
github-actions[bot]andKoenkk 7b72b85cf7 Update zigbee-herdsman-converters to 14.0.630 (#14186)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-25 08:15:30 +00:00
github-actions[bot]andKoenkk 47378c46bd Update dependencies (#14180)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-25 09:16:35 +02:00
github-actions[bot]andKoenkk 647d45c4fa Update zigbee-herdsman-converters to 14.0.629 (#14171)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-23 20:03:53 +00:00
github-actions[bot]andKoenkk 6775423b86 Update zigbee-herdsman to 0.14.59 (#14167)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-23 18:13:43 +00:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 3413d472ab Bump actions/stale from 5 to 6 (#14160)
Bumps [actions/stale](https://github.com/actions/stale) from 5 to 6.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-23 19:49:49 +02:00
github-actions[bot]andKoenkk d654e085ae Update zigbee-herdsman-converters to 14.0.628 (#14143)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-22 18:24:44 +00:00
github-actions[bot]andKoenkk 802803479e Update zigbee-herdsman to 0.14.58 (#14142)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-22 18:00:13 +00:00
github-actions[bot]andKoenkk 639babd9ab Update zigbee-herdsman-converters to 14.0.627 (#14127)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-21 18:05:46 +00:00
Koen Kanters 49f7a5ca1d Improve Home Assistant history view for sensors without unit. #14103 2022-09-21 17:11:03 +02:00
github-actions[bot]andKoenkk 615c70f3bb Update zigbee-herdsman to 0.14.57 (#14102)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-20 14:59:08 +00:00
github-actions[bot]andKoenkk 9b4a03c0e8 Update zigbee-herdsman-converters to 14.0.626 (#14083)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-19 16:17:25 +00:00
github-actions[bot]andKoenkk 0ccfb5aded Update zigbee-herdsman to 0.14.56 (#14082)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-19 18:01:46 +02:00
NoneangelandKoen Kanters 1966456814 Add HVAC swing mode to Home Assistant discovery (#13784)
* hvac swing mode

* test: add GW003-AS-IN-TE-FC to tested devices

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-09-19 17:56:58 +02:00
github-actions[bot]andKoenkk 925714022f Update dependencies (#14052)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-19 17:39:10 +02:00
github-actions[bot]andKoenkk 1e24734a6c Update zigbee-herdsman-converters to 14.0.625 (#14022)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-16 07:50:35 +00:00
github-actions[bot]andKoenkk c4fc5335d5 Update zigbee-herdsman to 0.14.55 (#14017)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-15 08:44:52 +00:00
github-actions[bot]andKoenkk 0133afaef0 Update zigbee-herdsman-converters to 14.0.624 (#14016)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-15 08:15:30 +00:00
github-actions[bot]andKoenkk 4d0fd3275b Update zigbee-herdsman-converters to 14.0.623 (#14004)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-14 07:41:56 +00:00
5f992cae76 Update zigbee-herdsman-converters to 14.0.622 (#13994)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-09-13 08:04:17 +00:00
Koen Kanters 5a24e62b51 Fix #ba1e3a06b62d9b53f456065f18807410333da3fd 2022-09-13 10:00:22 +02:00
Koen Kanters ba1e3a06b6 Fix cover value_template properties for multi endpoint devices. #13944 2022-09-13 09:16:24 +02:00
github-actions[bot]andKoenkk 809f5d3ed1 Update zigbee-herdsman-converters to 14.0.621 (#13977)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-12 09:25:13 +00:00
Koen Kanters 125ca61812 Log MQTT disconnect reason. #13965 2022-09-12 09:34:20 +02:00
Koen Kanters d38b8ff5f1 Fix cover state in Home Assistant for multi channel cover controllers. #13944 2022-09-12 09:30:07 +02:00
github-actions[bot]andKoenkk 3f7e9941e2 Update zigbee-herdsman-converters to 14.0.619 (#13961)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-11 08:13:59 +00:00
github-actions[bot]andKoenkk 8ba0fe9367 Update dependencies (#13955)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-11 09:39:20 +02:00
github-actions[bot]andKoenkk cbf75d6339 Update zigbee-herdsman-converters to 14.0.618 (#13949)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-10 07:51:44 +00:00
github-actions[bot]andKoenkk 0ea528f750 Update zigbee-herdsman-converters to 14.0.617 (#13936)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-09 07:51:25 +00:00
github-actions[bot]andKoenkk d12b6e0ca9 Update zigbee-herdsman to 0.14.54 (#13935)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-09 07:20:30 +00:00
github-actions[bot]andKoenkk 2b1d1ff6ef Update zigbee-herdsman-converters to 14.0.616 (#13915)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-08 08:11:04 +00:00
github-actions[bot]andKoenkk fc7de95d1d Update zigbee-herdsman-converters to 14.0.614 (#13897)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-07 08:16:05 +00:00
Koen Kanters 2bca5deb66 Fix setting devices/groups to file via environment variables not working. #7807 2022-09-07 10:07:16 +02:00
github-actions[bot]andKoenkk 8be8c4df56 Update zigbee-herdsman-converters to 14.0.613 (#13883)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-06 08:56:30 +00:00
Koen KantersandJohn Doe 9519ffdac7 Add install code support (#13780)
* Add install code support

* Update bridge.ts

Co-authored-by: John Doe <nurikk@users.noreply.github.com>
2022-09-06 09:30:03 +02:00
github-actions[bot]andKoenkk 0b645a4e6a Update zigbee-herdsman-converters to 14.0.611 (#13868)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-05 08:02:00 +00:00
github-actions[bot]andKoenkk 67a94621ab Update dependencies (#13842)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-05 09:10:10 +02:00
github-actions[bot]andnurikk 24d83b05f7 Update zigbee2mqtt-frontend to 0.6.111 (#13841)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-09-03 21:26:02 +00:00
Koen Kanters 178f72c304 Promote to dev 2022-09-01 11:27:14 +02:00
Koen Kanters 7dc48fb6d6 1.27.2 2022-09-01 11:24:20 +02:00
Koen Kanters 5017f556fa Undev 2022-09-01 11:24:17 +02:00
github-actions[bot]andKoenkk 437eeb350c Update zigbee-herdsman to 0.14.53 (#13793)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-01 11:23:29 +02:00
github-actions[bot]andKoenkk cfd792dc70 Update zigbee-herdsman to 0.14.52 (#13792)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-09-01 09:11:55 +00:00
Koen Kanters 2a4722bd38 Promote to dev 2022-09-01 08:42:29 +02:00
Koen Kanters d381f2daa4 1.27.1 2022-09-01 08:41:47 +02:00
Koen Kanters b05b4adf57 Undev 2022-09-01 08:40:53 +02:00
Koen Kanters 96d72103f2 Merge branch 'dev' 2022-09-01 08:37:54 +02:00
github-actions[bot]andKoenkk 97ffa9610b Update zigbee-herdsman-converters to 14.0.610 (#13782)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-31 16:46:59 +00:00
github-actions[bot]andKoenkk 09d6c8601c Update zigbee-herdsman to 0.14.51 (#13781)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-31 16:04:14 +00:00
github-actions[bot]andKoenkk fc409a6884 Update zigbee-herdsman-converters to 14.0.609 (#13769)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-30 15:38:45 +00:00
github-actions[bot]andnurikk fa63ede4b6 Update zigbee2mqtt-frontend to 0.6.110 (#13757)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-08-29 19:21:24 +00:00
github-actions[bot]andKoenkk fd24c8186e Update zigbee-herdsman to 0.14.50 (#13753)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-29 18:06:26 +00:00
github-actions[bot]andKoenkk 0816d07b93 Update zigbee-herdsman-converters to 14.0.608 (#13752)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-29 16:39:36 +00:00
github-actions[bot]andnurikk c1b9345613 Update zigbee2mqtt-frontend to 0.6.109 (#13748)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-08-29 10:30:15 +00:00
github-actions[bot]andKoenkk 7f198d18ac Update zigbee-herdsman-converters to 14.0.607 (#13739)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-28 17:49:58 +00:00
github-actions[bot]andKoenkk 802bccd1f3 Update zigbee-herdsman to 0.14.49 (#13736)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-28 15:26:35 +00:00
github-actions[bot]andKoenkk 77bd76d1ca Update zigbee-herdsman-converters to 14.0.606 (#13710)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-27 08:14:22 +00:00
github-actions[bot]andKoenkk 8dd8b2848c Update zigbee-herdsman-converters to 14.0.605 (#13703)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-26 19:23:43 +00:00
github-actions[bot]andKoenkk c5d54a845a Update zigbee-herdsman-converters to 14.0.604 (#13687)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-25 16:04:17 +00:00
github-actions[bot]andKoenkk f1a19151fc Update zigbee-herdsman-converters to 14.0.603 (#13670)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-24 17:08:37 +00:00
963c2d86d3 Update zigbee-herdsman-converters to 14.0.602 (#13654)
* Update zigbee-herdsman-converters to 14.0.602

* Fix tests

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-08-23 19:53:49 +00:00
9e6b4083b2 Update zigbee-herdsman-converters to 14.0.601 (#13646)
* Update zigbee-herdsman-converters to 14.0.601

* Fix tests

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-08-22 18:06:45 +00:00
github-actions[bot]andKoenkk f29c4a24c2 Update zigbee-herdsman-converters to 14.0.600 (#13634)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-21 18:23:36 +00:00
github-actions[bot]andKoenkk a75e1c2b2b Update dependencies (#13630)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-21 09:30:25 +02:00
github-actions[bot]andKoenkk 62499483ce Update zigbee-herdsman-converters to 14.0.599 (#13618)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-20 07:39:24 +00:00
github-actions[bot]andKoenkk 304bb7b9d1 Update zigbee-herdsman-converters to 14.0.598 (#13611)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-19 19:06:19 +00:00
github-actions[bot]andKoenkk 15a069e3c7 Update zigbee-herdsman to 0.14.48 (#13610)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-19 19:01:11 +00:00
Koen Kanters e0a9323d6e Update dont-stale label 2022-08-19 20:57:44 +02:00
github-actions[bot]andKoenkk a0182c2e39 Update zigbee-herdsman-converters to 14.0.597 (#13596)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-18 17:23:05 +00:00
github-actions[bot]andKoenkk 327f816c0e Update zigbee-herdsman-converters to 14.0.596 (#13586)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-17 18:29:55 +00:00
github-actions[bot]andnurikk 040d2a1b36 Update zigbee2mqtt-frontend to 0.6.108 (#13573)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-08-16 20:51:02 +00:00
github-actions[bot]andKoenkk 497a48b8b0 Update zigbee-herdsman-converters to 14.0.595 (#13569)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-16 18:59:33 +00:00
github-actions[bot]andKoenkk 36a4754430 Update zigbee-herdsman-converters to 14.0.594 (#13542)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-14 16:29:56 +00:00
Koen Kanters 60b9f6f6b2 Home Assistant discovery: add enums with only SET (e.g. selftest). https://github.com/Koenkk/zigbee2mqtt/issues/13532 2022-08-14 18:22:35 +02:00
github-actions[bot]andKoenkk 2bdc7b7aca Update dependencies (#13535)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-14 09:58:14 +02:00
github-actions[bot]andKoenkk fea5d44a57 Update zigbee-herdsman-converters to 14.0.593 (#13517)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-12 14:59:07 +00:00
Koen Kanters 281e3870d3 Fix tests 2022-08-11 20:32:01 +02:00
Koen Kanters c9b2a7f6d4 Revert "Publish device and bridge availability when Home Assistant comes online. https://github.com/Koenkk/zigbee2mqtt/issues/13382"
This reverts commit 619d5232db.
2022-08-11 20:23:40 +02:00
Koen Kanters 6314b86d9b Better fix for #13382 2022-08-11 20:23:19 +02:00
Koen Kanters 619d5232db Publish device and bridge availability when Home Assistant comes online. https://github.com/Koenkk/zigbee2mqtt/issues/13382 2022-08-11 19:50:46 +02:00
Koen Kanters da4a3b9a77 Fix exception when using group remove_all. https://github.com/Koenkk/zigbee2mqtt/issues/13484 2022-08-10 22:38:04 +02:00
github-actions[bot]andKoenkk 62284dbd1a Update zigbee-herdsman-converters to 14.0.592 (#13489)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-10 17:41:21 +00:00
wysiwyng addb09275a Add category and icon for flip_indicator_light Home Assistant discovery (#13477) 2022-08-10 16:57:31 +02:00
github-actions[bot]andKoenkk 9c45a5fdf0 Update zigbee-herdsman-converters to 14.0.591 (#13469)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-09 15:06:24 +00:00
Koen Kanters 0aa29a0fab Home Assistant discovery: always expose cover state. https://github.com/zigbee2mqtt/hassio-zigbee2mqtt/issues/359 2022-08-09 17:01:22 +02:00
github-actions[bot]andKoenkk 5f778a7570 Update zigbee-herdsman-converters to 14.0.590 (#13458)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-08 15:54:36 +00:00
github-actions[bot]andKoenkk e8f6def246 Update zigbee-herdsman-converters to 14.0.589 (#13447)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-07 16:27:47 +00:00
github-actions[bot]andKoenkk 99485fa324 Update dependencies (#13441)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-07 09:20:22 +02:00
github-actions[bot]andKoenkk 483ff4aa8a Update zigbee-herdsman-converters to 14.0.588 (#13424)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-06 08:02:28 +00:00
github-actions[bot]andKoenkk b6c0afc129 Update zigbee-herdsman-converters to 14.0.587 (#13402)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-04 19:55:35 +00:00
github-actions[bot]andKoenkk 7def5ea9bf Update zigbee-herdsman to 0.14.47 (#13394)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-03 16:06:19 +00:00
github-actions[bot]andKoenkk 4e590ece19 Update zigbee-herdsman-converters to 14.0.586 (#13376)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-02 17:42:22 +00:00
c2faa3815a Update zigbee-herdsman-converters to 14.0.585 (#13362)
* Update zigbee-herdsman-converters to 14.0.585

* Fix tests

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-08-01 18:12:28 +00:00
Koen Kanters 52f8753a09 Promote to dev 2022-08-01 17:44:02 +02:00
Koen Kanters a9b8808237 1.27.0 2022-08-01 17:43:26 +02:00
Koen Kanters 26b323e1f6 Undev 2022-08-01 17:43:20 +02:00
Koen Kanters 5990bb384a Merge branch 'dev' 2022-08-01 17:42:35 +02:00
github-actions[bot]andKoenkk be70b83be5 Update zigbee-herdsman-converters to 14.0.583 (#13355)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-08-01 15:08:54 +00:00
github-actions[bot]andKoenkk 7f28c557cd Update dependencies (#13340)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-31 09:55:29 +02:00
github-actions[bot]andKoenkk b1f9f5f3b3 Update zigbee-herdsman-converters to 14.0.582 (#13332)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-30 08:52:22 +00:00
github-actions[bot]andKoenkk f5740021a1 Update zigbee-herdsman-converters to 14.0.581 (#13327)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-29 15:16:24 +00:00
github-actions[bot]andKoenkk 2996cfaf07 Update zigbee-herdsman-converters to 14.0.580 (#13321)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-28 16:33:03 +00:00
github-actions[bot]andKoenkk eda087af99 Update zigbee-herdsman-converters to 14.0.579 (#13303)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-26 18:10:02 +00:00
Koen Kanters 343ef7fd9f Only republish retained messages when none are received. #9629 2022-07-25 19:37:33 +02:00
Koen Kanters 316daee49d Republish retained messages when reconnected to MQTT server. #9629 2022-07-24 22:17:29 +02:00
github-actions[bot]andKoenkk 68aae1a450 Update zigbee-herdsman-converters to 14.0.578 (#13272)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-24 15:23:53 +00:00
github-actions[bot]andKoenkk d92b2f2ea9 Update dependencies (#13266)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-24 16:59:01 +02:00
github-actions[bot]andKoenkk e132a22f20 Update zigbee-herdsman-converters to 14.0.577 (#13260)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-23 15:36:49 +00:00
github-actions[bot]andKoenkk ebcf49b504 Update zigbee-herdsman-converters to 14.0.576 (#13254)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-23 10:30:57 +00:00
github-actions[bot]andKoenkk 6a2de3cd3b Update zigbee-herdsman-converters to 14.0.575 (#13237)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-21 20:58:00 +00:00
github-actions[bot]andKoenkk 8d8da9f286 Update zigbee-herdsman-converters to 14.0.574 (#13226)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-20 18:16:35 +00:00
Andrew Lamchenko 759c2f3f00 Add new clusters for bind (#13214)
* Add new clasters for bind

Add new clasters for bind

* Add new clasters for bind

Add new clasters for bind
2022-07-20 19:41:46 +02:00
github-actions[bot]andKoenkk b140e4bfe6 Update zigbee-herdsman-converters to 14.0.573 (#13213)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-19 18:18:04 +00:00
github-actions[bot]andKoenkk 4ef9ea749d Update zigbee-herdsman-converters to 14.0.571 (#13187)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-17 20:56:28 +00:00
github-actions[bot]andKoenkk 11f3f5b170 Update zigbee-herdsman to 0.14.46 (#13185)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-17 20:30:52 +00:00
github-actions[bot]andKoenkk b6f88aad80 Update dependencies (#13173)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-17 22:14:33 +02:00
Koen Kanters d07b65a03d Fix coverage 2022-07-17 22:14:02 +02:00
Koen Kanters aabc010191 Log error stack on fromZigbee converter error. https://github.com/Koenkk/zigbee2mqtt/issues/13138 2022-07-17 22:03:24 +02:00
github-actions[bot]andnurikk cf8e7b10db Update zigbee2mqtt-frontend to 0.6.107 (#13175)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-07-17 03:15:43 +00:00
github-actions[bot]andKoenkk 63777464cc Update zigbee-herdsman-converters to 14.0.570 (#13162)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-15 15:33:36 +00:00
Koen Kanters 26fc4609f0 Enable publish to ghcr.io 2022-07-15 12:50:43 +02:00
github-actions[bot]andKoenkk 1d8d6fe070 Update zigbee-herdsman-converters to 14.0.569 (#13150)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-14 15:31:24 +00:00
Koen Kanters ca2186a9c5 Finally fix for https://github.com/Koenkk/zigbee2mqtt/issues/13080 2022-07-13 22:04:27 +02:00
github-actions[bot]andKoenkk 7d8b506c49 Update zigbee-herdsman-converters to 14.0.568 (#13134)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-13 17:39:24 +00:00
Koen Kanters 994de20f49 Another attempt to fix https://github.com/Koenkk/zigbee2mqtt/issues/13080 2022-07-13 18:05:45 +02:00
github-actions[bot]andKoenkk f553601ff1 Update zigbee-herdsman to 0.14.45 (#13132)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-13 15:40:54 +00:00
Koen Kanters 3478715926 Update ci.yml 2022-07-12 22:15:26 +02:00
Koen Kanters ed351ee712 TEMP: disable ghcr.io Docker build since ghcr.io is unstable 2022-07-12 22:09:43 +02:00
github-actions[bot]andKoenkk affa15cbae Update zigbee-herdsman to 0.14.44 (#13121)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-12 19:58:07 +00:00
Koen Kanters c6d504a5df Set device_class to temperature for local_temperature_calibration. https://github.com/Koenkk/zigbee2mqtt/issues/13080 2022-07-12 21:45:20 +02:00
Koen Kanters 420b34c909 Fix group and device states changing when cached states are published. https://github.com/Koenkk/zigbee2mqtt/issues/13028 2022-07-12 17:01:29 +02:00
github-actions[bot]andnurikk 4347034ba1 Update zigbee2mqtt-frontend to 0.6.106 (#13110)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-07-12 03:01:48 +00:00
github-actions[bot]andKoenkk ec8e7ed946 Update zigbee-herdsman-converters to 14.0.567 (#13104)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-11 15:57:15 +00:00
Koen Kanters 440fc74368 Fix Home Assistant discovery error: expected NumberDeviceClass or one of 'temperature' for dictionary value @ data['device_class']. https://github.com/Koenkk/zigbee2mqtt/issues/13080 2022-07-11 17:44:08 +02:00
Jorge Schrauwen a0255d0f2c Always treat filtered_* as full matches (#13083)
* Revert "update tests to use regex ^$ anchors"

This reverts commit 3d9bc552e9.

* utils: filterProperties should ensure full match
2022-07-11 17:24:34 +02:00
github-actions[bot]andKoenkk 14216b7454 Update zigbee-herdsman-converters to 14.0.566 (#13093)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-10 08:11:17 +00:00
github-actions[bot]andKoenkk 0da033ce95 Update zigbee-herdsman to 0.14.43 (#13092)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-10 07:57:07 +00:00
3bd3196a40 Update dependencies (#13089)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-07-10 09:23:51 +02:00
github-actions[bot]andnurikk 47e05c32ec Update zigbee2mqtt-frontend to 0.6.105 (#13090)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-07-10 01:55:15 +00:00
github-actions[bot]andKoenkk bcd19509fb Update zigbee-herdsman-converters to 14.0.565 (#13085)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-09 18:32:35 +00:00
github-actions[bot]andKoenkk 05a9920638 Update zigbee-herdsman to 0.14.42 (#13084)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-09 18:05:19 +00:00
Koen Kanters 8af3ad5541 Fix crash when ZIGBEE2MQTT_CONFIG_ADVANCED_NETWORK_KEY environment variable is set to GENERATE. https://github.com/Koenkk/zigbee2mqtt/issues/12999 2022-07-08 16:58:23 +02:00
Koen Kanters 6ef9e4f479 Fix matrix test jobs unstable (#13068)
* Update ci.yml

* Update ci.yml
2022-07-07 15:21:37 +02:00
183dad97e7 Update zigbee-herdsman to 0.14.41 (#13063)
* Update zigbee-herdsman to 0.14.41

* Update package-lock.json

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-07-07 07:44:34 +00:00
github-actions[bot]andKoenkk 3bbdf17fed Update zigbee-herdsman-converters to 14.0.564 (#13062)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-06 15:50:54 +00:00
Jorge Schrauwen db021e6711 Allow regexes for filtered_attributes, filtered_cache and filtered_optimistic options (#13047)
* Ensure filtered_attributes and filtered_optimistic are also regex

Bring filtered_attributes and filtered_optimistic in line with the newer filtered_cache.
All three of them are now regex matches instead of absolute matches.

* update tests to use regex ^$ anchors

* utils: add filterProperties
2022-07-06 17:07:22 +02:00
github-actions[bot]andKoenkk 4a58dbf84c Update zigbee-herdsman-converters to 14.0.563 (#13049)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-05 15:20:46 +00:00
github-actions[bot]andKoenkk ee227d85c7 Update zigbee-herdsman-converters to 14.0.562 (#13035)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-04 15:20:19 +00:00
github-actions[bot]andKoenkk d8c0ef8a9c Update dependencies (#13023)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-04 17:05:01 +02:00
github-actions[bot]andKoenkk 53ae00c46f Update zigbee-herdsman-converters to 14.0.561 (#13022)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-02 18:53:10 +00:00
Jorge SchrauwenandKoen Kanters dedbf336af Add filtered_cache option (#12988)
* want a way to prevent attribute from being cached

* Update filtered_cache description to be more clear

* Fix emitStateChange was returning wrong payload in to parameter

* Directly get filtered_cache from entity and forgo parameter to State.set()

* Add tests to cover filtered_cache

* Update state.ts

* Update controller.test.js

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-07-02 20:33:04 +02:00
Sam bc4ffc00b6 add search before issue create requirement (#13021) 2022-07-02 20:28:30 +02:00
5662e6c29e Update zigbee-herdsman-converters to 14.0.560 (#13016)
* Update zigbee-herdsman-converters to 14.0.560

* Fix tests

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-07-01 21:35:16 +00:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 4cc838accf Bump actions/dependency-review-action from 1 to 2 (#13009)
Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 1 to 2.
- [Release notes](https://github.com/actions/dependency-review-action/releases)
- [Commits](https://github.com/actions/dependency-review-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: actions/dependency-review-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-01 23:10:32 +02:00
github-actions[bot]andnurikk 3b58ac79dc Update zigbee2mqtt-frontend to 0.6.104 (#13008)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-07-01 15:20:07 +00:00
bab764e2be Binding to msRelativeHumidity (#12877)
* Binding to new clusters

Binding to new clusters. This is necessary for new EFEKTA devices.

* Update bind.ts

* Fix tests

Co-authored-by: nurikk <ainur@yojee.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-07-01 17:02:34 +02:00
Koen Kanters 81892ef70d Promote to dev 2022-07-01 16:42:33 +02:00
Koen Kanters cd23aeaa46 1.26.0 2022-07-01 16:41:38 +02:00
Koen Kanters 5d5b731053 Undev 2022-07-01 16:41:00 +02:00
Koen Kanters c973632efd Merge branch 'dev' 2022-07-01 16:40:18 +02:00
github-actions[bot]andKoenkk e0b63f2baa Update zigbee-herdsman-converters to 14.0.559 (#13004)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-07-01 14:39:37 +00:00
github-actions[bot]andKoenkk 3d406c3c0d Update zigbee-herdsman-converters to 14.0.558 (#12984)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-29 16:06:12 +00:00
github-actions[bot]andKoenkk d4811791fc Update zigbee-herdsman to 0.14.40 (#12983)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-29 16:01:43 +00:00
github-actions[bot]andKoenkk 3b7ef63300 Update zigbee-herdsman-converters to 14.0.557 (#12975)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-28 15:15:39 +00:00
github-actions[bot]andKoenkk 8adb2f1247 Update zigbee-herdsman-converters to 14.0.556 (#12967)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-27 17:18:22 +00:00
Vladimir Vitkov 326c2aaa90 Allow to specify MQTT server in secrets (#12904)
* add server, pan_id, ext_pan_id to secrets

* fix tests

* clean secrets before every test run

* add interpolation of mqtt.server, advanced.pan_id, advanced.ext_pan_id and split mqtt.user, mqtt.pass requirement

* remove pan_id and ext_pan_id from secrets processing
2022-06-27 18:42:05 +02:00
e291687870 Update zigbee-herdsman-converters to 14.0.555 (#12951)
* Update zigbee-herdsman-converters to 14.0.555

* Fix tests

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-06-26 17:01:17 +02:00
Koen Kanters 80f8fb4d98 Node 17 is EOL 2022-06-26 16:56:01 +02:00
RoboMagus 402081e39d Fix EnvVar parsing of settings scheme with 'oneOf'. (#12948) 2022-06-26 16:16:44 +02:00
Koen Kanters 05309db92b Fix crash when poll of bounded device fails. https://github.com/Koenkk/zigbee2mqtt/issues/12918 2022-06-26 16:14:21 +02:00
github-actions[bot]andKoenkk d3fa977ebf Update dependencies (#12942)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-26 09:46:15 +02:00
github-actions[bot]andKoenkk 92f7bc8eb5 Update zigbee-herdsman to 0.14.39 (#12926)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-24 14:19:32 +00:00
github-actions[bot]andKoenkk 80b6f1dfa3 Update zigbee-herdsman-converters to 14.0.554 (#12906)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-22 15:20:07 +00:00
github-actions[bot]andKoenkk 1eaa73bb52 Update zigbee-herdsman-converters to 14.0.553 (#12895)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-21 14:39:48 +00:00
github-actions[bot]andKoenkk 0fc831cd82 Update zigbee-herdsman-converters to 14.0.552 (#12886)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-20 16:20:23 +00:00
github-actions[bot]andKoenkk 59c18af1f7 Update dependencies (#12874)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-20 17:47:45 +02:00
github-actions[bot]andnurikk 0fd47c0ad1 Update zigbee2mqtt-frontend to 0.6.103 (#12885)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-06-20 15:32:50 +00:00
github-actions[bot]andnurikk 6b643f0e67 Update zigbee2mqtt-frontend to 0.6.102 (#12884)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-06-20 14:55:48 +00:00
github-actions[bot]andKoenkk 3c9fab143c Update zigbee-herdsman-converters to 14.0.551 (#12871)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-18 17:50:50 +00:00
Koen Kanters f2e953cf18 Add group off_state option (#12868) 2022-06-18 15:47:06 +02:00
github-actions[bot]andKoenkk ecb18a6c41 Update zigbee-herdsman-converters to 14.0.550 (#12864)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-18 09:24:55 +00:00
github-actions[bot]andKoenkk d405c43202 Update zigbee-herdsman-converters to 14.0.549 (#12862)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-18 08:30:31 +00:00
github-actions[bot]andKoenkk 24e7a368cb Update zigbee-herdsman to 0.14.38 (#12861)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-18 08:22:20 +00:00
github-actions[bot]andKoenkk 8848e1e6ce Update zigbee-herdsman-converters to 14.0.548 (#12856)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-17 15:08:56 +00:00
John Doeandnurikk 820c20af80 Fix windows tests (#12840)
Co-authored-by: nurikk <ainur@yojee.com>
2022-06-16 14:00:09 +08:00
github-actions[bot]andnurikk 4b8b951c28 Update zigbee2mqtt-frontend to 0.6.101 (#12839)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-06-16 05:37:34 +00:00
github-actions[bot]andnurikk 8964421350 Update zigbee2mqtt-frontend to 0.6.100 (#12838)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-06-16 05:13:27 +00:00
github-actions[bot]andKoenkk 0895f29a83 Update zigbee-herdsman-converters to 14.0.547 (#12833)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-15 16:00:32 +00:00
Koen Kanters f213729dcb Remove Home Assistant away_mode_* discovery. https://github.com/Koenkk/zigbee2mqtt/issues/11738 2022-06-15 17:56:13 +02:00
rikroeandKoen Kanters 6df20010dd Change HA hold_mode to preset_mode (#12565)
* Update homeassistant.ts

* Update homeassistant.test.js

* Update homeassistant.ts

* Update homeassistant.ts

* Updates

* Updates

* Updates

* Updates

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-06-15 17:40:44 +02:00
github-actions[bot]andKoenkk a5204cdeb1 Update zigbee-herdsman to 0.14.37 (#12832)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-15 15:14:36 +00:00
Koen Kanters dd129830d3 Create herdsman backup before backup. https://github.com/Koenkk/zigbee2mqtt/pull/12797 2022-06-15 17:05:20 +02:00
github-actions[bot]andKoenkk a8233e0521 Update zigbee-herdsman to 0.14.36 (#12831)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-15 17:04:20 +02:00
Koen Kanters 9b2a92106e Disable ghcr_cleanup 2022-06-15 17:03:16 +02:00
github-actions[bot]andKoenkk 8fe6ab4866 Update zigbee-herdsman-converters to 14.0.546 (#12826)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-14 18:36:31 +00:00
Koen Kanters a08ff9bf6d Prepare for zhc 14.0.546 2022-06-14 20:31:25 +02:00
Koen Kanters 83b490a968 Add zigbee2mqtt/bridge/request/backup (#12797)
* Add backup call

* Updates
2022-06-14 20:14:01 +02:00
github-actions[bot]andnurikk 3498c6e260 Update zigbee2mqtt-frontend to 0.6.99 (#12812)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-06-13 14:28:42 +00:00
github-actions[bot]andKoenkk 5c93aaf6db Update zigbee-herdsman-converters to 14.0.545 (#12804)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-12 19:51:52 +00:00
github-actions[bot]andKoenkk e860978564 Update zigbee-herdsman-converters to 14.0.544 (#12796)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-12 07:17:00 +00:00
github-actions[bot]andKoenkk 2d7a6e9f42 Update dependencies (#12795)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-12 08:48:41 +02:00
github-actions[bot]andKoenkk 1390bc1d04 Update zigbee-herdsman-converters to 14.0.543 (#12783)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-11 08:12:40 +00:00
github-actions[bot]andKoenkk a9349ac49d Update zigbee-herdsman to 0.14.35 (#12782)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-11 08:07:05 +00:00
github-actions[bot]andKoenkk 5bed214aef Update zigbee-herdsman-converters to 14.0.542 (#12781)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-11 07:53:34 +00:00
github-actions[bot]andKoenkk 4f181b0107 Update zigbee-herdsman-converters to 14.0.541 (#12767)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-09 19:25:49 +00:00
Koen Kanters 8e2f0f613f Send cached group state on startup and when Home Assistant comes online. https://github.com/Koenkk/zigbee2mqtt/issues/12693 2022-06-09 20:52:39 +02:00
github-actions[bot]andKoenkk 2bb4f91d1c Update zigbee-herdsman-converters to 14.0.540 (#12756)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-08 18:29:55 +00:00
Koen Kanters 389ff844c4 Revert "Revert "Revert "Temp: disable ghcr.io since it makes build fail"""
This reverts commit 975eb7d6ae.
2022-06-08 16:40:20 +02:00
github-actions[bot]andKoenkk cb0542eaad Update zigbee-herdsman-converters to 14.0.539 (#12746)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-07 16:17:18 +00:00
Koen Kanters 300b2973e1 Update ci.yml 2022-06-06 13:32:44 +02:00
Koen Kanters 5c44582b69 Update zigbee2mqtt/hassio-zigbee2mqtt trigger 2022-06-06 12:58:37 +02:00
github-actions[bot]andKoenkk 2f2a66db2e Update zigbee-herdsman-converters to 14.0.538 (#12728)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-05 20:07:53 +00:00
github-actions[bot]andKoenkk b075d6bbda Update dependencies (#12727)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-05 22:02:11 +02:00
Koen Kanters a252914ecd Update update_deps.yml 2022-06-05 21:48:26 +02:00
github-actions[bot]andKoenkk 87edd1e6f1 Update zigbee-herdsman-converters to 14.0.537 (#12712)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-04 12:25:18 +00:00
github-actions[bot]andKoenkk ba69e1788f Update zigbee-herdsman-converters to 14.0.536 (#12709)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-04 08:42:26 +00:00
Naveen 05538ec28b chore: Enable codeql action (#12708)
This action runs GitHub's industry-leading semantic code analysis engine,
CodeQL, against a repository's source code to find security vulnerabilities.

https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning-with-codeql

https://github.com/ossf/scorecard/blob/main/docs/checks.md#sast
Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com>
2022-06-04 10:28:44 +02:00
NaveenandKoen Kanters 2676c3f641 chore(deps): Included dependency review (#12695)
* chore(deps): Included dependency review

> Dependency Review GitHub Action in your repository to enforce dependency
> reviews on your pull requests.
> The action scans for vulnerable versions of dependencies introduced by package version
> changes in pull requests,
> and warns you about the associated security vulnerabilities.
> This gives you better visibility of what's changing in a pull request,
> and helps prevent vulnerabilities being added to your repository.

https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com>

* Update depsreview.yaml

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-06-03 16:41:06 +02:00
github-actions[bot]andKoenkk e525919160 Update zigbee-herdsman-converters to 14.0.535 (#12692)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-02 16:13:26 +00:00
John Doeandnurikk d064a73131 Rework ci and use package-lock.json instead of npm-shrinkwrap.json (#12631)
* Update ci

* Use package-lock

* Use package-lock.json

* Use cache for ci

* Enable node18 windows

* Revert "Enable node18 windows"

This reverts commit e427551acdd64c3a256b48a5b8e86b3c4c986405.

* Remove redundant cache

* Don't do shrinkwrap

* Remove shrinkwrap

* Remove redundant step

* Cache node-gyp

* Debug

* Add key

* Update ci.yml

* Add cache detection

* Fix

* Add deps

* Fix2

* Update caches

* Fix ci

* Update patsh

* Update paths

* Update paths

* Fix max cache path

* Change cache key

* Remove spaces

* Split caches

* Fix linux cache

* Fix linux cache

* Merge caches

* Ignore errs

* Find only dirs

* Run find after ci

* Fix mac cache

* Fix caches

* Remove env run

Co-authored-by: nurikk <ainur@yojee.com>
2022-06-02 14:38:07 +00:00
Koen Kanters 64ab3b0492 Revert "Downgrade docker/setup-qemu-action to v1"
This reverts commit 35b9e01230.
2022-06-02 16:27:18 +02:00
Koen Kanters e1c9d68c68 Revert "Check if ghcr.io build works again"
This reverts commit 1596714ccb.
2022-06-02 16:27:11 +02:00
Koen Kanters 35b9e01230 Downgrade docker/setup-qemu-action to v1 2022-06-02 16:13:40 +02:00
Koen Kanters 1596714ccb Check if ghcr.io build works again 2022-06-02 16:02:51 +02:00
Koen Kanters e852851273 Update ghcr_cleanup.yml 2022-06-02 08:30:55 +02:00
github-actions[bot]andKoenkk 24e9c5bc9f Update zigbee-herdsman-converters to 14.0.534 (#12676)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-01 17:22:40 +00:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> dc4f4ad047 Bump actions/github-script from 3 to 6 (#12674)
Bumps [actions/github-script](https://github.com/actions/github-script) from 3 to 6.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v3...v6)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-01 19:16:21 +02:00
neilnaveenandKoen Kanters cc42ab7584 chore: Set permissions for GitHub actions (#12626)
Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much.

- Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions

https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs

[Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)

Signed-off-by: neilnaveen <42328488+neilnaveen@users.noreply.github.com>

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-06-01 19:15:06 +02:00
Koen Kanters 03fdb0cb88 Fix Home Assistant rename creating duplicate entities. #12610 2022-06-01 18:57:02 +02:00
Koen Kanters f7c6518506 Promote to dev 2022-06-01 17:38:46 +02:00
Koen Kanters 3c5854fa9f 1.25.2 2022-06-01 17:38:09 +02:00
Koen Kanters 900175af47 Undev 2022-06-01 17:37:39 +02:00
Koen Kanters 9b9e2289d3 Merge remote-tracking branch 'origin/master' into dev 2022-06-01 17:36:50 +02:00
github-actions[bot]andKoenkk ea10936641 Update zigbee-herdsman-converters to 14.0.533 (#12672)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-01 15:14:02 +00:00
github-actions[bot]andKoenkk 6b56b0bcf8 Update zigbee-herdsman-converters to 14.0.532 (#12671)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-06-01 15:03:10 +00:00
Koen Kanters 975eb7d6ae Revert "Revert "Temp: disable ghcr.io since it makes build fail""
This reverts commit 4e28df88ae.
2022-06-01 16:57:47 +02:00
Koen Kanters 4de04c19c0 Update ghcr_cleanup.yml 2022-06-01 15:12:32 +02:00
Koen Kanters 1db12612e6 Add GHCR cleanup (#12669)
* Create ghcr_cleanup.yml

* Update ghcr_cleanup.yml

* Update ghcr_cleanup.yml

* Update ghcr_cleanup.yml

* Update ghcr_cleanup.yml
2022-06-01 14:18:41 +02:00
github-actions[bot]andKoenkk ec010df79a Update zigbee-herdsman-converters to 14.0.531 (#12659)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-31 15:17:42 +00:00
github-actions[bot]andKoenkk 88b65625de Update zigbee-herdsman to 0.14.34 (#12658)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-31 14:58:08 +00:00
Koen Kanters 4e28df88ae Revert "Temp: disable ghcr.io since it makes build fail"
This reverts commit a1db076c02.
2022-05-31 08:28:36 +02:00
github-actions[bot]andKoenkk 44815435e7 Update zigbee-herdsman-converters to 14.0.530 (#12645)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-30 16:11:37 +00:00
Koen Kanters fe011ba7b3 Disable node 18 testing for now (fails quite often) 2022-05-29 10:21:23 +02:00
Koen Kanters 68035a1256 Fix restart not working (#12629) 2022-05-29 08:15:47 +00:00
github-actions[bot]andKoenkk cc535f11c6 Update zigbee-herdsman-converters to 14.0.529 (#12628)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-29 07:23:01 +00:00
github-actions[bot]andKoenkk 7001b2fc79 Update dependencies (#12627)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-29 06:46:27 +00:00
Koen Kanters 05975109a4 Lock connect-gzip-static https://github.com/Koenkk/zigbee2mqtt/pull/12624/files#r884205347 2022-05-29 08:43:02 +02:00
github-actions[bot]andKoenkk 502443aae8 Update zigbee-herdsman-converters to 14.0.528 (#12615)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-27 19:15:31 +00:00
Koen Kanters 43a82ad835 Delete ghcr_delete_untagged.yml 2022-05-27 16:29:50 +02:00
Koen Kanters a1db076c02 Temp: disable ghcr.io since it makes build fail 2022-05-27 16:23:34 +02:00
Koen Kanters bfc70c3bb8 Update ghcr_delete_untagged.yml 2022-05-27 15:09:48 +02:00
Koen Kanters b268b1ed75 Update ghcr_delete_untagged.yml 2022-05-27 12:08:55 +02:00
Koen Kanters 64769b3e9f Update ghcr_delete_untagged.yml 2022-05-27 12:05:51 +02:00
Koen Kanters 66e804d71e Create ghcr_delete_untagged.yml 2022-05-27 12:01:21 +02:00
github-actions[bot]andKoenkk 1c30a4f4bc Update zigbee-herdsman to 0.14.33 (#12612)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-27 09:51:49 +00:00
Koen Kanters be55e3ee80 Revert "Temp disable ghcr.io push (seems to make build fail)"
This reverts commit c1372852e9.
2022-05-27 11:47:43 +02:00
github-actions[bot]andnurikk 1aa7971ca1 Update zigbee2mqtt-frontend to 0.6.97 (#12605)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-05-26 11:25:29 +00:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 6e2ab644a0 Bump peter-evans/create-pull-request from 3 to 4 (#12602)
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 3 to 4.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v3...v4)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-26 09:54:13 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 4fa6c33622 Bump peter-evans/enable-pull-request-automerge from 1 to 2 (#12600)
Bumps [peter-evans/enable-pull-request-automerge](https://github.com/peter-evans/enable-pull-request-automerge) from 1 to 2.
- [Release notes](https://github.com/peter-evans/enable-pull-request-automerge/releases)
- [Commits](https://github.com/peter-evans/enable-pull-request-automerge/compare/v1...v2)

---
updated-dependencies:
- dependency-name: peter-evans/enable-pull-request-automerge
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-26 09:53:39 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 3fd405e570 Bump actions/stale from 3 to 5 (#12601)
Bumps [actions/stale](https://github.com/actions/stale) from 3 to 5.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v3...v5)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-26 09:53:15 +02:00
Koen Kanters c1372852e9 Temp disable ghcr.io push (seems to make build fail) 2022-05-26 09:50:39 +02:00
Koen Kanters 95eedc9ec1 Add dependabot.yml 2022-05-26 09:48:43 +02:00
Koen Kanters d7b926d47f Update ci.yml dependencies 2022-05-26 09:43:11 +02:00
github-actions[bot]andKoenkk 67039a1a94 Update zigbee-herdsman-converters to 14.0.527 (#12599)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-26 07:27:42 +00:00
github-actions[bot]andKoenkk f79fb16e41 Update zigbee-herdsman-converters to 14.0.526 (#12595)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-25 16:58:18 +00:00
Koen Kanters d910c05e6e Improve tests 2022-05-25 11:38:37 +02:00
github-actions[bot]andnurikk 4858e06060 Update zigbee2mqtt-frontend to 0.6.96 (#12592)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-05-25 09:31:15 +00:00
f71db6816a Update zigbee-herdsman-converters to 14.0.525 (#12585)
* Update zigbee-herdsman-converters to 14.0.525

* Fix tests

* Ignore

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-05-24 18:27:17 +00:00
github-actions[bot]andnurikk c6b129c68d Update zigbee2mqtt-frontend to 0.6.95 (#12572)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-05-23 04:59:27 +00:00
e5dbe01329 Update zigbee-herdsman-converters to 14.0.522 (#12568)
* Update zigbee-herdsman-converters to 14.0.522

* Fix

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-05-22 20:32:15 +00:00
Koen Kanters c00768b7c7 Move ci before tests 2022-05-21 15:08:07 +02:00
Koen Kanters ad070c99ef Add official support for node 18 and drop for node 10, 12, 15 (#12553) 2022-05-21 08:29:22 +00:00
aec082c0cf Update zigbee-herdsman-converters to 14.0.521 (#12552)
* Update zigbee-herdsman-converters to 14.0.521

* Fixes

Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-05-21 08:20:37 +00:00
github-actions[bot]andKoenkk cc84452f23 Update zigbee-herdsman to 0.14.32 (#12551)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-21 07:45:02 +00:00
John Doeandnurikk 84bac2b8d8 Add compatibility tests (#12527)
* Add tests gh action

* Fix zigbee_ota_override_index_location

* Fix Shouldnt crash when it cannot save state test

* Add node17

* Update tests.yml

* Drop old versions

* Move to ci.yml

* Update controller.test.js

* Fix linebraks on windows

* Ignore windows and node 17

* Fail on error

* Add comment

* Mark node 18 as supported

Co-authored-by: nurikk <ainur@yojee.com>
2022-05-21 08:37:39 +02:00
github-actions[bot]andKoenkk 29a9d227de Update zigbee-herdsman-converters to 14.0.520 (#12546)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-20 14:58:14 +00:00
github-actions[bot]andnurikk 39ae0c775a Update zigbee2mqtt-frontend to 0.6.94 (#12540)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-05-20 02:44:04 +00:00
github-actions[bot]andKoenkk f1eaf2d7aa Update zigbee-herdsman-converters to 14.0.519 (#12530)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-18 15:35:44 +00:00
Koen Kanters c6840a9a43 Mark node 17 as supported 2022-05-18 14:56:17 +02:00
John Doeandnurikk 3a1c64a88e Downgrade connect-gzip-static to 2.1.1 (#12525)
Co-authored-by: nurikk <ainur@yojee.com>
2022-05-18 17:30:04 +08:00
github-actions[bot]andnurikk d4a0c93c91 Update zigbee2mqtt-frontend to 0.6.86 (#12524)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-05-18 08:14:56 +00:00
github-actions[bot]andKoenkk 5ae8347317 Update zigbee-herdsman-converters to 14.0.518 (#12518)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-17 15:06:53 +00:00
github-actions[bot]andKoenkk afbfa4631f Update zigbee-herdsman to 0.14.31 (#12504)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-16 16:05:24 +00:00
github-actions[bot]andKoenkk 096f906ac7 Update zigbee-herdsman-converters to 14.0.517 (#12503)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-16 14:44:14 +00:00
github-actions[bot]andnurikk b844f607ee Update zigbee2mqtt-frontend to 0.6.85 (#12502)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-05-16 13:59:21 +00:00
github-actions[bot]andKoenkk 6002bc475b Update dependencies (#12479)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-16 15:19:07 +02:00
github-actions[bot]andKoenkk 24cfdf4594 Update zigbee-herdsman to 0.14.30 (#12466)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-13 13:15:51 +00:00
github-actions[bot]andKoenkk bc5fd1a52f Update zigbee-herdsman to 0.14.29 (#12464)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-13 08:30:16 +00:00
Koen Kanters fd344a3017 Revert "Additional logging for https://github.com/Koenkk/zigbee2mqtt/issues/12432"
This reverts commit 920b4924b0.
2022-05-13 10:05:49 +02:00
github-actions[bot]andKoenkk f9bd184543 Update zigbee-herdsman-converters to 14.0.516 (#12460)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-12 17:53:53 +00:00
github-actions[bot]andKoenkk f2c1e85b4b Update zigbee-herdsman-converters to 14.0.515 (#12447)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-11 18:21:27 +00:00
Koen Kanters 920b4924b0 Additional logging for https://github.com/Koenkk/zigbee2mqtt/issues/12432 2022-05-11 17:22:48 +02:00
github-actions[bot]andKoenkk 99e67b1495 Update zigbee-herdsman-converters to 14.0.514 (#12435)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-10 18:03:45 +00:00
github-actions[bot]andKoenkk e65344c9fa Update zigbee-herdsman-converters to 14.0.513 (#12429)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-09 18:15:01 +00:00
147fe22f08 Update dependencies (#12416)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-05-08 10:01:25 +02:00
Koen Kanters 7f1f1497c6 Always return a device state 2022-05-08 09:58:30 +02:00
Koen Kanters 6278c86d02 Pass device options in global on event. https://github.com/Koenkk/zigbee2mqtt/commit/723dd8358f3cee0b90d624f27989a8bb587e25b0#comments 2022-05-07 14:40:25 +02:00
6f09d45a7b Update zigbee-herdsman-converters to 14.0.512 (#12413)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-05-07 12:39:32 +00:00
Koen Kanters 49a730f77d Update tests for https://github.com/Koenkk/zigbee2mqtt/pull/12413 2022-05-07 14:37:29 +02:00
github-actions[bot]andKoenkk e5a74894d2 Update zigbee-herdsman-converters to 14.0.511 (#12409)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-07 08:43:02 +00:00
Jorge SchrauwenandKoen Kanters 723dd8358f Pass device state to zhc onEvent (#12407)
* onEvent: want device state as argument

* onEvent: test should check deviceOptions and deviceState returns

* Update onEvent.ts

* Update onEvent.ts

* Fix

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-05-07 08:36:03 +00:00
github-actions[bot]andKoenkk 47a22cce2a Update zigbee-herdsman-converters to 14.0.510 (#12403)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-06 15:24:31 +00:00
github-actions[bot]andKoenkk b3791684fd Update zigbee-herdsman-converters to 14.0.509 (#12392)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-05 16:43:18 +00:00
github-actions[bot]andKoenkk ebd3255fc6 Update zigbee-herdsman to 0.14.28 (#12390)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-05 16:17:04 +00:00
github-actions[bot]andKoenkk 9b594a4cba Update zigbee-herdsman-converters to 14.0.508 (#12380)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-04 19:08:08 +00:00
Koen Kanters d0530b8214 Don't allow friendly names to include control character. #12379 2022-05-04 21:00:29 +02:00
5c7e968028 Update zigbee-herdsman-converters to 14.0.507 (#12368)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-05-03 17:42:17 +00:00
Koen Kanters 40ef638e0e Fix null not allowed for Home Assistant device options. #12340 2022-05-03 19:39:30 +02:00
github-actions[bot]andKoenkk b9499618d3 Update zigbee-herdsman-converters to 14.0.506 (#12354)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-02 17:35:37 +00:00
Alex Kay 6618872839 Add new config and diagnostic entities to HA (#12353) 2022-05-02 19:23:40 +02:00
Alex Kay b977dd1140 Add battery2 for HA (#12332) 2022-05-02 14:20:45 +00:00
github-actions[bot]andnurikk 71d5c7b4a2 Update zigbee2mqtt-frontend to 0.6.84 (#12351)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-05-02 12:31:28 +00:00
github-actions[bot]andKoenkk dd8a83e592 Update zigbee-herdsman-converters to 14.0.505 (#12338)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-01 18:45:05 +00:00
Koen Kanters 664182def2 Promote to dev 2022-05-01 20:16:18 +02:00
Koen Kanters 3f6a13786e 1.25.1 2022-05-01 20:14:19 +02:00
Koen Kanters a800197262 Undev 2022-05-01 20:14:12 +02:00
github-actions[bot]andKoenkk 0c145d81cf Update zigbee-herdsman-converters to 14.0.504 (#12336)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-05-01 17:53:38 +00:00
github-actions[bot]andKoenkk 7d7f8aabfe Update zigbee-herdsman-converters to 14.0.503 (#12321)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-30 07:50:44 +00:00
github-actions[bot]andKoenkk 95c2fcfb00 Update zigbee-herdsman-converters to 14.0.502 (#12317)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-29 20:45:59 +00:00
github-actions[bot]andKoenkk 2a6a6c43ce Update zigbee-herdsman-converters to 14.0.501 (#12309)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-28 16:26:57 +00:00
github-actions[bot]andKoenkk 47ed86d735 Update zigbee-herdsman-converters to 14.0.500 (#12294)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-27 07:34:32 +00:00
github-actions[bot]andKoenkk 50990d1f7a Update zigbee-herdsman-converters to 14.0.499 (#12288)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-26 18:05:33 +00:00
Koen Kanters f7b484f24f Log stack trace of "Failed to execute LQI" error. https://github.com/Koenkk/zigbee2mqtt/issues/11968 2022-04-26 20:02:18 +02:00
github-actions[bot]andKoenkk f6ad3c9926 Update zigbee-herdsman-converters to 14.0.498 (#12280)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-25 18:31:28 +00:00
11b415634c Update zigbee-herdsman to 0.14.27 (#12267)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-04-24 18:40:24 +00:00
github-actions[bot]andKoenkk d980d38747 Update zigbee-herdsman-converters to 14.0.497 (#12266)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-24 18:32:09 +00:00
github-actions[bot]andKoenkk 808671dd59 Update dependencies (#12256)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-24 13:55:36 +02:00
Koen Kanters cf22dd60a0 Always respond to OTA request (#12247)
* Always respond to OTA request

* Improve

* Rename
2022-04-23 10:12:29 +02:00
github-actions[bot]andKoenkk 3b820bae9f Update zigbee-herdsman-converters to 14.0.496 (#12249)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-22 18:35:06 +00:00
github-actions[bot]andKoenkk 60a987c004 Update zigbee-herdsman-converters to 14.0.495 (#12240)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-21 15:46:27 +00:00
github-actions[bot]andKoenkk d90be2dc66 Update zigbee-herdsman-converters to 14.0.494 (#12233)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-20 17:09:34 +00:00
Koen Kanters e305ecf571 Improve #ec2bf1a95d6c45c093f68df832bc6bcbdd372a5a 2022-04-20 17:59:16 +02:00
Koen Kanters ec2bf1a95d Fix out of memory error when starting on system with low RAM. #12034 2022-04-20 16:59:30 +02:00
github-actions[bot]andKoenkk 7d5c44a5bd Update zigbee-herdsman-converters to 14.0.493 (#12213)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-19 07:09:28 +00:00
github-actions[bot]andKoenkk 8c4312db72 Update zigbee-herdsman-converters to 14.0.492 (#12210)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-18 17:32:40 +00:00
github-actions[bot]andKoenkk 037a72e0f3 Update zigbee-herdsman-converters to 14.0.491 (#12200)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-17 18:18:25 +00:00
github-actions[bot]andKoenkk d657ea48cf Update dependencies (#12195)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-17 11:47:00 +02:00
github-actions[bot]andKoenkk b4e0c3afcf Update zigbee-herdsman-converters to 14.0.490 (#12193)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-16 07:32:45 +00:00
John Doeandnurikk 27bc646cf6 Add home assistant name to settings schema (#12191)
Co-authored-by: nurikk <ainur@yojee.com>
2022-04-16 10:27:41 +08:00
github-actions[bot]andKoenkk 23ef22e9ba Update zigbee-herdsman-converters to 14.0.489 (#12190)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-15 22:09:50 +00:00
github-actions[bot]andKoenkk 84c8da2532 Update zigbee-herdsman-converters to 14.0.488 (#12186)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-15 15:05:35 +00:00
github-actions[bot]andnurikk e6ec66c844 Update zigbee2mqtt-frontend to 0.6.83 (#12185)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-04-15 14:16:14 +00:00
github-actions[bot]andnurikk d1c26f9aa0 Update zigbee2mqtt-frontend to 0.6.82 (#12181)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-04-15 12:44:03 +00:00
github-actions[bot]andnurikk a7704b9038 Update zigbee2mqtt-frontend to 0.6.81 (#12179)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-04-15 09:36:36 +00:00
github-actions[bot]andKoenkk eabd662757 Update zigbee-herdsman-converters to 14.0.487 (#12172)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-14 15:38:56 +00:00
github-actions[bot]andKoenkk 764895b9d2 Update zigbee-herdsman-converters to 14.0.486 (#12164)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-13 17:48:12 +00:00
Míguel Ángel Mulero MartínezandKoen Kanters 8f5b26a2fb Mark calibration, calibration_time and motor_reversal as config sensors (#12146)
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-04-13 19:37:41 +02:00
github-actions[bot]andKoenkk 533cd36ffd Update zigbee-herdsman to 0.14.26 (#12159)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-12 19:26:50 +02:00
github-actions[bot]andKoenkk 3a77ebf52d Update zigbee-herdsman-converters to 14.0.485 (#12156)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-12 15:11:50 +00:00
github-actions[bot]andKoenkk 0e3bef7e42 Update zigbee-herdsman to 0.14.25 (#12155)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-12 15:00:48 +00:00
github-actions[bot]andKoenkk dda63bd65a Update zigbee-herdsman-converters to 14.0.484 (#12145)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-11 15:59:24 +00:00
github-actions[bot]andKoenkk 2aa1b4ead3 Update zigbee-herdsman-converters to 14.0.483 (#12133)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-10 08:12:57 +00:00
github-actions[bot]andKoenkk 422b7e0168 Update dependencies (#12128)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-10 09:48:40 +02:00
github-actions[bot]andKoenkk 8053eceb84 Update zigbee-herdsman-converters to 14.0.482 (#12124)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-09 16:14:15 +00:00
github-actions[bot]andKoenkk d10d3c9b56 Update zigbee-herdsman-converters to 14.0.481 (#12118)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-08 14:54:54 +00:00
github-actions[bot]andKoenkk 6ff45b1006 Update zigbee-herdsman-converters to 14.0.480 (#12109)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-07 20:39:48 +00:00
github-actions[bot]andKoenkk c901e66e7a Update zigbee-herdsman-converters to 14.0.479 (#12103)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-07 16:01:10 +00:00
github-actions[bot]andKoenkk 6ee7f56df3 Update zigbee-herdsman-converters to 14.0.478 (#12094)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-06 15:38:55 +00:00
github-actions[bot]andKoenkk d7073409d4 Update zigbee-herdsman to 0.14.24 (#12092)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-06 15:27:58 +00:00
github-actions[bot]andKoenkk e46ddb8c79 Update zigbee-herdsman-converters to 14.0.477 (#12091)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-06 15:12:18 +00:00
github-actions[bot]andKoenkk f91d0f6bfe Update zigbee-herdsman-converters to 14.0.476 (#12084)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-05 18:21:15 +00:00
github-actions[bot]andKoenkk 7e61252d11 Update zigbee-herdsman-converters to 14.0.475 (#12069)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-04 18:26:35 +00:00
github-actions[bot]andKoenkk 67c5481965 Update zigbee-herdsman-converters to 14.0.474 (#12068)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-04 18:22:54 +00:00
github-actions[bot]andKoenkk e251fc0803 Update zigbee-herdsman-converters to 14.0.473 (#12060)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-03 19:27:11 +00:00
Koen Kanters 5d4268515c Fix garage door status incorrect in Home Assistant. https://github.com/Koenkk/zigbee2mqtt/issues/12038 2022-04-03 21:09:26 +02:00
github-actions[bot]andKoenkk 91d80f1bb0 Update zigbee-herdsman-converters to 14.0.472 (#12056)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-03 12:14:53 +00:00
github-actions[bot]andKoenkk c9fbc6d52e Update zigbee-herdsman to 0.14.23 (#12055)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-03 12:08:18 +00:00
github-actions[bot]andKoenkk b84ad454e5 Update zigbee-herdsman-converters to 14.0.471 (#12049)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-03 07:31:13 +00:00
github-actions[bot]andKoenkk 51ae801cb8 Update dependencies (#12047)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-03 08:49:18 +02:00
Koen Kanters cabef43421 Revert "Switch to package-lock.json"
This reverts commit 0163b7281a.
2022-04-03 08:49:03 +02:00
Koen Kanters 8fd8df75be Reduce Docker image size again. 2022-04-02 21:50:12 +02:00
Koen Kanters 51f8c1c487 Fix Docker build 2022-04-02 21:13:22 +02:00
Koen Kanters aeb9927c20 Reduce Docker image build time 2022-04-02 21:09:02 +02:00
Koen Kanters 0163b7281a Switch to package-lock.json 2022-04-02 20:57:44 +02:00
Koen Kanters 0471eb5501 Switch to package-lock.json 2022-04-02 20:51:32 +02:00
2679219d87 Update zigbee-herdsman to 0.14.22 (#12046)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2022-04-02 18:47:51 +00:00
Koen Kanters d83eb72c4b Add registry url 2022-04-02 20:44:16 +02:00
Koen Kanters 414ea10b14 Update actions 2022-04-02 20:41:18 +02:00
github-actions[bot]andKoenkk d6e29538b1 Update zigbee-herdsman-converters to 14.0.470 (#12045)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-02 18:38:36 +00:00
Koen Kanters eb9b764cc5 Anoter attempt to fix shrinkwrap 2022-04-02 20:25:02 +02:00
Koen Kanters db642832f8 Update shrinkwrap 2022-04-02 19:59:40 +02:00
github-actions[bot]andKoenkk a56e5e0f36 Update zigbee-herdsman to 0.14.21 (#12043)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-04-02 17:58:11 +00:00
Koen Kanters 1b0fbf556b Fix invalid Home Assistant device class for garage_door_contact. #12038 2022-04-02 19:31:32 +02:00
Artem Draft 3e7eddf3ce Improve handle motor_state in HA (#12028) 2022-04-02 19:17:36 +02:00
Koen Kanters ad24c4f677 Promote to dev 2022-04-01 08:28:18 +02:00
Koen Kanters 6f1460e47b 1.25.0 2022-04-01 08:26:35 +02:00
Koen Kanters 91239291ec Undev 2022-04-01 08:26:33 +02:00
Koen Kanters beccc18ba7 Merge branch 'master' into dev 2022-03-31 22:02:47 +02:00
github-actions[bot]andKoenkk 2901df37fb Update zigbee-herdsman-converters to 14.0.467 (#12008)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-31 19:28:24 +00:00
github-actions[bot]andnurikk 1c1ca6faea Update zigbee2mqtt-frontend to 0.6.80 (#12001)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-03-31 07:49:42 +00:00
github-actions[bot]andKoenkk 85308daf5f Update zigbee-herdsman-converters to 14.0.466 (#11991)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-30 15:31:23 +00:00
github-actions[bot]andKoenkk 4631f6fc22 Update zigbee-herdsman-converters to 14.0.465 (#11984)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-29 19:05:17 +00:00
github-actions[bot]andKoenkk 95c698758d Update zigbee-herdsman-converters to 14.0.464 (#11974)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-28 18:32:35 +00:00
github-actions[bot]andKoenkk 95c48309a0 Update dependencies (#11962)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-27 09:55:27 +02:00
github-actions[bot]andKoenkk 2e42f50d6a Update zigbee-herdsman-converters to 14.0.463 (#11961)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-26 22:05:47 +00:00
github-actions[bot]andKoenkk 62a7b5115c Update zigbee-herdsman-converters to 14.0.462 (#11959)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-26 14:01:19 +00:00
github-actions[bot]andKoenkk b805dadceb Update zigbee-herdsman-converters to 14.0.461 (#11947)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-24 18:18:15 +00:00
Artem Draft f95c0bb048 Handle cover motor_state in HA (#11926)
* Handle cover motor_state in HA

* lint
2022-03-23 17:19:06 +01:00
github-actions[bot]andKoenkk 0202399ff6 Update zigbee-herdsman-converters to 14.0.460 (#11927)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-22 18:44:49 +00:00
github-actions[bot]andKoenkk e4d4f04a05 Update zigbee-herdsman-converters to 14.0.459 (#11920)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-21 16:39:48 +00:00
github-actions[bot]andKoenkk efe768d24a Update zigbee-herdsman-converters to 14.0.458 (#11912)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-20 15:51:12 +00:00
github-actions[bot]andKoenkk 0a868b451f Update dependencies (#11906)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-20 16:12:41 +01:00
Koen Kanters a73caa3e66 Update issue template 2022-03-19 16:44:09 +01:00
Koen Kanters 02bc325fc2 Fix configure failing when rejoining device. #10973 2022-03-19 16:41:22 +01:00
github-actions[bot]andKoenkk 847e7f8652 Update zigbee-herdsman-converters to 14.0.457 (#11901)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-19 14:22:43 +00:00
github-actions[bot]andKoenkk 0cd02c7495 Update zigbee-herdsman-converters to 14.0.456 (#11898)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-18 16:11:22 +00:00
github-actions[bot]andKoenkk cae83c90b9 Update zigbee-herdsman-converters to 14.0.455 (#11888)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-17 18:33:40 +00:00
Koen Kanters 2524e030fa Fix device reconnect resulting in brightness 1 when device is off. #11864 2022-03-17 19:21:35 +01:00
github-actions[bot]andKoenkk 652d4018dd Update zigbee-herdsman-converters to 14.0.454 (#11877)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-16 19:28:58 +00:00
github-actions[bot]andKoenkk 5b730575e4 Update zigbee-herdsman-converters to 14.0.452 (#11857)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-15 16:00:14 +00:00
github-actions[bot]andKoenkk 83f8250358 Update zigbee-herdsman-converters to 14.0.451 (#11845)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-14 17:12:06 +00:00
Koen Kanters 8bf06901c2 Availability for groups (#11626)
* Availability for groups. https://github.com/Koenkk/zigbee2mqtt/issues/9176

* Updates

* Fix
2022-03-14 15:51:02 +01:00
github-actions[bot]andKoenkk 4a0cd427de Update zigbee-herdsman-converters to 14.0.450 (#11839)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-13 18:20:54 +00:00
github-actions[bot]andKoenkk 23aacc4c00 Update dependencies (#11824)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-13 18:51:28 +01:00
github-actions[bot]andnurikk e7aef4c208 Update zigbee2mqtt-frontend to 0.6.79 (#11833)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-03-13 13:27:05 +00:00
github-actions[bot]andKoenkk 3cf3366070 Update zigbee-herdsman-converters to 14.0.449 (#11814)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-12 09:21:24 +00:00
Artem Draft 8f1787ed4a Expose cover running state to Home Assistant (#11789)
* handle cover running state in HA

* add running if the expose

* find running in definitionExposes
2022-03-12 10:14:25 +01:00
Koen Kanters b515c3213f Node 16 (#11804)
* Node 16

* More Node 16
2022-03-11 20:39:25 +01:00
github-actions[bot]andKoenkk 1aea3194bb Update zigbee-herdsman-converters to 14.0.448 (#11801)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-11 16:18:36 +00:00
github-actions[bot]andKoenkk 8f98a2f6d0 Update zigbee-herdsman-converters to 14.0.447 (#11787)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-10 17:27:39 +00:00
github-actions[bot]andKoenkk 52d151e70f Update zigbee-herdsman-converters to 14.0.446 (#11764)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-08 18:34:43 +00:00
github-actions[bot]andKoenkk 42f229b19e Update zigbee-herdsman-converters to 14.0.445 (#11753)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-07 17:52:33 +00:00
Koen Kanters e5d6bd1d68 Don't cache no_occupancy_since. https://github.com/Koenkk/zigbee2mqtt/issues/11183 2022-03-07 18:38:36 +01:00
github-actions[bot]andKoenkk c49f546256 Update zigbee-herdsman-converters to 14.0.444 (#11737)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-06 20:41:29 +00:00
github-actions[bot]andKoenkk 141f9f6d04 Update dependencies (#11726)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-06 20:13:20 +01:00
github-actions[bot]andnurikk a73a5b2cd4 Update zigbee2mqtt-frontend to 0.6.78 (#11733)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-03-06 08:39:44 +00:00
github-actions[bot]andKoenkk f7c6207d4f Update zigbee-herdsman-converters to 14.0.443 (#11716)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-05 15:36:48 +00:00
github-actions[bot]andKoenkk 9592147972 Update zigbee-herdsman-converters to 14.0.442 (#11696)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-03 17:24:06 +00:00
github-actions[bot]andnurikk a1cc8049b1 Update zigbee2mqtt-frontend to 0.6.77 (#11691)
Co-authored-by: nurikk <nurikk@users.noreply.github.com>
2022-03-03 14:57:17 +00:00
st4ro 625236721f new device class GARAGE for garage door opener (#11680) 2022-03-02 21:31:15 +01:00
Andrew Berry 364a6dd2aa Only colorize output if logging to a tty (#11645) 2022-03-02 20:07:22 +01:00
github-actions[bot]andKoenkk 3535b2c6c2 Update zigbee-herdsman-converters to 14.0.439 (#11662)
Co-authored-by: Koenkk <Koenkk@users.noreply.github.com>
2022-03-01 18:44:56 +00:00
Koen Kanters 91d597e53d Dev 2022-03-01 17:03:45 +01:00
69 changed files with 17767 additions and 23565 deletions
+1
View File
@@ -15,6 +15,7 @@ module.exports = {
'indent': ['error', 4],
'max-len': ['error', {'code': 120}],
'no-prototype-builtins': 'off',
'linebreak-style': ['error', (process.platform === 'win32' ? 'windows' : 'unix')], // https://stackoverflow.com/q/39114446/2771889
},
'plugins': [
'jest',
@@ -8,6 +8,7 @@ body:
value: |
**IMPORTANT:** Before submitting:
- Make sure this device is not already supported in the [dev branch](https://www.zigbee2mqtt.io/advanced/more/switch-to-dev-branch.html)
- Make sure there is no existing issue or PR for this device already, search for your device here: https://github.com/Koenkk/zigbee2mqtt/issues
- Follow this [guide](https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html)
- If you are using the Home Assistant addon and are still on 1.18.1, check the first point of [this](https://github.com/Koenkk/zigbee2mqtt/releases/tag/1.19.0)
- type: input
+1 -1
View File
@@ -37,7 +37,7 @@ body:
id: z2m_version
attributes:
label: Zigbee2MQTT version
description: Can be found in the frontend -> settings -> about -> Zigbee2MQTT version
description: Can be found in the frontend -> settings -> about -> Zigbee2MQTT version. Are you running Zigbee2MQTT 1.18.1? Then read [this](https://github.com/Koenkk/zigbee2mqtt/releases/tag/1.19.0).
placeholder: '1.22.1'
validations:
required: true
+13
View File
@@ -0,0 +1,13 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
target-branch: dev
- package-ecosystem: "docker"
directory: "/docker"
schedule:
interval: "daily"
target-branch: dev
+43 -24
View File
@@ -2,27 +2,20 @@ name: CI
on: [push, pull_request]
permissions:
contents: read
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2-beta
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: 18
registry-url: https://registry.npmjs.org/
- name: Get NodeJS Version
id: nodeversion
run: |
echo "::set-output name=version::$(node --version)"
- name: Restore node_modules cache
id: cache-node-modules
uses: actions/cache@v2
with:
path: node_modules
key: ${{ runner.os }}-${{ steps.nodeversion.outputs.version }}-${{ hashFiles('npm-shrinkwrap.json') }}
cache: 'npm'
- name: Install dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: npm ci
- name: Build
run: npm run build
@@ -38,13 +31,13 @@ jobs:
run: echo ${{ secrets.CR_PAT }} | docker login ghcr.io -u koenkk --password-stdin
- name: Docker setup - QEMU
if: (github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/')) && github.event_name == 'push'
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
with:
platforms: all
- name: Docker setup - Buildx
if: (github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/')) && github.event_name == 'push'
id: buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
with:
version: latest
- name: Docker build dev
@@ -52,8 +45,9 @@ jobs:
run: |
docker buildx build \
--build-arg COMMIT=$(git rev-parse --short HEAD) \
--platform linux/arm64/v8,linux/amd64,linux/arm/v6,linux/arm/v7 \
--platform linux/arm64/v8,linux/386,linux/amd64,linux/arm/v6,linux/arm/v7 \
-f docker/Dockerfile \
--provenance=false \
--push \
-t koenkk/zigbee2mqtt:latest-dev -t ghcr.io/koenkk/zigbee2mqtt:latest-dev \
.
@@ -63,8 +57,9 @@ jobs:
TAG="$(git describe --tags)"
docker buildx build \
--build-arg COMMIT=$(git rev-parse --short HEAD) \
--platform linux/arm64/v8,linux/amd64,linux/arm/v6,linux/arm/v7 \
--platform linux/arm64/v8,linux/386,linux/amd64,linux/arm/v6,linux/arm/v7 \
-f docker/Dockerfile \
--provenance=false \
--push \
-t koenkk/zigbee2mqtt:latest -t "koenkk/zigbee2mqtt:$TAG" -t ghcr.io/koenkk/zigbee2mqtt:latest -t "ghcr.io/koenkk/zigbee2mqtt:$TAG" \
.
@@ -76,9 +71,33 @@ jobs:
- name: Trigger zigbee2mqtt/hassio-zigbee2mqtt build
if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
run: |
curl -s \
--request POST \
--header "Content-Type: application/json" \
--data '{"definition": {"id": 9}}' \
-u ${{ secrets.HASSIO_TRIGGER_SECRET }} \
"https://dev.azure.com/zigbee2mqtt/Zigbee2mqtt%20Add-on/_apis/build/builds?api-version=5.1"
curl \
-X POST \
-H "Authorization: token ${{ secrets.CR_PAT }}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/zigbee2mqtt/hassio-zigbee2mqtt/actions/workflows/ci.yml/dispatches \
-d '{"ref":"master","inputs":{}}'
tests:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [14, 16, 18, 19]
runs-on: ${{ matrix.os }}
continue-on-error: true
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
registry-url: https://registry.npmjs.org/
cache: 'npm'
- name: Install dependencies
# --ignore-scripts prevents the serialport build which often fails on Windows
run: npm ci --ignore-scripts
- name: Lint
run: npm run eslint
- name: Build
run: npm run build
- name: Test
run: npm run test-with-coverage
+34
View File
@@ -0,0 +1,34 @@
name: "Code Scanning - Action"
on:
pull_request:
push:
jobs:
CodeQL-Build:
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
runs-on: ubuntu-latest
permissions:
# required for all workflows
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below).
- name: Autobuild
uses: github/codeql-action/autobuild@v2
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
+14
View File
@@ -0,0 +1,14 @@
name: 'Dependency review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout repository'
uses: actions/checkout@v3
- name: 'Dependency review'
uses: actions/dependency-review-action@v3
+34
View File
@@ -0,0 +1,34 @@
on:
workflow_dispatch:
name: GHCR cleanup
permissions: {}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Delete untagged images
uses: actions/github-script@v6
with:
github-token: ${{ secrets.CR_PAT }}
script: |
const response = await github.request("GET /${{ env.OWNER }}/packages/container/${{ env.PACKAGE_NAME }}/versions",
{ per_page: ${{ env.PER_PAGE }}
});
for(version of response.data) {
if (version.metadata.container.tags.length == 0) {
try {
console.log("delete " + version.id)
const deleteResponse = await github.request("DELETE /${{ env.OWNER }}/packages/container/${{ env.PACKAGE_NAME }}/versions/" + version.id, { });
console.log("status " + deleteResponse.status)
} catch (e) {
console.log("failed")
}
}
}
env:
OWNER: user
PACKAGE_NAME: zigbee2mqtt
PER_PAGE: 2000
+8 -2
View File
@@ -4,11 +4,17 @@ on:
- cron: "0 0 * * *"
workflow_dispatch:
permissions:
contents: read
jobs:
stale:
permissions:
issues: write # for actions/stale to close stale issues
pull-requests: write # for actions/stale to close stale PRs
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
- uses: actions/stale@v7
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days'
@@ -16,4 +22,4 @@ jobs:
days-before-stale: 30
days-before-close: 7
operations-per-run: 500
exempt-issue-labels: 'breaking change'
exempt-issue-labels: dont-stale
+12 -7
View File
@@ -4,21 +4,26 @@ on:
schedule:
- cron: "0 0 * * 0"
permissions:
contents: read
jobs:
update_deps:
permissions:
contents: write # for peter-evans/create-pull-request to create branch
pull-requests: write # for peter-evans/create-pull-request to create a PR
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
ref: dev
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
- uses: actions/setup-node@v2-beta
- uses: actions/setup-node@v3
with:
node-version: 14
- run: rm -rf npm-shrinkwrap.json
- run: npx npm-check-updates -u
- run: npm install && npm shrinkwrap --dev
- uses: peter-evans/create-pull-request@v3
node-version: 18
- run: npx npm-check-updates -u -x connect-gzip-static # connect-gzip-static only supports node 16
- run: npm install
- uses: peter-evans/create-pull-request@v4
with:
commit-message: Update dependencies
branch: "update_deps"
+10 -5
View File
@@ -3,26 +3,31 @@ on:
repository_dispatch:
types: update_frontend
permissions: {}
jobs:
update_frontend:
permissions:
contents: write # to create branch (peter-evans/create-pull-request)
pull-requests: write # to create a PR (peter-evans/create-pull-request)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
ref: dev
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
- uses: actions/setup-node@v2-beta
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: 18
- run: npm install zigbee2mqtt-frontend@${{ github.event.client_payload.version }} --save-exact
- uses: peter-evans/create-pull-request@v3
- uses: peter-evans/create-pull-request@v4
id: cpr
with:
commit-message: Update zigbee2mqtt-frontend to ${{ github.event.client_payload.version }}
branch: "update_frontend"
title: Update zigbee-frontend to ${{ github.event.client_payload.version }}
- run: sleep 5 # Otherwise pull request may not exist yet causing automerge to fail
- uses: peter-evans/enable-pull-request-automerge@v1
- uses: peter-evans/enable-pull-request-automerge@v2
if: steps.cpr.outputs.pull-request-operation == 'created'
with:
token: ${{ secrets.CR_PAT }}
+10 -5
View File
@@ -3,26 +3,31 @@ on:
repository_dispatch:
types: update_zh
permissions: {}
jobs:
update_zh:
permissions:
contents: write # to create branch (peter-evans/create-pull-request)
pull-requests: write # to create a PR (peter-evans/create-pull-request)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
ref: dev
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
- uses: actions/setup-node@v2-beta
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: 18
- run: npm install zigbee-herdsman@${{ github.event.client_payload.version }} --save-exact
- uses: peter-evans/create-pull-request@v3
- uses: peter-evans/create-pull-request@v4
id: cpr
with:
commit-message: Update zigbee-herdsman to ${{ github.event.client_payload.version }}
branch: "update_zh"
title: Update zigbee-herdsman to ${{ github.event.client_payload.version }}
- run: sleep 5 # Otherwise pull request may not exist yet causing automerge to fail
- uses: peter-evans/enable-pull-request-automerge@v1
- uses: peter-evans/enable-pull-request-automerge@v2
if: steps.cpr.outputs.pull-request-operation == 'created'
with:
token: ${{ secrets.CR_PAT }}
+10 -5
View File
@@ -3,26 +3,31 @@ on:
repository_dispatch:
types: update_zhc
permissions: {}
jobs:
update_zhc:
permissions:
contents: write # to create branch (peter-evans/create-pull-request)
pull-requests: write # to create a PR (peter-evans/create-pull-request)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
ref: dev
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
- uses: actions/setup-node@v2-beta
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: 18
- run: npm install zigbee-herdsman-converters@${{ github.event.client_payload.version }} --save-exact
- uses: peter-evans/create-pull-request@v3
- uses: peter-evans/create-pull-request@v4
id: cpr
with:
commit-message: Update zigbee-herdsman-converters to ${{ github.event.client_payload.version }}
branch: "update_zhc"
title: Update zigbee-herdsman-converters to ${{ github.event.client_payload.version }}
- run: sleep 5 # Otherwise pull request may not exist yet causing automerge to fail
- uses: peter-evans/enable-pull-request-automerge@v1
- uses: peter-evans/enable-pull-request-automerge@v2
if: steps.cpr.outputs.pull-request-operation == 'created'
with:
token: ${{ secrets.CR_PAT }}
+1 -1
View File
@@ -54,7 +54,7 @@ Zigbee2MQTT integrates well with (almost) every home automation solution because
### [Home Assistant](https://www.home-assistant.io/)
- [Home Assistant](https://www.home-assistant.io/hassio/): Using [the official addon](https://github.com/zigbee2mqtt/hassio-zigbee2mqtt)
- Generic install or Hassbian: Using instructions [here](https://www.zigbee2mqtt.io/guide/usage/integrations/home_assistant.html)
- Generic install: using instructions [here](https://www.zigbee2mqtt.io/guide/usage/integrations/home_assistant.html)
<img align="left" height="100px" width="100px" src="https://user-images.githubusercontent.com/2734836/47615848-b8dd8700-dabd-11e8-9d77-175002dd8987.png">
+10 -11
View File
@@ -1,29 +1,26 @@
FROM node:14-alpine3.12 as base
FROM alpine:3.17.2 as base
WORKDIR /app
RUN apk add --no-cache tzdata eudev tini
COPY package.json ./
RUN apk add --no-cache tzdata eudev tini nodejs
# Dependencies and build
FROM base as dependencies_and_build
COPY npm-shrinkwrap.json tsconfig.json index.js ./
COPY package*.json tsconfig.json index.js ./
COPY lib ./lib
RUN apk add --no-cache --virtual .buildtools make gcc g++ python3 linux-headers git && \
npm ci --no-audit --no-optional --no-update-notifier && \
npm run build && \
rm -rf node_modules && \
RUN apk add --no-cache --virtual .buildtools make gcc g++ python3 linux-headers git npm && \
npm ci --production --no-audit --no-optional --no-update-notifier && \
# Serialport needs to be rebuild for Alpine https://serialport.io/docs/9.x.x/guide-installation#alpine-linux
npm rebuild --build-from-source && \
apk del .buildtools
# Release
FROM base as release
COPY --from=dependencies_and_build /app/node_modules ./node_modules
COPY --from=dependencies_and_build /app/dist ./dist
COPY LICENSE index.js data/configuration.yaml ./
COPY dist ./dist
COPY package.json LICENSE index.js data/configuration.yaml ./
COPY docker/docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
@@ -33,5 +30,7 @@ RUN mkdir /app/data
ARG COMMIT
RUN echo "$COMMIT" > dist/.hash
ENV NODE_ENV production
ENTRYPOINT ["docker-entrypoint.sh"]
CMD [ "/sbin/tini", "--", "node", "index.js"]
+25 -13
View File
@@ -1,9 +1,7 @@
require('core-js/features/object/from-entries');
require('core-js/features/array/flat');
const semver = require('semver');
const engines = require('./package.json').engines;
const indexJsRestart = 'indexjs.restart';
const fs = require('fs');
const os = require('os');
const path = require('path');
const {exec} = require('child_process');
const rimraf = require('rimraf');
@@ -15,12 +13,12 @@ let stopping = false;
const hashFile = path.join(__dirname, 'dist', '.hash');
async function restart() {
await stop(indexJsRestart);
await stop(true);
await start();
}
async function exit(code, reason) {
if (reason !== indexJsRestart) {
async function exit(code, restart) {
if (!restart) {
process.exit(code);
}
}
@@ -44,7 +42,15 @@ async function build(reason) {
return new Promise((resolve, reject) => {
process.stdout.write(`Building Zigbee2MQTT... (${reason})`);
rimraf.sync('dist');
exec('npm run build', {cwd: __dirname}, async (err, stdout, stderr) => {
const env = {...process.env};
const _600mb = 629145600;
if (_600mb > os.totalmem() && !env.NODE_OPTIONS) {
// Prevent OOM on tsc compile for system with low memory
// https://github.com/Koenkk/zigbee2mqtt/issues/12034
env.NODE_OPTIONS = '--max_old_space_size=256';
}
exec('npm run build', {env, cwd: __dirname}, async (err, stdout, stderr) => {
if (err) {
process.stdout.write(', failed\n');
if (err.code === 134) {
@@ -101,21 +107,27 @@ async function start() {
await controller.start();
}
async function stop(reason=null) {
await controller.stop(reason);
async function stop(restart) {
await controller.stop(restart);
}
async function handleQuit() {
if (!stopping && controller) {
stopping = true;
await stop();
await stop(false);
}
}
if (process.argv.length === 3 && process.argv[2] === 'writehash') {
writeHash();
if (require.main === module || require.main.filename.endsWith(path.sep + 'cli.js')) {
if (process.argv.length === 3 && process.argv[2] === 'writehash') {
writeHash();
} else {
process.on('SIGINT', handleQuit);
process.on('SIGTERM', handleQuit);
start();
}
} else {
process.on('SIGINT', handleQuit);
process.on('SIGTERM', handleQuit);
start();
module.exports = {start};
}
+22 -19
View File
@@ -39,24 +39,25 @@ const AllExtensions = [
type ExtensionArgs = [Zigbee, MQTT, State, PublishEntityState, EventBus,
(enable: boolean, name: string) => Promise<void>, () => void, (extension: Extension) => Promise<void>];
class Controller {
export class Controller {
private eventBus: EventBus;
private zigbee: Zigbee;
private state: State;
private mqtt: MQTT;
private restartCallback: () => void;
private exitCallback: (code: number) => void;
private exitCallback: (code: number, restart: boolean) => void;
private extensions: Extension[];
private extensionArgs: ExtensionArgs;
constructor(restartCallback: () => void, exitCallback: (code: number) => void) {
constructor(restartCallback: () => void, exitCallback: (code: number, restart: boolean) => void) {
logger.init();
this.eventBus = new EventBus( /* istanbul ignore next */ (error) => {
logger.error(`Error: ${error.message}`);
logger.debug(error.stack);
});
this.zigbee = new Zigbee(this.eventBus);
this.mqtt = new MQTT(this.eventBus);
this.state = new State(this.eventBus);
this.state = new State(this.eventBus, this.zigbee);
this.restartCallback = restartCallback;
this.exitCallback = exitCallback;
@@ -143,8 +144,7 @@ class Controller {
try {
await this.mqtt.connect();
} catch (error) {
logger.error(`MQTT failed to connect: ${error.message}`);
logger.error('Exiting...');
logger.error(`MQTT failed to connect, exiting...`);
await this.zigbee.stop();
await this.exit(1);
}
@@ -154,15 +154,17 @@ class Controller {
// Send all cached states.
if (settings.get().advanced.cache_state_send_on_startup && settings.get().advanced.cache_state) {
for (const device of devices) {
if (this.state.exists(device)) {
this.publishEntityState(device, this.state.get(device));
for (const entity of [...devices, ...this.zigbee.groups()]) {
if (this.state.exists(entity)) {
this.publishEntityState(entity, this.state.get(entity), 'publishCached');
}
}
}
this.eventBus.onLastSeenChanged(this,
(data) => utils.publishLastSeen(data, settings.get(), false, this.publishEntityState));
logger.info(`Zigbee2MQTT started!`);
}
@bind async enableDisableExtension(enable: boolean, name: string): Promise<void> {
@@ -186,7 +188,7 @@ class Controller {
await this.callExtensions('start', [extension]);
}
async stop(): Promise<void> {
async stop(restart = false): Promise<void> {
// Call extensions
await this.callExtensions('stop', this.extensions);
this.eventBus.removeListeners(this);
@@ -198,16 +200,16 @@ class Controller {
try {
await this.zigbee.stop();
logger.info('Stopped Zigbee2MQTT');
await this.exit(0);
await this.exit(0, restart);
} catch (error) {
logger.error('Failed to stop Zigbee2MQTT');
await this.exit(1);
await this.exit(1, restart);
}
}
async exit(code: number): Promise<void> {
async exit(code: number, restart = false): Promise<void> {
await logger.end();
this.exitCallback(code);
this.exitCallback(code, restart);
}
@bind async onZigbeeAdapterDisconnected(): Promise<void> {
@@ -241,11 +243,14 @@ class Controller {
message.device = {
friendlyName: entity.name, model: entity.definition ? entity.definition.model : 'unknown',
ieeeAddr: entity.ieeeAddr, networkAddress: entity.zh.networkAddress, type: entity.zh.type,
manufacturerID: entity.zh.manufacturerID, manufacturerName: entity.zh.manufacturerName,
manufacturerID: entity.zh.manufacturerID,
powerSource: entity.zh.powerSource, applicationVersion: entity.zh.applicationVersion,
stackVersion: entity.zh.stackVersion, zclVersion: entity.zh.zclVersion,
hardwareVersion: entity.zh.hardwareVersion, dateCode: entity.zh.dateCode,
softwareBuildID: entity.zh.softwareBuildID,
// Manufacturer name can contain \u0000, remove this.
// https://github.com/home-assistant/core/issues/85691
manufacturerName: entity.zh.manufacturerName?.split('\u0000')[0],
};
}
@@ -264,10 +269,8 @@ class Controller {
extension.adjustMessageBeforePublish?.(entity, message);
}
// filter mqtt message attributes
if (entity.options.filtered_attributes) {
entity.options.filtered_attributes.forEach((a) => delete message[a]);
}
// Filter mqtt message attributes
utils.filterProperties(entity.options.filtered_attributes, message);
if (Object.entries(message).length) {
const output = settings.get().advanced.output;
+57 -35
View File
@@ -5,6 +5,12 @@ import * as settings from '../util/settings';
import debounce from 'debounce';
import bind from 'bind-decorator';
const retrieveOnReconnect = [
{keys: ['state']},
{keys: ['brightness'], condition: (state: KeyValue): boolean => state.state === 'ON'},
{keys: ['color', 'color_temp'], condition: (state: KeyValue): boolean => state.state === 'ON'},
];
export default class Availability extends Extension {
private timers: {[s: string]: NodeJS.Timeout} = {};
private availabilityCache: {[s: string]: boolean} = {};
@@ -28,9 +34,14 @@ export default class Availability extends Extension {
device.zh.powerSource === 'Mains (single phase)';
}
private isAvailable(device: Device): boolean {
const ago = Date.now() - device.zh.lastSeen;
return ago < this.getTimeout(device);
private isAvailable(entity: Device | Group): boolean {
if (entity.isDevice()) {
const ago = Date.now() - entity.zh.lastSeen;
return ago < this.getTimeout(entity);
} else {
return entity.membersDevices().length === 0 ||
entity.membersDevices().map((d) => this.availabilityCache[d.ieeeAddr]).includes(true);
}
}
private resetTimer(device: Device): void {
@@ -93,7 +104,7 @@ export default class Availability extends Extension {
override async start(): Promise<void> {
this.eventBus.onEntityRenamed(this, (data) => {
if (data.entity.isDevice() && utils.isAvailabilityEnabledForDevice(data.entity, settings.get())) {
if (utils.isAvailabilityEnabledForEntity(data.entity, settings.get())) {
this.mqtt.publish(`${data.from}/availability`, null, {retain: true, qos: 0});
this.publishAvailability(data.entity, false, true);
}
@@ -103,57 +114,67 @@ export default class Availability extends Extension {
this.eventBus.onDeviceLeave(this, (data) => clearTimeout(this.timers[data.ieeeAddr]));
this.eventBus.onDeviceAnnounce(this, (data) => this.retrieveState(data.device));
this.eventBus.onLastSeenChanged(this, this.onLastSeenChanged);
this.eventBus.onPublishAvailability(this, this.publishAvailabilityForAllDevices);
this.publishAvailabilityForAllDevices();
this.eventBus.onPublishAvailability(this, this.publishAvailabilityForAllEntities);
this.eventBus.onGroupMembersChanged(this, (data) => this.publishAvailability(data.group, false));
this.publishAvailabilityForAllEntities();
}
@bind private publishAvailabilityForAllDevices(): void {
for (const device of this.zigbee.devices(false)) {
if (utils.isAvailabilityEnabledForDevice(device, settings.get())) {
@bind private publishAvailabilityForAllEntities(): void {
for (const entity of [...this.zigbee.devices(false), ...this.zigbee.groups()]) {
if (utils.isAvailabilityEnabledForEntity(entity, settings.get())) {
// Publish initial availablility
this.publishAvailability(device, true);
this.publishAvailability(entity, true, false, true);
this.resetTimer(device);
if (entity.isDevice()) {
this.resetTimer(entity);
// If an active device is initially unavailable, ping it.
if (this.isActiveDevice(device) && !this.isAvailable(device)) {
this.addToPingQueue(device);
// If an active device is initially unavailable, ping it.
if (this.isActiveDevice(entity) && !this.isAvailable(entity)) {
this.addToPingQueue(entity);
}
}
}
}
}
private publishAvailability(device: Device, logLastSeen: boolean, forcePublish=false): void {
if (logLastSeen) {
const ago = Date.now() - device.zh.lastSeen;
if (this.isActiveDevice(device)) {
logger.debug(`Active device '${device.name}' was last seen ` +
private publishAvailability(entity: Device | Group, logLastSeen: boolean,
forcePublish=false, skipGroups=false): void {
if (logLastSeen && entity.isDevice()) {
const ago = Date.now() - entity.zh.lastSeen;
if (this.isActiveDevice(entity)) {
logger.debug(`Active device '${entity.name}' was last seen ` +
`'${(ago / utils.minutes(1)).toFixed(2)}' minutes ago.`);
} else {
logger.debug(
`Passive device '${device.name}' was last seen '${(ago / utils.hours(1)).toFixed(2)}' hours ago.`);
`Passive device '${entity.name}' was last seen '${(ago / utils.hours(1)).toFixed(2)}' hours ago.`);
}
}
const available = this.isAvailable(device);
if (!forcePublish && this.availabilityCache[device.ieeeAddr] == available) {
const available = this.isAvailable(entity);
if (!forcePublish && this.availabilityCache[entity.ID] == available) {
return;
}
if (device.ieeeAddr in this.availabilityCache && available &&
this.availabilityCache[device.ieeeAddr] === false) {
logger.debug(`Device '${device.name}' reconnected`);
this.retrieveState(device);
if (entity.isDevice() && entity.ieeeAddr in this.availabilityCache && available &&
this.availabilityCache[entity.ieeeAddr] === false) {
logger.debug(`Device '${entity.name}' reconnected`);
this.retrieveState(entity);
}
const topic = `${device.name}/availability`;
const topic = `${entity.name}/availability`;
const payload = utils.availabilityPayload(available ? 'online' : 'offline', settings.get());
this.availabilityCache[device.ieeeAddr] = available;
this.availabilityCache[entity.ID] = available;
this.mqtt.publish(topic, payload, {retain: true, qos: 0});
if (!skipGroups && entity.isDevice()) {
this.zigbee.groups().filter((g) => g.hasMember(entity))
.filter((g) => utils.isAvailabilityEnabledForEntity(g, settings.get()))
.forEach((g) => this.publishAvailability(g, false, forcePublish));
}
}
@bind private onLastSeenChanged(data: eventdata.LastSeenChanged): void {
if (utils.isAvailabilityEnabledForDevice(data.device, settings.get())) {
if (utils.isAvailabilityEnabledForEntity(data.device, settings.get())) {
// Remove from ping queue, not necessary anymore since we know the device is online.
this.removeFromPingQueue(data.device);
this.resetTimer(data.device);
@@ -172,17 +193,18 @@ export default class Availability extends Extension {
* device can send multiple times after each other.
*/
if (device.definition && !device.zh.interviewing && !this.retrieveStateDebouncers[device.ieeeAddr]) {
this.retrieveStateDebouncers[device.ieeeAddr] = debounce(() => {
this.retrieveStateDebouncers[device.ieeeAddr] = debounce(async () => {
logger.debug(`Retrieving state of '${device.name}' after reconnect`);
// Color and color temperature converters do both, only needs to be called once.
const keySet = [['state'], ['brightness'], ['color', 'color_temp']];
for (const keys of keySet) {
const converter = device.definition.toZigbee.find((c) => c.key.find((k) => keys.includes(k)));
converter?.convertGet?.(device.endpoint(), keys[0],
{message: this.state.get(device) || {}, mapped: device.definition})
for (const item of retrieveOnReconnect) {
if (item.condition && this.state.get(device) && !item.condition(this.state.get(device))) continue;
const converter = device.definition.toZigbee.find((c) => c.key.find((k) => item.keys.includes(k)));
await converter?.convertGet?.(device.endpoint(), item.keys[0],
{message: this.state.get(device), mapped: device.definition})
.catch((e) => {
logger.error(`Failed to read state of '${device.name}' after reconnect (${e.message})`);
});
await utils.sleep(500);
}
}, utils.seconds(2));
}
+27 -4
View File
@@ -13,7 +13,8 @@ const legacyApi = settings.get().advanced.legacy_api;
const legacyTopicRegex = new RegExp(`^${settings.get().mqtt.base_topic}/bridge/(bind|unbind)/.+$`);
const topicRegex = new RegExp(`^${settings.get().mqtt.base_topic}/bridge/request/device/(bind|unbind)`);
const clusterCandidates = ['genScenes', 'genOnOff', 'genLevelCtrl', 'lightingColorCtrl', 'closuresWindowCovering',
'hvacThermostat', 'msTemperatureMeasurement'];
'hvacThermostat', 'msIlluminanceMeasurement', 'msTemperatureMeasurement', 'msRelativeHumidity',
'msSoilMoisture', 'msCO2'];
// See zigbee-herdsman-converters
const defaultBindGroup = {type: 'group_number', ID: 901, name: 'default_bind_group'};
@@ -67,7 +68,8 @@ const reportClusters: {[s: string]:
type PollOnMessage = {
cluster: {[s: string]: {type: string, data: KeyValue}[]}
read: {cluster: string, attributes: string[], attributesForEndpoint?: (endpoint: zh.Endpoint) => Promise<string[]>}
manufacturerIDs: number[]
manufacturerIDs: number[],
manufacturerNames: string [],
}[];
const pollOnMessage: PollOnMessage = [
@@ -100,6 +102,11 @@ const pollOnMessage: PollOnMessage = [
zigbeeHersdman.Zcl.ManufacturerCode.GLEDOPTO_CO_LTD,
zigbeeHersdman.Zcl.ManufacturerCode.MUELLER_LICHT_INT,
zigbeeHersdman.Zcl.ManufacturerCode.TELINK,
zigbeeHersdman.Zcl.ManufacturerCode.BUSCH_JAEGER,
],
manufacturerNames: [
'GLEDOPTO',
'Trust International B.V.\u0000',
],
},
{
@@ -131,6 +138,11 @@ const pollOnMessage: PollOnMessage = [
zigbeeHersdman.Zcl.ManufacturerCode.GLEDOPTO_CO_LTD,
zigbeeHersdman.Zcl.ManufacturerCode.MUELLER_LICHT_INT,
zigbeeHersdman.Zcl.ManufacturerCode.TELINK,
zigbeeHersdman.Zcl.ManufacturerCode.BUSCH_JAEGER,
],
manufacturerNames: [
'GLEDOPTO',
'Trust International B.V.\u0000',
],
},
{
@@ -158,6 +170,11 @@ const pollOnMessage: PollOnMessage = [
zigbeeHersdman.Zcl.ManufacturerCode.GLEDOPTO_CO_LTD,
zigbeeHersdman.Zcl.ManufacturerCode.MUELLER_LICHT_INT,
zigbeeHersdman.Zcl.ManufacturerCode.TELINK,
// Note: ManufacturerCode.BUSCH_JAEGER is left out intentionally here as their devices don't support colors
],
manufacturerNames: [
'GLEDOPTO',
'Trust International B.V.\u0000',
],
},
];
@@ -455,7 +472,8 @@ export default class Bind extends Extension {
for (const endpoint of toPoll) {
for (const poll of polls) {
if (!poll.manufacturerIDs.includes(endpoint.getDevice().manufacturerID) ||
if ((!poll.manufacturerIDs.includes(endpoint.getDevice().manufacturerID) &&
!poll.manufacturerNames.includes(endpoint.getDevice().manufacturerName)) ||
!endpoint.supportsInputCluster(poll.read.cluster)) {
continue;
}
@@ -469,7 +487,12 @@ export default class Bind extends Extension {
const key = `${endpoint.getDevice().ieeeAddr}_${endpoint.ID}_${pollOnMessage.indexOf(poll)}`;
if (!this.pollDebouncers[key]) {
this.pollDebouncers[key] = debounce(async () => {
await endpoint.read(poll.read.cluster, readAttrs);
try {
await endpoint.read(poll.read.cluster, readAttrs);
} catch (error) {
logger.error(`Failed to poll ${readAttrs} from ` +
`${this.zigbee.resolveEntity(endpoint.getDevice()).name}`);
}
}, 1000);
}
+39 -32
View File
@@ -6,10 +6,12 @@ import Transport from 'winston-transport';
import bind from 'bind-decorator';
import stringify from 'json-stable-stringify-without-jsonify';
import objectAssignDeep from 'object-assign-deep';
import {detailedDiff} from 'deep-object-diff';
import Extension from './extension';
import Device from '../model/device';
import Group from '../model/group';
import data from '../util/data';
import JSZip from 'jszip';
import fs from 'fs';
const requestRegex = new RegExp(`${settings.get().mqtt.base_topic}/bridge/request/(.*)`);
@@ -38,8 +40,10 @@ export default class Bridge extends Extension {
'group/rename': this.groupRename,
'permit_join': this.permitJoin,
'restart': this.restart,
'backup': this.backup,
'touchlink/factory_reset': this.touchlinkFactoryReset,
'touchlink/identify': this.touchlinkIdentify,
'install_code/add': this.installCodeAdd,
'touchlink/scan': this.touchlinkScan,
'health_check': this.healthCheck,
'options': this.bridgeOptions,
@@ -143,35 +147,7 @@ export default class Bridge extends Extension {
throw new Error(`Invalid payload`);
}
const diff: KeyValue = detailedDiff(settings.get(), message.options);
// Remove any settings that are in the deleted.diff but not in the passed options
const cleanupDeleted = (options: KeyValue, deleted: KeyValue): void => {
for (const key of Object.keys(deleted)) {
if (!(key in options)) {
delete deleted[key];
} else if (!Array.isArray(options[key])) {
cleanupDeleted(options[key], deleted[key]);
}
}
};
cleanupDeleted(message.options, diff.deleted);
const newSettings = objectAssignDeep({}, diff.added, diff.updated, diff.deleted);
// deep-object-diff converts arrays to objects, set original array back here
const convertBackArray = (before: KeyValue, after: KeyValue): void => {
for (const [key, afterValue] of Object.entries(after)) {
const beforeValue = before[key];
if (Array.isArray(beforeValue)) {
after[key] = beforeValue;
} else if (afterValue && typeof beforeValue === 'object') {
convertBackArray(beforeValue, afterValue);
}
}
};
convertBackArray(message.options, newSettings);
const newSettings = utils.computeSettingsToChange(settings.get(), message.options);
const restartRequired = settings.apply(newSettings);
if (restartRequired) this.restartRequired = true;
@@ -233,6 +209,28 @@ export default class Bridge extends Extension {
return utils.getResponse(message, {}, null);
}
@bind async backup(message: string | KeyValue): Promise<MQTTResponse> {
await this.zigbee.backup();
const dataPath = data.getPath();
const files = utils.getAllFiles(dataPath).map((f) => [f, f.substring(dataPath.length + 1)])
.filter((f) => !f[1].startsWith('log'));
const zip = new JSZip();
files.forEach((f) => zip.file(f[1], fs.readFileSync(f[0])));
const base64Zip = await zip.generateAsync({type: 'base64'});
return utils.getResponse(message, {zip: base64Zip}, null);
}
@bind async installCodeAdd(message: KeyValue | string): Promise<MQTTResponse> {
if (typeof message === 'object' && !message.hasOwnProperty('value')) {
throw new Error('Invalid payload');
}
const value = typeof message === 'object' ? message.value : message;
await this.zigbee.addInstallCode(value);
logger.info('Successfully added new install code');
return utils.getResponse(message, {value}, null);
}
@bind async permitJoin(message: KeyValue | string): Promise<MQTTResponse> {
if (typeof message === 'object' && !message.hasOwnProperty('value')) {
throw new Error('Invalid payload');
@@ -392,15 +390,23 @@ export default class Bridge extends Extension {
const ID = message.id;
const entity = this.getEntity(entityType, ID);
const currentOptions = entityType === 'device' ? settings.get().devices[entity.ID] :
settings.get().groups[entity.ID];
const options = utils.computeSettingsToChange(currentOptions, message.options);
const oldOptions = objectAssignDeep({}, cleanup(entity.options));
settings.changeEntityOptions(ID, message.options);
const restartRequired = settings.changeEntityOptions(ID, options);
if (restartRequired) this.restartRequired = true;
const newOptions = cleanup(entity.options);
await this.publishInfo();
logger.info(`Changed config for ${entityType} ${ID}`);
this.eventBus.emitEntityOptionsChanged({from: oldOptions, to: newOptions, entity});
return utils.getResponse(message, {from: oldOptions, to: newOptions, id: ID}, null);
return utils.getResponse(
message,
{from: oldOptions, to: newOptions, id: ID, restart_required: this.restartRequired},
null,
);
}
@bind async deviceConfigureReporting(message: string | KeyValue): Promise<MQTTResponse> {
@@ -650,6 +656,7 @@ export default class Bridge extends Extension {
network_address: device.zh.networkAddress,
supported: !!device.definition,
friendly_name: device.name,
disabled: !!device.options.disabled,
description: device.options.description,
definition: this.getDefinitionPayload(device),
power_source: device.zh.powerSource,
+6 -4
View File
@@ -64,9 +64,11 @@ export default class Configure extends Extension {
}
override async start(): Promise<void> {
for (const device of this.zigbee.devices(false)) {
await this.configure(device, 'started');
}
setImmediate(async () => {
for (const device of this.zigbee.devices(false)) {
await this.configure(device, 'started');
}
});
this.eventBus.onDeviceJoined(this, (data) => {
if (data.device.zh.meta.hasOwnProperty('configured')) {
@@ -85,7 +87,7 @@ export default class Configure extends Extension {
private async configure(device: Device, event: 'started' | 'zigbee_event' | 'reporting_disabled' | 'mqtt_message',
force=false, thowError=false): Promise<void> {
if (!force) {
if (!device.definition?.configure || device.zh.interviewing) {
if (device.options.disabled || !device.definition?.configure || !device.zh.interviewCompleted) {
return;
}
+2 -2
View File
@@ -56,7 +56,7 @@ export default class ExternalExtension extends Extension {
@bind private async saveExtension(message: KeyValue): Promise<MQTTResponse> {
const {name, code} = message;
const ModuleConstructor = utils.loadModuleFromText(code) as typeof Extension;
const ModuleConstructor = utils.loadModuleFromText(code, name) as typeof Extension;
await this.loadExtension(ModuleConstructor);
const basePath = this.getExtensionsBasePath();
/* istanbul ignore else */
@@ -95,7 +95,7 @@ export default class ExternalExtension extends Extension {
private loadUserDefinedExtensions(): void {
const extensions = this.getListOfUserDefinedExtensions();
extensions
.map(({code}) => utils.loadModuleFromText(code))
.map(({code, name}) => utils.loadModuleFromText(code, name))
.map(this.loadExtension);
}
+32 -9
View File
@@ -1,4 +1,5 @@
import http from 'http';
import https from 'https';
import gzipStatic, {RequestHandler} from 'connect-gzip-static';
import finalhandler from 'finalhandler';
import logger from '../util/logger';
@@ -6,6 +7,7 @@ import frontend from 'zigbee2mqtt-frontend';
import WebSocket from 'ws';
import net from 'net';
import url from 'url';
import fs from 'fs';
import * as settings from '../util/settings';
import utils from '../util/utils';
import stringify from 'json-stable-stringify-without-jsonify';
@@ -19,6 +21,8 @@ export default class Frontend extends Extension {
private mqttBaseTopic = settings.get().mqtt.base_topic;
private host = settings.get().frontend.host;
private port = settings.get().frontend.port;
private sslCert = settings.get().frontend.ssl_cert;
private sslKey = settings.get().frontend.ssl_key;
private authToken = settings.get().frontend.auth_token;
private retainedMessages = new Map();
private server: http.Server;
@@ -33,8 +37,28 @@ export default class Frontend extends Extension {
this.eventBus.onMQTTMessagePublished(this, this.onMQTTPublishMessage);
}
private isHttpsConfigured():boolean {
if (this.sslCert && this.sslKey) {
if (!fs.existsSync(this.sslCert) || !fs.existsSync(this.sslKey)) {
logger.error(`defined ssl_cert '${this.sslCert}' or ssl_key '${this.sslKey}' file path does not exists, server won't be secured.`); /* eslint-disable-line max-len */
return false;
}
return true;
}
return false;
}
override async start(): Promise<void> {
this.server = http.createServer(this.onRequest);
if (this.isHttpsConfigured()) {
const serverOptions = {
key: fs.readFileSync(this.sslKey),
cert: fs.readFileSync(this.sslCert)};
this.server = https.createServer(serverOptions, this.onRequest);
} else {
this.server = http.createServer(this.onRequest);
}
this.server.on('upgrade', this.onUpgrade);
/* istanbul ignore next */
@@ -56,12 +80,15 @@ export default class Frontend extends Extension {
override async stop(): Promise<void> {
super.stop();
for (const client of this.wss.clients) {
this.wss?.clients.forEach((client) => {
client.send(stringify({topic: 'bridge/state', payload: 'offline'}));
client.terminate();
});
this.wss?.close();
/* istanbul ignore else */
if (this.server) {
return new Promise((cb: () => void) => this.server.close(cb));
}
this.wss.close();
return new Promise((cb: () => void) => this.server.close(cb));
}
@bind private onRequest(request: http.IncomingMessage, response: http.ServerResponse): void {
@@ -100,11 +127,7 @@ export default class Frontend extends Extension {
}
for (const device of this.zigbee.devices(false)) {
let payload: KeyValue = {};
if (this.state.exists(device)) {
payload = {...payload, ...this.state.get(device)};
}
const payload = this.state.get(device);
const lastSeen = settings.get().advanced.last_seen;
/* istanbul ignore if */
if (lastSeen !== 'disable') {
+25 -13
View File
@@ -101,7 +101,7 @@ export default class Groups extends Extension {
@bind async onStateChange(data: eventdata.StateChange): Promise<void> {
const reason = 'groupOptimistic';
if (data.reason === reason) {
if (data.reason === reason || data.reason === 'publishCached') {
return;
}
@@ -129,11 +129,10 @@ export default class Groups extends Extension {
if (entity instanceof Device) {
for (const group of groups) {
if (group.zh.hasMember(entity.endpoint(endpointName)) &&
!equals(this.lastOptimisticState[group.ID], payload)) {
if (!payload || payload.state !== 'OFF' || this.areAllMembersOff(group)) {
this.lastOptimisticState[group.ID] = payload;
await this.publishEntityState(group, payload, reason);
}
!equals(this.lastOptimisticState[group.ID], payload) &&
this.shouldPublishPayloadForGroup(group, payload)) {
this.lastOptimisticState[group.ID] = payload;
await this.publishEntityState(group, payload, reason);
}
}
} else {
@@ -143,6 +142,7 @@ export default class Groups extends Extension {
const groupsToPublish: Set<Group> = new Set();
for (const member of entity.zh.members) {
const device = this.zigbee.resolveEntity(member.getDevice()) as Device;
if (device.options.disabled) continue;
const exposes = device.exposes();
const memberPayload: KeyValue = {};
Object.keys(payload).forEach((key) => {
@@ -161,10 +161,9 @@ export default class Groups extends Extension {
await this.publishEntityState(device, memberPayload, reason);
for (const zigbeeGroup of groups) {
if (zigbeeGroup.zh.hasMember(member)) {
if (!payload || payload.state !== 'OFF' || this.areAllMembersOff(zigbeeGroup)) {
groupsToPublish.add(zigbeeGroup);
}
if (zigbeeGroup.zh.hasMember(member) &&
this.shouldPublishPayloadForGroup(zigbeeGroup, payload)) {
groupsToPublish.add(zigbeeGroup);
}
}
}
@@ -176,12 +175,19 @@ export default class Groups extends Extension {
}
}
private shouldPublishPayloadForGroup(group: Group, payload: KeyValue): boolean {
if (group.options.off_state === 'last_member_state') return true;
if (!payload || payload.state !== 'OFF') return true;
if (this.areAllMembersOff(group)) return true;
return false;
}
private areAllMembersOff(group: Group): boolean {
for (const member of group.zh.members) {
const device = this.zigbee.resolveEntity(member.getDevice());
if (this.state.exists(device)) {
const state = this.state.get(device);
if (state && state.state === 'ON') {
if (state.state === 'ON') {
return false;
}
}
@@ -287,6 +293,7 @@ export default class Groups extends Extension {
groupKey, deviceKey, skipDisableReporting, resolvedEntityEndpoint,
} = parsed;
const message = utils.parseJSON(data.message, data.message);
let changedGroups: Group[] = [];
const responseData: KeyValue = {device: deviceKey};
if (groupKey) {
@@ -315,6 +322,7 @@ export default class Groups extends Extension {
logger.info(`Adding '${resolvedEntityDevice.name}' to '${resolvedEntityGroup.name}'`);
await resolvedEntityEndpoint.addToGroup(resolvedEntityGroup.zh);
settings.addDeviceToGroup(resolvedEntityGroup.ID.toString(), keys);
changedGroups.push(resolvedEntityGroup);
/* istanbul ignore else */
if (settings.get().advanced.legacy_api) {
@@ -328,6 +336,7 @@ export default class Groups extends Extension {
logger.info(`Removing '${resolvedEntityDevice.name}' from '${resolvedEntityGroup.name}'`);
await resolvedEntityEndpoint.removeFromGroup(resolvedEntityGroup.zh);
settings.removeDeviceFromGroup(resolvedEntityGroup.ID.toString(), keys);
changedGroups.push(resolvedEntityGroup);
/* istanbul ignore else */
if (settings.get().advanced.legacy_api) {
@@ -339,6 +348,7 @@ export default class Groups extends Extension {
}
} else { // remove_all
logger.info(`Removing '${resolvedEntityDevice.name}' from all groups`);
changedGroups = this.zigbee.groups().filter((g) => g.zh.members.includes(resolvedEntityEndpoint));
await resolvedEntityEndpoint.removeFromAllGroups();
for (const settingsGroup of settings.getGroups()) {
settings.removeDeviceFromGroup(settingsGroup.ID.toString(), keys);
@@ -367,8 +377,10 @@ export default class Groups extends Extension {
if (error) {
logger.error(error);
} else {
this.eventBus.emitGroupMembersChanged({
group: resolvedEntityGroup, action: type, endpoint: resolvedEntityEndpoint, skipDisableReporting});
for (const group of changedGroups) {
this.eventBus.emitGroupMembersChanged({
group, action: type, endpoint: resolvedEntityEndpoint, skipDisableReporting});
}
}
}
}
+213 -94
View File
@@ -111,7 +111,7 @@ export default class HomeAssistant extends Extension {
}
private exposeToConfig(exposes: zhc.DefinitionExpose[], entityType: 'device' | 'group',
definition?: zhc.Definition, definitionExposes?: zhc.DefinitionExpose[]): DiscoveryEntry[] {
allExposes: zhc.DefinitionExpose[], definition?: zhc.Definition): DiscoveryEntry[] {
// For groups an array of exposes (of the same type) is passed, this is to determine e.g. what features
// to use for a bulb (e.g. color_xy/color_temp)
assert(entityType === 'group' || exposes.length === 1, 'Multiple exposes for device not allowed');
@@ -171,10 +171,11 @@ export default class HomeAssistant extends Extension {
discoveryEntry.discovery_payload.min_mireds = min;
}
const effect = definitionExposes?.find((e) => e.type === 'enum' && e.name === 'effect');
if (effect) {
const effects = utils.arrayUnique(utils.flatten(
allExposes.filter((e) => e.type === 'enum' && e.name === 'effect').map((e) => e.values)));
if (effects.length) {
discoveryEntry.discovery_payload.effect = true;
discoveryEntry.discovery_payload.effect_list = effect.values;
discoveryEntry.discovery_payload.effect_list = effects;
}
discoveryEntries.push(discoveryEntry);
@@ -282,21 +283,22 @@ export default class HomeAssistant extends Extension {
discoveryEntry.discovery_payload.fan_mode_state_topic = true;
}
const preset = firstExpose.features.find((f) => f.name === 'preset');
if (preset) {
discoveryEntry.discovery_payload.hold_modes = preset.values;
discoveryEntry.discovery_payload.hold_command_topic = true;
discoveryEntry.discovery_payload.hold_state_template =
`{{ value_json.${preset.property} }}`;
discoveryEntry.discovery_payload.hold_state_topic = true;
const swingMode = firstExpose.features.find((f) => f.name === 'swing_mode');
if (swingMode) {
discoveryEntry.discovery_payload.swing_modes = swingMode.values;
discoveryEntry.discovery_payload.swing_mode_command_topic = true;
discoveryEntry.discovery_payload.swing_mode_state_template =
`{{ value_json.${swingMode.property} }}`;
discoveryEntry.discovery_payload.swing_mode_state_topic = true;
}
const awayMode = firstExpose.features.find((f) => f.name === 'away_mode');
if (awayMode) {
discoveryEntry.discovery_payload.away_mode_command_topic = true;
discoveryEntry.discovery_payload.away_mode_state_topic = true;
discoveryEntry.discovery_payload.away_mode_state_template =
`{{ value_json.${awayMode.property} }}`;
const preset = firstExpose.features.find((f) => f.name === 'preset');
if (preset) {
discoveryEntry.discovery_payload.preset_modes = preset.values;
discoveryEntry.discovery_payload.preset_mode_command_topic = 'preset';
discoveryEntry.discovery_payload.preset_mode_value_template =
`{{ value_json.${preset.property} }}`;
discoveryEntry.discovery_payload.preset_mode_state_topic = true;
}
const tempCalibration = firstExpose.features.find((f) => f.name === 'local_temperature_calibration');
@@ -310,6 +312,7 @@ export default class HomeAssistant extends Extension {
command_topic: true,
command_topic_prefix: endpoint,
command_topic_postfix: tempCalibration.property,
device_class: 'temperature',
entity_category: 'config',
icon: 'mdi:math-compass',
...(tempCalibration.unit && {unit_of_measurement: tempCalibration.unit}),
@@ -318,6 +321,9 @@ export default class HomeAssistant extends Extension {
if (tempCalibration.value_min != null) discoveryEntry.discovery_payload.min = tempCalibration.value_min;
if (tempCalibration.value_max != null) discoveryEntry.discovery_payload.max = tempCalibration.value_max;
if (tempCalibration.value_step != null) {
discoveryEntry.discovery_payload.step = tempCalibration.value_step;
}
discoveryEntries.push(discoveryEntry);
}
@@ -378,26 +384,63 @@ export default class HomeAssistant extends Extension {
discoveryEntries.push(discoveryEntry);
} else if (firstExpose.type === 'cover') {
const position = exposes.find((expose) => expose.features.find((e) => e.name === 'position'));
const tilt = exposes.find((expose) => expose.features.find((e) => e.name === 'tilt'));
const state = exposes.find((expose) => expose.features.find((e) => e.name === 'state'))
?.features.find((f) => f.name === 'state');
const position = exposes.find((expose) => expose.features.find((e) => e.name === 'position'))
?.features.find((f) => f.name === 'position');
const tilt = exposes.find((expose) => expose.features.find((e) => e.name === 'tilt'))
?.features.find((f) => f.name === 'tilt');
const motorState = allExposes?.find((e) => e.type === 'enum' &&
['motor_state', 'moving'].includes(e.name) && e.access === ACCESS_STATE);
const running = allExposes?.find((e) => e.type === 'binary' && e.name === 'running');
const discoveryEntry: DiscoveryEntry = {
type: 'cover',
mockProperties: [],
mockProperties: [{property: state.property, value: null}],
object_id: endpoint ? `cover_${endpoint}` : 'cover',
discovery_payload: {
command_topic_prefix: endpoint,
command_topic: true,
state_topic: true,
state_topic_postfix: endpoint,
},
};
// For covers only supporting tilt don't discover the command/state_topic, otherwise
// HA does not correctly reflect the state
// - https://github.com/home-assistant/core/issues/51793
// - https://github.com/Koenkk/zigbee-herdsman-converters/pull/2663
if (!tilt || (tilt && position)) {
discoveryEntry.discovery_payload.command_topic = true;
discoveryEntry.discovery_payload.state_topic = !position;
discoveryEntry.discovery_payload.command_topic_prefix = endpoint;
// If curtains have `running` property, use this in discovery.
// The movement direction is calculated (assumed) in this case.
if (running) {
discoveryEntry.discovery_payload.value_template = `{% if "${running.property}" in value_json ` +
`and value_json.${running.property} %} {% if value_json.${position.property} > 0 %} closing ` +
`{% else %} opening {% endif %} {% else %} stopped {% endif %}`;
}
// If curtains have `motor_state` or `moving` property, lookup for possible
// state names to detect movement direction and use this in discovery.
if (motorState) {
const openingLookup = ['opening', 'open', 'forward', 'up', 'rising'];
const closingLookup = ['closing', 'close', 'backward', 'back', 'reverse', 'down', 'declining'];
const stoppedLookup = ['stopped', 'stop', 'pause', 'paused'];
const openingState = motorState.values.find((s) => openingLookup.includes(s.toLowerCase()));
const closingState = motorState.values.find((s) => closingLookup.includes(s.toLowerCase()));
const stoppedState = motorState.values.find((s) => stoppedLookup.includes(s.toLowerCase()));
if (openingState && closingState && stoppedState) {
discoveryEntry.discovery_payload.state_opening = openingState;
discoveryEntry.discovery_payload.state_closing = closingState;
discoveryEntry.discovery_payload.state_stopped = stoppedState;
discoveryEntry.discovery_payload.value_template = `{% if "${motorState.property}" in value_json ` +
`and value_json.${motorState.property} %} {{ value_json.${motorState.property} }} {% else %} ` +
`${stoppedState} {% endif %}`;
}
}
// If curtains do not have `running`, `motor_state` or `moving` properties.
if (!discoveryEntry.discovery_payload.value_template) {
discoveryEntry.discovery_payload.value_template =
`{{ value_json.${featurePropertyWithoutEndpoint(state)} }}`,
discoveryEntry.discovery_payload.state_open = 'OPEN';
discoveryEntry.discovery_payload.state_closed = 'CLOSE';
}
if (!position && !tilt) {
@@ -405,21 +448,19 @@ export default class HomeAssistant extends Extension {
}
if (position) {
const p = position.features.find((f) => f.name === 'position');
discoveryEntry.discovery_payload = {...discoveryEntry.discovery_payload,
position_template: `{{ value_json.${getProperty(p)} }}`,
set_position_template: `{ "${getProperty(p)}": {{ position }} }`,
position_template: `{{ value_json.${featurePropertyWithoutEndpoint(position)} }}`,
set_position_template: `{ "${getProperty(position)}": {{ position }} }`,
set_position_topic: true,
position_topic: true,
};
}
if (tilt) {
const t = tilt.features.find((f) => f.name === 'tilt');
discoveryEntry.discovery_payload = {...discoveryEntry.discovery_payload,
tilt_command_topic: true,
tilt_status_topic: true,
tilt_status_template: `{{ value_json.${getProperty(t)} }}`,
tilt_status_template: `{{ value_json.${featurePropertyWithoutEndpoint(tilt)} }}`,
};
}
@@ -481,7 +522,7 @@ export default class HomeAssistant extends Extension {
discoveryEntry.discovery_payload.speed_range_max = speeds.length - 1;
assert(presets.length !== 0);
discoveryEntry.discovery_payload.preset_mode_state_topic = true;
discoveryEntry.discovery_payload.preset_mode_command_topic = true;
discoveryEntry.discovery_payload.preset_mode_command_topic = 'fan_mode';
discoveryEntry.discovery_payload.preset_mode_value_template =
`{{ value_json.${speed.property} if value_json.${speed.property} in [${presetList}]` +
` else 'None' | default('None') }}`;
@@ -493,19 +534,25 @@ export default class HomeAssistant extends Extension {
const lookup: {[s: string]: KeyValue}= {
battery_low: {entity_category: 'diagnostic', device_class: 'battery'},
button_lock: {entity_category: 'config', icon: 'mdi:lock'},
calibration: {entity_category: 'config', icon: 'mdi:progress-wrench'},
carbon_monoxide: {device_class: 'safety'},
card: {entity_category: 'config', icon: 'mdi:clipboard-check'},
child_lock: {entity_category: 'config', icon: 'mdi:account-lock'},
color_sync: {entity_category: 'config', icon: 'mdi:sync-circle'},
consumer_connected: {entity_category: 'diagnostic', device_class: 'connectivity'},
contact: {device_class: 'door'},
garage_door_contact: {device_class: 'garage_door', payload_on: false, payload_off: true},
eco_mode: {entity_category: 'config', icon: 'mdi:leaf'},
expose_pin: {entity_category: 'config', icon: 'mdi:pin'},
flip_indicator_light: {entity_category: 'config', icon: 'mdi:arrow-left-right'},
gas: {device_class: 'gas'},
indicator_mode: {entity_category: 'config', icon: 'mdi:led-on'},
invert_cover: {entity_category: 'config', icon: 'mdi:arrow-left-right'},
led_disabled_night: {entity_category: 'config', icon: 'mdi:led-off'},
led_indication: {entity_category: 'config', icon: 'mdi:led-on'},
led_enable: {entity_category: 'config', icon: 'mdi:led-on'},
legacy: {entity_category: 'config', icon: 'mdi:cog'},
motor_reversal: {entity_category: 'config', icon: 'mdi:arrow-left-right'},
moving: {device_class: 'moving'},
no_position_support: {entity_category: 'config', icon: 'mdi:minus-circle-outline'},
occupancy: {device_class: 'motion'},
@@ -514,9 +561,12 @@ export default class HomeAssistant extends Extension {
smoke: {device_class: 'smoke'},
sos: {device_class: 'safety'},
tamper: {device_class: 'tamper'},
temperature_scale: {entity_category: 'config', icon: 'mdi:temperature-celsius'},
test: {entity_category: 'diagnostic', icon: 'mdi:test-tube'},
valve_state: {device_class: 'opening'},
vibration: {device_class: 'vibration'},
water_leak: {device_class: 'moisture'},
window: {device_class: 'window'},
};
/**
@@ -574,9 +624,13 @@ export default class HomeAssistant extends Extension {
away_preset_days: {entity_category: 'config', icon: 'mdi:timer'},
away_preset_temperature: {entity_category: 'config', icon: 'mdi:thermometer'},
battery: {device_class: 'battery', entity_category: 'diagnostic', state_class: 'measurement'},
battery2: {device_class: 'battery', entity_category: 'diagnostic', state_class: 'measurement'},
battery_voltage: {device_class: 'voltage', entity_category: 'diagnostic', state_class: 'measurement'},
boost_heating_countdown: {device_class: 'duration'},
boost_heating_countdown_time_set: {entity_category: 'config', icon: 'mdi:timer'},
boost_time: {entity_category: 'config', icon: 'mdi:timer'},
calibration: {entity_category: 'config'},
calibration: {entity_category: 'config', icon: 'mdi:wrench-clock'},
calibration_time: {entity_category: 'config', icon: 'mdi:wrench-clock'},
co2: {device_class: 'carbon_dioxide', state_class: 'measurement'},
comfort_temperature: {entity_category: 'config', icon: 'mdi:thermometer'},
cpu_temperature: {
@@ -605,6 +659,7 @@ export default class HomeAssistant extends Extension {
device_temperature: {
device_class: 'temperature', entity_category: 'diagnostic', state_class: 'measurement',
},
duration: {entity_category: 'config', icon: 'mdi:timer'},
eco2: {device_class: 'carbon_dioxide', state_class: 'measurement'},
eco_temperature: {entity_category: 'config', icon: 'mdi:thermometer'},
energy: {device_class: 'energy', state_class: 'total_increasing'},
@@ -612,6 +667,10 @@ export default class HomeAssistant extends Extension {
gas_density: {icon: 'mdi:google-circles-communities', state_class: 'measurement'},
hcho: {icon: 'mdi:air-filter', state_class: 'measurement'},
humidity: {device_class: 'humidity', state_class: 'measurement'},
humidity_calibration: {entity_category: 'config', icon: 'mdi:wrench-clock'},
humidity_max: {entity_category: 'config', icon: 'mdi:water-percent'},
humidity_min: {entity_category: 'config', icon: 'mdi:water-percent'},
illuminance_calibration: {entity_category: 'config', icon: 'mdi:wrench-clock'},
illuminance_lux: {device_class: 'illuminance', state_class: 'measurement'},
illuminance: {device_class: 'illuminance', enabled_by_default: false, state_class: 'measurement'},
linkquality: {
@@ -621,9 +680,10 @@ export default class HomeAssistant extends Extension {
state_class: 'measurement',
},
local_temperature: {device_class: 'temperature', state_class: 'measurement'},
max_temperature: {entity_category: 'config', icon: 'mdi:thermometer'},
max_temperature_limit: {entity_category: 'config', icon: 'mdi:thermometer'},
min_temperature: {entity_category: 'config', icon: 'mdi:thermometer'},
max_temperature: {entity_category: 'config', icon: 'mdi:thermometer-high'},
max_temperature_limit: {entity_category: 'config', icon: 'mdi:thermometer-high'},
min_temperature_limit: {entity_category: 'config', icon: 'mdi:thermometer-low'},
min_temperature: {entity_category: 'config', icon: 'mdi:thermometer-low'},
measurement_poll_interval: {entity_category: 'config', icon: 'mdi:clock-out'},
occupancy_timeout: {entity_category: 'config', icon: 'mdi:timer'},
pm10: {device_class: 'pm10', state_class: 'measurement'},
@@ -636,6 +696,7 @@ export default class HomeAssistant extends Extension {
precision: {entity_category: 'config', icon: 'mdi:decimal-comma-increase'},
pressure: {device_class: 'pressure', state_class: 'measurement'},
presence_timeout: {entity_category: 'config', icon: 'mdi:timer'},
reporting_time: {entity_category: 'config', icon: 'mdi:clock-time-one-outline'},
requested_brightness_level: {
enabled_by_default: false, entity_category: 'diagnostic', icon: 'mdi:brightness-5',
},
@@ -645,6 +706,9 @@ export default class HomeAssistant extends Extension {
smoke_density: {icon: 'mdi:google-circles-communities', state_class: 'measurement'},
soil_moisture: {icon: 'mdi:water-percent', state_class: 'measurement'},
temperature: {device_class: 'temperature', state_class: 'measurement'},
temperature_calibration: {entity_category: 'config', icon: 'mdi:wrench-clock'},
temperature_max: {entity_category: 'config', icon: 'mdi:thermometer-plus'},
temperature_min: {entity_category: 'config', icon: 'mdi:thermometer-minus'},
transition: {entity_category: 'config', icon: 'mdi:transition'},
voc: {device_class: 'volatile_organic_compounds', state_class: 'measurement'},
vibration_timeout: {entity_category: 'config', icon: 'mdi:timer'},
@@ -692,6 +756,14 @@ export default class HomeAssistant extends Extension {
...extraAttrs,
},
};
// When a device_class is set, unit_of_measurement must be set, otherwise warnings are generated.
// https://github.com/Koenkk/zigbee2mqtt/issues/15958#issuecomment-1377483202
if (discoveryEntry.discovery_payload.device_class &&
!discoveryEntry.discovery_payload.unit_of_measurement) {
delete discoveryEntry.discovery_payload.device_class;
}
discoveryEntries.push(discoveryEntry);
/**
@@ -710,10 +782,17 @@ export default class HomeAssistant extends Extension {
command_topic_prefix: endpoint,
command_topic_postfix: firstExpose.property,
...(firstExpose.unit && {unit_of_measurement: firstExpose.unit}),
...(firstExpose.value_step && {step: firstExpose.value_step}),
...lookup[firstExpose.name],
},
};
if (lookup[firstExpose.name]?.device_class === 'temperature') {
discoveryEntry.discovery_payload.device_class == lookup[firstExpose.name]?.device_class;
} else {
delete discoveryEntry.discovery_payload.device_class;
}
if (firstExpose.value_min != null) discoveryEntry.discovery_payload.min = firstExpose.value_min;
if (firstExpose.value_max != null) discoveryEntry.discovery_payload.max = firstExpose.value_max;
@@ -727,11 +806,15 @@ export default class HomeAssistant extends Extension {
backlight_auto_dim: {entity_category: 'config', icon: 'mdi:brightness-auto'},
backlight_mode: {entity_category: 'config', icon: 'mdi:lightbulb'},
color_power_on_behavior: {entity_category: 'config', icon: 'mdi:palette'},
control_mode: {entity_category: 'config', icon: 'mdi:tune'},
device_mode: {entity_category: 'config', icon: 'mdi:tune'},
effect: {enabled_by_default: false, icon: 'mdi:palette'},
force: {enabled_by_default: false, icon: 'mdi:valve'},
keep_time: {entity_category: 'config', icon: 'mdi:av-timer'},
keypad_lockout: {entity_category: 'config', icon: 'mdi:lock'},
load_detection_mode: {entity_category: 'config', icon: 'mdi:tune'},
load_dimmable: {entity_category: 'diagnostic', icon: 'mdi:chart-bell-curve'},
load_type: {entity_category: 'diagnostic', icon: 'mdi:led-on'},
melody: {entity_category: 'config', icon: 'mdi:music-note'},
mode_phase_control: {entity_category: 'config', icon: 'mdi:tune'},
mode: {entity_category: 'config', icon: 'mdi:tune'},
@@ -739,54 +822,61 @@ export default class HomeAssistant extends Extension {
operation_mode: {entity_category: 'config', icon: 'mdi:tune'},
power_on_behavior: {entity_category: 'config', icon: 'mdi:power-settings'},
power_outage_memory: {entity_category: 'config', icon: 'mdi:power-settings'},
power_supply_mode: {entity_category: 'diagnostic', icon: 'mdi:power-settings'},
power_type: {entity_category: 'diagnostic', icon: 'mdi:lightning-bolt-circle'},
sensitivity: {entity_category: 'config', icon: 'mdi:tune'},
sensors_type: {entity_category: 'config', icon: 'mdi:tune'},
sound_volume: {entity_category: 'config', icon: 'mdi:volume-high'},
status: {icon: 'mdi:state-machine'},
switch_type: {entity_category: 'config', icon: 'mdi:tune'},
temperature_sensor_select: {entity_category: 'config', icon: 'mdi:home-thermometer'},
thermostat_unit: {entity_category: 'config', icon: 'mdi:thermometer'},
volume: {entity_category: 'config', icon: 'mdi: volume-high'},
week: {entity_category: 'config', icon: 'mdi:calendar-clock'},
};
const valueTemplate = firstExpose.access & ACCESS_STATE ?
`{{ value_json.${firstExpose.property} }}` : undefined;
if (firstExpose.access & ACCESS_STATE) {
discoveryEntries.push({
type: 'sensor',
object_id: firstExpose.property,
mockProperties: [{property: firstExpose.property, value: null}],
discovery_payload: {
value_template: `{{ value_json.${firstExpose.property} }}`,
value_template: valueTemplate,
enabled_by_default: !(firstExpose.access & ACCESS_SET),
...lookup[firstExpose.name],
},
});
/**
* If enum attribute has SET access then expose as SELECT entity too.
* Note: currently both sensor and select are discovered, this is to avoid
* breaking changes for sensors already existing in HA (legacy).
*/
if ((firstExpose.access & ACCESS_SET)) {
discoveryEntries.push({
type: 'select',
object_id: firstExpose.property,
mockProperties: [{property: firstExpose.property, value: null}],
discovery_payload: {
value_template: `{{ value_json.${firstExpose.property} }}`,
state_topic: true,
command_topic_prefix: endpoint,
command_topic: true,
command_topic_postfix: firstExpose.property,
options: firstExpose.values.map((v) => v.toString()),
...lookup[firstExpose.name],
},
});
}
}
} else if (firstExpose.type === 'text' || firstExpose.type === 'composite') {
/**
* If enum attribute has SET access then expose as SELECT entity too.
* Note: currently both sensor and select are discovered, this is to avoid
* breaking changes for sensors already existing in HA (legacy).
*/
if ((firstExpose.access & ACCESS_SET)) {
discoveryEntries.push({
type: 'select',
object_id: firstExpose.property,
mockProperties: [], // Already mocked above in case access STATE is supported
discovery_payload: {
value_template: valueTemplate,
state_topic: !!(firstExpose.access & ACCESS_STATE),
command_topic_prefix: endpoint,
command_topic: true,
command_topic_postfix: firstExpose.property,
options: firstExpose.values.map((v) => v.toString()),
...lookup[firstExpose.name],
},
});
}
} else if (firstExpose.type === 'text' || firstExpose.type === 'composite' || firstExpose.type === 'list') {
if (firstExpose.access & ACCESS_STATE) {
const lookup: {[s: string]: KeyValue} = {
action: {icon: 'mdi:gesture-double-tap'},
programming_mode: {icon: 'mdi:calendar-clock'},
};
const discoveryEntry: DiscoveryEntry = {
@@ -832,7 +922,11 @@ export default class HomeAssistant extends Extension {
const entity = this.zigbee.resolveEntity(data.entity.name);
if (entity.isDevice() && this.discovered[entity.ieeeAddr]) {
for (const objectID of this.discovered[entity.ieeeAddr].objectIDs) {
const match = /light_(.*)/.exec(objectID);
const lightMatch = /light_(.*)/.exec(objectID);
const coverMatch = /cover_(.*)/.exec(objectID);
const match = lightMatch || coverMatch;
if (match) {
const endpoint = match[1];
const endpointRegExp = new RegExp(`(.*)_${endpoint}`);
@@ -879,7 +973,7 @@ export default class HomeAssistant extends Extension {
}
}
@bind onEntityRenamed(data: eventdata.EntityRenamed): void {
@bind async onEntityRenamed(data: eventdata.EntityRenamed): Promise<void> {
logger.debug(`Refreshing Home Assistant discovery topic for '${data.entity.name}'`);
// Clear before rename so Home Assistant uses new friendly_name
@@ -889,6 +983,10 @@ export default class HomeAssistant extends Extension {
const topic = this.getDiscoveryTopic(config, data.entity);
this.mqtt.publish(topic, null, {retain: true, qos: 0}, this.discoveryTopic, false, false);
}
// Make sure Home Assistant deletes the old entity first otherwise another one (_2) is created
// https://github.com/Koenkk/zigbee2mqtt/issues/12610
await utils.sleep(2);
}
this.discover(data.entity, true);
@@ -911,7 +1009,7 @@ export default class HomeAssistant extends Extension {
if (isDevice) {
const exposes = entity.exposes(); // avoid calling it hundred of times/s
for (const expose of exposes) {
configs.push(...this.exposeToConfig([expose], 'device', entity.definition, exposes));
configs.push(...this.exposeToConfig([expose], 'device', exposes, entity.definition));
}
for (const mapping of legacyMapping) {
@@ -928,10 +1026,13 @@ export default class HomeAssistant extends Extension {
}
} else { // group
const exposesByType: {[s: string]: zhc.DefinitionExpose[]} = {};
const allExposes: zhc.DefinitionExpose[] = [];
entity.zh.members.map((e) => this.zigbee.resolveEntity(e.getDevice()) as Device)
.filter((d) => d.definition).forEach((device) => {
for (const expose of device.exposes().filter((e) => groupSupportedTypes.includes(e.type))) {
const exposes = device.exposes();
allExposes.push(...exposes);
for (const expose of exposes.filter((e) => groupSupportedTypes.includes(e.type))) {
let key = expose.type;
if (['switch', 'lock', 'cover'].includes(expose.type) && expose.endpoint) {
// A device can have multiple of these types which have to discovered seperately.
@@ -946,7 +1047,7 @@ export default class HomeAssistant extends Extension {
});
configs = [].concat(...Object.values(exposesByType)
.map((exposes) => this.exposeToConfig(exposes, 'group')));
.map((exposes) => this.exposeToConfig(exposes, 'group', allExposes)));
}
if (isDevice && settings.get().advanced.last_seen !== 'disable') {
@@ -974,7 +1075,7 @@ export default class HomeAssistant extends Extension {
const updateStateSensor: DiscoveryEntry = {
type: 'sensor',
object_id: 'update_state',
mockProperties: [{property: 'update', value: {state: null}}],
mockProperties: [], // update is mocked below with updateSensor
discovery_payload: {
icon: 'mdi:update',
value_template: `{{ value_json['update']['state'] }}`,
@@ -992,12 +1093,28 @@ export default class HomeAssistant extends Extension {
payload_on: true,
payload_off: false,
value_template: `{{ value_json['update']['state'] == "available" }}`,
enabled_by_default: true,
enabled_by_default: false,
device_class: 'update',
entity_category: 'diagnostic',
},
};
configs.push(updateAvailableSensor);
const updateSensor: DiscoveryEntry = {
type: 'update',
object_id: 'update',
mockProperties: [{property: 'update', value: {state: null}}],
discovery_payload: {
entity_picture: 'https://github.com/Koenkk/zigbee2mqtt/raw/master/images/logo.png',
latest_version_topic: true,
state_topic: true,
device_class: 'firmware',
command_topic: `${settings.get().mqtt.base_topic}/bridge/request/device/ota_update/update`,
payload_install: `{"id": "${entity.ieeeAddr}"}`,
value_template: `{{ value_json['update']['installed_version'] }}`,
latest_version_template: `{{ value_json['update']['latest_version'] }}`,
},
};
configs.push(updateSensor);
}
if (isDevice && entity.options.hasOwnProperty('legacy') && !entity.options.legacy) {
@@ -1093,15 +1210,16 @@ export default class HomeAssistant extends Extension {
// Availability payload
payload.availability = [{topic: `${settings.get().mqtt.base_topic}/bridge/state`}];
const availabilityEnabled =
entity.isDevice() && utils.isAvailabilityEnabledForDevice(entity, settings.get());
/* istanbul ignore next */
if (availabilityEnabled) {
if (utils.isAvailabilityEnabledForEntity(entity, settings.get())) {
payload.availability_mode = 'all';
payload.availability.push({topic: `${baseTopic}/availability`});
}
if (!settings.get().advanced.legacy_availability_payload) {
if (entity.isDevice() && entity.options.disabled) {
// Mark disabled device always as unavailable
payload.availability.forEach((a: KeyValue) => a.value_template = '{{ "offline" }}');
} else if (!settings.get().advanced.legacy_availability_payload) {
payload.availability.forEach((a: KeyValue) => a.value_template = '{{ value_json.state }}');
}
@@ -1111,7 +1229,7 @@ export default class HomeAssistant extends Extension {
delete payload.command_topic_postfix;
const commandTopic = `${baseTopic}/${commandTopicPrefix}set${commandTopicPostfix}`;
if (payload.command_topic) {
if (payload.command_topic && typeof payload.command_topic !== 'string') {
payload.command_topic = commandTopic;
}
@@ -1131,22 +1249,6 @@ export default class HomeAssistant extends Extension {
payload.mode_command_topic = `${baseTopic}/${commandTopicPrefix}set/system_mode`;
}
if (payload.hold_command_topic) {
payload.hold_command_topic = `${baseTopic}/${commandTopicPrefix}set/preset`;
}
if (payload.hold_state_topic) {
payload.hold_state_topic = stateTopic;
}
if (payload.away_mode_state_topic) {
payload.away_mode_state_topic = stateTopic;
}
if (payload.away_mode_command_topic) {
payload.away_mode_command_topic = `${baseTopic}/${commandTopicPrefix}set/away_mode`;
}
if (payload.current_temperature_topic) {
payload.current_temperature_topic = stateTopic;
}
@@ -1182,10 +1284,22 @@ export default class HomeAssistant extends Extension {
payload.fan_mode_state_topic = stateTopic;
}
if (payload.latest_version_topic) {
payload.latest_version_topic = stateTopic;
}
if (payload.fan_mode_command_topic) {
payload.fan_mode_command_topic = `${baseTopic}/${commandTopicPrefix}set/fan_mode`;
}
if (payload.swing_mode_state_topic) {
payload.swing_mode_state_topic = stateTopic;
}
if (payload.swing_mode_command_topic) {
payload.swing_mode_command_topic = `${baseTopic}/${commandTopicPrefix}set/swing_mode`;
}
if (payload.percentage_state_topic) {
payload.percentage_state_topic = stateTopic;
}
@@ -1199,7 +1313,8 @@ export default class HomeAssistant extends Extension {
}
if (payload.preset_mode_command_topic) {
payload.preset_mode_command_topic = `${baseTopic}/${commandTopicPrefix}set/fan_mode`;
payload.preset_mode_command_topic = `${baseTopic}/${commandTopicPrefix}set/` +
payload.preset_mode_command_topic;
}
if (payload.action_topic) {
@@ -1301,9 +1416,9 @@ export default class HomeAssistant extends Extension {
data.message.toLowerCase() === 'online') {
const timer = setTimeout(async () => {
// Publish all device states.
for (const device of this.zigbee.devices(false)) {
if (this.state.exists(device)) {
this.publishEntityState(device, this.state.get(device));
for (const entity of [...this.zigbee.devices(false), ...this.zigbee.groups()]) {
if (this.state.exists(entity)) {
this.publishEntityState(entity, this.state.get(entity), 'publishCached');
}
}
@@ -1364,6 +1479,10 @@ export default class HomeAssistant extends Extension {
message.color.s = message.color.saturation;
}
}
if (entity.isDevice() && entity.definition?.ota && message.update?.latest_version == null) {
message.update = {...message.update, installed_version: -1, latest_version: -1};
}
}
private getEncodedBaseTopic(): string {
+2 -1
View File
@@ -214,7 +214,7 @@ export default class NetworkMap extends Extension {
async networkScan(includeRoutes: boolean): Promise<Topology> {
logger.info(`Starting network scan (includeRoutes '${includeRoutes}')`);
const devices = this.zigbee.devices().filter((d) => d.zh.type !== 'GreenPower');
const devices = this.zigbee.devices().filter((d) => d.zh.type !== 'GreenPower' && !d.options.disabled);
const lqis: Map<Device, zh.LQI> = new Map();
const routingTables: Map<Device, zh.RoutingTable> = new Map();
const failed: Map<Device, string[]> = new Map();
@@ -244,6 +244,7 @@ export default class NetworkMap extends Extension {
} catch (error) {
failed.get(device).push('lqi');
logger.error(`Failed to execute LQI for '${device.name}'`);
logger.debug(error.stack);
}
if (includeRoutes) {
+3 -2
View File
@@ -40,10 +40,11 @@ export default class OnEvent extends Extension {
}
private async callOnEvent(device: Device, type: string, data: KeyValue): Promise<void> {
zhc.onEvent(type, data, device.zh);
const state = this.state.get(device);
zhc.onEvent(type, data, device.zh, device.options, state);
if (device.definition?.onEvent) {
await device.definition.onEvent(type, data, device.zh, device.options);
await device.definition.onEvent(type, data, device.zh, device.options, state);
}
}
}
+43 -31
View File
@@ -24,8 +24,13 @@ function isValidUrl(url: string): boolean {
type UpdateState = 'updating' | 'idle' | 'available';
interface UpdatePayload {
update_available?: boolean
// eslint-disable-next-line camelcase
update: {progress?: number, remaining?: number, state: UpdateState}, update_available?: boolean}
update: {
progress?: number, remaining?: number, state: UpdateState,
installed_version: number | null, latest_version: number | null
}
}
const legacyTopicRegex = new RegExp(`^${settings.get().mqtt.base_topic}/bridge/ota_update/.+$`);
const topicRegex =
@@ -65,38 +70,39 @@ export default class OTAUpdate extends Extension {
}
private removeProgressAndRemainingFromState(device: Device): void {
delete this.state.get(device)?.update?.progress;
delete this.state.get(device)?.update?.remaining;
delete this.state.get(device).update?.progress;
delete this.state.get(device).update?.remaining;
}
@bind private async onZigbeeEvent(data: eventdata.DeviceMessage): Promise<void> {
if (settings.get().ota.disable_automatic_update_check) return;
if (data.type !== 'commandQueryNextImageRequest' || !data.device.definition) return;
if (data.type !== 'commandQueryNextImageRequest' || !data.device.definition ||
this.inProgress.has(data.device.ieeeAddr)) return;
logger.debug(`Device '${data.device.name}' requested OTA`);
const automaticOTACheckDisabled = settings.get().ota.disable_automatic_update_check;
let supportsOTA = data.device.definition.hasOwnProperty('ota');
if (supportsOTA) {
if (supportsOTA && !automaticOTACheckDisabled) {
// 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 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;
if (!check || this.inProgress.has(data.device.ieeeAddr)) return;
if (!check) return;
this.lastChecked[data.device.ieeeAddr] = Date.now();
let available = false;
let availableResult: zhc.OtaUpdateAvailableResult = null;
try {
available = await data.device.definition.ota.isUpdateAvailable(data.device.zh, logger, data.data);
availableResult = await data.device.definition.ota.isUpdateAvailable(data.device.zh, logger, data.data);
} catch (e) {
supportsOTA = false;
logger.debug(`Failed to check if update available for '${data.device.name}' (${e.message})`);
}
const payload = this.getEntityPublishPayload(available ? 'available' : 'idle');
const payload = this.getEntityPublishPayload(data.device, availableResult ?? 'idle');
this.publishEntityState(data.device, payload);
if (available) {
if (availableResult?.available) {
const message = `Update available for '${data.device.name}'`;
logger.info(message);
@@ -111,14 +117,10 @@ export default class OTAUpdate extends Extension {
}
}
// Respond to the OTA request:
// - In case we don't support OTA: respond with NO_IMAGE_AVAILABLE (0x98) (so the client stops requesting OTAs)
// - In case we do support OTA: respond with ABORT (0x95) as we don't want to update now.
const endpoint = data.device.zh.endpoints.find((e) => e.supportsOutputCluster('genOta'));
if (endpoint) {
// Some devices send OTA requests without defining OTA cluster as input cluster.
await endpoint.commandResponse('genOta', 'queryNextImageResponse', {status: supportsOTA ? 0x95 : 0x98});
}
// Respond to the OTA request: respond with NO_IMAGE_AVAILABLE (0x98) (so the client stops requesting OTAs)
const endpoint = data.device.zh.endpoints.find((e) => e.supportsOutputCluster('genOta')) || data.endpoint;
await endpoint.commandResponse('genOta', 'queryNextImageResponse', {status: 0x98});
logger.debug(`Responded to OTA request of '${data.device.name}' with 'NO_IMAGE_AVAILABLE'`);
}
private async readSoftwareBuildIDAndDateCode(device: Device, sendWhen: 'active' | 'immediate'):
@@ -132,14 +134,22 @@ export default class OTAUpdate extends Extension {
}
}
private getEntityPublishPayload(state: UpdateState, progress: number=null, remaining: number=null): UpdatePayload {
const payload: UpdatePayload = {update: {state}};
private getEntityPublishPayload(device: Device, state: zhc.OtaUpdateAvailableResult | UpdateState,
progress: number=null, remaining: number=null): UpdatePayload {
const deviceUpdateState = this.state.get(device).update;
const payload: UpdatePayload = {update: {
state: typeof state === 'string' ? state : (state.available ? 'available' : 'idle'),
installed_version: typeof state === 'string' ?
deviceUpdateState?.installed_version : state.currentFileVersion,
latest_version: typeof state === 'string' ?
deviceUpdateState?.latest_version : state.otaFileVersion,
}};
if (progress !== null) payload.update.progress = progress;
if (remaining !== null) payload.update.remaining = Math.round(remaining);
/* istanbul ignore else */
if (this.legacyApi) {
payload.update_available = state === 'available';
payload.update_available = typeof state === 'string' ? state === 'available' : state.available;
}
return payload;
@@ -190,23 +200,24 @@ export default class OTAUpdate extends Extension {
}
try {
const available = await device.definition.ota.isUpdateAvailable(device.zh, logger);
const msg = `${available ? 'Update' : 'No update'} available for '${device.name}'`;
const availableResult = await device.definition.ota.isUpdateAvailable(device.zh, logger);
const msg = `${availableResult.available ? 'Update' : 'No update'} available for '${device.name}'`;
logger.info(msg);
/* istanbul ignore else */
if (settings.get().advanced.legacy_api) {
const meta = {status: available ? 'available' : 'not_available', device: device.name};
const meta = {
status: availableResult.available ? 'available' : 'not_available', device: device.name};
this.mqtt.publish(
'bridge/log',
stringify({type: `ota_update`, message: msg, meta}),
);
}
const payload = this.getEntityPublishPayload(available ? 'available' : 'idle');
const payload = this.getEntityPublishPayload(device, availableResult);
this.publishEntityState(device, payload);
this.lastChecked[device.ieeeAddr] = Date.now();
responseData.updateAvailable = available;
responseData.updateAvailable = availableResult.available;
} catch (e) {
error = `Failed to check if update available for '${device.name}' (${e.message})`;
errorStack = e.stack;
@@ -242,7 +253,7 @@ export default class OTAUpdate extends Extension {
logger.info(msg);
const payload = this.getEntityPublishPayload('updating', progress, remaining);
const payload = this.getEntityPublishPayload(device, 'updating', progress, remaining);
this.publishEntityState(device, payload);
/* istanbul ignore else */
@@ -253,11 +264,12 @@ export default class OTAUpdate extends Extension {
};
const from_ = await this.readSoftwareBuildIDAndDateCode(device, 'immediate');
await device.definition.ota.updateToLatest(device.zh, logger, onProgress);
const fileVersion = await device.definition.ota.updateToLatest(device.zh, logger, onProgress);
logger.info(`Finished update of '${device.name}'`);
this.eventBus.emitReconfigure({device});
this.removeProgressAndRemainingFromState(device);
const payload = this.getEntityPublishPayload('idle');
const payload = this.getEntityPublishPayload(device,
{available: false, currentFileVersion: fileVersion, otaFileVersion: fileVersion});
this.publishEntityState(device, payload);
const to = await this.readSoftwareBuildIDAndDateCode(device, 'active');
const [fromS, toS] = [stringify(from_), stringify(to)];
@@ -277,7 +289,7 @@ export default class OTAUpdate extends Extension {
errorStack = e.stack;
this.removeProgressAndRemainingFromState(device);
const payload = this.getEntityPublishPayload('available');
const payload = this.getEntityPublishPayload(device, 'available');
this.publishEntityState(device, payload);
/* istanbul ignore else */
+5 -3
View File
@@ -1,6 +1,7 @@
import * as settings from '../util/settings';
import zigbeeHerdsmanConverters from 'zigbee-herdsman-converters';
import philips from 'zigbee-herdsman-converters/lib/philips';
import logger from '../util/logger';
import utils from '../util/utils';
import Extension from './extension';
@@ -18,7 +19,7 @@ const sceneConverterKeys = ['scene_store', 'scene_add', 'scene_remove', 'scene_r
const defaultGroupConverters = [
zigbeeHerdsmanConverters.toZigbeeConverters.light_onoff_brightness,
zigbeeHerdsmanConverters.toZigbeeConverters.light_color_colortemp,
zigbeeHerdsmanConverters.toZigbeeConverters.effect,
philips.tz.effect, // Support Hue effects for groups
zigbeeHerdsmanConverters.toZigbeeConverters.ignore_transition,
zigbeeHerdsmanConverters.toZigbeeConverters.cover_position_tilt,
zigbeeHerdsmanConverters.toZigbeeConverters.thermostat_occupied_heating_setpoint,
@@ -135,7 +136,7 @@ export default class Publish extends Extension {
}
const device = re instanceof Device ? re.zh : null;
const entitySettings = re.options;
const entityState = this.state.get(re) || {};
const entityState = this.state.get(re);
const membersState = re instanceof Group ?
Object.fromEntries(re.zh.members.map((e) => [e.getDevice().ieeeAddr,
this.state.get(this.zigbee.resolveEntity(e.getDevice().ieeeAddr))])) : null;
@@ -256,7 +257,8 @@ export default class Publish extends Extension {
}
// filter out attribute listed in filtered_optimistic
entitySettings.filtered_optimistic?.forEach((a) => delete msg[a]);
utils.filterProperties(entitySettings.filtered_optimistic, msg);
addToToPublish(re, msg);
}
+2 -2
View File
@@ -145,9 +145,9 @@ export default class Receive extends Extension {
if (converted) {
payload = {...payload, ...converted};
}
} catch (error) {
// istanbul ignore next
} catch (error) /* istanbul ignore next */ {
logger.error(`Exception while calling fromZigbee converter: ${error.message}}`);
logger.debug(error.stack);
}
}
+11 -1
View File
@@ -4,13 +4,23 @@ import zigbeeHerdsmanConverters from 'zigbee-herdsman-converters';
export default class Group {
public zh: zh.Group;
private resolveDevice: (ieeeAddr: string) => Device;
get ID(): number {return this.zh.groupID;}
get options(): GroupOptions {return {...settings.getGroup(this.ID)};}
get name(): string {return this.options?.friendly_name || this.ID.toString();}
constructor(group: zh.Group) {
constructor(group: zh.Group, resolveDevice: (ieeeAddr: string) => Device) {
this.zh = group;
this.resolveDevice = resolveDevice;
}
hasMember(device: Device): boolean {
return !!device.zh.endpoints.find((e) => this.zh.members.includes(e));
}
membersDevices(): Device[] {
return this.zh.members.map((e) => this.resolveDevice(e.getDevice().ieeeAddr)).filter((d) => d);
}
membersDefinitions(): zhc.Definition[] {
+34 -2
View File
@@ -10,6 +10,10 @@ export default class MQTT {
private connectionTimer: NodeJS.Timeout;
private client: mqtt.MqttClient;
private eventBus: EventBus;
private initialConnect = true;
private republishRetainedTimer: NodeJS.Timer;
private retainedMessages: {[s: string]: {payload: string, options: MQTTOptions,
skipLog: boolean, skipReceive: boolean, topic: string, base: string}} = {};
constructor(eventBus: EventBus) {
this.eventBus = eventBus;
@@ -79,7 +83,10 @@ export default class MQTT {
resolve();
});
this.client.on('error', (err) => reject(err));
this.client.on('error', (err) => {
logger.error(`MQTT error: ${err.message}`);
reject(err);
});
this.client.on('message', this.onMessage);
});
}
@@ -94,8 +101,19 @@ export default class MQTT {
}, utils.seconds(10));
logger.info('Connected to MQTT server');
this.subscribe(`${settings.get().mqtt.base_topic}/#`);
await this.publishStateOnline();
if (!this.initialConnect) {
this.republishRetainedTimer = setTimeout(() => {
// Republish retained messages in case MQTT broker does not persist them.
// https://github.com/Koenkk/zigbee2mqtt/issues/9629
Object.values(this.retainedMessages).forEach((e) =>
this.publish(e.topic, e.payload, e.options, e.base, e.skipLog, e.skipReceive));
}, 2000);
}
this.initialConnect = false;
this.subscribe(`${settings.get().mqtt.base_topic}/#`);
}
async publishStateOnline(): Promise<void> {
@@ -121,6 +139,11 @@ export default class MQTT {
logger.debug(`Received MQTT message on '${topic}' with data '${message}'`);
this.eventBus.emitMQTTMessage({topic, message: message + ''});
}
if (this.republishRetainedTimer && topic == `${settings.get().mqtt.base_topic}/bridge/state`) {
clearTimeout(this.republishRetainedTimer);
this.republishRetainedTimer = null;
}
}
isConnected(): boolean {
@@ -137,6 +160,15 @@ export default class MQTT {
this.publishedTopics.add(topic);
}
if (options.retain) {
if (payload) {
this.retainedMessages[topic] =
{payload, options, skipReceive, skipLog, topic: topic.substring(base.length + 1), base};
} else {
delete this.retainedMessages[topic];
}
}
this.eventBus.emitMQTTMessagePublished({topic, payload, options: {...defaultOptions, ...options}});
if (!this.isConnected()) {
+17 -16
View File
@@ -1,25 +1,26 @@
import logger from './util/logger';
import data from './util/data';
import * as settings from './util/settings';
import utils from './util/utils';
import fs from 'fs';
import objectAssignDeep from 'object-assign-deep';
const saveInterval = 1000 * 60 * 5; // 5 minutes
const dontCacheProperties = [
'^action$', '^action_.*$', '^button$', '^button_left$', '^button_right$', '^click$', '^forgotten$', '^keyerror$',
'^step_size$', '^transition_time$', '^group_list$', '^group_capacity$', '^no_occupancy_since$',
'^step_mode$', '^transition_time$', '^duration$', '^elapsed$', '^from_side$', '^to_side$',
'action', 'action_.*', 'button', 'button_left', 'button_right', 'click', 'forgotten', 'keyerror',
'step_size', 'transition_time', 'group_list', 'group_capacity', 'no_occupancy_since',
'step_mode', 'transition_time', 'duration', 'elapsed', 'from_side', 'to_side',
];
class State {
private state: {[s: string | number]: KeyValue} = {};
private file = data.joinPath('state.json');
private timer: NodeJS.Timer = null;
private eventBus: EventBus;
constructor(eventBus: EventBus) {
constructor(private readonly eventBus: EventBus, private readonly zigbee: Zigbee) {
this.eventBus = eventBus;
this.zigbee = zigbee;
}
start(): void {
@@ -27,11 +28,14 @@ class State {
// Save the state on every interval
this.timer = setInterval(() => this.save(), saveInterval);
this.eventBus.onDeviceLeave(this, (data) => delete this.state[data.ieeeAddr]);
}
stop(): void {
this.eventBus.removeListeners(this);
// Remove any invalid states (ie when the device has left the network) when the system is stopped
Object.keys(this.state)
.filter((k) => typeof k === 'string' && !this.zigbee.resolveEntity(k)) // string key = ieeeAddr
.forEach((k) => delete this.state[k]);
clearTimeout(this.timer);
this.save();
}
@@ -68,23 +72,20 @@ class State {
}
get(entity: Group | Device): KeyValue {
return this.state[entity.ID];
return this.state[entity.ID] || {};
}
set(entity: Group | Device, update: KeyValue, reason: string=null): KeyValue {
const fromState = this.state[entity.ID] || {};
const toState = objectAssignDeep({}, fromState, update);
const result = {...toState};
const newCache = {...toState};
const entityDontCacheProperties = entity.options.filtered_cache || [];
for (const property of Object.keys(toState)) {
if (dontCacheProperties.find((p) => property.match(p))) {
delete toState[property];
}
}
utils.filterProperties(dontCacheProperties.concat(entityDontCacheProperties), newCache);
this.state[entity.ID] = toState;
this.state[entity.ID] = newCache;
this.eventBus.emitStateChange({entity, from: fromState, to: toState, reason, update});
return result;
return toState;
}
remove(ID: string | number): void {
+17 -7
View File
@@ -42,7 +42,7 @@ declare global {
// Types
interface MQTTResponse {data: KeyValue, status: 'error' | 'ok', error?: string, transaction?: string}
interface MQTTOptions {qos?: mqtt.QoS, retain?: boolean, properties?: {messageExpiryInterval: number}}
type StateChangeReason = 'publishDebounce' | 'groupOptimistic' | 'lastSeenChanged';
type StateChangeReason = 'publishDebounce' | 'groupOptimistic' | 'lastSeenChanged' | 'publishCached';
type PublishEntityState = (entity: Device | Group, payload: KeyValue,
stateChangeReason?: StateChangeReason) => Promise<void>;
type RecursivePartial<T> = {[P in keyof T]?: RecursivePartial<T[P]>;};
@@ -100,10 +100,12 @@ declare global {
interface DefinitionExpose {
type: string, name?: string, features?: DefinitionExposeFeature[],
endpoint?: string, values?: string[], value_off?: string, value_on?: string,
endpoint?: string, values?: string[], value_off?: string, value_on?: string, value_step?: number,
access: number, property: string, unit?: string,
value_min?: number, value_max?: number}
interface OtaUpdateAvailableResult {available: boolean, currentFileVersion: number, otaFileVersion: number}
interface Definition {
model: string,
zigbeeModel: string[],
@@ -117,11 +119,13 @@ declare global {
exposes: DefinitionExpose[] | ((device: zh.Device, options: KeyValue) => DefinitionExpose[])
configure?: (device: zh.Device, coordinatorEndpoint: zh.Endpoint, logger: Logger,
options?: DeviceOptions) => Promise<void>;
onEvent?: (type: string, data: KeyValue, device: zh.Device, settings: KeyValue) => Promise<void>;
onEvent?: (type: string, data: KeyValue, device: zh.Device,
settings: KeyValue, state: KeyValue) => Promise<void>;
ota?: {
isUpdateAvailable: (device: zh.Device, logger: Logger, data?: KeyValue) => Promise<boolean>;
isUpdateAvailable: (device: zh.Device, logger: Logger, data?: KeyValue)
=> Promise<OtaUpdateAvailableResult>;
updateToLatest: (device: zh.Device, logger: Logger,
onProgress: (progress: number, remaining: number) => void) => Promise<void>;
onProgress: (progress: number, remaining: number) => void) => Promise<number>;
}
}
@@ -232,6 +236,8 @@ declare global {
host?: string,
port?: number,
url?: string,
ssl_cert?: string,
ssl_key?: string,
},
devices?: {[s: string]: DeviceOptions},
groups?: {[s: string]: GroupOptions},
@@ -273,17 +279,19 @@ declare global {
interface DeviceOptions {
ID?: string,
disabled?: boolean,
retention?: number,
availability?: boolean | {timeout: number},
optimistic?: boolean,
retrieve_state?: boolean,
debounce?: number,
debounce_ignore?: string[],
filtered_attributes?: string[],
filtered_cache?: string[],
filtered_optimistic?: string[],
icon?: string,
homeassistant?: KeyValue,
legacy?: boolean,
filtered_attributes?: string[],
friendly_name: string,
description?: string,
qos?: 0 | 1 | 2,
@@ -293,10 +301,12 @@ declare global {
devices?: string[],
ID?: number,
optimistic?: boolean,
off_state?: 'all_members_off' | 'last_member_state'
filtered_attributes?: string[],
filtered_cache?: string[],
filtered_optimistic?: string[],
retrieve_state?: boolean,
homeassistant?: KeyValue,
filtered_attributes?: string[],
friendly_name: string,
description?: string,
qos?: 0 | 1 | 2,
+6 -1
View File
@@ -4,7 +4,8 @@ declare module 'zigbee-herdsman-converters' {
export const toZigbeeConverters: {[s: string]: zhc.ToZigbeeConverter};
export const definitions: zhc.Definition[];
export function addDeviceDefinition(definition: zhc.Definition): Promise<void>;
export function onEvent(type: string, data: KeyValue, device: zh.Device): Promise<void>;
export function onEvent(type: string, data: KeyValue, device: zh.Device, settings: KeyValue,
state: KeyValue): Promise<void>;
}
declare module 'zigbee-herdsman-converters/lib/ota/tradfri' {
@@ -15,3 +16,7 @@ declare module 'zigbee-herdsman-converters/lib/ota/zigbeeOTA' {
export function useIndexOverride(indexFileName: string): void;
export function setDataDir(dataDir: string): void;
}
declare module 'zigbee-herdsman-converters/lib/philips' {
export const tz: {[s: string]: zhc.ToZigbeeConverter};
}
+1 -1
View File
@@ -14,7 +14,7 @@ function load(): void {
load();
function joinPath(file: string): string {
return path.join(dataPath, file);
return path.resolve(dataPath, file);
}
function getPath(): string {
+98 -83
View File
@@ -9,40 +9,12 @@ import assert from 'assert';
const colorizer = winston.format.colorize();
// What transports to enable
const output = settings.get().advanced.log_output;
// Directory to log to
const timestamp = moment(Date.now()).format('YYYY-MM-DD.HH-mm-ss');
const directory = settings.get().advanced.log_directory.replace('%TIMESTAMP%', timestamp);
const logFilename = settings.get().advanced.log_file.replace('%TIMESTAMP%', timestamp);
// 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);
}
}
type Z2MLogLevel = 'warn' | 'debug' | 'info' | 'error';
type WinstonLogLevel = 'warning' | 'debug' | 'info' | 'error';
const z2mToWinstonLevel = (level: Z2MLogLevel): WinstonLogLevel => level === 'warn' ? 'warning' : level;
const winstonToZ2mLevel = (level: WinstonLogLevel): Z2MLogLevel => level === 'warning' ? 'warn' : level;
// Determine the log level.
const z2mLevel = settings.get().advanced.log_level;
const validLevels = ['info', 'error', 'warn', 'debug'];
assert(validLevels.includes(z2mLevel), `'${z2mLevel}' is not valid log_level, use one of '${validLevels.join(', ')}'`);
const level = z2mToWinstonLevel(z2mLevel);
const levelWithCompensatedLength: {[s: string]: string} = {
'info': 'info ',
'error': 'error',
@@ -50,71 +22,113 @@ const levelWithCompensatedLength: {[s: string]: string} = {
'debug': 'debug',
};
const timestampFormat = (): string => moment().format(settings.get().advanced.timestamp_format);
let logger: winston.Logger;
let fileTransport : winston.transport;
let output: string[];
let directory: string;
let logFilename: string;
let transportsToUse: winston.transport[];
// Setup default console logger
const transportsToUse: winston.transport[] = [
new winston.transports.Console({
function init(): void {
// What transports to enable
output = settings.get().advanced.log_output;
// Directory to log to
const timestamp = moment(Date.now()).format('YYYY-MM-DD.HH-mm-ss');
directory = settings.get().advanced.log_directory.replace('%TIMESTAMP%', timestamp);
logFilename = settings.get().advanced.log_file.replace('%TIMESTAMP%', timestamp);
// 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;
/* istanbul ignore next */
if (fs.existsSync(current)) {
fs.unlinkSync(current);
}
fs.symlinkSync(actual, current);
}
}
// Determine the log level.
const z2mLevel = settings.get().advanced.log_level;
const validLevels = ['info', 'error', 'warn', 'debug'];
assert(validLevels.includes(z2mLevel),
`'${z2mLevel}' is not valid log_level, use one of '${validLevels.join(', ')}'`);
const level = z2mToWinstonLevel(z2mLevel);
const timestampFormat = (): string => moment().format(settings.get().advanced.timestamp_format);
// Setup default console logger
transportsToUse = [
new winston.transports.Console({
level,
silent: !output.includes('console'),
format: winston.format.combine(
winston.format.timestamp({format: timestampFormat}),
winston.format.printf(/* istanbul ignore next */(info) => {
const {timestamp, level, message} = info;
const l = winstonToZ2mLevel(level as WinstonLogLevel);
const plainPrefix = `Zigbee2MQTT:${levelWithCompensatedLength[l]}`;
let prefix = plainPrefix;
if (process.stdout.isTTY) {
prefix = colorizer.colorize(l, plainPrefix);
}
return `${prefix} ${timestamp.split('.')[0]}: ${message}`;
}),
),
}),
];
// Add file logger when enabled
// NOTE: the initiation of the logger, even when not added as transport tries to create the logging directory
const transportFileOptions: KeyValue = {
filename: path.join(directory, logFilename),
json: false,
level,
silent: !output.includes('console'),
format: winston.format.combine(
winston.format.timestamp({format: timestampFormat}),
winston.format.printf(/* istanbul ignore next */(info) => {
const {timestamp, level, message} = info;
const l = winstonToZ2mLevel(level as WinstonLogLevel);
const prefix = colorizer.colorize(l, `Zigbee2MQTT:${levelWithCompensatedLength[l]}`);
return `${prefix} ${timestamp.split('.')[0]}: ${message}`;
return `${levelWithCompensatedLength[l]} ${timestamp.split('.')[0]}: ${message}`;
}),
),
}),
];
// Add file logger when enabled
// NOTE: the initiation of the logger, even when not added as transport tries to create the logging directory
const transportFileOptions: KeyValue = {
filename: path.join(directory, logFilename),
json: false,
level,
format: winston.format.combine(
winston.format.timestamp({format: timestampFormat}),
winston.format.printf(/* istanbul ignore next */(info) => {
const {timestamp, level, message} = info;
const l = winstonToZ2mLevel(level as WinstonLogLevel);
return `${levelWithCompensatedLength[l]} ${timestamp.split('.')[0]}: ${message}`;
}),
),
};
if (settings.get().advanced.log_rotation) {
transportFileOptions.tailable = true;
transportFileOptions.maxFiles = 3; // Keep last 3 files
transportFileOptions.maxsize = 10000000; // 10MB
}
let fileTransport : winston.transport;
if (output.includes('file')) {
fileTransport = new winston.transports.File(transportFileOptions);
transportsToUse.push(fileTransport);
}
/* istanbul ignore next */
if (output.includes('syslog')) {
// eslint-disable-next-line
require('winston-syslog').Syslog;
const options: KeyValue = {
app_name: 'Zigbee2MQTT',
format: winston.format.printf(/* istanbul ignore next */(info) => {
return `${info.message}`;
}),
...settings.get().advanced.log_syslog,
};
if (options.hasOwnProperty('type')) options.type = options.type.toString();
// @ts-ignore
transportsToUse.push(new winston.transports.Syslog(options));
}
// Create logger
const logger = winston.createLogger({transports: transportsToUse, levels: winston.config.syslog.levels});
if (settings.get().advanced.log_rotation) {
transportFileOptions.tailable = true;
transportFileOptions.maxFiles = 3; // Keep last 3 files
transportFileOptions.maxsize = 10000000; // 10MB
}
if (output.includes('file')) {
fileTransport = new winston.transports.File(transportFileOptions);
transportsToUse.push(fileTransport);
}
/* istanbul ignore next */
if (output.includes('syslog')) {
// eslint-disable-next-line
require('winston-syslog').Syslog;
const options: KeyValue = {
app_name: 'Zigbee2MQTT',
format: winston.format.printf(/* istanbul ignore next */(info) => {
return `${info.message}`;
}),
...settings.get().advanced.log_syslog,
};
if (options.hasOwnProperty('type')) options.type = options.type.toString();
// @ts-ignore
transportsToUse.push(new winston.transports.Syslog(options));
}
logger = winston.createLogger({transports: transportsToUse, levels: winston.config.syslog.levels});
}
// Cleanup any old log directory.
function cleanup(): void {
@@ -206,5 +220,6 @@ async function end(): Promise<void> {
}
export default {
logOutput, warn, warning, error, info, debug, setLevel, getLevel, cleanup, addTransport, end, winston: logger,
init, logOutput, warn, warning, error, info, debug, setLevel, getLevel, cleanup, addTransport, end,
winston: (): winston.Logger => logger,
};
+60 -14
View File
@@ -388,6 +388,18 @@
"title": "URL",
"description": "URL on which the frontend can be reached, currently only used for the Home Assistant device configuration page",
"requiresRestart": true
},
"ssl_cert" : {
"type": ["string", "null"],
"title": "Certificate file path",
"description": "SSL Certificate file path for exposing HTTPS. The sibling property 'ssl_key' must be set for HTTPS to be activated.",
"requiresRestart": true
},
"ssl_key" : {
"type": ["string", "null"],
"title": "key file path",
"description": "SSL key file path for exposing HTTPS. The sibling property 'ssl_cert' must be set for HTTPS to be activated.",
"requiresRestart": true
}
}
}
@@ -499,13 +511,13 @@
"type": "number",
"title": "Port",
"description": "The port on the host that syslog is running on, defaults to syslogd's default port.",
"default": 123
"default": 514
},
"protocol": {
"type": "string",
"title": "Protocol",
"description": "The network protocol to log over (e.g. tcp4, udp4, tls4, unix, unix-connect, etc).",
"default": "tcp4",
"default": "udp4",
"examples": [
"udp4",
"tls4",
@@ -782,6 +794,12 @@
"title": "Retain",
"description": "Retain MQTT messages of this device"
},
"disabled": {
"type": "boolean",
"title": "Disabled",
"description": "Disables the device (excludes device from network scans, availability and group state updates)",
"requiresRestart": true
},
"retention": {
"type": "number",
"title": "Retention",
@@ -812,28 +830,48 @@
"description": "Publish optimistic state after set",
"default": true
},
"filtered_optimistic": {
"type": "array",
"items": {
"type": "string"
},
"examples": ["color_mode", "color_temp", "color"],
"title": "Filtered optimistic attributes",
"description": "Filter attributes from optimistic publish payload when calling /set. (This has no effect if optimistic is set to false)."
},
"filtered_attributes": {
"type": "array",
"items": {
"type": "string"
},
"examples": ["temperature", "battery", "action"],
"examples": ["^temperature$", "^battery$", "^action$"],
"title": "Filtered publish attributes",
"description": "Filter attributes from publish payload."
"description": "Filter attributes with regex from published payload."
},
"filtered_cache": {
"type": "array",
"items": {
"type": "string"
},
"examples": ["^input_actions$"],
"title": "Filtered attributes from cache",
"description": "Filter attributes with regex from being added to the cache, this prevents the attribute from being in the published payload when the value didn't change."
},
"filtered_optimistic": {
"type": "array",
"items": {
"type": "string"
},
"examples": ["^color_(mode|temp)$", "color"],
"title": "Filtered optimistic attributes",
"description": "Filter attributes with regex from optimistic publish payload when calling /set. (This has no effect if optimistic is set to false)."
},
"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"
"description": "The user-defined device icon for the frontend. It can be a full URL link to an image (e.g. https://SOME.SITE/MODEL123.jpg) (you cannot use a path to a local file) or base64 encoded data URL (e.g. image/svg+xml;base64,PHN2ZyB3aW....R0aD)"
},
"homeassistant": {
"type": ["object", "null"],
"title": "Home Assistant",
"properties": {
"name": {
"type": "string",
"title": "Home Assistant name",
"description": "Name of the device in Home Assistant"
}
}
}
},
"required": ["friendly_name"]
@@ -859,6 +897,14 @@
"qos": {
"type": "number"
},
"off_state": {
"type": ["string"],
"enum": ["all_members_off", "last_member_state"],
"title": "Group off state",
"default": "auto",
"requiresRestart": true,
"description": "Control when to publish state OFF for a group. 'all_members_off': only publish state OFF when all group memebers are in state OFF, 'last_member_state': publish state OFF whenever one of its members changes to OFF"
},
"filtered_attributes": {
"type": "array",
"items": {
+50 -18
View File
@@ -3,7 +3,7 @@ import utils from './utils';
import objectAssignDeep from 'object-assign-deep';
import path from 'path';
import yaml from './yaml';
import Ajv from 'ajv';
import Ajv, {ValidateFunction} from 'ajv';
import schemaJson from './settings.schema.json';
export let schema = schemaJson;
// @ts-ignore
@@ -31,7 +31,10 @@ const file = process.env.ZIGBEE2MQTT_CONFIG ?? data.joinPath('configuration.yaml
const ajvSetting = new Ajv({allErrors: true}).addKeyword('requiresRestart').compile(schemaJson);
const ajvRestartRequired = new Ajv({allErrors: true})
.addKeyword({keyword: 'requiresRestart', validate: (s: unknown) => !s}).compile(schemaJson);
const ajvRestartRequiredDeviceOptions = new Ajv({allErrors: true})
.addKeyword({keyword: 'requiresRestart', validate: (s: unknown) => !s}).compile(schemaJson.definitions.device);
const ajvRestartRequiredGroupOptions = new Ajv({allErrors: true})
.addKeyword({keyword: 'requiresRestart', validate: (s: unknown) => !s}).compile(schemaJson.definitions.group);
const defaults: RecursivePartial<Settings> = {
permit_join: false,
external_converters: [],
@@ -187,6 +190,20 @@ function loadSettingsWithDefaults(): void {
_settingsWithDefaults.whitelist && _settingsWithDefaults.passlist.push(..._settingsWithDefaults.whitelist);
}
function parseValueRef(text: string): {filename: string, key: string} | null {
const match = /!(.*) (.*)/g.exec(text);
if (match) {
let filename = match[1];
// This is mainly for backward compatibility.
if (!filename.endsWith('.yaml') && !filename.endsWith('.yml')) {
filename += '.yaml';
}
return {filename, key: match[2]};
} else {
return null;
}
}
function write(): void {
const settings = getInternalSettings();
const toWrite: KeyValue = objectAssignDeep({}, settings);
@@ -196,15 +213,16 @@ function write(): void {
// In case the setting is defined in a separte file (e.g. !secret network_key) update it there.
for (const path of [
['mqtt', 'server'],
['mqtt', 'user'],
['mqtt', 'password'],
['advanced', 'network_key'],
['frontend', 'auth_token'],
]) {
if (actual[path[0]] && actual[path[0]][path[1]]) {
const match = /!(.*) (.*)/g.exec(actual[path[0]][path[1]]);
if (match) {
yaml.updateIfChanged(data.joinPath(`${match[1]}.yaml`), match[2], toWrite[path[0]][path[1]]);
const ref = parseValueRef(actual[path[0]][path[1]]);
if (ref) {
yaml.updateIfChanged(data.joinPath(ref.filename), ref.key, toWrite[path[0]][path[1]]);
toWrite[path[0]][path[1]] = actual[path[0]][path[1]];
}
}
@@ -212,7 +230,7 @@ function write(): void {
// Write devices/groups to separate file if required.
const writeDevicesOrGroups = (type: 'devices' | 'groups'): void => {
if (typeof actual[type] === 'string' || Array.isArray(actual[type])) {
if (typeof actual[type] === 'string' || (Array.isArray(actual[type]) && actual[type].length > 0)) {
const fileToWrite = Array.isArray(actual[type]) ? actual[type][0] : actual[type];
const content = objectAssignDeep({}, settings[type]);
@@ -308,26 +326,31 @@ export function validate(): string[] {
function read(): Settings {
const s = yaml.read(file) as Settings;
applyEnvironmentVariables(s);
// Read !secret MQTT username and password if set
// eslint-disable-next-line
const interpetValue = (value: any): any => {
const re = /!(.*) (.*)/g;
const match = re.exec(value);
if (match) {
const file = data.joinPath(`${match[1]}.yaml`);
const key = match[2];
return yaml.read(file)[key];
const ref = parseValueRef(value);
if (ref) {
return yaml.read(data.joinPath(ref.filename))[ref.key];
} else {
return value;
}
};
if (s.mqtt?.user && s.mqtt?.password) {
if (s.mqtt?.user) {
s.mqtt.user = interpetValue(s.mqtt.user);
}
if (s.mqtt?.password) {
s.mqtt.password = interpetValue(s.mqtt.password);
}
if (s.mqtt?.server) {
s.mqtt.server = interpetValue(s.mqtt.server);
}
if (s.advanced?.network_key) {
s.advanced.network_key = interpetValue(s.advanced.network_key);
}
@@ -338,7 +361,7 @@ function read(): Settings {
// Read devices/groups configuration from separate file if specified.
const readDevicesOrGroups = (type: 'devices' | 'groups'): void => {
if (typeof s[type] === 'string' || Array.isArray(s[type])) {
if (typeof s[type] === 'string' || (Array.isArray(s[type]) && Array(s[type]).length > 0)) {
/* eslint-disable-line */ // @ts-ignore
const files: string[] = Array.isArray(s[type]) ? s[type] : [s[type]];
s[type] = {};
@@ -373,7 +396,11 @@ function applyEnvironmentVariables(settings: Partial<Settings>): void {
}, settings);
if (type.indexOf('object') >= 0 || type.indexOf('array') >= 0) {
setting[key] = JSON.parse(process.env[envVariableName]);
try {
setting[key] = JSON.parse(process.env[envVariableName]);
} catch (error) {
setting[key] = process.env[envVariableName];
}
} else if (type.indexOf('number') >= 0) {
/* eslint-disable-line */ // @ts-ignore
setting[key] = process.env[envVariableName] * 1;
@@ -390,7 +417,7 @@ function applyEnvironmentVariables(settings: Partial<Settings>): void {
if (typeof obj[key] === 'object' && obj[key]) {
const newPath = [...path];
if (key !== 'properties') {
if (key !== 'properties' && key !== 'oneOf' && !Number.isInteger(Number(key))) {
newPath.push(key);
}
iterate(obj[key], newPath);
@@ -404,7 +431,6 @@ function applyEnvironmentVariables(settings: Partial<Settings>): void {
function getInternalSettings(): Partial<Settings> {
if (!_settings) {
_settings = read();
applyEnvironmentVariables(_settings);
}
return _settings;
@@ -644,21 +670,27 @@ export function removeGroup(IDorName: string | number): void {
write();
}
export function changeEntityOptions(IDorName: string, newOptions: KeyValue): void {
export function changeEntityOptions(IDorName: string, newOptions: KeyValue): boolean {
const settings = getInternalSettings();
delete newOptions.friendly_name;
delete newOptions.devices;
let validator: ValidateFunction;
if (getDevice(IDorName)) {
objectAssignDeep(settings.devices[getDevice(IDorName).ID], newOptions);
utils.removeNullPropertiesFromObject(settings.devices[getDevice(IDorName).ID]);
validator = ajvRestartRequiredDeviceOptions;
} else if (getGroup(IDorName)) {
objectAssignDeep(settings.groups[getGroup(IDorName).ID], newOptions);
utils.removeNullPropertiesFromObject(settings.groups[getGroup(IDorName).ID]);
validator = ajvRestartRequiredGroupOptions;
} else {
throw new Error(`Device or group '${IDorName}' does not exist`);
}
write();
validator(newOptions);
const restartRequired = validator.errors && !!validator.errors.find((e) => e.keyword === 'requiresRestart');
return restartRequired;
}
export function changeFriendlyName(IDorName: string, newName: string): void {
+111 -11
View File
@@ -4,6 +4,8 @@ import data from './data';
import vm from 'vm';
import fs from 'fs';
import path from 'path';
import {detailedDiff} from 'deep-object-diff';
import objectAssignDeep from 'object-assign-deep';
// construct a local ISO8601 string (instead of UTC-based)
// Example:
@@ -38,7 +40,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', 'wifi',
'heat', 'cool', 'water', 'meter', 'wifi', 'no_occupancy_since',
];
function capitalize(s: string): string {
@@ -77,7 +79,7 @@ async function getZigbee2MQTTVersion(includeCommitHash=true): Promise<{commitHas
}
async function getDependencyVersion(depend: string): Promise<{version: string}> {
const packageJSON = await import(path.join(__dirname, '..', '..', 'node_modules', depend, 'package.json'));
const packageJSON = await import(path.join(require.resolve(depend), '..', '..', 'package.json'));
const version = packageJSON.version;
return {version};
}
@@ -132,8 +134,8 @@ function parseJSON(value: string, fallback: string): KeyValue | string {
}
}
function loadModuleFromText(moduleCode: string): unknown {
const moduleFakePath = path.join(__dirname, 'externally-loaded.js');
function loadModuleFromText(moduleCode: string, name?: string): unknown {
const moduleFakePath = path.join(__dirname, '..', '..', 'data', 'extension', name || 'externally-loaded.js');
const sandbox = {
require: require,
module: {},
@@ -210,6 +212,43 @@ function toSnakeCase(value: string | KeyValue): any {
}
}
function charRange(start: string, stop: string): number[] {
const result = [];
for (let idx=start.charCodeAt(0), end=stop.charCodeAt(0); idx <=end; ++idx) {
result.push(idx);
}
return result;
}
const controlCharacters = [
...charRange('\u0000', '\u001F'),
...charRange('\u007f', '\u009F'),
...charRange('\ufdd0', '\ufdef'),
];
function containsControlCharacter(str: string): boolean {
for (let i = 0; i < str.length; i++) {
const ch = str.charCodeAt(i);
if (controlCharacters.includes(ch) || [0xFFFE, 0xFFFF].includes(ch & 0xFFFF)) {
return true;
}
}
return false;
}
function getAllFiles(path_: string): string[] {
const result = [];
for (let item of fs.readdirSync(path_)) {
item = path.join(path_, item);
if (fs.lstatSync(item).isFile()) {
result.push(item);
} else {
result.push(...getAllFiles(item));
}
}
return result;
}
function validateFriendlyName(name: string, throwFirstError=false): string[] {
const errors = [];
for (const endpointName of endpointNames) {
@@ -220,7 +259,7 @@ function validateFriendlyName(name: string, throwFirstError=false): string[] {
if (name.length === 0) errors.push(`friendly_name must be at least 1 char long`);
if (name.endsWith('/') || name.startsWith('/')) errors.push(`friendly_name is not allowed to end or start with /`);
if (name.endsWith(String.fromCharCode(0))) errors.push(`friendly_name is not allowed to contain null char`);
if (containsControlCharacter(name)) errors.push(`friendly_name is not allowed to contain control char`);
if (endpointNames.includes(name)) errors.push(`Following friendly_name are not allowed: '${endpointNames}'`);
if (name.match(/.*\/\d*$/)) errors.push(`Friendly name cannot end with a "/DIGIT" ('${name}')`);
if (name.includes('#') || name.includes('+')) {
@@ -245,22 +284,28 @@ function sanitizeImageParameter(parameter: string): string {
return sanitized;
}
function isAvailabilityEnabledForDevice(device: Device, settings: Settings): boolean {
if (device.options.hasOwnProperty('availability')) {
return !!device.options.availability;
function isAvailabilityEnabledForEntity(entity: Device | Group, settings: Settings): boolean {
if (entity.isGroup()) {
return !entity.membersDevices().map((d) => isAvailabilityEnabledForEntity(d, settings)).includes(false);
}
if (entity.options.hasOwnProperty('availability')) {
return !!entity.options.availability;
}
// availability_timeout = deprecated
const enabledGlobal = settings.advanced.availability_timeout || settings.availability;
if (!enabledGlobal) return false;
if (entity.isDevice() && entity.options.disabled) return false;
const passlist = settings.advanced.availability_passlist.concat(settings.advanced.availability_whitelist);
if (passlist.length > 0) {
return passlist.includes(device.name) || passlist.includes(device.ieeeAddr);
return passlist.includes(entity.name) || passlist.includes(entity.ieeeAddr);
}
const blocklist = settings.advanced.availability_blacklist.concat(settings.advanced.availability_blocklist);
return !blocklist.includes(device.name) && !blocklist.includes(device.ieeeAddr);
return !blocklist.includes(entity.name) && !blocklist.includes(entity.ieeeAddr);
}
const entityIDRegex = new RegExp(`^(.+?)(?:/(${endpointNames.join('|')}|\\d+))?$`);
@@ -273,6 +318,14 @@ function isEndpoint(obj: unknown): obj is zh.Endpoint {
return obj.constructor.name.toLowerCase() === 'endpoint';
}
function flatten<Type>(arr: Type[][]): Type[] {
return [].concat(...arr);
}
function arrayUnique<Type>(arr: Type[]): Type[] {
return [...new Set(arr)];
}
function isZHGroup(obj: unknown): obj is zh.Group {
return obj.constructor.name.toLowerCase() === 'group';
}
@@ -300,11 +353,58 @@ function publishLastSeen(data: eventdata.LastSeenChanged, settings: Settings, al
}
}
function filterProperties(filter: string[], data: KeyValue): void {
if (filter) {
for (const property of Object.keys(data)) {
if (filter.find((p) => property.match(`^${p}$`))) {
delete data[property];
}
}
}
}
function clone(obj: KeyValue): KeyValue {
return JSON.parse(JSON.stringify(obj));
}
function computeSettingsToChange(current: KeyValue, new_: KeyValue): KeyValue {
const diff: KeyValue = detailedDiff(current, new_);
// Remove any settings that are in the deleted.diff but not in the passed options
const cleanupDeleted = (options: KeyValue, deleted: KeyValue): void => {
for (const key of Object.keys(deleted)) {
if (!(key in options)) {
delete deleted[key];
} else if (!Array.isArray(options[key])) {
cleanupDeleted(options[key], deleted[key]);
}
}
};
cleanupDeleted(new_, diff.deleted);
// objectAssignDeep requires object prototype which is missing from detailedDiff, therefore clone
const newSettings = objectAssignDeep({}, clone(diff.added), clone(diff.updated), clone(diff.deleted));
// deep-object-diff converts arrays to objects, set original array back here
const convertBackArray = (before: KeyValue, after: KeyValue): void => {
for (const [key, afterValue] of Object.entries(after)) {
const beforeValue = before[key];
if (Array.isArray(beforeValue)) {
after[key] = beforeValue;
} else if (afterValue && typeof beforeValue === 'object') {
convertBackArray(beforeValue, afterValue);
}
}
};
convertBackArray(new_, newSettings);
return newSettings;
}
export default {
endpointNames, capitalize, getZigbee2MQTTVersion, getDependencyVersion, formatDate, objectHasProperties,
equalsPartial, getObjectProperty, getResponse, parseJSON, loadModuleFromText, loadModuleFromFile,
getExternalConvertersDefinitions, removeNullPropertiesFromObject, toNetworkAddressHex, toSnakeCase,
parseEntityID, isEndpoint, isZHGroup, hours, minutes, seconds, validateFriendlyName, sleep,
sanitizeImageParameter, isAvailabilityEnabledForDevice, publishLastSeen, availabilityPayload,
sanitizeImageParameter, isAvailabilityEnabledForEntity, publishLastSeen, availabilityPayload,
getAllFiles, filterProperties, flatten, arrayUnique, clone, computeSettingsToChange,
};
+10 -2
View File
@@ -183,6 +183,10 @@ export default class Zigbee {
return this.herdsman.isStopping();
}
async backup(): Promise<void> {
return this.herdsman.backup();
}
async getNetworkParameters(): Promise<zh.NetworkParameters> {
return this.herdsman.getNetworkParameters();
}
@@ -219,7 +223,7 @@ export default class Zigbee {
}
}
private resolveDevice(ieeeAddr: string): Device {
@bind private resolveDevice(ieeeAddr: string): Device {
if (!this.deviceLookup[ieeeAddr]) {
const device = this.herdsman.getDeviceByIeeeAddr(ieeeAddr);
device && (this.deviceLookup[ieeeAddr] = new Device(device));
@@ -235,7 +239,7 @@ export default class Zigbee {
private resolveGroup(groupID: number): Group {
const group = this.herdsman.getGroupByID(Number(groupID));
if (group && !this.groupLookup[groupID]) {
this.groupLookup[groupID] = new Group(group);
this.groupLookup[groupID] = new Group(group, this.resolveDevice);
}
return this.groupLookup[groupID];
@@ -306,6 +310,10 @@ export default class Zigbee {
return this.herdsman.touchlinkFactoryReset(ieeeAddr, channel);
}
async addInstallCode(installCode: string): Promise<void> {
await this.herdsman.addInstallCode(installCode);
}
async touchlinkIdentify(ieeeAddr: string, channel: number): Promise<void> {
await this.herdsman.touchlinkIdentify(ieeeAddr, channel);
}
-22922
View File
File diff suppressed because it is too large Load Diff
+15756
View File
File diff suppressed because it is too large Load Diff
+32 -32
View File
@@ -1,6 +1,6 @@
{
"name": "zigbee2mqtt",
"version": "1.24.0",
"version": "1.30.2",
"description": "Zigbee to MQTT bridge using Zigbee-herdsman",
"main": "index.js",
"repository": {
@@ -8,7 +8,7 @@
"url": "git+https://github.com/Koenkk/zigbee2mqtt.git"
},
"engines": {
"node": "^10 || ^12 || ^14 || ^15 || ^16"
"node": "^14 || ^16 || ^18 || ^19"
},
"keywords": [
"xiaomi",
@@ -35,56 +35,56 @@
},
"homepage": "https://koenkk.github.io/zigbee2mqtt",
"dependencies": {
"ajv": "^8.10.0",
"ajv": "^8.12.0",
"bind-decorator": "^1.0.11",
"connect-gzip-static": "^2.1.1",
"core-js": "^3.21.1",
"connect-gzip-static": "2.1.1",
"debounce": "^1.2.1",
"deep-object-diff": "^1.1.7",
"deep-object-diff": "^1.1.9",
"fast-deep-equal": "^3.1.3",
"finalhandler": "^1.1.2",
"finalhandler": "^1.2.0",
"git-last-commit": "^1.0.1",
"humanize-duration": "^3.27.1",
"humanize-duration": "^3.28.0",
"js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"jszip": "^3.10.1",
"mkdir-recursive": "^0.4.0",
"moment": "^2.29.1",
"mqtt": "4.3.6",
"moment": "^2.29.4",
"mqtt": "4.3.7",
"object-assign-deep": "^0.4.0",
"rimraf": "^3.0.2",
"semver": "^7.3.5",
"rimraf": "^4.1.2",
"semver": "^7.3.8",
"source-map-support": "^0.5.21",
"uri-js": "^4.4.1",
"winston": "^3.6.0",
"winston-syslog": "^2.5.0",
"winston": "^3.8.2",
"winston-syslog": "^2.7.0",
"winston-transport": "^4.5.0",
"ws": "^8.5.0",
"zigbee-herdsman": "0.14.20",
"zigbee-herdsman-converters": "14.0.438",
"zigbee2mqtt-frontend": "0.6.76"
"ws": "^8.12.1",
"zigbee-herdsman": "0.14.96",
"zigbee-herdsman-converters": "15.0.58",
"zigbee2mqtt-frontend": "0.6.125"
},
"devDependencies": {
"@babel/core": "^7.17.5",
"@babel/plugin-proposal-decorators": "^7.17.2",
"@babel/preset-env": "^7.16.11",
"@babel/preset-typescript": "^7.16.7",
"@babel/core": "^7.21.0",
"@babel/plugin-proposal-decorators": "^7.21.0",
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.21.0",
"@types/debounce": "^1.2.1",
"@types/finalhandler": "^1.1.1",
"@types/finalhandler": "^1.2.0",
"@types/humanize-duration": "^3.27.1",
"@types/jest": "^27.4.1",
"@types/jest": "^29.4.0",
"@types/js-yaml": "^4.0.5",
"@types/object-assign-deep": "^0.4.0",
"@types/rimraf": "^3.0.2",
"@types/ws": "^8.5.1",
"@typescript-eslint/eslint-plugin": "^5.12.1",
"@typescript-eslint/parser": "^5.12.1",
"babel-jest": "^27.5.1",
"eslint": "^8.10.0",
"@types/ws": "^8.5.4",
"@typescript-eslint/eslint-plugin": "^5.53.0",
"@typescript-eslint/parser": "^5.53.0",
"babel-jest": "^29.4.3",
"eslint": "^8.34.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-jest": "^26.1.1",
"jest": "^27.5.1",
"eslint-plugin-jest": "^27.2.1",
"jest": "^29.4.3",
"tmp": "^0.2.1",
"typescript": "^4.5.5"
"typescript": "^4.9.5"
},
"jest": {
"coverageThreshold": {
+3 -2
View File
@@ -5,7 +5,8 @@ const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
for (const line of text.split('\n')) {
const model = zigbeeHerdsmanConverters.devices.find((d) => d.model === line);
const [modelNumber, user] = line.split(',').map((t) => t.trim());
const model = zigbeeHerdsmanConverters.devices.find((d) => d.model === modelNumber);
if (!model) throw new Error(`${line} does not exist`);
console.log(`- \`${line}\` ${model.vendor} ${model.description}`);
console.log(`- \`${modelNumber}\` ${model.vendor} ${model.description} (${user})`);
}
+22
View File
@@ -0,0 +1,22 @@
const assert = require('assert');
const vm = require('vm');
const fs = require('fs');
const path = require('path');
const filename = process.argv[2];
const moduleCode = fs.readFileSync(filename);
const moduleFakePath = path.join(__dirname, 'externally-loaded.js');
const sandbox = {
require: require,
module: {},
console,
setTimeout,
clearTimeout,
setInterval,
clearInterval,
setImmediate,
clearImmediate,
};
vm.runInNewContext(moduleCode, sandbox, moduleFakePath);
const converter = sandbox.module.exports;
assert(!converter.toZigbee.includes(undefined));
assert(!converter.fromZigbee.includes(undefined));
+31
View File
@@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIUU70Q1tbGP071yeQ8EcHd/0rxtnwwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjEyMDMwMDA1MTBaFw0yMzAx
MDIwMDA1MTBaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQDR6bYQPgkfWlGQq19U2nMsAo0RZR7wSUuFS0MFpbQS
2Rr5x/4FwwKhTMOlfr6H2Xo/5pQvGOlhFE69j1HxQRooWDAswnscMv/9pb+BUqoE
7J29SEndIpmCaI0c3ejZsu4Nq8DxGod/RsQhJdbDU+hkw8qARJ0JjnTb+aN1KH8g
J3KeSMTOL3guBVZQujO0Unbjv47yBIFwi0IihR18aoRaxinb94Aqf92HcjZN++WU
gq7/2Qlm3tF5uJwuNtG/DmzReSblRcUgzPri7qIhb9z51gFNdNX6cTH3yNoF/KtT
XwEArvvsAyMCYuC6w8KI7WNmPI6yxSksgHdcNPlUVZYquLD+z2kYAdIByiyHmIpm
OH3jVN7lRJ6xITOGmyNktfRuSUi2GzECAOWIGpDD/5/gK1pacbOXpJWqVrTjUIAN
BrQf496CbabVgwaQEvq1QJJbuMbpma21/IlS6NpZS7vm/q1ojNsbEB6PYkSsBTzP
iZiiaomjhV2w5yIp5Zn8xyMFVKLb+SEDQBtZZ6CErmbgqp4B3U2b4k5LippLmZZK
pSk7BOuMpsZK8FIGS4KlANFfGVs79y6N+Jxue2IO9pRcpcpbqOXty4662BsPKInw
dKxKTr6TcTe0gEq1fpf1npYwcZ9t36LMJ7L51TbaaJ5sEsXe5QNOOOUgSwPqWmrE
lwIDAQABo1MwUTAdBgNVHQ4EFgQUYD/x9cCuGJgLUPkYLIVa8uvseBkwHwYDVR0j
BBgwFoAUYD/x9cCuGJgLUPkYLIVa8uvseBkwDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAgEAI+gp+8qqO4anj8NHgjJvXhrETLPJIeLuBp/cjF9HA2IL
oAd5rXWPnQ6qgh3q/HazILgIHwI0wSrhVtRlprgGIxNa59cD3RcZCtqFSWIqhAqZ
JnAye3bnGU/KahazQX3oP+y564b/QZvwpJDKC1EoMv1wdpXND2NVn4HwaBc7Tu/d
SX/Tr6k+e32K8mwE+00/yf2rLrmWmNjWtP0f7zRmH3j1+ovktk7UoVhjKXfhqMUE
pWdhPZIXQJ65JNMGKdeFI2ULQY9IbXHeWQUgBCyhTciMvm2XZzopk7rxrh9NZopS
pAlCrWBkOZrs6hfZrus9FOzwSkeIEY7NnhNk05kslERJxjkoFytp7mDd4mTKCVW0
dKc7G1hZWYfO3oe0Zjxi0ragyReNKtyL1BqMbDKJmxHl91iPbdueWix1xxhNFakH
l3eOzfa/DEixvzxy3hzCcvagNb5RsXFVMQXQTgnIW/5GcG5VVB2/o7KidPL3XtqR
Hc/0ebQvloGXgqJbyTXG9EInkwB35wXDQuHgwt1PhwzP1yfp2BCvDsQWrR3IxnBT
DO1o2RpsurgCgUpd0vcW17DePLNfprrhhU2uTPn2bNcWdT/rZmEImkNaA29Rku+3
SZQJZWIx4s2FMdVdAv6ZauROStTY/WayudfcFfP+hYvJ5/ccQ9Gkb7vrGUssFRw=
-----END CERTIFICATE-----
+54
View File
@@ -0,0 +1,54 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIJnDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIrNH7wPLdpbUCAggA
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECN97bYsRcF6xBIIJSLVWpqTzdlNO
5J7kOrNcdbbg+SSEYbtT+G9gtwtkI8KO+xzYQZ/fdqmXgNqf9AQmikwDWQkoS4gC
qq6S+iKYn7Y8ZNZ/xu7gWW6L6uNZ3LTe/vkpenU6kmZrDysFTW5b7iH2VmMc/2h/
J3o3unxeMLMVSaoDG3MG08qj53yTmetTkZZZc4fgf6vK9/4fTJhdXu6n+1COBLBI
KbqbTRKnai3CNiYzz3UHyp9CGx1nX06beTJW8bYJUld9cJz+ozLNSV78oCkcUfwG
yR7p/6+86cWor5SwYG1wEm6w2bXrIJILTUdT92gXC8fhc/B6Id8hcuLIHcvFQ/CP
31y4Qwea3vY6b1TeRbqS4/fYOYajsiZi9ps0Meg55qMJj/UuNW2iLlR7PVsDXmPO
33X6cpEVyIlNCJzRREotzSoGmcXjQ5Dgd1LkxZPb163NGkRoJT4GcKCtQxYIyIzy
qyU0YF7I5LPKtNt1IPURHHerW42jM2jFlISxUixgl5Pj3WrmXeEmXq7htItn6X/q
tVEVUf6srs3aos2Ohx7Ji9PVDNuMGGGKxleCM6fU9ax/gYuk5r6PMYGPsD26xuZ0
A9WbFFFI6N1V+M3YsJJdxevZRV1NB3RymYGwFoZFDOKLb5DYJmPP3VVN/DsMNPkw
qaue7rinxBdLi8J6Itusiscg5pCyYQaujXtkK/bi6c1HCld4RvWCDgeU52SWRdJ9
2Np2629AeBvBfHP1/DsaUsyQPJAgDJk0HXoJyqstoALkRZ6ICoi1833LW/JGIWOv
xnl3JZ2q12aqb2OWxiBUKspnt2y5C2KpQJdmuEL68lAKLg+fzLi/jhJG1bwzWo79
I5G+QeV9+kI3vAIYHu331a+Yevs2p84sIumDGFSCSHAaWMmsrizJ4eKl5NnwZHS+
xUvcW+ISRKNRm4DWAL/nlwBJWMhCz+nsTKYvE1JO/IH2P5xxtD6bTjJ3YkVAHkBZ
wfApCBxdiQurEiabj06C4OCcNRkqJ/GwLrdxiwTCAt2hd7Dn+ttLo3Fi6iPRae8c
ZtWsCWaFObZ1QBeu7lKm+ev/Ab2SHtp6QMfrArNsrdIxSH1+Sm4DgfHmTmte2Tse
KFHy5Rwokst+Y18zjp3auJ3+NTTr9D1x2JCdQ6wkh66Pyd2FBLqRrMI1fHq9t9P+
r4DQm9I6FbgALm9yJ2QxV4ytwFGsowAye3vF+hfO5OjAScrG5DrxASRXlnp59zpd
+vMLk6rzcfiHzaJzYc/SOU9ubKN93aJmlL0Zgf1gg54oGnmPbEJeqQzeKVBtisro
FrNUPEFx5QOaqjVipPOpZfpTb0oaUpBdp4RpeI7W3Gb/dsmsRj7ItxvM6QxFdd5e
XfDZEYaUJRwSG3lHg9URWwSmfRWV81BhEuwvji4rNIEQ32VMsi2WWWPLOYYKGIw/
yE56xWBw7K78XwVx/b5yoNHBNjVNyjpNZ7jXkx6zdOjbqEpXJP+WfgVkYwlhlvAq
cCDbrF7jVWFqTV9tZNxlbaFlS8f17vld8DmmJ29Lo+WecsOo3M9n2Z6i79u7Xg2O
ip0V2Textq8rrKOwC1TLCRoQLypENO/cwdaF5amVkoXYDlY0rQtxf65Xe9bnJLrM
1G+tG8NZQu/bvW0mgrm0XHt2i6yfjn6sXEOY5VEC2+gRUriQ+GCETgzMe6ukb26/
VT38Va10SIu+xXwf/GXTwLskOO0AyWLBopTpL5q6faM4o/USX+Xl98sQVNQurHMS
xSQtpL6YPhQrmW7q5Q57OVWy70kEU8RpOJx6I7uyoUDz2g3bjmpIPpQX55vhofXK
3Xn76Ce9TyiVol71mPtBT1tYzi3ytZh/EYm2Wq3lEhbMT7zjw3T1Ypb4+q12VdCy
0Y9swKsQdhRCT6FwcCFSpCc2TzCCJCR6mChTe+z6rNm5BS2M6BaYcrX8PP82rZ8k
L0l3ymSLqSJ3J6Q+fdKhRq8EbCq6ngi31Q/l7fPHkW5VAJyowPRayD7UM09n6ou+
sg/kfQB8nh46uVxRRDpyUsrfhtIEQec2xrU17NmCr2VlAeOjWBn8lE/J1Gfn8WyV
05mY1aDGcRk/x02+74UujyuozYMfIVDXHpxp8YteTnBfiKVrRq+Aa9zVX9bkyagp
SJUTpF7lqMmiuvyZnG2xfLDfILR/zTRIRrm+ZIJLHeVQJtibOJ1llxE6kRvKx6zp
La47YCHKH+rLDTlNgrE5K/JtQgOKc+7bGQ6SCszf8OZWi5B2+Z+Ht36c3xQk9IOW
cjNpvjZxpiw6L1MhlQPE/wxz2JkOlKjJN0MmLscIyu15X+W/BvHwB8d11CRKUUiE
pV7OUoW2Ol1IgFHrEY33IhxwtyKtAKfQCiORarnwk/GvcD3TqmnzUeQdscdww4BI
wsO3c3aGr+wvU3P/8oFAoffD1KRihtoZ6CB347JcnaeEPlOS13a28JsJCOtjMxy9
wBH6UgzTwo04lDAStST+aIT4TaU4dlWmsAEQTpE8sa4DjpFtzK/ll+Wg2sA/SYaA
uAugsAOnTb1pkgk43GoYfc2fZCu1g9b/L3mZrE62W8HDfm67PWT65XMJziy/hcCy
DbXMAWfohLdePKDG7J0QQI8xcTN9TT5q3ZCglI9Xf7PE/qrHROdRgF8c8zyvB9dG
AVx96Z7akBoveqlFS44MnxIOGI0AzV8MrVbN51W6RHNyg/6UTL50/8zHmRWZj+iO
tfqiW+CtSHacYPy+Tcuft30PWZZkQDGphbRxaBRB00Fb+Bo57epDw4JS+4wRru33
2RHaVzQmnXwR6kP85x4uAR53UdgMgfK4cyylnFqGDlLFrHZfauFHg3kMIwqgVIVA
uMRrWC9XXU11j6NnP9J6Y64uSrjsh6eZOrtJIwA16U2r3PMMbn1hIdADrKu1MsPt
bkNsnPQUKJyX8DbRX45kje5ssUerbkxhvewvHQJlTyDxtgk/pGHOyKXoT+5vQEj9
pwHOrXi+QWidzi2vfRoNQJ0wXJr39dDTn0hVdsgFo2PsTh98W9cocVQfJnCL4Djs
Zlsp/BJOwlb2e3Q28E6pNyT+N63ZYEO9zLV/WmCB/eV2uMVoKibX3KszYkn0jAs0
RBytgnB8YW3n9RyorShchCKJzdjzR7nw79/lSLgDFE6W6Xh3VaGM07hz0vYWfaui
yvytkM9LPan2/GJM4zLFeA==
-----END ENCRYPTED PRIVATE KEY-----
+31 -5
View File
@@ -179,6 +179,15 @@ describe('Availability', () => {
expect(devices.bulb_color.ping).toHaveBeenCalledTimes(1);
});
it('Should not ping disabled devices', async () => {
settings.set(['devices', devices.bulb_color.ieeeAddr, 'disabled'], true);
await resetExtension();
MQTT.publish.mockClear();
await advancedTime(utils.minutes(15));
expect(devices.bulb_color.ping).toHaveBeenCalledTimes(0);
});
it('Should allow to change availability timeout via avaiability options', async () => {
settings.set(['availability'], {active: {timeout: 30}});
await resetExtension();
@@ -241,6 +250,9 @@ describe('Availability', () => {
it('Should retrieve device state when it reconnects', async () => {
MQTT.publish.mockClear();
const device = controller.zigbee.resolveEntity(devices.bulb_color.ieeeAddr);
controller.state.set(device, {state: 'OFF'})
const endpoint = devices.bulb_color.getEndpoint(1);
endpoint.read.mockClear();
@@ -253,18 +265,15 @@ describe('Availability', () => {
expect(endpoint.read).toHaveBeenCalledTimes(0);
await advancedTime(utils.seconds(2));
expect(endpoint.read).toHaveBeenCalledTimes(3);
expect(endpoint.read).toHaveBeenCalledTimes(1);
expect(endpoint.read).toHaveBeenCalledWith('genOnOff', ['onOff']);
expect(endpoint.read).toHaveBeenCalledWith('genLevelCtrl', ['currentLevel']);
expect(endpoint.read).toHaveBeenCalledWith('lightingColorCtrl',
['colorMode', 'currentX', 'currentY', 'enhancedCurrentHue', 'currentSaturation', 'colorTemperature']);
endpoint.read.mockClear();
await zigbeeHerdsman.events.deviceAnnounce({device: devices.bulb_color});
await flushPromises();
endpoint.read.mockImplementationOnce(() => {throw new Error('')});
await advancedTime(utils.seconds(3));
expect(endpoint.read).toHaveBeenCalledTimes(3);
expect(endpoint.read).toHaveBeenCalledTimes(1);
});
it('Should republish availability when device is renamed', async () => {
@@ -318,4 +327,21 @@ describe('Availability', () => {
await advancedTime(utils.minutes(12));
expect(devices.bulb_color.ping).toHaveBeenCalledTimes(1);
});
it('Should publish availabilty for groups', async () => {
settings.set(['devices', devices.bulb_color_2.ieeeAddr, 'availability'], true);
await resetExtension();
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/group_tradfri_remote/availability',
'online', {retain: true, qos: 0}, expect.any(Function));
MQTT.publish.mockClear();
await advancedTime(utils.minutes(12));
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/group_tradfri_remote/availability',
'offline', {retain: true, qos: 0}, expect.any(Function));
MQTT.publish.mockClear();
devices.bulb_color_2.lastSeen = Date.now();
await zigbeeHerdsman.events.lastSeenChanged({device: devices.bulb_color_2});
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/group_tradfri_remote/availability',
'online', {retain: true, qos: 0}, expect.any(Function));
});
});
+2 -1
View File
@@ -588,6 +588,7 @@ describe('Bind', () => {
it('Should poll bounded Hue bulb when receiving message from scene controller', async () => {
const remote = zigbeeHerdsman.devices.bj_scene_switch;
const data = {"action": "recall_2_row_1"};
zigbeeHerdsman.devices.bulb_color_2.getEndpoint(1).read.mockImplementationOnce(() => {throw new Error('failed')});
const payload = {data, cluster: 'genScenes', device: remote, endpoint: remote.getEndpoint(10), type: 'commandRecall', linkquality: 10, groupID: 0};
await zigbeeHerdsman.events.message(payload);
await flushPromises();
@@ -595,7 +596,7 @@ describe('Bind', () => {
expect(debounce).toHaveBeenCalledTimes(3);
expect(zigbeeHerdsman.devices.bulb_color_2.getEndpoint(1).read).toHaveBeenCalledWith("genOnOff", ["onOff"]);
expect(zigbeeHerdsman.devices.bulb_color_2.getEndpoint(1).read).toHaveBeenCalledWith("genLevelCtrl", ["currentLevel"]);
expect(zigbeeHerdsman.devices.bulb_color_2.getEndpoint(1).read).toHaveBeenCalledWith("lightingColorCtrl", ["currentX", "currentY", "colorTemperature"]);
expect(zigbeeHerdsman.devices.bulb_color_2.getEndpoint(1).read).toHaveBeenCalledWith("lightingColorCtrl", ["currentX", "currentY", "colorTemperature"]);
});
it('Should poll grouped Hue bulb when receiving message from TRADFRI remote', async () => {
+115 -7
View File
File diff suppressed because one or more lines are too long
+16 -15
View File
@@ -65,6 +65,7 @@ describe('Configure', () => {
jest.useFakeTimers();
controller = new Controller(jest.fn(), jest.fn());
await controller.start();
await jest.runOnlyPendingTimers();
await flushPromises();
});
@@ -72,8 +73,9 @@ describe('Configure', () => {
data.writeDefaultConfiguration();
settings.reRead();
mocksClear.forEach((m) => m.mockClear());
coordinatorEndpoint = zigbeeHerdsman.devices.coordinator.getEndpoint(1);
coordinatorEndpoint = zigbeeHerdsman.devices.coordinator.getEndpoint(1);
await resetExtension();
await jest.runOnlyPendingTimers();
});
afterAll(async () => {
@@ -100,6 +102,17 @@ describe('Configure', () => {
expectBulbConfigured();
});
it('Should not re-configure disabled devices', async () => {
expectBulbConfigured();
const device = zigbeeHerdsman.devices.bulb;
await flushPromises();
mockClear(device);
settings.set(['devices', device.ieeeAddr, 'disabled'], true);
zigbeeHerdsman.events.deviceJoined({device});
await flushPromises();
expectBulbNotConfigured();
});
it('Should reconfigure reporting on reconfigure event', async () => {
expectBulbConfigured();
const device = controller.zigbee.resolveEntity(zigbeeHerdsman.devices.bulb);
@@ -192,19 +205,7 @@ describe('Configure', () => {
expect(logger.warn).toHaveBeenCalledWith(`Skipping configure of 'ZNLDP12LM', device does not require this.`)
});
it('Should not configure when interviewing', async () => {
const device = zigbeeHerdsman.devices.remote;
delete device.meta.configured;
device.interviewing = true;
const endpoint = device.getEndpoint(1);
mockClear(device);
await zigbeeHerdsman.events.lastSeenChanged({device});
await flushPromises();
expectRemoteNotConfigured();
device.interviewing = false;
});
it('Should configure when not interviewCompleted', async () => {
it('Should not configure when interview not completed', async () => {
const device = zigbeeHerdsman.devices.remote;
delete device.meta.configured;
device.interviewCompleted = false;
@@ -212,7 +213,7 @@ describe('Configure', () => {
mockClear(device);
await zigbeeHerdsman.events.lastSeenChanged({device});
await flushPromises();
expectRemoteConfigured();
expectRemoteNotConfigured();
device.interviewCompleted = true;
});
+80 -9
View File
@@ -120,6 +120,7 @@ describe('Controller', () => {
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb", stringify({"state":"ON","brightness":50,"color_temp":370,"linkquality":99}), {"qos": 0, "retain": true}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/remote", stringify({"brightness":255}), {"qos": 0, "retain": true}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/group_1", stringify({"state":'ON'}), {"qos": 0, "retain":false}, expect.any(Function));
});
it('Start controller should not publish cached states when disabled', async () => {
@@ -146,7 +147,6 @@ describe('Controller', () => {
logger.error.mockClear();
controller.mqtt.client.reconnecting = true;
jest.advanceTimersByTime(11 * 1000);
await flushPromises();
expect(logger.error).toHaveBeenCalledWith("Not connected to MQTT server!");
controller.mqtt.client.reconnecting = false;
});
@@ -201,9 +201,10 @@ describe('Controller', () => {
});
await controller.start();
await flushPromises();
expect(logger.error).toHaveBeenCalledWith('MQTT failed to connect: addr not found');
expect(logger.error).toHaveBeenCalledWith('MQTT error: addr not found');
expect(logger.error).toHaveBeenCalledWith('MQTT failed to connect, exiting...');
expect(mockExit).toHaveBeenCalledTimes(1);
expect(mockExit).toHaveBeenCalledWith(1);
expect(mockExit).toHaveBeenCalledWith(1, false);
});
it('Start controller with permit join true', async () => {
@@ -220,13 +221,13 @@ describe('Controller', () => {
expect(zigbeeHerdsman.setTransmitPower).toHaveBeenCalledWith(14);
});
it('Start controller and stop', async () => {
it('Start controller and stop with restart', async () => {
await controller.start();
await controller.stop();
await controller.stop(true);
expect(MQTT.end).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsman.stop).toHaveBeenCalledTimes(1);
expect(mockExit).toHaveBeenCalledTimes(1);
expect(mockExit).toHaveBeenCalledWith(0);
expect(mockExit).toHaveBeenCalledWith(0, true);
});
it('Start controller and stop', async () => {
@@ -236,7 +237,7 @@ describe('Controller', () => {
expect(MQTT.end).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsman.stop).toHaveBeenCalledTimes(1);
expect(mockExit).toHaveBeenCalledTimes(1);
expect(mockExit).toHaveBeenCalledWith(1);
expect(mockExit).toHaveBeenCalledWith(1, false);
});
it('Start controller adapter disconnects', async () => {
@@ -247,7 +248,7 @@ describe('Controller', () => {
expect(MQTT.end).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsman.stop).toHaveBeenCalledTimes(1);
expect(mockExit).toHaveBeenCalledTimes(1);
expect(mockExit).toHaveBeenCalledWith(1);
expect(mockExit).toHaveBeenCalledWith(1, false);
});
it('Handle mqtt message', async () => {
@@ -489,6 +490,46 @@ describe('Controller', () => {
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb", stringify({"state":"ON","brightness":200}), {"qos": 0, "retain": true}, expect.any(Function));
});
it('Publish entity state attribute_json output filtered cache', async () => {
await controller.start();
settings.set(['advanced', 'output'], 'attribute_and_json');
settings.set(['devices', zigbeeHerdsman.devices.bulb.ieeeAddr, 'filtered_cache'], ['linkquality']);
MQTT.publish.mockClear();
const device = controller.zigbee.resolveEntity('bulb');
expect(controller.state.state[device.ieeeAddr]).toStrictEqual({"brightness":50,"color_temp":370,"linkquality":99,"state":"ON"});
await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 87});
await flushPromises();
expect(controller.state.state[device.ieeeAddr]).toStrictEqual({"brightness":200,"color_temp":370,"state":"ON"});
expect(MQTT.publish).toHaveBeenCalledTimes(5);
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb/state", "ON", {"qos": 0, "retain": true}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb/brightness", "200", {"qos": 0, "retain": true}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb/linkquality", "87", {"qos": 0, "retain": true}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb", stringify({"state":"ON","brightness":200,"color_temp":370,"linkquality":87}), {"qos": 0, "retain": true}, expect.any(Function));
});
it('Publish entity state attribute_json output filtered cache (device_options)', async () => {
await controller.start();
settings.set(['advanced', 'output'], 'attribute_and_json');
settings.set(['device_options', 'filtered_cache'], ['linkquality']);
MQTT.publish.mockClear();
const device = controller.zigbee.resolveEntity('bulb');
expect(controller.state.state[device.ieeeAddr]).toStrictEqual({"brightness":50,"color_temp":370,"linkquality":99,"state":"ON"});
await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 87});
await flushPromises();
expect(controller.state.state[device.ieeeAddr]).toStrictEqual({"brightness":200,"color_temp":370,"state":"ON"});
expect(MQTT.publish).toHaveBeenCalledTimes(5);
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb/state", "ON", {"qos": 0, "retain": true}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb/brightness", "200", {"qos": 0, "retain": true}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb/linkquality", "87", {"qos": 0, "retain": true}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb", stringify({"state":"ON","brightness":200,"color_temp":370,"linkquality":87}), {"qos": 0, "retain": true}, expect.any(Function));
});
it('Publish entity state with device information', async () => {
await controller.start();
settings.set(['mqtt', 'include_device_information'], true);
@@ -569,7 +610,7 @@ describe('Controller', () => {
logger.error.mockClear();
controller.state.file = "/";
await controller.state.save();
expect(logger.error).toHaveBeenCalledWith(`Failed to write state to '/' (EISDIR: illegal operation on a directory, open '/')`);
expect(logger.error).toHaveBeenCalledWith(expect.stringMatching(/Failed to write state to \'\/\'/));
});
it('Publish should not cache when set', async () => {
@@ -604,6 +645,27 @@ describe('Controller', () => {
expect(MQTT.connect).toHaveBeenCalledWith("mqtt://localhost", expected);
});
it('Should republish retained messages on MQTT reconnect', async () => {
await controller.start();
MQTT.publish.mockClear();
MQTT.events['connect']();
await flushPromises();
jest.runOnlyPendingTimers();
expect(MQTT.publish).toHaveBeenCalledTimes(13);
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/info', expect.any(String), { retain: true, qos: 0 }, expect.any(Function));
});
it('Should not republish retained messages on MQTT reconnect when retained message are sent', async () => {
await controller.start();
MQTT.publish.mockClear();
MQTT.events['connect']();
await flushPromises();
await MQTT.events.message('zigbee2mqtt/bridge/state', 'online');
jest.runOnlyPendingTimers();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/state', expect.any(String), { retain: true, qos: 0 }, expect.any(Function));
});
it('Should prevent any message being published with retain flag when force_disable_retain is set', async () => {
settings.set(['mqtt', 'force_disable_retain'], true);
await controller.mqtt.connect()
@@ -656,4 +718,13 @@ describe('Controller', () => {
await flushPromises();
expect(logger.debug).toHaveBeenCalledWith(`Received Zigbee message from 'Coordinator', type 'attributeReport', cluster 'genBasic', data '{"modelId":null}' from endpoint 1, ignoring since it is from coordinator`);
});
it('Should remove state of removed device when stopped', async () => {
await controller.start();
const device = controller.zigbee.resolveEntity('bulb');
expect(controller.state.state[device.ieeeAddr]).toStrictEqual({"brightness":50,"color_temp":370,"linkquality":99,"state":"ON"});
device.zh.isDeleted = true;
await controller.stop();
expect(controller.state.state[device.ieeeAddr]).toStrictEqual(undefined);
});
});
+1
View File
@@ -19,6 +19,7 @@ describe('Data', () => {
const actual = data.getPath();
expect(actual).toBe(expected);
expect(data.joinPath('test')).toStrictEqual(path.join(expected, 'test'));
expect(data.joinPath('/test')).toStrictEqual(path.resolve(expected, '/test'));
delete process.env.ZIGBEE2MQTT_DATA;
data.testingOnlyReload();
});
+6 -1
View File
@@ -84,7 +84,12 @@ describe('User extensions', () => {
MQTT.events.message('zigbee2mqtt/bridge/request/extension/save', stringify({"name": "foo.js", "code": extensionCode}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/response/extension/save', stringify({"data":{},"error":"Unexpected identifier","status":"error"}), { retain: false, qos: 0 }, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/response/extension/save', expect.any(String), { retain: false, qos: 0 }, expect.any(Function));
const payload = JSON.parse(MQTT.publish.mock.calls[0][1]);
expect(payload).toEqual(
expect.objectContaining({"data":{},"status":"error"})
);
expect(payload.error).toMatch("Unexpected identifier");
});
it('Removes user extension', async () => {
+60 -3
View File
@@ -7,6 +7,7 @@ const Controller = require('../lib/controller');
const stringify = require('json-stable-stringify-without-jsonify');
const flushPromises = require('./lib/flushPromises');
const zigbeeHerdsman = require('./stub/zigbeeHerdsman');
const path = require("path");
jest.spyOn(process, 'exit').mockImplementation(() => {});
const mockHTTP = {
@@ -19,6 +20,16 @@ const mockHTTP = {
events: {},
};
const mockHTTPS = {
implementation: {
listen: jest.fn(),
on: (event, handler) => {mockHTTPS.events[event] = handler},
close: jest.fn().mockImplementation((cb) => cb()),
},
variables: {},
events: {},
};
const mockWSocket = {
close: jest.fn(),
};
@@ -50,6 +61,13 @@ jest.mock('http', () => ({
}),
}));
jest.mock('https', () => ({
createServer: jest.fn().mockImplementation((onRequest) => {
mockHTTPS.variables.onRequest = onRequest;
return mockHTTPS.implementation;
}),
}));
jest.mock("connect-gzip-static", () =>
jest.fn().mockImplementation((path) => {
mockNodeStatic.variables.path = path
@@ -98,7 +116,6 @@ describe('Frontend', () => {
await controller.start();
expect(mockNodeStatic.variables.path).toBe("my/dummy/path");
expect(mockHTTP.implementation.listen).toHaveBeenCalledWith(8081, "127.0.0.1");
const mockWSClient = {
implementation: {
terminate: jest.fn(),
@@ -111,6 +128,46 @@ describe('Frontend', () => {
expect(mockWSClient.implementation.terminate).toHaveBeenCalledTimes(1);
expect(mockHTTP.implementation.close).toHaveBeenCalledTimes(1);
expect(mockWS.implementation.close).toHaveBeenCalledTimes(1);
mockHTTP.implementation.listen.mockClear();
mockHTTPS.implementation.listen.mockClear();
});
it('Start/stop HTTPS valid', async () => {
settings.set(['frontend','ssl_cert'], path.join(__dirname,'assets','certs','dummy.crt'));
settings.set(['frontend','ssl_key'], path.join(__dirname,'assets','certs','dummy.key'));
controller = new Controller(jest.fn(), jest.fn());
await controller.start();
expect(mockHTTP.implementation.listen).not.toHaveBeenCalledWith(8081, "127.0.0.1");
expect(mockHTTPS.implementation.listen).toHaveBeenCalledWith(8081, "127.0.0.1");
await controller.stop();
mockHTTP.implementation.listen.mockClear();
mockHTTPS.implementation.listen.mockClear();
});
it('Start/stop HTTPS invalid : missing config', async () => {
settings.set(['frontend','ssl_cert'], path.join(__dirname,'assets','certs','dummy.crt'));
controller = new Controller(jest.fn(), jest.fn());
await controller.start();
expect(mockHTTP.implementation.listen).toHaveBeenCalledWith(8081, "127.0.0.1");
expect(mockHTTPS.implementation.listen).not.toHaveBeenCalledWith(8081, "127.0.0.1");
await controller.stop();
mockHTTP.implementation.listen.mockClear();
mockHTTPS.implementation.listen.mockClear();
});
it('Start/stop HTTPS invalid : missing file', async () => {
settings.set(['frontend','ssl_cert'], 'filesNotExists.crt');
settings.set(['frontend','ssl_key'], path.join(__dirname,'assets','certs','dummy.key'));
controller = new Controller(jest.fn(), jest.fn());
await controller.start();
expect(mockHTTP.implementation.listen).toHaveBeenCalledWith(8081, "127.0.0.1");
expect(mockHTTPS.implementation.listen).not.toHaveBeenCalledWith(8081, "127.0.0.1");
await controller.stop();
mockHTTP.implementation.listen.mockClear();
mockHTTPS.implementation.listen.mockClear();
});
it('Websocket interaction', async () => {
@@ -140,7 +197,7 @@ describe('Frontend', () => {
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bulb_color',
stringify({state: 'ON', linkquality: null, update_available: null, update: {state: null}}),
stringify({state: 'ON', power_on_behavior:null, linkquality: null, update_available: null, update: {state: null, installed_version: -1, latest_version: -1}}),
{ retain: false, qos: 0 },
expect.any(Function)
);
@@ -151,7 +208,7 @@ describe('Frontend', () => {
// Received message on socket
expect(mockWSClient.implementation.send).toHaveBeenCalledTimes(1);
expect(mockWSClient.implementation.send).toHaveBeenCalledWith(stringify({topic: 'bulb_color', payload: {state: 'ON', linkquality: null, update_available: null, update: {state: null}}}));
expect(mockWSClient.implementation.send).toHaveBeenCalledWith(stringify({topic: 'bulb_color', payload: {state: 'ON', power_on_behavior:null, linkquality: null, update_available: null, update: {state: null, installed_version: -1, latest_version: -1}}}));
// Shouldnt set when not ready
mockWSClient.implementation.send.mockClear();
+40
View File
@@ -334,6 +334,22 @@ describe('Groups', () => {
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/group_1", stringify({"state":"ON"}), {"retain": false, qos: 0}, expect.any(Function));
});
it('Should not publish state change when group changes state and device is disabled', async () => {
const device = zigbeeHerdsman.devices.bulb_color;
const endpoint = device.getEndpoint(1);
const group = zigbeeHerdsman.groups.group_1;
group.members.push(endpoint);
settings.set(['devices', device.ieeeAddr, 'disabled'], true);
settings.set(['groups'], {'1': {friendly_name: 'group_1', retain: false, devices: [device.ieeeAddr]}});
await resetExtension();
MQTT.publish.mockClear();
await MQTT.events.message('zigbee2mqtt/group_1/set', stringify({state: 'ON'}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/group_1", stringify({"state":"ON"}), {"retain": false, qos: 0}, expect.any(Function));
});
it('Should publish state change for group when members state change', async () => {
// Created for https://github.com/Koenkk/zigbee2mqtt/issues/5725
const device = zigbeeHerdsman.devices.bulb_color;
@@ -469,6 +485,30 @@ describe('Groups', () => {
expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb_color", stringify({state:"OFF"}), {"retain": false, qos: 0}, expect.any(Function));
});
it('Should publish state change off if any lights within are still on when changed via device when off_state: last_member_state is used', 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, off_state: 'last_member_state'}
});
await resetExtension();
await MQTT.events.message('zigbee2mqtt/group_1/set', stringify({state: 'ON'}));
await flushPromises();
MQTT.publish.mockClear();
await MQTT.events.message('zigbee2mqtt/bulb_color/set', stringify({state: 'OFF'}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(2);
expect(MQTT.publish).toHaveBeenNthCalledWith(1, "zigbee2mqtt/group_1", stringify({state:"OFF"}), {"retain": false, qos: 0}, expect.any(Function));
expect(MQTT.publish).toHaveBeenNthCalledWith(2, "zigbee2mqtt/bulb_color", stringify({state:"OFF"}), {"retain": false, qos: 0}, expect.any(Function));
});
it('Should not publish state change off if any lights within are still on when changed via shared group', async () => {
const device_1 = zigbeeHerdsman.devices.bulb_color;
const device_2 = zigbeeHerdsman.devices.bulb;
+176 -25
View File
@@ -98,6 +98,19 @@ describe('HomeAssistant extension', () => {
"xy",
"color_temp"
],
"effect":true,
"effect_list":[
"blink",
"breathe",
"okay",
"channel_change",
"candle",
"fireplace",
"colorloop",
"finish_effect",
"stop_effect",
"stop_hue_effect",
],
"unique_id":"9_light_zigbee2mqtt"
};
@@ -752,9 +765,6 @@ describe('HomeAssistant extension', () => {
"topic":"zigbee2mqtt/bridge/state"
}
],
"away_mode_command_topic":"zigbee2mqtt/TS0601_thermostat/set/away_mode",
"away_mode_state_template":"{{ value_json.away_mode }}",
"away_mode_state_topic":"zigbee2mqtt/TS0601_thermostat",
"current_temperature_template":"{{ value_json.local_temperature }}",
"current_temperature_topic":"zigbee2mqtt/TS0601_thermostat",
"device":{
@@ -766,17 +776,18 @@ describe('HomeAssistant extension', () => {
"name":"TS0601_thermostat",
"sw_version":null
},
"hold_command_topic":"zigbee2mqtt/TS0601_thermostat/set/preset",
"hold_modes":[
"preset_mode_command_topic":"zigbee2mqtt/TS0601_thermostat/set/preset",
"preset_modes":[
"schedule",
"manual",
"boost",
"complex",
"comfort",
"eco"
"eco",
"away"
],
"hold_state_template":"{{ value_json.preset }}",
"hold_state_topic":"zigbee2mqtt/TS0601_thermostat",
"preset_mode_value_template":"{{ value_json.preset }}",
"preset_mode_state_topic":"zigbee2mqtt/TS0601_thermostat",
"json_attributes_topic":"zigbee2mqtt/TS0601_thermostat",
"max_temp":"35",
"min_temp":"5",
@@ -814,6 +825,10 @@ describe('HomeAssistant extension', () => {
set_position_topic: 'zigbee2mqtt/smart vent/set',
set_position_template: '{ "position": {{ position }} }',
position_template: '{{ value_json.position }}',
state_topic: 'zigbee2mqtt/smart vent',
value_template: `{{ value_json.state }}`,
state_open: 'OPEN',
state_closed: 'CLOSE',
json_attributes_topic: 'zigbee2mqtt/smart vent',
name: 'smart vent',
unique_id: '0x0017880104e45551_cover_zigbee2mqtt',
@@ -834,6 +849,39 @@ describe('HomeAssistant extension', () => {
{ retain: true, qos: 0 },
expect.any(Function),
);
payload = {
"availability": [{ "topic": "zigbee2mqtt/bridge/state" }],
"command_topic": "zigbee2mqtt/zigfred_plus/l6/set",
"device": {
"identifiers": ["zigbee2mqtt_0xf4ce368a38be56a1"],
"manufacturer": "Siglis",
"model": "zigfred plus smart in-wall switch (ZFP-1A-CH)",
"name": "zigfred_plus",
"sw_version": null
},
"json_attributes_topic": "zigbee2mqtt/zigfred_plus/l6",
"name": "zigfred_plus_l6",
"position_template": "{{ value_json.position }}",
"position_topic": "zigbee2mqtt/zigfred_plus/l6",
"set_position_template": "{ \"position_l6\": {{ position }} }",
"set_position_topic": "zigbee2mqtt/zigfred_plus/l6/set",
"state_closed": "CLOSE",
"state_open": "OPEN",
"state_topic": "zigbee2mqtt/zigfred_plus/l6",
"tilt_command_topic": "zigbee2mqtt/zigfred_plus/l6/set/tilt",
"tilt_status_template": "{{ value_json.tilt }}",
"tilt_status_topic": "zigbee2mqtt/zigfred_plus/l6",
"unique_id": "0xf4ce368a38be56a1_cover_l6_zigbee2mqtt",
"value_template": "{{ value_json.state }}"
}
expect(MQTT.publish).toHaveBeenCalledWith(
'homeassistant/cover/0xf4ce368a38be56a1/cover_l6/config',
stringify(payload),
{ retain: true, qos: 0 },
expect.any(Function),
);
});
it('Should discover devices with custom homeassistant_discovery_topic', async () => {
@@ -912,7 +960,7 @@ describe('HomeAssistant extension', () => {
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bulb_color',
stringify({"color":{"hue": 0, "saturation": 100, "h": 0, "s": 100}, "color_mode": "hs", "linkquality": null, "state": null, "update_available": null, "update": {"state": null}}),
stringify({"color":{"hue": 0, "saturation": 100, "h": 0, "s": 100}, "color_mode": "hs", "linkquality": null, "state": null, "update_available": null, "power_on_behavior":null, "update": {"state": null, "installed_version": -1, "latest_version": -1}}),
{ retain: false, qos: 0 },
expect.any(Function),
);
@@ -928,7 +976,7 @@ describe('HomeAssistant extension', () => {
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bulb_color',
stringify({"color": {"x": 0.4576,"y": 0.41}, "color_mode": "xy", "linkquality": null,"state": null, "update_available": null, "update": {"state": null}}),
stringify({"color": {"x": 0.4576,"y": 0.41}, "color_mode": "xy", "linkquality": null,"state": null, "update_available": null, "power_on_behavior":null, "update": {"state": null, "installed_version": -1, "latest_version": -1}}),
{ retain: false, qos: 0 },
expect.any(Function),
);
@@ -944,7 +992,7 @@ describe('HomeAssistant extension', () => {
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bulb_color',
stringify({"linkquality": null,"state": "ON", "update_available": null, "update": {"state": null}}),
stringify({"linkquality": null,"state": "ON", "update_available": null, "power_on_behavior": null, "update": {"state": null, "installed_version": -1, "latest_version": -1}}),
{ retain: false, qos: 0 },
expect.any(Function),
);
@@ -1032,16 +1080,22 @@ describe('HomeAssistant extension', () => {
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bulb',
stringify({"state":"ON","brightness":50,"color_temp":370,"linkquality":99,"power_on_behavior":null, "update_available": null, "update": {"state": null}}),
stringify({"state":"ON","brightness":50,"color_temp":370,"linkquality":99,"power_on_behavior":null, "update_available": null, "update": {"state": null, "installed_version": -1, "latest_version": -1}}),
{ retain: true, qos: 0 },
expect.any(Function)
);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/remote',
stringify({"action":null,"action_duration":null,"battery":null,"brightness":255,"linkquality":null, "update_available": null, "update": {"state": null}}),
stringify({"action":null,"action_duration":null,"battery":null,"brightness":255,"linkquality":null, "update_available": null, "update": {"state": null, "installed_version": -1, "latest_version": -1}}),
{ retain: true, qos: 0 },
expect.any(Function)
);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/group_1',
stringify({"state":'ON'}),
{ retain: false, qos: 0 },
expect.any(Function)
);
});
it('Should send all status when home assistant comes online', async () => {
@@ -1056,13 +1110,13 @@ describe('HomeAssistant extension', () => {
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bulb',
stringify({"state":"ON","brightness":50,"color_temp":370,"linkquality":99,"power_on_behavior":null, "update_available": null, "update": {"state": null}}),
stringify({"state":"ON","brightness":50,"color_temp":370,"linkquality":99,"power_on_behavior":null, "update_available": null, "update": {"state": null, "installed_version": -1, "latest_version": -1}}),
{ retain: true, qos: 0 },
expect.any(Function)
);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/remote',
stringify({"action":null,"action_duration":null,"battery":null,"brightness":255,"linkquality":null, "update_available": null, "update": {"state": null}}),
stringify({"action":null,"action_duration":null,"battery":null,"brightness":255,"linkquality":null, "update_available": null, "update": {"state": null, "installed_version": -1, "latest_version": -1}}),
{ retain: true, qos: 0 },
expect.any(Function)
);
@@ -1178,6 +1232,8 @@ describe('HomeAssistant extension', () => {
MQTT.publish.mockClear();
MQTT.events.message('zigbee2mqtt/bridge/request/device/rename', stringify({"from": "weather_sensor", "to": "weather_sensor_renamed","homeassistant_rename":true}));
await flushPromises();
jest.runOnlyPendingTimers();
await flushPromises();
const payload = {
'unit_of_measurement': '°C',
@@ -1240,6 +1296,8 @@ describe('HomeAssistant extension', () => {
MQTT.publish.mockClear();
MQTT.events.message('zigbee2mqtt/bridge/request/group/rename', stringify({"from": "ha_discovery_group", "to": "ha_discovery_group_new","homeassistant_rename":true}));
await flushPromises();
jest.runOnlyPendingTimers();
await flushPromises();
const payload = {
"availability":[{"topic":"zigbee2mqtt/bridge/state"}],
@@ -1262,6 +1320,19 @@ describe('HomeAssistant extension', () => {
"xy",
"color_temp"
],
"effect":true,
"effect_list":[
"blink",
"breathe",
"okay",
"channel_change",
"candle",
"fireplace",
"colorloop",
"finish_effect",
"stop_effect",
"stop_hue_effect",
],
"unique_id":"9_light_zigbee2mqtt"
};
@@ -1325,7 +1396,7 @@ describe('HomeAssistant extension', () => {
"payload_on":true,
"payload_off":false,
"value_template":`{{ value_json['update']['state'] == "available" }}`,
"enabled_by_default": true,
"enabled_by_default": false,
"state_topic":"zigbee2mqtt/bulb",
"json_attributes_topic":"zigbee2mqtt/bulb",
"name":"bulb update available",
@@ -1354,7 +1425,7 @@ describe('HomeAssistant extension', () => {
it('Should discover trigger when click is published', async () => {
const discovered = MQTT.publish.mock.calls.filter((c) => c[0].includes('0x0017880104e45520')).map((c) => c[0]);
expect(discovered.length).toBe(5);
expect(discovered.length).toBe(7);
expect(discovered).toContain('homeassistant/sensor/0x0017880104e45520/click/config');
expect(discovered).toContain('homeassistant/sensor/0x0017880104e45520/action/config');
@@ -1429,21 +1500,21 @@ describe('HomeAssistant extension', () => {
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/button',
stringify({action: "single", click: "single", battery: null, linkquality: null, voltage: null}),
stringify({action: "single", click: "single", battery: null, linkquality: null, voltage: null, power_outage_count: null, device_temperature: null}),
{ retain: false, qos: 0 },
expect.any(Function),
);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/button',
stringify({action: "", battery: null, linkquality: null, voltage: null, click: null}),
stringify({action: "", battery: null, linkquality: null, voltage: null, click: null, power_outage_count: null, device_temperature: null}),
{ retain: false, qos: 0 },
expect.any(Function),
);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/button',
stringify({click: "", action: null, battery: null, linkquality: null, voltage: null}),
stringify({click: "", action: null, battery: null, linkquality: null, voltage: null, power_outage_count: null, device_temperature: null}),
{ retain: false, qos: 0 },
expect.any(Function),
);
@@ -1530,7 +1601,7 @@ describe('HomeAssistant extension', () => {
await resetExtension();
const discovered = MQTT.publish.mock.calls.filter((c) => c[0].includes('0x0017880104e45520')).map((c) => c[0]);
expect(discovered.length).toBe(4);
expect(discovered.length).toBe(6);
expect(discovered).toContain('homeassistant/sensor/0x0017880104e45520/action/config');
expect(discovered).toContain('homeassistant/sensor/0x0017880104e45520/battery/config');
expect(discovered).toContain('homeassistant/sensor/0x0017880104e45520/linkquality/config');
@@ -1541,7 +1612,7 @@ describe('HomeAssistant extension', () => {
await resetExtension();
const discovered = MQTT.publish.mock.calls.filter((c) => c[0].includes('0x0017880104e45520')).map((c) => c[0]);
expect(discovered.length).toBe(3);
expect(discovered.length).toBe(5);
expect(discovered).not.toContain('homeassistant/sensor/0x0017880104e45520/click/config');
expect(discovered).not.toContain('homeassistant/sensor/0x0017880104e45520/action/config');
@@ -1586,7 +1657,7 @@ describe('HomeAssistant extension', () => {
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/button',
stringify({action: "single", "battery":null,"linkquality":null,"voltage":null}),
stringify({action: "single", "battery":null,"linkquality":null,"voltage":null, "power_outage_count": null, "device_temperature": null}),
{ retain: false, qos: 0 },
expect.any(Function),
);
@@ -1623,10 +1694,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', click: null, battery: null, linkquality: null, voltage: null});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({action: 'single', click: null, battery: null, linkquality: null, voltage: null, power_outage_count: null, device_temperature: 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: '', click: null, battery: null, linkquality: null, voltage: null});
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({action: '', click: null, battery: null, linkquality: null, voltage: null, power_outage_count: null, device_temperature: 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');
@@ -1778,6 +1849,19 @@ describe('HomeAssistant extension', () => {
"xy",
"color_temp"
],
"effect":true,
"effect_list":[
"blink",
"breathe",
"okay",
"channel_change",
"candle",
"fireplace",
"colorloop",
"finish_effect",
"stop_effect",
"stop_hue_effect",
],
"unique_id":"9_light_zigbee2mqtt"
};
@@ -1814,6 +1898,19 @@ describe('HomeAssistant extension', () => {
"xy",
"color_temp"
],
"effect":true,
"effect_list":[
"blink",
"breathe",
"okay",
"channel_change",
"candle",
"fireplace",
"colorloop",
"finish_effect",
"stop_effect",
"stop_hue_effect",
],
"unique_id":"9_light_zigbee2mqtt"
};
@@ -1825,6 +1922,60 @@ describe('HomeAssistant extension', () => {
);
});
it('Should discover with availability offline when device is disabled', async () => {
settings.set(['devices', '0x000b57fffec6a5b2', 'disabled'], true);
await resetExtension();
const payload = {
"availability":[
{
"topic":"zigbee2mqtt/bridge/state",
"value_template": `{{ "offline" }}`,
}
],
"brightness":true,
"brightness_scale":254,
"color_mode":true,
"command_topic":"zigbee2mqtt/bulb/set",
"device":{
"identifiers":[
"zigbee2mqtt_0x000b57fffec6a5b2"
],
"manufacturer":"IKEA",
"model":"TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white (LED1545G12)",
"name":"bulb",
"sw_version":null
},
"effect":true,
"effect_list":[
"blink",
"breathe",
"okay",
"channel_change",
"finish_effect",
"stop_effect"
],
"json_attributes_topic":"zigbee2mqtt/bulb",
"max_mireds":454,
"min_mireds":250,
"name":"bulb",
"schema":"json",
"state_topic":"zigbee2mqtt/bulb",
"supported_color_modes":[
"color_temp"
],
"unique_id":"0x000b57fffec6a5b2_light_zigbee2mqtt"
};
expect(MQTT.publish).toHaveBeenCalledWith(
'homeassistant/light/0x000b57fffec6a5b2/light/config',
stringify(payload),
{ retain: true, qos: 0 },
expect.any(Function),
);
});
it('Should discover last_seen when enabled', async () => {
settings.set(['advanced', 'last_seen'], 'ISO_8601');
await resetExtension();
+26 -13
View File
@@ -25,6 +25,7 @@ describe('Logger', () => {
it('Create log directory', () => {
const logger = require('../lib/util/logger').default;
logger.init();
logger.logOutput();
const dirs = fs.readdirSync(dir.name);
expect(dirs.length).toBe(1);
@@ -32,6 +33,7 @@ describe('Logger', () => {
it('Should cleanup', () => {
const logger = require('../lib/util/logger').default;
logger.init();
logger.logOutput();
for (const d of fs.readdirSync(dir.name)) {
@@ -49,6 +51,7 @@ describe('Logger', () => {
it('Should not cleanup when there is no timestamp set', () => {
const logger = require('../lib/util/logger').default;
logger.init();
logger.logOutput();
for (let i = 30; i < 40; i++) {
fs.mkdirSync(path.join(dir.name, `log_${i}`));
@@ -62,6 +65,7 @@ describe('Logger', () => {
it('Set and get log level', () => {
const logger = require('../lib/util/logger').default;
logger.init();
logger.logOutput();
logger.setLevel('debug');
expect(logger.getLevel()).toBe('debug');
@@ -74,23 +78,26 @@ describe('Logger', () => {
}
const logger = require('../lib/util/logger').default;
expect(logger.winston.transports.length).toBe(2);
logger.init();
expect(logger.winston().transports.length).toBe(2);
logger.addTransport(new DummyTransport());
expect(logger.winston.transports.length).toBe(3);
expect(logger.winston().transports.length).toBe(3);
});
it('Set and get log level warn <-> warning', () => {
const logger = require('../lib/util/logger').default;
logger.init();
logger.logOutput();
logger.setLevel('warn');
expect(logger.winston.transports[0].level).toBe('warning');
expect(logger.winston().transports[0].level).toBe('warning');
expect(logger.getLevel()).toBe('warn');
});
it('Logger should be console and file by default', () => {
const logger = require('../lib/util/logger').default;
logger.init();
logger.logOutput();
const pipes = logger.winston._readableState.pipes;
const pipes = logger.winston()._readableState.pipes;
expect(pipes.length).toBe(2);
expect(pipes[0].constructor.name).toBe('Console');
expect(pipes[0].silent).toBe(false);
@@ -101,8 +108,9 @@ describe('Logger', () => {
it('Logger can be file only', () => {
settings.set(['advanced', 'log_output'], ['file']);
const logger = require('../lib/util/logger').default;
logger.init();
logger.logOutput();
const pipes = logger.winston._readableState.pipes;
const pipes = logger.winston()._readableState.pipes;
expect(pipes.length).toBe(2);
expect(pipes[0].constructor.name).toBe('Console');
expect(pipes[0].silent).toBe(true);
@@ -113,8 +121,9 @@ describe('Logger', () => {
it('Logger can be console only', () => {
settings.set(['advanced', 'log_output'], ['console']);
const logger = require('../lib/util/logger').default;
logger.init();
logger.logOutput();
const pipes = logger.winston._readableState.pipes;
const pipes = logger.winston()._readableState.pipes;
expect(pipes.constructor.name).toBe('Console');
expect(pipes.silent).toBe(false);
});
@@ -122,8 +131,9 @@ describe('Logger', () => {
it('Logger can be nothing', () => {
settings.set(['advanced', 'log_output'], []);
const logger = require('../lib/util/logger').default;
logger.init();
logger.logOutput();
const pipes = logger.winston._readableState.pipes;
const pipes = logger.winston()._readableState.pipes;
expect(pipes.constructor.name).toBe('Console');
expect(pipes.silent).toBe(true);
});
@@ -131,8 +141,9 @@ describe('Logger', () => {
it('Should allow to disable log rotation', () => {
settings.set(['advanced', 'log_rotation'], false);
const logger = require('../lib/util/logger').default;
logger.init();
logger.logOutput();
const pipes = logger.winston._readableState.pipes;
const pipes = logger.winston()._readableState.pipes;
expect(pipes[1].constructor.name).toBe('File');
expect(pipes[1].maxFiles).toBeNull();
expect(pipes[1].tailable).toBeFalsy();
@@ -142,6 +153,7 @@ describe('Logger', () => {
it('Should allow to symlink logs to current directory', () => {
settings.set(['advanced', 'log_symlink_current'], true);
let logger = require('../lib/util/logger').default;
logger.init();
logger.logOutput();
expect(fs.readdirSync(dir.name).includes('current')).toBeTruthy()
@@ -151,23 +163,24 @@ describe('Logger', () => {
it('Log', () => {
const logger = require('../lib/util/logger').default;
const warn = jest.spyOn(logger.winston, 'warning');
logger.init();
const warn = jest.spyOn(logger.winston(), 'warning');
logger.warn('warn');
expect(warn).toHaveBeenCalledWith('warn');
const debug = jest.spyOn(logger.winston, 'debug');
const debug = jest.spyOn(logger.winston(), 'debug');
logger.debug('debug');
expect(debug).toHaveBeenCalledWith('debug');
const warning = jest.spyOn(logger.winston, 'warning');
const warning = jest.spyOn(logger.winston(), 'warning');
logger.warning('warning');
expect(warning).toHaveBeenCalledWith('warning');
const info = jest.spyOn(logger.winston, 'info');
const info = jest.spyOn(logger.winston(), 'info');
logger.info('info');
expect(info).toHaveBeenCalledWith('info');
const error = jest.spyOn(logger.winston, 'error');
const error = jest.spyOn(logger.winston(), 'error');
logger.error('error');
expect(error).toHaveBeenCalledWith('error');
});
+17 -2
View File
@@ -102,7 +102,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, power_on_behavior, 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"}]};
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, power_on_behavior, 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), power_on_behavior, 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, power_outage_count, 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);
/**
@@ -276,7 +276,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, power_on_behavior, 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 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, power_on_behavior, 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), power_on_behavior, 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, power_outage_count, 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);
});
@@ -292,4 +292,19 @@ describe('Networkmap', () => {
{retain: false, qos: 0}, expect.any(Function)
);
});
it('Should exclude disabled devices from networkmap', async () => {
settings.set(['devices', '0x000b57fffec6a5b2', 'disabled'], true);
mock();
MQTT.publish.mockClear();
MQTT.events.message('zigbee2mqtt/bridge/request/networkmap', stringify({type: 'raw', routes: true}));
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
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":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":"Hue Go","model":"7146060PH","supports":"light (state, brightness, color_temp, color_temp_startup, color_xy, color_hs), power_on_behavior, 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, power_outage_count, 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);
});
});
+4 -2
View File
@@ -48,6 +48,8 @@ describe('On event', () => {
expect(call[0]).toBe('start')
expect(call[1]).toStrictEqual({})
expect(call[2]).toBe(device);
expect(call[3]).toStrictEqual(settings.getDevice(device.ieeeAddr));
expect(call[4]).toStrictEqual({});
});
it('Should call with stop event', async () => {
@@ -66,7 +68,7 @@ describe('On event', () => {
await zigbeeHerdsman.events.deviceAnnounce({device});
await flushPromises();
expect(mockOnEvent).toHaveBeenCalledTimes(1);
expect(mockOnEvent).toHaveBeenCalledWith('deviceAnnounce', {device}, device, settings.getDevice(device.ieeeAddr));
expect(mockOnEvent).toHaveBeenCalledWith('deviceAnnounce', {device}, device, settings.getDevice(device.ieeeAddr), {});
});
it('Should call index onEvent with zigbee event', async () => {
@@ -74,6 +76,6 @@ describe('On event', () => {
await zigbeeHerdsman.events.deviceAnnounce({device});
await flushPromises();
expect(zigbeeHerdsmanConverters.onEvent).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsmanConverters.onEvent).toHaveBeenCalledWith('deviceAnnounce', {device}, device);
expect(zigbeeHerdsmanConverters.onEvent).toHaveBeenCalledWith('deviceAnnounce', {device}, device, settings.getDevice(device.ieeeAddr), {});
});
});
+23 -17
View File
@@ -1,3 +1,5 @@
const path = require('path');
const data = require('./stub/data');
const logger = require('./stub/logger');
const zigbeeHerdsman = require('./stub/zigbeeHerdsman');
@@ -11,6 +13,7 @@ const zigbeeOTA = require('zigbee-herdsman-converters/lib/ota/zigbeeOTA');
const spyUseIndexOverride = jest.spyOn(zigbeeOTA, 'useIndexOverride');
describe('OTA update', () => {
let controller;
@@ -33,6 +36,7 @@ describe('OTA update', () => {
jest.useFakeTimers();
controller = new Controller(jest.fn(), jest.fn());
await controller.start();
await jest.runOnlyPendingTimers();
await flushPromises();
});
@@ -68,6 +72,7 @@ describe('OTA update', () => {
mapped.ota.updateToLatest.mockImplementationOnce((a, b, onUpdate) => {
onUpdate(0, null);
onUpdate(10, 3600.2123);
return 90;
});
MQTT.events.message('zigbee2mqtt/bridge/request/device/ota_update/update', 'bulb');
@@ -95,7 +100,7 @@ describe('OTA update', () => {
);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bulb',
stringify({"update_available":false,"update":{"state":"idle"}}),
stringify({"update_available":false,"update":{"state":"idle","installed_version":90,"latest_version":90}}),
{retain: true, qos: 0}, expect.any(Function)
);
expect(MQTT.publish).toHaveBeenCalledWith(
@@ -141,7 +146,7 @@ describe('OTA update', () => {
const mapped = zigbeeHerdsmanConverters.findByDevice(device)
mockClear(mapped);
mapped.ota.isUpdateAvailable.mockReturnValueOnce(false);
mapped.ota.isUpdateAvailable.mockReturnValueOnce({available: false, currentFileVersion: 10, otaFileVersion: 10});
MQTT.events.message('zigbee2mqtt/bridge/request/device/ota_update/check', "bulb");
await flushPromises();
expect(mapped.ota.isUpdateAvailable).toHaveBeenCalledTimes(1);
@@ -153,7 +158,7 @@ describe('OTA update', () => {
);
MQTT.publish.mockClear();
mapped.ota.isUpdateAvailable.mockReturnValueOnce(true);
mapped.ota.isUpdateAvailable.mockReturnValueOnce({available: true, currentFileVersion: 10, otaFileVersion: 12});
MQTT.events.message('zigbee2mqtt/bridge/request/device/ota_update/check', "bulb");
await flushPromises();
expect(mapped.ota.isUpdateAvailable).toHaveBeenCalledTimes(2);
@@ -246,7 +251,7 @@ describe('OTA update', () => {
const data = {imageType: 12382};
const mapped = zigbeeHerdsmanConverters.findByDevice(device)
mockClear(mapped);
mapped.ota.isUpdateAvailable.mockReturnValueOnce(true);
mapped.ota.isUpdateAvailable.mockReturnValueOnce({available: true, currentFileVersion: 10, otaFileVersion: 12});
const payload = {data, cluster: 'genOta', device, endpoint: device.getEndpoint(1), type: 'commandQueryNextImageRequest', linkquality: 10};
logger.info.mockClear();
await zigbeeHerdsman.events.message(payload);
@@ -255,7 +260,7 @@ describe('OTA update', () => {
expect(mapped.ota.isUpdateAvailable).toHaveBeenCalledWith(device, logger, {"imageType": 12382});
expect(logger.info).toHaveBeenCalledWith(`Update available for 'bulb'`);
expect(device.endpoints[0].commandResponse).toHaveBeenCalledTimes(1);
expect(device.endpoints[0].commandResponse).toHaveBeenCalledWith("genOta", "queryNextImageResponse", {"status": 0x95});
expect(device.endpoints[0].commandResponse).toHaveBeenCalledWith("genOta", "queryNextImageResponse", {"status": 0x98});
// Should not request again when device asks again after a short time
await zigbeeHerdsman.events.message(payload);
@@ -263,13 +268,13 @@ describe('OTA update', () => {
expect(mapped.ota.isUpdateAvailable).toHaveBeenCalledTimes(1);
logger.info.mockClear();
mapped.ota.isUpdateAvailable.mockReturnValueOnce(false);
mapped.ota.isUpdateAvailable.mockReturnValueOnce({available: false, currentFileVersion: 10, otaFileVersion: 10});
await zigbeeHerdsman.events.message(payload);
await flushPromises();
expect(logger.info).not.toHaveBeenCalledWith(`Update available for 'bulb'`);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bulb',
stringify({"update_available":true,"update":{"state":"available"}}),
stringify({"update_available":true,"update":{"state":"available","installed_version":10,"latest_version":12}}),
{retain: true, qos: 0}, expect.any(Function)
);
});
@@ -302,7 +307,7 @@ describe('OTA update', () => {
const data = {imageType: 12382};
const mapped = zigbeeHerdsmanConverters.findByDevice(device)
mockClear(mapped);
mapped.ota.isUpdateAvailable.mockReturnValueOnce(false);
mapped.ota.isUpdateAvailable.mockReturnValueOnce({available: false, currentFileVersion: 13, otaFileVersion: 13});
const payload = {data, cluster: 'genOta', device, endpoint: device.getEndpoint(1), type: 'commandQueryNextImageRequest', linkquality: 10};
logger.info.mockClear();
await zigbeeHerdsman.events.message(payload);
@@ -310,10 +315,10 @@ describe('OTA update', () => {
expect(mapped.ota.isUpdateAvailable).toHaveBeenCalledTimes(1);
expect(mapped.ota.isUpdateAvailable).toHaveBeenCalledWith(device, logger, {"imageType": 12382});
expect(device.endpoints[0].commandResponse).toHaveBeenCalledTimes(1);
expect(device.endpoints[0].commandResponse).toHaveBeenCalledWith("genOta", "queryNextImageResponse", {"status": 0x95});
expect(device.endpoints[0].commandResponse).toHaveBeenCalledWith("genOta", "queryNextImageResponse", {"status": 0x98});
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bulb',
stringify({"update_available":false,"update":{"state":"idle"}}),
stringify({"update_available":false,"update":{"state":"idle","installed_version": 13, "latest_version": 13}}),
{retain: true, qos: 0}, expect.any(Function)
);
});
@@ -324,7 +329,7 @@ describe('OTA update', () => {
const data = {imageType: 12382};
const mapped = zigbeeHerdsmanConverters.findByDevice(device)
mockClear(mapped);
mapped.ota.isUpdateAvailable.mockReturnValueOnce(true);
mapped.ota.isUpdateAvailable.mockReturnValueOnce({available: true, currentFileVersion: 10, otaFileVersion: 13});
const payload = {data, cluster: 'genOta', device, endpoint: device.getEndpoint(1), type: 'commandQueryNextImageRequest', linkquality: 10};
logger.info.mockClear();
await zigbeeHerdsman.events.message(payload);
@@ -342,15 +347,15 @@ describe('OTA update', () => {
expect(device.endpoints[0].commandResponse).toHaveBeenCalledWith("genOta", "queryNextImageResponse", {"status": 152});
});
it('Shouldnt respond with NO_IMAGE_AVAILABLE when not supporting OTA and device has no OTA endpoint', async () => {
it('Should respond with NO_IMAGE_AVAILABLE when not supporting OTA and device has no OTA endpoint to standard endpoint', async () => {
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();
await zigbeeHerdsman.events.message(payload);
await flushPromises();
expect(device.endpoints[0].commandResponse).toHaveBeenCalledTimes(0);
expect(logger.error).toHaveBeenCalledTimes(0);
expect(device.endpoints[0].commandResponse).toHaveBeenCalledTimes(1);
expect(device.endpoints[0].commandResponse).toHaveBeenCalledWith("genOta", "queryNextImageResponse", {"status": 152});
});
it('Legacy api: Should OTA update a device', async () => {
@@ -369,6 +374,7 @@ describe('OTA update', () => {
mapped.ota.updateToLatest.mockImplementationOnce((a, b, onUpdate) => {
onUpdate(0, null);
onUpdate(10, 3600);
return 91;
});
MQTT.events.message('zigbee2mqtt/bridge/ota_update/update', 'bulb');
@@ -411,7 +417,7 @@ describe('OTA update', () => {
mockClear(mapped);
logger.info.mockClear();
mapped.ota.isUpdateAvailable.mockReturnValueOnce(false);
mapped.ota.isUpdateAvailable.mockReturnValueOnce({available: false, currentFileVersion: 13, otaFileVersion: 13});
MQTT.events.message('zigbee2mqtt/bridge/ota_update/check', 'bulb');
await flushPromises();
expect(mapped.ota.isUpdateAvailable).toHaveBeenCalledTimes(1);
@@ -419,7 +425,7 @@ describe('OTA update', () => {
expect(logger.info).toHaveBeenCalledWith(`No update available for 'bulb'`);
logger.info.mockClear();
mapped.ota.isUpdateAvailable.mockReturnValueOnce(true);
mapped.ota.isUpdateAvailable.mockReturnValueOnce({available: true, currentFileVersion: 13, otaFileVersion: 15});
MQTT.events.message('zigbee2mqtt/bridge/ota_update/check', 'bulb');
await flushPromises();
expect(mapped.ota.isUpdateAvailable).toHaveBeenCalledTimes(2);
@@ -468,7 +474,7 @@ describe('OTA update', () => {
it('Set zigbee_ota_override_index_location', async () => {
settings.set(['ota', 'zigbee_ota_override_index_location'], 'local.index.json');
await resetExtension();
expect(spyUseIndexOverride).toHaveBeenCalledWith(data.mockDir + '/local.index.json');
expect(spyUseIndexOverride).toHaveBeenCalledWith(path.join(data.mockDir, 'local.index.json'));
spyUseIndexOverride.mockClear();
settings.set(['ota', 'zigbee_ota_override_index_location'], 'http://my.site/index.json');
+16 -4
View File
@@ -507,6 +507,18 @@ describe('Publish', () => {
expect(endpoint3.read).toHaveBeenCalledWith('genOnOff', ['onOff']);
});
it('Should handle get with multiple cover endpoints', async () => {
const device = zigbeeHerdsman.devices.zigfred_plus;
const endpoint11 = device.getEndpoint(11);
const endpoint12 = device.getEndpoint(12);
await MQTT.events.message('zigbee2mqtt/zigfred_plus/get', stringify({state_l6: '', state_l7: ''}));
await flushPromises();
expect(endpoint11.read).toHaveBeenCalledTimes(1);
expect(endpoint11.read).toHaveBeenCalledWith('closuresWindowCovering', ['currentPositionLiftPercentage']);
expect(endpoint12.read).toHaveBeenCalledTimes(1);
expect(endpoint12.read).toHaveBeenCalledWith('closuresWindowCovering', ['currentPositionLiftPercentage']);
});
it('Should log error when device has no such endpoint (via topic)', async () => {
const device = zigbeeHerdsman.devices.QBKG03LM;
const endpoint2 = device.getEndpoint(2);
@@ -919,11 +931,11 @@ describe('Publish', () => {
expect(endpoint.command).toHaveBeenCalledTimes(3);
expect(endpoint.command.mock.calls[0]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 50, transtime: 0}, {}]);
expect(endpoint.command.mock.calls[1]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 0, transtime: 0}, {}]);
expect(endpoint.command.mock.calls[2]).toEqual(["genOnOff", "on", {}, {}]);
expect(endpoint.command.mock.calls[2]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 50, transtime: 0}, {}]);
expect(MQTT.publish).toHaveBeenCalledTimes(3);
expect(MQTT.publish.mock.calls[0]).toEqual(["zigbee2mqtt/bulb_color", stringify({state: 'ON', brightness: 50}), {"qos": 0, "retain": false}, expect.any(Function)]);
expect(MQTT.publish.mock.calls[1]).toEqual(["zigbee2mqtt/bulb_color", stringify({state: 'OFF', brightness: 0}), {"qos": 0, "retain": false}, expect.any(Function)]);
expect(MQTT.publish.mock.calls[2]).toEqual(["zigbee2mqtt/bulb_color", stringify({state: 'ON', brightness: 1}), {"qos": 0, "retain": false}, expect.any(Function)]);
expect(MQTT.publish.mock.calls[2]).toEqual(["zigbee2mqtt/bulb_color", stringify({state: 'ON', brightness: 50}), {"qos": 0, "retain": false}, expect.any(Function)]);
});
it('Should turn device off when brightness 0 is send with transition', async () => {
@@ -938,11 +950,11 @@ describe('Publish', () => {
expect(endpoint.command).toHaveBeenCalledTimes(3);
expect(endpoint.command.mock.calls[0]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 50, transtime: 0}, {}]);
expect(endpoint.command.mock.calls[1]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 0, transtime: 30}, {}]);
expect(endpoint.command.mock.calls[2]).toEqual(["genOnOff", "on", {}, {}]);
expect(endpoint.command.mock.calls[2]).toEqual(["genLevelCtrl", "moveToLevelWithOnOff", {level: 50, transtime: 0}, {}]);
expect(MQTT.publish).toHaveBeenCalledTimes(3);
expect(MQTT.publish.mock.calls[0]).toEqual(["zigbee2mqtt/bulb_color", stringify({state: 'ON', brightness: 50}), {"qos": 0, "retain": false}, expect.any(Function)]);
expect(MQTT.publish.mock.calls[1]).toEqual(["zigbee2mqtt/bulb_color", stringify({state: 'OFF', brightness: 0}), {"qos": 0, "retain": false}, expect.any(Function)]);
expect(MQTT.publish.mock.calls[2]).toEqual(["zigbee2mqtt/bulb_color", stringify({state: 'ON', brightness: 1}), {"qos": 0, "retain": false}, expect.any(Function)]);
expect(MQTT.publish.mock.calls[2]).toEqual(["zigbee2mqtt/bulb_color", stringify({state: 'ON', brightness: 50}), {"qos": 0, "retain": false}, expect.any(Function)]);
});
it('Should allow to set color via hue and saturation', async () => {
+10 -8
View File
@@ -16,6 +16,8 @@ describe('Receive', () => {
jest.useFakeTimers();
controller = new Controller(jest.fn(), jest.fn());
await controller.start();
await jest.runOnlyPendingTimers();
await flushPromises();
});
beforeEach(async () => {
@@ -84,7 +86,7 @@ describe('Receive', () => {
await zigbeeHerdsman.events.message({data: {currentPositionLiftPercentage: 90, currentPositionTiltPercentage: 80}, cluster: 'closuresWindowCovering', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10});
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/J1_cover', stringify({position: 10, tilt: 20}), {retain: false, qos: 0}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/J1_cover', stringify({position: 10, tilt: 20, state: 'OPEN'}), {retain: false, qos: 0}, expect.any(Function));
// Inverted
MQTT.publish.mockClear();
@@ -92,7 +94,7 @@ describe('Receive', () => {
await zigbeeHerdsman.events.message({data: {currentPositionLiftPercentage: 90, currentPositionTiltPercentage: 80}, cluster: 'closuresWindowCovering', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10});
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/J1_cover', stringify({position: 90, tilt: 80}), {retain: false, qos: 0}, expect.any(Function));
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/J1_cover', stringify({position: 90, tilt: 80, state: 'OPEN'}), {retain: false, qos: 0}, expect.any(Function));
});
it('Should allow to disable the legacy integration', async () => {
@@ -242,15 +244,15 @@ describe('Receive', () => {
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 1, "retain": false});
});
it('Should handle a zigbee message with voltage 3010', async () => {
it('Should handle a zigbee message with voltage 2990', async () => {
const device = zigbeeHerdsman.devices.WXKG02LM_rev1;
const data = {'65281': {'1': 3010}}
const data = {'65281': {'1': 2990}}
const payload = {data, cluster: 'genBasic', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10};
await zigbeeHerdsman.events.message(payload);
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/button_double_key');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({battery: 100, voltage: 3010});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({battery: 93, voltage: 2990});
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false});
});
@@ -262,7 +264,7 @@ describe('Receive', () => {
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/occupancy_sensor');
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({'battery': 100, 'illuminance': 381, "illuminance_lux": 381, 'voltage': 3045, 'temperature': 19});
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({'battery': 100, 'illuminance': 381, "illuminance_lux": 381, 'voltage': 3045, 'device_temperature': 19, 'power_outage_count': 34});
expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false});
});
@@ -419,7 +421,7 @@ describe('Receive', () => {
const data = {instantaneousDemand:496,currentSummDelivered:[0,6648]}
const SP600_NEW = zigbeeHerdsman.devices.SP600_NEW;
await zigbeeHerdsman.events.message({data, cluster: 'seMetering', device: SP600_NEW, endpoint: SP600_NEW.getEndpoint(1), type: 'attributeReport', linkquality: 10});
await zigbeeHerdsman.events.message({data, cluster: 'seMetering', device: SP600_NEW, endpoint: SP600_NEW.getEndpoint(1), type: 'attributeReport', linkquality: 10, meta: {zclTransactionSequenceNumber: 1}});
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/SP600_NEW');
@@ -427,7 +429,7 @@ describe('Receive', () => {
MQTT.publish.mockClear();
const SP600_OLD = zigbeeHerdsman.devices.SP600_OLD;
await zigbeeHerdsman.events.message({data, cluster: 'seMetering', device: SP600_OLD, endpoint: SP600_OLD.getEndpoint(1), type: 'attributeReport', linkquality: 10});
await zigbeeHerdsman.events.message({data, cluster: 'seMetering', device: SP600_OLD, endpoint: SP600_OLD.getEndpoint(1), type: 'attributeReport', linkquality: 10, meta: {zclTransactionSequenceNumber: 2}});
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledTimes(1);
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/SP600_OLD');
+95 -13
View File
@@ -39,6 +39,7 @@ describe('Settings', () => {
beforeEach(() => {
remove(configurationFile);
remove(secretFile);
remove(devicesFile);
remove(groupsFile);
clearEnvironmentVariables();
@@ -66,20 +67,42 @@ describe('Settings', () => {
it('Should apply environment variables', () => {
process.env['ZIGBEE2MQTT_CONFIG_SERIAL_DISABLE_LED'] = 'true';
process.env['ZIGBEE2MQTT_CONFIG_ADVANCED_SOFT_RESET_TIMEOUT'] = 1;
process.env['ZIGBEE2MQTT_CONFIG_ADVANCED_OUTPUT'] = 'csvtest';
process.env['ZIGBEE2MQTT_CONFIG_ADVANCED_OUTPUT'] = 'attribute_and_json';
process.env['ZIGBEE2MQTT_CONFIG_ADVANCED_LOG_OUTPUT'] = '["console"]';
process.env['ZIGBEE2MQTT_CONFIG_MAP_OPTIONS_GRAPHVIZ_COLORS_FILL'] = '{"enddevice": "#ff0000", "coordinator": "#00ff00", "router": "#0000ff"}';
process.env['ZIGBEE2MQTT_CONFIG_MQTT_BASE_TOPIC'] = 'testtopic';
process.env['ZIGBEE2MQTT_CONFIG_MQTT_SERVER'] = 'testserver';
process.env['ZIGBEE2MQTT_CONFIG_ADVANCED_NETWORK_KEY'] = 'GENERATE';
process.env['ZIGBEE2MQTT_CONFIG_DEVICES'] = 'devices.yaml';
const contentDevices = {
'0x00158d00018255df': {
friendly_name: '0x00158d00018255df',
retain: false,
},
};
write(configurationFile, {});
write(devicesFile, contentDevices);
expect(settings.validate()).toStrictEqual([]);
const s = settings.get();
const expected = objectAssignDeep.noMutate({}, settings.testing.defaults);
expected.devices = {};
expected.devices = {
'0x00158d00018255df': {
friendly_name: '0x00158d00018255df',
retain: false,
},
};
expected.groups = {};
expected.serial.disable_led = true;
expected.advanced.soft_reset_timeout = 1;
expected.advanced.output = 'csvtest';
expected.advanced.log_output = ["console"];
expected.advanced.output = 'attribute_and_json';
expected.map_options.graphviz.colors.fill = {enddevice: '#ff0000', coordinator: '#00ff00', router: '#0000ff'};
expected.mqtt.base_topic = 'testtopic';
expected.mqtt.server = 'testserver';
expected.advanced.network_key = 'GENERATE';
expect(s).toStrictEqual(expected);
});
@@ -100,6 +123,22 @@ describe('Settings', () => {
expect(actual).toStrictEqual(expected);
});
it('Should add devices even when devices exist empty', () => {
write(configurationFile, {devices: []});
settings.addDevice('0x12345678');
const actual = read(configurationFile);
const expected = {
devices: {
'0x12345678': {
friendly_name: '0x12345678',
},
},
};
expect(actual).toStrictEqual(expected);
});
it('Should read devices', () => {
const content = {
devices: {
@@ -171,6 +210,49 @@ describe('Settings', () => {
expect(read(secretFile)).toStrictEqual({...contentSecret, username: 'test123', network_key: [1,2,3,4]});
});
it('Should read ALL secrets form a separate file', () => {
const contentConfiguration = {
mqtt: {
server: '!secret server',
user: '!secret username',
password: '!secret.yaml password',
},
advanced: {
network_key: '!secret network_key',
}
};
const contentSecret = {
server: 'my.mqtt.server',
username: 'mysecretusername',
password: 'mysecretpassword',
network_key: [1,2,3],
};
write(secretFile, contentSecret, false);
write(configurationFile, contentConfiguration);
const expected = {
base_topic: 'zigbee2mqtt',
include_device_information: false,
force_disable_retain: false,
password: "mysecretpassword",
server: "my.mqtt.server",
user: "mysecretusername",
};
expect(settings.get().mqtt).toStrictEqual(expected);
expect(settings.get().advanced.network_key).toStrictEqual([1,2,3]);
settings.testing.write();
expect(read(configurationFile)).toStrictEqual(contentConfiguration);
expect(read(secretFile)).toStrictEqual(contentSecret);
settings.set(['mqtt', 'server'], 'not.secret.server');
expect(read(configurationFile)).toStrictEqual(contentConfiguration);
expect(read(secretFile)).toStrictEqual({...contentSecret, server: 'not.secret.server'});
});
it('Should read devices form a separate file', () => {
const contentConfiguration = {
devices: 'devices.yaml',
@@ -747,15 +829,15 @@ describe('Settings', () => {
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
});
it('Configuration friendly name cannot contain null char', async () => {
it('Configuration friendly name cannot contain control char', async () => {
write(configurationFile, {
...minimalConfig,
devices: {'0x0017880104e45519': {friendly_name: 'blaa/blaa' + String.fromCharCode(0), retain: false}},
devices: {'0x0017880104e45519': {friendly_name: 'blaa/blaa\u009f', retain: false}},
});
settings.reRead();
const error = `friendly_name is not allowed to contain null char`;
const error = `friendly_name is not allowed to contain control char`;
expect(settings.validate()).toEqual(expect.arrayContaining([error]));
});
@@ -838,7 +920,7 @@ describe('Settings', () => {
it('Frontend config', () => {
write(configurationFile, {...minimalConfig,
frontend: true,
frontend: true,
});
settings.reRead();
@@ -847,7 +929,7 @@ describe('Settings', () => {
it('Baudrate config', () => {
write(configurationFile, {...minimalConfig,
advanced: {baudrate: 20},
advanced: {baudrate: 20},
});
settings.reRead();
@@ -856,7 +938,7 @@ describe('Settings', () => {
it('ikea_ota_use_test_url config', () => {
write(configurationFile, {...minimalConfig,
advanced: {ikea_ota_use_test_url: true},
advanced: {ikea_ota_use_test_url: true},
});
settings.reRead();
@@ -865,7 +947,7 @@ describe('Settings', () => {
it('transmit_power config', () => {
write(configurationFile, {...minimalConfig,
experimental: {transmit_power: 1337},
experimental: {transmit_power: 1337},
});
settings.reRead();
@@ -874,7 +956,7 @@ describe('Settings', () => {
it('output config', () => {
write(configurationFile, {...minimalConfig,
experimental: {output: 'json'},
experimental: {output: 'json'},
});
settings.reRead();
@@ -883,7 +965,7 @@ describe('Settings', () => {
it('Baudrartsctste config', () => {
write(configurationFile, {...minimalConfig,
advanced: {rtscts: true},
advanced: {rtscts: true},
});
settings.reRead();
@@ -892,7 +974,7 @@ describe('Settings', () => {
it('Deprecated: Home Assistant config', () => {
write(configurationFile, {...minimalConfig,
homeassistant: {discovery_topic: 'new'},
homeassistant: {discovery_topic: 'new'},
advanced: {homeassistant_discovery_topic: 'old', homeassistant_status_topic: 'olds'},
});
+20
View File
@@ -153,6 +153,23 @@ function writeDefaultConfiguration() {
'0x0017880104e43559': {
friendly_name: 'U202DST600ZB'
},
'0xf4ce368a38be56a1': {
retain: false,
friendly_name: 'zigfred_plus',
front_surface_enabled: 'true',
dimmer_1_enabled: 'true',
dimmer_1_dimming_enabled: 'true',
dimmer_2_enabled: 'true',
dimmer_2_dimming_enabled: 'true',
dimmer_3_enabled: 'true',
dimmer_3_dimming_enabled: 'true',
dimmer_4_enabled: 'true',
dimmer_4_dimming_enabled: 'true',
cover_1_enabled: 'true',
cover_1_tilt_enabled: 'true',
cover_2_enabled: 'true',
cover_2_tilt_enabled: 'true',
},
'0x0017880104e44559': {
friendly_name: '3157100_thermostat',
},
@@ -243,6 +260,9 @@ const defaultState = {
"0x0017880104e45517": {
"brightness": 255
},
"1": {
'state': 'ON',
}
}
function getDefaultState() {
+1
View File
@@ -12,6 +12,7 @@ const callTransports = (level, message) => {
}
const mock = {
init: jest.fn(),
info: jest.fn().mockImplementation((msg) => callTransports('info', msg)),
warn: jest.fn().mockImplementation((msg) => callTransports('warn', msg)),
error: jest.fn().mockImplementation((msg) => callTransports('error', msg)),
+10 -2
View File
@@ -27,7 +27,11 @@ const clusters = {
'lightingColorCtrl': 768,
'closuresWindowCovering': 258,
'hvacThermostat': 513,
'msIlluminanceMeasurement': 1024,
'msTemperatureMeasurement': 1026,
'msRelativeHumidity': 1029,
'msSoilMoisture': 1032,
'msCO2': 1037
}
class Endpoint {
@@ -133,6 +137,7 @@ const TS0601_thermostat = new Device('EndDevice', '0x0017882104a44559', 6544,41
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 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');
const zigfred_plus = new Device('Router', '0xf4ce368a38be56a1', 6589, 0x129C, [new Endpoint(5, [0, 3, 4, 5, 6, 8, 0x0300, 0xFC42], [0xFC42], '0xf4ce368a38be56a1'), new Endpoint(7, [0, 3, 4, 5, 6, 8], [], '0xf4ce368a38be56a1'), new Endpoint(8, [0, 3, 4, 5, 6, 8], [], '0xf4ce368a38be56a1'), new Endpoint(9, [0, 3, 4, 5, 6, 8], [], '0xf4ce368a38be56a1'), new Endpoint(10, [0, 3, 4, 5, 6, 8], [], '0xf4ce368a38be56a1'), new Endpoint(11, [0, 3, 4, 5, 0x0102], [], '0xf4ce368a38be56a1'), new Endpoint(12, [0, 3, 4, 5, 0x0102], [], '0xf4ce368a38be56a1')], true, "Mains (single phase)", 'zigfred plus', false, 'Siglis');
const groups = {
'group_1': new Group(1, []),
@@ -188,7 +193,8 @@ const devices = {
'MKS-CM-W5': new Device('Router', '0x90fd9ffffe4b64ac', 33901, 4476, [new Endpoint(1, [0,4,3,5,10,258,13,19,6,1,1030,8,768,1027,1029,1026], [0,3,4,6,8,5], '0x90fd9ffffe4b64aa', [], {})], true, "Mains (single phase)", "qnazj70", false),
'GL-S-007ZS': new Device('Router', '0x0017880104e45526', 6540,4151, [new Endpoint(1, [0], [], '0x0017880104e45526')], true, "Mains (single phase)", 'GL-S-007ZS'),
'U202DST600ZB': new Device('Router', '0x0017880104e43559', 6540,4151, [new Endpoint(10, [0, 6], [], '0x0017880104e43559'), new Endpoint(11, [0, 6], [], '0x0017880104e43559')], true, "Mains (single phase)", 'U202DST600ZB'),
'3157100': new Device('Router', '0x0017880104e44559', 6542,4151, [new Endpoint(1, [], [], '0x0017880104e44559')], true, "Mains (single phase)", '3157100'),
'zigfred_plus': zigfred_plus,
'3157100': new Device('Router', '0x0017880104e44559', 6542,4151, [new Endpoint(1, [], [], '0x0017880104e44559')], true, "Mains (single phase)", '3157100', false, 'Centralite'),
'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', [new Endpoint(1, [], [], '0x0017880104e45511')], false, null, 'external_converter_device' ),
@@ -197,7 +203,7 @@ const devices = {
'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"),
'bj_scene_switch': new Device('EndDevice', '0xd85def11a1002caa', 50117, 4398, [new Endpoint(10, [0,4096], [3,4,5,6,8,25,768,4096], '0xd85def11a1002caa', [{target: bulb_color_2.endpoints[0], cluster: {ID: 8, name: 'genLevelCtrl'}}, {target: bulb_color_2.endpoints[0], cluster: {ID: 6, name: 'genOnOff'}}, {target: bulb_color_2.endpoints[0], cluster: {ID: 768, name: 'lightingColorCtrl'}},]), new Endpoint(11, [0,4096], [3,4,5,6,8,25,768,4096], '0xd85def11a1002caa')], true, 'Battery', 'RB01', false, 'Busch-Jaeger', '20161222', '1.2.0'),
'GW003-AS-IN-TE-FC': new Device('Router', '0x0017548104a44669', 6545,4699, [new Endpoint(1, [3], [0,3,513,514], '0x0017548104a44669')], true, "Mains (single phase)", 'Adapter Zigbee FUJITSU'),
}
const mock = {
@@ -207,8 +213,10 @@ const mock = {
touchlinkScan: jest.fn(),
touchlinkIdentify: jest.fn(),
start: jest.fn(),
backup: jest.fn(),
isStopping: jest.fn(),
permitJoin: jest.fn(),
addInstallCode: jest.fn(),
getCoordinatorVersion: jest.fn().mockReturnValue({type: 'z-Stack', meta: {version: 1, revision: 20190425}}),
getNetworkParameters: jest.fn().mockReturnValue({panID: 0x162a, extendedPanID: [0, 11, 22], channel: 15}),
on: (type, handler) => {
-1
View File
@@ -18,7 +18,6 @@ echo "Creating backup of configuration..."
cp -R data data-backup
echo "Updating..."
git checkout HEAD -- npm-shrinkwrap.json
git pull
echo "Installing dependencies..."