mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-08-29 23:28:34 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06b3395cff | ||
|
|
0b59a51c3c | ||
|
|
1cee011ca0 | ||
|
|
630b4ec560 | ||
|
|
4b6f50daf3 | ||
|
|
0361b13b66 | ||
|
|
49dea233b6 | ||
|
|
c16abdd832 | ||
|
|
c37f3e834e | ||
|
|
f3e79df4b4 | ||
|
|
03ba745e46 | ||
|
|
7e7d3c6328 | ||
|
|
59001babca | ||
|
|
0d716288bf | ||
|
|
a879382cbd | ||
|
|
a858798054 | ||
|
|
416e561b32 | ||
|
|
a240487bb4 | ||
|
|
518972882c | ||
|
|
ed639ec9d7 | ||
|
|
6372d84259 | ||
|
|
45579dcf10 | ||
|
|
97eac16aaf | ||
|
|
032557b1db | ||
|
|
de7bc7cf60 | ||
|
|
92588fefe3 | ||
|
|
8de20e2cf1 | ||
|
|
a1360d8e90 | ||
|
|
9f3b10235c | ||
|
|
1d6d386a47 | ||
|
|
76ea57b732 | ||
|
|
e76f568f0f | ||
|
|
080f3b6b50 | ||
|
|
a741b2f598 | ||
|
|
ac74fac1db | ||
|
|
ab9124a517 | ||
|
|
4e997c7b83 | ||
|
|
0007db42b0 | ||
|
|
6ccbb11fc2 | ||
|
|
4fe4e2ec2f | ||
|
|
2bd7df84eb | ||
|
|
ec3e37350d | ||
|
|
769bc14163 | ||
|
|
a38b88455f | ||
|
|
9a9bcd503e | ||
|
|
f58ee7ad58 | ||
|
|
3c9620428e | ||
|
|
2bf244c2de | ||
|
|
5c8f95ae01 | ||
|
|
363792aee8 | ||
|
|
ce7d022fda | ||
|
|
52f25eb101 | ||
|
|
ef84ff86fe | ||
|
|
dfbe93ef9d | ||
|
|
6bbe8d1844 | ||
|
|
9eaaa0f9d1 | ||
|
|
0807049b6c | ||
|
|
759c235923 | ||
|
|
14ac9a8f68 | ||
|
|
d942db9a92 | ||
|
|
212c70913c | ||
|
|
b17c22bb50 | ||
|
|
c8c5ea2de3 | ||
|
|
00230baedf | ||
|
|
540969be21 | ||
|
|
804182e30c | ||
|
|
99a57bfd08 | ||
|
|
b8edf273c6 | ||
|
|
e9aee4c6dc | ||
|
|
e6bcf91e17 | ||
|
|
7e37365a5f | ||
|
|
32b1d5b073 | ||
|
|
cb7b773e0d | ||
|
|
84387b27a4 | ||
|
|
3d8f0fc3a8 | ||
|
|
02a587f745 |
@@ -57,6 +57,14 @@ body:
|
||||
placeholder: Electrolama zig-a-zig-ah! (zzh!), Slaesh's CC2652RB stick, ...
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: setup
|
||||
attributes:
|
||||
label: Setup
|
||||
description: How do you run Z2M (plain, add-on...) and on what machine (Pi, x86-64, containerized...)?
|
||||
placeholder: Add-on on Home Assistant OS on Intel NUC, Plain on Docker container, ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: latest
|
||||
- name: Docker build dev
|
||||
- name: "dev: Docker build"
|
||||
if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
|
||||
run: |
|
||||
docker buildx build \
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
--push \
|
||||
-t koenkk/zigbee2mqtt:latest-dev -t ghcr.io/koenkk/zigbee2mqtt:latest-dev \
|
||||
.
|
||||
- name: Docker build release
|
||||
- name: "release: Docker build"
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'push'
|
||||
run: |
|
||||
TAG="$(git describe --tags)"
|
||||
@@ -64,12 +64,12 @@ jobs:
|
||||
--push \
|
||||
-t koenkk/zigbee2mqtt:latest -t "koenkk/zigbee2mqtt:$TAG" -t ghcr.io/koenkk/zigbee2mqtt:latest -t "ghcr.io/koenkk/zigbee2mqtt:$TAG" \
|
||||
.
|
||||
- name: Publish to npm
|
||||
- name: "release: Publish to npm"
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'push'
|
||||
run: npm publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN }}
|
||||
- name: Trigger zigbee2mqtt/hassio-zigbee2mqtt build
|
||||
- name: "dev: Trigger zigbee2mqtt/hassio-zigbee2mqtt build"
|
||||
if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
|
||||
run: |
|
||||
curl \
|
||||
@@ -78,6 +78,36 @@ jobs:
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/zigbee2mqtt/hassio-zigbee2mqtt/actions/workflows/ci.yml/dispatches \
|
||||
-d '{"ref":"master","inputs":{}}'
|
||||
- name: "release: Trigger zigbee2mqtt/hassio-zigbee2mqtt build"
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'push'
|
||||
run: |
|
||||
TAG=${GITHUB_REF#refs/*/}
|
||||
echo "Triggering with tag '$TAG'"
|
||||
curl \
|
||||
-X POST \
|
||||
-H "Authorization: token ${{ secrets.GH_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github.everest-preview+json" \
|
||||
-H "Content-Type: application/json" \
|
||||
https://api.github.com/repos/zigbee2mqtt/hassio-zigbee2mqtt/dispatches \
|
||||
--data "{\"event_type\": \"release\", \"client_payload\": { \"version\": \"$TAG-1\"}}"
|
||||
- name: "release: merge dev -> master and promote dev"
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'push'
|
||||
run: |
|
||||
TAG=${GITHUB_REF#refs/*/}
|
||||
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git fetch origin
|
||||
git checkout master
|
||||
git merge -m 'chore: merge dev to master' origin/dev
|
||||
git push origin master
|
||||
git checkout dev
|
||||
jq ".version = \"$TAG-dev\"" package.json > package.json.tmp
|
||||
jq ".version = \"$TAG-dev\"" package-lock.json > package-lock.json.tmp
|
||||
mv package.json.tmp package.json
|
||||
mv package-lock.json.tmp package-lock.json
|
||||
git add -A
|
||||
git commit -m "chore: promote to dev"
|
||||
git push origin dev
|
||||
|
||||
tests:
|
||||
strategy:
|
||||
|
||||
@@ -11,4 +11,4 @@ jobs:
|
||||
- name: 'Checkout repository'
|
||||
uses: actions/checkout@v4
|
||||
- name: 'Dependency review'
|
||||
uses: actions/dependency-review-action@v3
|
||||
uses: actions/dependency-review-action@v4
|
||||
|
||||
@@ -23,7 +23,6 @@ jobs:
|
||||
- uses: google-github-actions/release-please-action@v4
|
||||
id: release
|
||||
with:
|
||||
release-type: node
|
||||
target-branch: dev
|
||||
token: ${{secrets.GH_TOKEN}}
|
||||
|
||||
@@ -39,7 +38,7 @@ jobs:
|
||||
ref: master
|
||||
|
||||
- name: Restore cache commit-user-lookup.json
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: z2m/scripts/commit-user-lookup.json
|
||||
key: commit-user-lookup-dummy
|
||||
@@ -51,67 +50,20 @@ jobs:
|
||||
MASTER_ZHC_VERSION=$(cat z2m-master/package.json | jq -r '.dependencies."zigbee-herdsman-converters"')
|
||||
MASTER_ZH_VERSION=$(cat z2m-master/package.json | jq -r '.dependencies."zigbee-herdsman"')
|
||||
MASTER_FRONTEND_VERSION=$(cat z2m-master/package.json | jq -r '.dependencies."zigbee2mqtt-frontend"')
|
||||
wget -q -O - https://raw.githubusercontent.com/Koenkk/zigbee2mqtt/release-please--branches--dev--components--release-please-action/CHANGELOG.md > z2m/CHANGELOG.md || true
|
||||
wget -q -O - https://raw.githubusercontent.com/Koenkk/zigbee2mqtt/release-please--branches--dev--components--zigbee2mqtt/CHANGELOG.md > z2m/CHANGELOG.md
|
||||
cd z2m
|
||||
npm ci
|
||||
node scripts/generateChangelog.js $MASTER_Z2M_VERSION $MASTER_ZHC_VERSION $MASTER_ZH_VERSION $MASTER_FRONTEND_VERSION >> ../changelog.md
|
||||
env:
|
||||
GH_TOKEN: ${{secrets.GH_TOKEN}}
|
||||
- name: Update changelog in release PR
|
||||
- name: Update changelog gist
|
||||
run: |
|
||||
gh gist edit bfd4c3d1725a2cccacc11d6ba51008ba -a changelog.md
|
||||
env:
|
||||
GH_TOKEN: ${{secrets.GH_TOKEN}}
|
||||
- name: Upload changelog
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: changelog
|
||||
path: changelog.md
|
||||
- name: Save cache commit-user-lookup.json
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: always()
|
||||
with:
|
||||
path: z2m/scripts/commit-user-lookup.json
|
||||
key: commit-user-lookup-${{ hashFiles('z2m/scripts/commit-user-lookup.json') }}
|
||||
|
||||
create_release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [release-please]
|
||||
if: ${{ needs.release-please.outputs.release_created }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: dev
|
||||
token: ${{secrets.GH_TOKEN}}
|
||||
- name: Merge dev -> master
|
||||
run: |
|
||||
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git checkout master
|
||||
git merge -m 'chore: merge dev to master'
|
||||
git push origin master
|
||||
- name: Promote to dev
|
||||
run: |
|
||||
jq '.version = "${{ needs.release-please.outputs.version }}-dev"' package.json > package.json.tmp
|
||||
jq '.version = "${{ needs.release-please.outputs.version }}-dev"' package-lock.json > package-lock.json.tmp
|
||||
mv package.json.tmp package.json
|
||||
mv package-lock.json.tmp package-lock.json
|
||||
- uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: "chore: promote to dev"
|
||||
- name: Download changelog
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: changelog
|
||||
path: ../changelog
|
||||
- name: update release
|
||||
id: update_release
|
||||
uses: tubone24/update_release@v1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
TAG_NAME: ${{ needs.release-please.outputs.version }}
|
||||
with:
|
||||
body_path: ../changelog/changelog.md
|
||||
- name: Trigger HA addon update
|
||||
run: |
|
||||
curl -XPOST -H "Authorization: token ${{ secrets.GH_TOKEN }}" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" https://api.github.com/repos/zigbee2mqtt/hassio-zigbee2mqtt/dispatches --data "{\"event_type\": \"release\", \"client_payload\": { \"version\": \"${{ needs.release-please.outputs.version }}-1\"}}"
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
- run: npm install ${{ github.event.client_payload.package }}@${{ github.event.client_payload.version }} --save-exact
|
||||
- uses: peter-evans/create-pull-request@v5
|
||||
- uses: peter-evans/create-pull-request@v6
|
||||
id: cpr
|
||||
with:
|
||||
commit-message: "fix(ignore): update ${{ github.event.client_payload.package }} to ${{ github.event.client_payload.version }}"
|
||||
@@ -30,9 +30,7 @@ jobs:
|
||||
title: Update ${{ github.event.client_payload.package }} to ${{ github.event.client_payload.version }}
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
- run: sleep 5 # Otherwise pull request may not exist yet causing automerge to fail
|
||||
- uses: peter-evans/enable-pull-request-automerge@v3
|
||||
- run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}"
|
||||
if: steps.cpr.outputs.pull-request-operation == 'created'
|
||||
with:
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
|
||||
merge-method: squash
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
- run: npx npm-check-updates -u -x connect-gzip-static
|
||||
- run: rm -f package-lock.json
|
||||
- run: npm install
|
||||
- uses: peter-evans/create-pull-request@v5
|
||||
- uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
commit-message: "fix(ignore): update dependencies"
|
||||
branch: "deps/all"
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
{
|
||||
".": "1.35.0",
|
||||
"bootstrap-sha": "7ee207fc0e05f32c9636c0298b48eea1b91ed9e1",
|
||||
"include-v-in-tag": false
|
||||
".": "1.35.2"
|
||||
}
|
||||
@@ -1,5 +1,67 @@
|
||||
# Changelog
|
||||
|
||||
## [1.35.2](https://github.com/Koenkk/zigbee2mqtt/compare/1.35.1...1.35.2) (2024-01-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Added icon and device_class for some Aqara device entities ([#20746](https://github.com/Koenkk/zigbee2mqtt/issues/20746)) ([ac74fac](https://github.com/Koenkk/zigbee2mqtt/commit/ac74fac1db9b1ee6d473c5045989003548e451f6))
|
||||
* Home Assistant: additional icons for Aqara TRV entities and various others ([#20903](https://github.com/Koenkk/zigbee2mqtt/issues/20903)) ([92588fe](https://github.com/Koenkk/zigbee2mqtt/commit/92588fefe3f10783c93c145b9b937c39bd6a5773))
|
||||
* **ignore:** Ability to trigger events from converters on incoming Zigbee messages ([#20776](https://github.com/Koenkk/zigbee2mqtt/issues/20776)) ([0007db4](https://github.com/Koenkk/zigbee2mqtt/commit/0007db42b0365c0b14510f2b03f60277a2a22303))
|
||||
* **ignore:** update zigbee-herdsman to 0.31.0 ([#20639](https://github.com/Koenkk/zigbee2mqtt/issues/20639)) ([ef84ff8](https://github.com/Koenkk/zigbee2mqtt/commit/ef84ff86fed89d0957961580f92541b20546b951))
|
||||
* **ignore:** update zigbee-herdsman to 0.32.0 ([#20681](https://github.com/Koenkk/zigbee2mqtt/issues/20681)) ([52f25eb](https://github.com/Koenkk/zigbee2mqtt/commit/52f25eb101ba6102a2c9fcb20d0bb9c56d1bd627))
|
||||
* **ignore:** update zigbee-herdsman to 0.32.1 ([#20706](https://github.com/Koenkk/zigbee2mqtt/issues/20706)) ([2bf244c](https://github.com/Koenkk/zigbee2mqtt/commit/2bf244c2dea1b6c9db6f8273dcb03e4a40fbe18a))
|
||||
* **ignore:** update zigbee-herdsman to 0.32.2 ([#20726](https://github.com/Koenkk/zigbee2mqtt/issues/20726)) ([9a9bcd5](https://github.com/Koenkk/zigbee2mqtt/commit/9a9bcd503eb736d3227dcf4fd3853739cfee293a))
|
||||
* **ignore:** update zigbee-herdsman to 0.32.3 ([#20744](https://github.com/Koenkk/zigbee2mqtt/issues/20744)) ([769bc14](https://github.com/Koenkk/zigbee2mqtt/commit/769bc14163666df402d52abba4c14a7eef99667a))
|
||||
* **ignore:** update zigbee-herdsman to 0.32.4 ([#20772](https://github.com/Koenkk/zigbee2mqtt/issues/20772)) ([ec3e373](https://github.com/Koenkk/zigbee2mqtt/commit/ec3e37350dde666512d7a966dd28db54d3da7e7c))
|
||||
* **ignore:** update zigbee-herdsman to 0.32.5 ([#20826](https://github.com/Koenkk/zigbee2mqtt/issues/20826)) ([4fe4e2e](https://github.com/Koenkk/zigbee2mqtt/commit/4fe4e2ec2f9d0d1a6173c7cca2641204c702e933))
|
||||
* **ignore:** update zigbee-herdsman to 0.32.6 ([#20846](https://github.com/Koenkk/zigbee2mqtt/issues/20846)) ([4e997c7](https://github.com/Koenkk/zigbee2mqtt/commit/4e997c7b83772dfbd73272f7ebd3acbda1a1c55e))
|
||||
* **ignore:** update zigbee-herdsman to 0.32.7 ([#20900](https://github.com/Koenkk/zigbee2mqtt/issues/20900)) ([a1360d8](https://github.com/Koenkk/zigbee2mqtt/commit/a1360d8e901ae0c5b3e3987215794e48f56ec65d))
|
||||
* **ignore:** update zigbee-herdsman to 0.33.0 ([#20932](https://github.com/Koenkk/zigbee2mqtt/issues/20932)) ([032557b](https://github.com/Koenkk/zigbee2mqtt/commit/032557b1dbf810872cef61c3a65e2f6df93441e7))
|
||||
* **ignore:** update zigbee-herdsman to 0.33.1 ([#20965](https://github.com/Koenkk/zigbee2mqtt/issues/20965)) ([ed639ec](https://github.com/Koenkk/zigbee2mqtt/commit/ed639ec9d7867785aeb776c63c927929b365993d))
|
||||
* **ignore:** update zigbee-herdsman to 0.33.2 ([#20994](https://github.com/Koenkk/zigbee2mqtt/issues/20994)) ([a240487](https://github.com/Koenkk/zigbee2mqtt/commit/a240487bb4711a1403fd1f069a8f32dc454e5b55))
|
||||
* **ignore:** update zigbee-herdsman to 0.33.3 ([#21094](https://github.com/Koenkk/zigbee2mqtt/issues/21094)) ([59001ba](https://github.com/Koenkk/zigbee2mqtt/commit/59001babca79f04938127e1592f553106b2b0b9f))
|
||||
* **ignore:** update zigbee-herdsman to 0.33.4 ([#21104](https://github.com/Koenkk/zigbee2mqtt/issues/21104)) ([03ba745](https://github.com/Koenkk/zigbee2mqtt/commit/03ba745e46b849cf7a62bdf598b8bf1d128281d2))
|
||||
* **ignore:** update zigbee-herdsman to 0.33.5 ([#21113](https://github.com/Koenkk/zigbee2mqtt/issues/21113)) ([49dea23](https://github.com/Koenkk/zigbee2mqtt/commit/49dea233b6248d699a2d0f641ce0a84c9b91e92c))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.10.1 ([#20705](https://github.com/Koenkk/zigbee2mqtt/issues/20705)) ([5c8f95a](https://github.com/Koenkk/zigbee2mqtt/commit/5c8f95ae0146aff91c305643c9fa41c8dc690fa7))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.11.0 ([#20742](https://github.com/Koenkk/zigbee2mqtt/issues/20742)) ([a38b884](https://github.com/Koenkk/zigbee2mqtt/commit/a38b88455f8a77fe5e9997f05374d3454b100b41))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.13.0 ([#20828](https://github.com/Koenkk/zigbee2mqtt/issues/20828)) ([6ccbb11](https://github.com/Koenkk/zigbee2mqtt/commit/6ccbb11fc20d63f86eea03ffc26c9bd790b2ee5e))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.14.0 ([#20847](https://github.com/Koenkk/zigbee2mqtt/issues/20847)) ([ab9124a](https://github.com/Koenkk/zigbee2mqtt/commit/ab9124a5179bd87d496944d7bab5794eab6505e3))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.15.0 ([#20860](https://github.com/Koenkk/zigbee2mqtt/issues/20860)) ([080f3b6](https://github.com/Koenkk/zigbee2mqtt/commit/080f3b6b50c58636aa217d143a0f3d18fbb55c7f))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.15.1 ([#20876](https://github.com/Koenkk/zigbee2mqtt/issues/20876)) ([9f3b102](https://github.com/Koenkk/zigbee2mqtt/commit/9f3b10235cf0f5db38098c4a73bd64d4d53ba6c2))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.16.0 ([#20901](https://github.com/Koenkk/zigbee2mqtt/issues/20901)) ([8de20e2](https://github.com/Koenkk/zigbee2mqtt/commit/8de20e2cf1107366dd958c7e781a2011f7dd8f2d))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.17.0 ([#20907](https://github.com/Koenkk/zigbee2mqtt/issues/20907)) ([de7bc7c](https://github.com/Koenkk/zigbee2mqtt/commit/de7bc7cf60752874262f684ac7f3923057aab3c2))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.19.0 ([#20966](https://github.com/Koenkk/zigbee2mqtt/issues/20966)) ([5189728](https://github.com/Koenkk/zigbee2mqtt/commit/518972882c7a02bfc076aa5093853f23947d769d))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.20.0 ([#20996](https://github.com/Koenkk/zigbee2mqtt/issues/20996)) ([416e561](https://github.com/Koenkk/zigbee2mqtt/commit/416e561b329b65fa50af23e08c3d82cbc52387da))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.21.0 ([#21012](https://github.com/Koenkk/zigbee2mqtt/issues/21012)) ([a879382](https://github.com/Koenkk/zigbee2mqtt/commit/a879382cbd32bd0935d91b62e6cbbf2a0c9987a4))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.23.1 ([#21093](https://github.com/Koenkk/zigbee2mqtt/issues/21093)) ([7e7d3c6](https://github.com/Koenkk/zigbee2mqtt/commit/7e7d3c6328c0cbd89264d6313367dbd1295b0b42))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.24.0 ([#21106](https://github.com/Koenkk/zigbee2mqtt/issues/21106)) ([f3e79df](https://github.com/Koenkk/zigbee2mqtt/commit/f3e79df4b4c7a5c68a70375e25507e58c6378b1a))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.25.1 ([#21129](https://github.com/Koenkk/zigbee2mqtt/issues/21129)) ([0b59a51](https://github.com/Koenkk/zigbee2mqtt/commit/0b59a51c3c740da5c5d7b86514651c21a5c7387b))
|
||||
* **ignore:** update zigbee2mqtt-frontend to 0.6.152 ([#21003](https://github.com/Koenkk/zigbee2mqtt/issues/21003)) ([a858798](https://github.com/Koenkk/zigbee2mqtt/commit/a85879805489761d429d1dec4d98c1ae2ebd9400))
|
||||
* Notify systemd for start, stop, watchdog ([#20482](https://github.com/Koenkk/zigbee2mqtt/issues/20482)) ([97eac16](https://github.com/Koenkk/zigbee2mqtt/commit/97eac16aaf10d9bec4a5353b07ae3ebef92868e5))
|
||||
* Remove deprecated sendWhen ([#20861](https://github.com/Koenkk/zigbee2mqtt/issues/20861)) ([e76f568](https://github.com/Koenkk/zigbee2mqtt/commit/e76f568f0fe0a36e5324b20b8ca3173f618cd8e6))
|
||||
* Republish correctly on scene changes to Home Assistant ([#20952](https://github.com/Koenkk/zigbee2mqtt/issues/20952)) ([6372d84](https://github.com/Koenkk/zigbee2mqtt/commit/6372d842596240685ead4a5a10f9a739ec208504))
|
||||
* Revert "Enable incremental TSC builds ([#19293](https://github.com/Koenkk/zigbee2mqtt/issues/19293))" https://github.com/Koenkk/zigbee2mqtt/discussions/20805 ([a741b2f](https://github.com/Koenkk/zigbee2mqtt/commit/a741b2f598159e1fbd6799619d0e575ad11c0256))
|
||||
* Set Home Assistant entity categories `config` and `diagnostic` according to expose categories ([#20663](https://github.com/Koenkk/zigbee2mqtt/issues/20663)) ([363792a](https://github.com/Koenkk/zigbee2mqtt/commit/363792aee8f9535163e7c0aa3e5b9961165fc088))
|
||||
* Use Alpine 3.18.4 as base https://github.com/Koenkk/zigbee2mqtt/issues/20868 ([c16abdd](https://github.com/Koenkk/zigbee2mqtt/commit/c16abdd83233c51fa5f7d6b56db6b19bea9b81f6))
|
||||
|
||||
## [1.35.1](https://github.com/Koenkk/zigbee2mqtt/compare/1.35.0...1.35.1) (2024-01-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fix configure on startup crashing coordinator https://github.com/Koenkk/zigbee2mqtt/issues/20526 ([e9aee4c](https://github.com/Koenkk/zigbee2mqtt/commit/e9aee4c6dc1b7dcfedfa821723b029e1a0423d15))
|
||||
* Fix crash due to unhandled Promise exception https://github.com/Koenkk/zigbee2mqtt/issues/20473 ([e6bcf91](https://github.com/Koenkk/zigbee2mqtt/commit/e6bcf91e17747eff38ce7774107d697aeff4be15))
|
||||
* Fix Home Assistant `program` not truncated when too large https://github.com/Koenkk/zigbee2mqtt/issues/19788 ([32b1d5b](https://github.com/Koenkk/zigbee2mqtt/commit/32b1d5b0732544a2026f8582f8bb12a3e5691b2b))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.4.0 ([#20523](https://github.com/Koenkk/zigbee2mqtt/issues/20523)) ([7e37365](https://github.com/Koenkk/zigbee2mqtt/commit/7e37365a5faec6d8d33db406ed18d5492fa2fc19))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.6.0 ([#20585](https://github.com/Koenkk/zigbee2mqtt/issues/20585)) ([b17c22b](https://github.com/Koenkk/zigbee2mqtt/commit/b17c22bb501599fcc68685ff0fc65642d1dea9ca))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.8.0 ([#20613](https://github.com/Koenkk/zigbee2mqtt/issues/20613)) ([14ac9a8](https://github.com/Koenkk/zigbee2mqtt/commit/14ac9a8f68480c433450cb1f33f8feda00359268))
|
||||
* **ignore:** update zigbee-herdsman-converters to 18.9.0 ([#20635](https://github.com/Koenkk/zigbee2mqtt/issues/20635)) ([759c235](https://github.com/Koenkk/zigbee2mqtt/commit/759c2359234a5f83b9a7f2a5b97e75aef9d0d567))
|
||||
* **ignore:** update zigbee2mqtt-frontend to 0.6.151 ([#20509](https://github.com/Koenkk/zigbee2mqtt/issues/20509)) ([cb7b773](https://github.com/Koenkk/zigbee2mqtt/commit/cb7b773e0defb1e28dc17af42e3807e7628338df))
|
||||
* Prevent extension errors from crashing Zigbee2MQTT https://github.com/Koenkk/zigbee2mqtt/issues/20477 ([212c709](https://github.com/Koenkk/zigbee2mqtt/commit/212c70913c06a97dea8dac7d532a7d601c69a3d1))
|
||||
* Prevent warnings for bridge entities with legacy_entity_attributes enabled ([#20548](https://github.com/Koenkk/zigbee2mqtt/issues/20548)) ([99a57bf](https://github.com/Koenkk/zigbee2mqtt/commit/99a57bfd080fcf311f7cc45e7d0d04cdc0a6138a))
|
||||
* Support legacy_availability_payload for Home Assistant connection_state ([#20547](https://github.com/Koenkk/zigbee2mqtt/issues/20547)) ([b8edf27](https://github.com/Koenkk/zigbee2mqtt/commit/b8edf273c6de799e30c95c607f315f02b0dcacdd))
|
||||
|
||||
## [1.35.0](https://github.com/Koenkk/zigbee2mqtt/compare/1.34.0...v1.35.0) (2024-01-01)
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.18.5 as base
|
||||
FROM alpine:3.18.4 as base
|
||||
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache tzdata eudev tini nodejs
|
||||
|
||||
+19
-4
@@ -39,6 +39,14 @@ const AllExtensions = [
|
||||
type ExtensionArgs = [Zigbee, MQTT, State, PublishEntityState, EventBus,
|
||||
(enable: boolean, name: string) => Promise<void>, () => void, (extension: Extension) => Promise<void>];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let sdNotify: any = null;
|
||||
try {
|
||||
sdNotify = process.env.NOTIFY_SOCKET ? require('sd-notify') : null;
|
||||
} catch {
|
||||
// sd-notify is optional
|
||||
}
|
||||
|
||||
export class Controller {
|
||||
private eventBus: EventBus;
|
||||
private zigbee: Zigbee;
|
||||
@@ -51,10 +59,7 @@ export class Controller {
|
||||
|
||||
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.eventBus = new EventBus();
|
||||
this.zigbee = new Zigbee(this.eventBus);
|
||||
this.mqtt = new MQTT(this.eventBus);
|
||||
this.state = new State(this.eventBus, this.zigbee);
|
||||
@@ -165,6 +170,12 @@ export class Controller {
|
||||
(data) => utils.publishLastSeen(data, settings.get(), false, this.publishEntityState));
|
||||
|
||||
logger.info(`Zigbee2MQTT started!`);
|
||||
|
||||
const watchdogInterval = sdNotify?.watchdogInterval() || 0;
|
||||
if (watchdogInterval > 0) {
|
||||
sdNotify.startWatchdogMode(Math.floor(watchdogInterval / 2));
|
||||
}
|
||||
sdNotify?.ready();
|
||||
}
|
||||
|
||||
@bind async enableDisableExtension(enable: boolean, name: string): Promise<void> {
|
||||
@@ -189,6 +200,8 @@ export class Controller {
|
||||
}
|
||||
|
||||
async stop(restart = false): Promise<void> {
|
||||
sdNotify?.stopping();
|
||||
|
||||
// Call extensions
|
||||
await this.callExtensions('stop', this.extensions);
|
||||
this.eventBus.removeListeners(this);
|
||||
@@ -205,6 +218,8 @@ export class Controller {
|
||||
logger.error('Failed to stop Zigbee2MQTT');
|
||||
await this.exit(1, restart);
|
||||
}
|
||||
|
||||
sdNotify?.stopWatchdogMode();
|
||||
}
|
||||
|
||||
async exit(code: number, restart = false): Promise<void> {
|
||||
|
||||
+23
-9
@@ -1,5 +1,5 @@
|
||||
import events from 'events';
|
||||
events.captureRejections = true;
|
||||
import logger from './util/logger';
|
||||
|
||||
// eslint-disable-next-line
|
||||
type ListenerKey = object;
|
||||
@@ -8,9 +8,8 @@ export default class EventBus {
|
||||
private callbacksByExtension: { [s: string]: { event: string, callback: (...args: unknown[]) => void }[] } = {};
|
||||
private emitter = new events.EventEmitter();
|
||||
|
||||
constructor(onError: (error: Error) => void) {
|
||||
constructor() {
|
||||
this.emitter.setMaxListeners(100);
|
||||
this.emitter.on('error', onError);
|
||||
}
|
||||
|
||||
public emitAdapterDisconnected(): void {
|
||||
@@ -91,6 +90,13 @@ export default class EventBus {
|
||||
this.on('entityOptionsChanged', callback, key);
|
||||
}
|
||||
|
||||
public emitExposesChanged(data: eventdata.ExposesChanged): void {
|
||||
this.emitter.emit('exposesChanged', data);
|
||||
}
|
||||
public onExposesChanged(key: ListenerKey, callback: (data: eventdata.ExposesChanged) => void): void {
|
||||
this.on('exposesChanged', callback, key);
|
||||
}
|
||||
|
||||
public emitDeviceLeave(data: eventdata.DeviceLeave): void {
|
||||
this.emitter.emit('deviceLeave', data);
|
||||
}
|
||||
@@ -140,10 +146,10 @@ export default class EventBus {
|
||||
this.on('devicesChanged', callback, key);
|
||||
}
|
||||
|
||||
public emitScenesChanged(): void {
|
||||
this.emitter.emit('scenesChanged');
|
||||
public emitScenesChanged(data: eventdata.ScenesChanged): void {
|
||||
this.emitter.emit('scenesChanged', data);
|
||||
}
|
||||
public onScenesChanged(key: ListenerKey, callback: () => void): void {
|
||||
public onScenesChanged(key: ListenerKey, callback: (data: eventdata.ScenesChanged) => void): void {
|
||||
this.on('scenesChanged', callback, key);
|
||||
}
|
||||
|
||||
@@ -161,10 +167,18 @@ export default class EventBus {
|
||||
this.on('stateChange', callback, key);
|
||||
}
|
||||
|
||||
private on(event: string, callback: (...args: unknown[]) => void, key: ListenerKey): void {
|
||||
private on(event: string, callback: (...args: unknown[]) => (Promise<void> | void), key: ListenerKey): void {
|
||||
if (!this.callbacksByExtension[key.constructor.name]) this.callbacksByExtension[key.constructor.name] = [];
|
||||
this.callbacksByExtension[key.constructor.name].push({event, callback});
|
||||
this.emitter.on(event, callback);
|
||||
const wrappedCallback = async (...args: unknown[]): Promise<void> => {
|
||||
try {
|
||||
await callback(...args);
|
||||
} catch (error) {
|
||||
logger.error(`EventBus error '${key.constructor.name}/${event}': ${error.message}`);
|
||||
logger.debug(error.stack);
|
||||
}
|
||||
};
|
||||
this.callbacksByExtension[key.constructor.name].push({event, callback: wrappedCallback});
|
||||
this.emitter.on(event, wrappedCallback);
|
||||
}
|
||||
|
||||
public removeListeners(key: ListenerKey): void {
|
||||
|
||||
@@ -66,6 +66,9 @@ export default class Configure extends Extension {
|
||||
override async start(): Promise<void> {
|
||||
setImmediate(async () => {
|
||||
for (const device of this.zigbee.devices(false)) {
|
||||
// Sleep 10 seconds between configuring on startup to not DDoS the coordinator
|
||||
// when many devices have to be configured.
|
||||
await utils.sleep(10);
|
||||
await this.configure(device, 'started');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -146,6 +146,7 @@ export default class HomeAssistant extends Extension {
|
||||
this.eventBus.onDeviceMessage(this, this.onZigbeeEvent);
|
||||
this.eventBus.onScenesChanged(this, this.onScenesChanged);
|
||||
this.eventBus.onEntityOptionsChanged(this, (data) => this.discover(data.entity, true));
|
||||
this.eventBus.onExposesChanged(this, (data) => this.discover(data.device, true));
|
||||
|
||||
this.mqtt.subscribe(this.statusTopic);
|
||||
this.mqtt.subscribe(defaultStatusTopic);
|
||||
@@ -599,6 +600,7 @@ export default class HomeAssistant extends Extension {
|
||||
discoveryEntries.push(discoveryEntry);
|
||||
} else if (isBinaryExposeFeature(firstExpose)) {
|
||||
const lookup: {[s: string]: KeyValue}= {
|
||||
auto_off: {icon: 'mdi:flash-auto'},
|
||||
battery_low: {entity_category: 'diagnostic', device_class: 'battery'},
|
||||
button_lock: {entity_category: 'config', icon: 'mdi:lock'},
|
||||
calibration: {entity_category: 'config', icon: 'mdi:progress-wrench'},
|
||||
@@ -630,8 +632,10 @@ export default class HomeAssistant extends Extension {
|
||||
occupancy: {device_class: 'motion'},
|
||||
power_outage_memory: {entity_category: 'config', icon: 'mdi:memory'},
|
||||
presence: {device_class: 'presence'},
|
||||
setup: {device_class: 'running'},
|
||||
smoke: {device_class: 'smoke'},
|
||||
sos: {device_class: 'safety'},
|
||||
schedule: {icon: 'mdi:calendar'},
|
||||
status_capacitive_load: {entity_category: 'diagnostic', icon: 'mdi:tune'},
|
||||
status_forward_phase_control: {entity_category: 'diagnostic', icon: 'mdi:tune'},
|
||||
status_inductive_load: {entity_category: 'diagnostic', icon: 'mdi:tune'},
|
||||
@@ -640,10 +644,15 @@ export default class HomeAssistant extends Extension {
|
||||
tamper: {device_class: 'tamper'},
|
||||
temperature_scale: {entity_category: 'config', icon: 'mdi:temperature-celsius'},
|
||||
test: {entity_category: 'diagnostic', icon: 'mdi:test-tube'},
|
||||
trigger_indicator: {icon: 'mdi:led-on'},
|
||||
valve_alarm: {device_class: 'problem'},
|
||||
valve_detection: {icon: 'mdi:pipe-valve'},
|
||||
valve_state: {device_class: 'opening'},
|
||||
vibration: {device_class: 'vibration'},
|
||||
water_leak: {device_class: 'moisture'},
|
||||
window: {device_class: 'window'},
|
||||
window_detection: {icon: 'mdi:window-open-variant'},
|
||||
window_open: {device_class: 'window'},
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -700,6 +709,7 @@ export default class HomeAssistant extends Extension {
|
||||
const lookup: {[s: string]: KeyValue} = {
|
||||
ac_frequency: {device_class: 'frequency', enabled_by_default: false, entity_category: 'diagnostic',
|
||||
state_class: 'measurement'},
|
||||
action_duration: {icon: 'mdi:timer', device_class: 'duration'},
|
||||
alarm_humidity_max: {device_class: 'humidity', entity_category: 'config', icon: 'mdi:water-plus'},
|
||||
alarm_humidity_min: {device_class: 'humidity', entity_category: 'config', icon: 'mdi:water-minus'},
|
||||
alarm_temperature_max: {device_class: 'temperature', entity_category: 'config',
|
||||
@@ -750,6 +760,7 @@ export default class HomeAssistant extends Extension {
|
||||
state_class: 'measurement',
|
||||
},
|
||||
deadzone_temperature: {entity_category: 'config', icon: 'mdi:thermometer'},
|
||||
detection_interval: {icon: 'mdi:timer'},
|
||||
device_temperature: {
|
||||
device_class: 'temperature', entity_category: 'diagnostic', state_class: 'measurement',
|
||||
},
|
||||
@@ -757,6 +768,7 @@ export default class HomeAssistant extends Extension {
|
||||
eco2: {device_class: 'carbon_dioxide', state_class: 'measurement'},
|
||||
eco_temperature: {entity_category: 'config', icon: 'mdi:thermometer'},
|
||||
energy: {device_class: 'energy', state_class: 'total_increasing'},
|
||||
external_temperature_input: {icon: 'mdi:thermometer'},
|
||||
formaldehyd: {state_class: 'measurement'},
|
||||
gas_density: {icon: 'mdi:google-circles-communities', state_class: 'measurement'},
|
||||
hcho: {icon: 'mdi:air-filter', state_class: 'measurement'},
|
||||
@@ -781,6 +793,7 @@ export default class HomeAssistant extends Extension {
|
||||
minimum_on_level: {entity_category: 'config'},
|
||||
measurement_poll_interval: {entity_category: 'config', icon: 'mdi:clock-out'},
|
||||
occupancy_timeout: {entity_category: 'config', icon: 'mdi:timer'},
|
||||
overload_protection: {icon: 'mdi:flash'},
|
||||
pm10: {device_class: 'pm10', state_class: 'measurement'},
|
||||
pm25: {device_class: 'pm25', state_class: 'measurement'},
|
||||
people: {state_class: 'measurement', icon: 'mdi:account-multiple'},
|
||||
@@ -788,6 +801,7 @@ export default class HomeAssistant extends Extension {
|
||||
power: {device_class: 'power', entity_category: 'diagnostic', state_class: 'measurement'},
|
||||
power_factor: {device_class: 'power_factor', enabled_by_default: false,
|
||||
entity_category: 'diagnostic', state_class: 'measurement'},
|
||||
power_outage_count: {icon: 'mdi:counter'},
|
||||
precision: {entity_category: 'config', icon: 'mdi:decimal-comma-increase'},
|
||||
pressure: {device_class: 'atmospheric_pressure', state_class: 'measurement'},
|
||||
presence_timeout: {entity_category: 'config', icon: 'mdi:timer'},
|
||||
@@ -925,6 +939,7 @@ export default class HomeAssistant extends Extension {
|
||||
alarm_temperature: {entity_category: 'config', icon: 'mdi:thermometer-alert'},
|
||||
backlight_auto_dim: {entity_category: 'config', icon: 'mdi:brightness-auto'},
|
||||
backlight_mode: {entity_category: 'config', icon: 'mdi:lightbulb'},
|
||||
calibrate: {icon: 'mdi:tune'},
|
||||
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'},
|
||||
@@ -938,6 +953,7 @@ export default class HomeAssistant extends Extension {
|
||||
melody: {entity_category: 'config', icon: 'mdi:music-note'},
|
||||
mode_phase_control: {entity_category: 'config', icon: 'mdi:tune'},
|
||||
mode: {entity_category: 'config', icon: 'mdi:tune'},
|
||||
mode_switch: {icon: 'mdi:tune'},
|
||||
motion_sensitivity: {entity_category: 'config', icon: 'mdi:tune'},
|
||||
operation_mode: {entity_category: 'config', icon: 'mdi:tune'},
|
||||
power_on_behavior: {entity_category: 'config', icon: 'mdi:power-settings'},
|
||||
@@ -945,6 +961,7 @@ export default class HomeAssistant extends Extension {
|
||||
power_supply_mode: {entity_category: 'config', icon: 'mdi:power-settings'},
|
||||
power_type: {entity_category: 'config', icon: 'mdi:lightning-bolt-circle'},
|
||||
sensitivity: {entity_category: 'config', icon: 'mdi:tune'},
|
||||
sensor: {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'},
|
||||
@@ -1000,10 +1017,12 @@ export default class HomeAssistant extends Extension {
|
||||
const settableText = firstExpose.type === 'text' && firstExpose.access & ACCESS_SET;
|
||||
const lookup: {[s: string]: KeyValue} = {
|
||||
action: {icon: 'mdi:gesture-double-tap'},
|
||||
color_options: {icon: 'mdi:palette'},
|
||||
level_config: {entity_category: 'diagnostic'},
|
||||
programming_mode: {icon: 'mdi:calendar-clock'},
|
||||
program: {value_template: `{{ value_json.${firstExpose.property}|default('',true) ` +
|
||||
program: {value_template: `{{ value_json.${firstExpose.property}|default('',True) ` +
|
||||
`| truncate(254, True, '', 0) }}`},
|
||||
schedule_settings: {icon: 'mdi:calendar-clock'},
|
||||
};
|
||||
if (firstExpose.access & ACCESS_STATE) {
|
||||
const discoveryEntry: DiscoveryEntry = {
|
||||
@@ -1039,6 +1058,14 @@ export default class HomeAssistant extends Extension {
|
||||
throw new Error(`Unsupported exposes type: '${firstExpose.type}'`);
|
||||
}
|
||||
|
||||
// Exposes with category 'config' or 'diagnostic' are always added to the respective category.
|
||||
// This takes precedence over definitions in this file.
|
||||
if (firstExpose.category === 'config') {
|
||||
discoveryEntries.forEach((d) => d.discovery_payload.entity_category = 'config');
|
||||
} else if (firstExpose.category === 'diagnostic') {
|
||||
discoveryEntries.forEach((d) => d.discovery_payload.entity_category = 'diagnostic');
|
||||
}
|
||||
|
||||
discoveryEntries.forEach((d) => {
|
||||
// If a sensor has entity category `config`, then change
|
||||
// it to `diagnostic`. Sensors have no input, so can't be configured.
|
||||
@@ -1378,7 +1405,7 @@ export default class HomeAssistant extends Extension {
|
||||
payload.tilt_status_topic = stateTopic;
|
||||
}
|
||||
|
||||
if (this.entityAttributes) {
|
||||
if (this.entityAttributes && (isDevice || isGroup) ) {
|
||||
payload.json_attributes_topic = stateTopic;
|
||||
}
|
||||
|
||||
@@ -1640,20 +1667,15 @@ export default class HomeAssistant extends Extension {
|
||||
this.discover(data.device);
|
||||
}
|
||||
|
||||
@bind async onScenesChanged(): Promise<void> {
|
||||
// Re-trigger MQTT discovery of all devices and groups, similar to bridge.ts
|
||||
const entities = [...this.zigbee.devices(), ...this.zigbee.groups()];
|
||||
const clearedEntities = new Set<Device|Group>();
|
||||
@bind async onScenesChanged(data: eventdata.ScenesChanged): Promise<void> {
|
||||
// Re-trigger MQTT discovery of changed devices and groups, similar to bridge.ts
|
||||
|
||||
// First, clear existing scene discovery topics
|
||||
entities.forEach((entity) => {
|
||||
logger.debug(`Clearing Home Assistant scene discovery topics for '${entity.name}'`);
|
||||
this.discovered[this.getDiscoverKey(entity)]?.topics.forEach((topic) => {
|
||||
if (topic.startsWith('scene')) {
|
||||
this.mqtt.publish(topic, null, {retain: true, qos: 1}, this.discoveryTopic, false, false);
|
||||
clearedEntities.add(entity);
|
||||
}
|
||||
});
|
||||
logger.debug(`Clearing Home Assistant scene discovery topics for '${data.entity.name}'`);
|
||||
this.discovered[this.getDiscoverKey(data.entity)]?.topics.forEach((topic) => {
|
||||
if (topic.startsWith('scene')) {
|
||||
this.mqtt.publish(topic, null, {retain: true, qos: 1}, this.discoveryTopic, false, false);
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure Home Assistant deletes the old entity first otherwise another one (_2) is created
|
||||
@@ -1661,11 +1683,9 @@ export default class HomeAssistant extends Extension {
|
||||
logger.debug(`Finished clearing scene discovery topics, waiting for Home Assistant.`);
|
||||
await utils.sleep(2);
|
||||
|
||||
// Re-discover all entities (including their new scenes).
|
||||
// Re-discover entity (including any new scenes).
|
||||
logger.debug(`Re-discovering entities with their scenes.`);
|
||||
clearedEntities.forEach((entity) => {
|
||||
this.discover(entity, true);
|
||||
});
|
||||
this.discover(data.entity, true);
|
||||
}
|
||||
|
||||
private getDevicePayload(entity: Device | Group | Bridge): KeyValue {
|
||||
@@ -1796,6 +1816,7 @@ export default class HomeAssistant extends Extension {
|
||||
const discovery: DiscoveryEntry[] = [];
|
||||
const bridge = new Bridge(coordinatorIeeeAddress, coordinatorVersion, discovery);
|
||||
const baseTopic = `${settings.get().mqtt.base_topic}/${bridge.name}`;
|
||||
const legacyAvailability = settings.get().advanced.legacy_availability_payload;
|
||||
|
||||
discovery.push(
|
||||
// Binary sensors.
|
||||
@@ -1809,7 +1830,7 @@ export default class HomeAssistant extends Extension {
|
||||
entity_category: 'diagnostic',
|
||||
state_topic: true,
|
||||
state_topic_postfix: 'state',
|
||||
value_template: '{{ value_json.state }}',
|
||||
value_template: !legacyAvailability ? '{{ value_json.state }}' : '{{ value }}',
|
||||
payload_on: 'online',
|
||||
payload_off: 'offline',
|
||||
availability: false,
|
||||
|
||||
@@ -125,11 +125,11 @@ export default class OTAUpdate extends Extension {
|
||||
logger.debug(`Responded to OTA request of '${data.device.name}' with 'NO_IMAGE_AVAILABLE'`);
|
||||
}
|
||||
|
||||
private async readSoftwareBuildIDAndDateCode(device: Device, sendWhen: 'active' | 'immediate'):
|
||||
private async readSoftwareBuildIDAndDateCode(device: Device, sendPolicy?: 'immediate'):
|
||||
Promise<{softwareBuildID: string, dateCode: string}> {
|
||||
try {
|
||||
const endpoint = device.zh.endpoints.find((e) => e.supportsInputCluster('genBasic'));
|
||||
const result = await endpoint.read('genBasic', ['dateCode', 'swBuildId'], {sendWhen});
|
||||
const result = await endpoint.read('genBasic', ['dateCode', 'swBuildId'], {sendPolicy});
|
||||
return {softwareBuildID: result.swBuildId, dateCode: result.dateCode};
|
||||
} catch (e) {
|
||||
return null;
|
||||
@@ -273,7 +273,7 @@ export default class OTAUpdate extends Extension {
|
||||
const payload = this.getEntityPublishPayload(device,
|
||||
{available: false, currentFileVersion: fileVersion, otaFileVersion: fileVersion});
|
||||
this.publishEntityState(device, payload);
|
||||
const to = await this.readSoftwareBuildIDAndDateCode(device, 'active');
|
||||
const to = await this.readSoftwareBuildIDAndDateCode(device);
|
||||
const [fromS, toS] = [stringify(from_), stringify(to)];
|
||||
logger.info(`Device '${device.name}' was updated from '${fromS}' to '${toS}'`);
|
||||
responseData.from = from_ ? utils.toSnakeCase(from_) : null;
|
||||
|
||||
@@ -298,7 +298,7 @@ export default class Publish extends Extension {
|
||||
const scenesChanged = Object.values(usedConverters)
|
||||
.some((cl) => cl.some((c) => c.key.some((k) => sceneConverterKeys.includes(k))));
|
||||
if (scenesChanged) {
|
||||
this.eventBus.emitScenesChanged();
|
||||
this.eventBus.emitScenesChanged({entity: re});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ export default class Receive extends Extension {
|
||||
// for e.g. click switches where we need to count number of clicks and detect long presses.
|
||||
const publish = (payload: KeyValue): void => {
|
||||
const options: KeyValue = data.device.options;
|
||||
zhc.postProcessConvertedFromZigbeeMessage(data.device.definition, payload, options);
|
||||
zhc.postProcessConvertedFromZigbeeMessage(data.device.definition, payload, options, logger);
|
||||
|
||||
if (settings.get().advanced.elapsed) {
|
||||
const now = Date.now();
|
||||
@@ -138,7 +138,13 @@ export default class Receive extends Extension {
|
||||
}
|
||||
};
|
||||
|
||||
const meta = {device: data.device.zh, logger, state: this.state.get(data.device)};
|
||||
const deviceExposesChanged = (): void => {
|
||||
this.eventBus.emitDevicesChanged();
|
||||
this.eventBus.emitExposesChanged({device: data.device});
|
||||
};
|
||||
|
||||
const meta = {device: data.device.zh, logger, state: this.state.get(data.device),
|
||||
deviceExposesChanged: deviceExposesChanged};
|
||||
let payload: KeyValue = {};
|
||||
for (const converter of converters) {
|
||||
try {
|
||||
|
||||
Vendored
+2
@@ -90,6 +90,7 @@ declare global {
|
||||
type DeviceInterview = { device: Device, status: 'started' | 'successful' | 'failed' };
|
||||
type DeviceJoined = { device: Device };
|
||||
type EntityOptionsChanged = { entity: Device | Group, from: KeyValue, to: KeyValue };
|
||||
type ExposesChanged = { device: Device };
|
||||
type Reconfigure = { device: Device };
|
||||
type DeviceLeave = { ieeeAddr: string, name: string };
|
||||
type GroupMembersChanged = {group: Group, action: 'remove' | 'add' | 'remove_all',
|
||||
@@ -106,6 +107,7 @@ declare global {
|
||||
data: KeyValue | Array<string | number>;
|
||||
meta: {zclTransactionSequenceNumber?: number; manufacturerCode?: number; frameControl?: ZHFrameControl;};
|
||||
};
|
||||
type ScenesChanged = { entity: Device | Group };
|
||||
}
|
||||
|
||||
// Settings
|
||||
|
||||
Generated
+67
-40
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "zigbee2mqtt",
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "zigbee2mqtt",
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.2",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"ajv": "^8.12.0",
|
||||
@@ -33,9 +33,9 @@
|
||||
"winston-syslog": "^2.7.0",
|
||||
"winston-transport": "^4.6.0",
|
||||
"ws": "^8.16.0",
|
||||
"zigbee-herdsman": "0.30.0",
|
||||
"zigbee-herdsman-converters": "18.3.0",
|
||||
"zigbee2mqtt-frontend": "0.6.150"
|
||||
"zigbee-herdsman": "0.33.5",
|
||||
"zigbee-herdsman-converters": "18.25.1",
|
||||
"zigbee2mqtt-frontend": "0.6.152"
|
||||
},
|
||||
"bin": {
|
||||
"zigbee2mqtt": "cli.js"
|
||||
@@ -67,6 +67,9 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18 || ^20 || ^21"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"sd-notify": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@aashutoshrathi/word-wrap": {
|
||||
@@ -3597,11 +3600,6 @@
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
||||
"integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ=="
|
||||
},
|
||||
"node_modules/array-union": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||
@@ -3622,11 +3620,11 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.3.tgz",
|
||||
"integrity": "sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww==",
|
||||
"version": "1.6.5",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
|
||||
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"follow-redirects": "^1.15.4",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
@@ -3936,12 +3934,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/bonjour-service": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz",
|
||||
"integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz",
|
||||
"integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==",
|
||||
"dependencies": {
|
||||
"array-flatten": "^2.1.2",
|
||||
"dns-equal": "^1.0.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"multicast-dns": "^7.2.5"
|
||||
}
|
||||
@@ -4502,11 +4498,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/dns-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
||||
"integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg=="
|
||||
},
|
||||
"node_modules/dns-packet": {
|
||||
"version": "5.6.1",
|
||||
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz",
|
||||
@@ -5715,6 +5706,17 @@
|
||||
"resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.31.0.tgz",
|
||||
"integrity": "sha512-fRrehgBG26NNZysRlTq1S+HPtDpp3u+Jzdc/d5A4cEzOD86YLAkDaJyJg8krSdCi7CJ+s7ht3fwRj8Dl+Btd0w=="
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
@@ -8764,6 +8766,29 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"node_modules/sd-notify": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/sd-notify/-/sd-notify-2.8.0.tgz",
|
||||
"integrity": "sha512-e+D1v0Y6UzmqXcPlaTkHk1QMdqk36mF/jIYv5gwry/N2Tb8/UNnpfG6ktGLpeBOR6TCC5hPKgqA+0hTl9sm2tA==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux",
|
||||
"darwin",
|
||||
"win32"
|
||||
],
|
||||
"dependencies": {
|
||||
"bindings": "1.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||
@@ -9120,9 +9145,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz",
|
||||
"integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==",
|
||||
"version": "3.1.7",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
|
||||
"integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.4",
|
||||
"fast-fifo": "^1.2.0",
|
||||
@@ -9782,14 +9807,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/zigbee-herdsman": {
|
||||
"version": "0.30.0",
|
||||
"resolved": "https://registry.npmjs.org/zigbee-herdsman/-/zigbee-herdsman-0.30.0.tgz",
|
||||
"integrity": "sha512-EHnO34Ra0911cuUbhu6xWnQA9Weaerosd69oxpPbtNgnx6amRsA94SfbXxYM7hHZP4h1wJ0xfysyRbIat8v8vQ==",
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/zigbee-herdsman/-/zigbee-herdsman-0.33.5.tgz",
|
||||
"integrity": "sha512-oA02QU4jM44OjSPdJ3GM90HAIU1Emk2csiTXAZas0Is6FAY3S1Gv6SoO+lhqxBzMugPFp+AZI/kgPg9W3B0Umw==",
|
||||
"dependencies": {
|
||||
"@serialport/bindings-cpp": "^12.0.1",
|
||||
"@serialport/parser-delimiter": "^12.0.0",
|
||||
"@serialport/stream": "^12.0.0",
|
||||
"bonjour-service": "^1.1.1",
|
||||
"bonjour-service": "^1.2.1",
|
||||
"debounce": "^2.0.0",
|
||||
"debug": "^4.3.4",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
@@ -9799,21 +9824,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/zigbee-herdsman-converters": {
|
||||
"version": "18.3.0",
|
||||
"resolved": "https://registry.npmjs.org/zigbee-herdsman-converters/-/zigbee-herdsman-converters-18.3.0.tgz",
|
||||
"integrity": "sha512-JYyHtU3iB9KYHdmSEG1sF+Xf3RqAGEXol8udK9e0aNiP8TObUwQmqfRS8SPhBVW/A3IgOUyS0opT/lE+/51M5A==",
|
||||
"version": "18.25.1",
|
||||
"resolved": "https://registry.npmjs.org/zigbee-herdsman-converters/-/zigbee-herdsman-converters-18.25.1.tgz",
|
||||
"integrity": "sha512-7Y2aTI+BhyI56mmSf0rhnOcVV+PxJAtKd+HH/shs4/cyxuyR/rdq0EuJNXva/NeTRRpglV6kflVsJ4n+gcS7XQ==",
|
||||
"dependencies": {
|
||||
"axios": "^1.6.3",
|
||||
"axios": "^1.6.5",
|
||||
"buffer-crc32": "^0.2.13",
|
||||
"https-proxy-agent": "^7.0.2",
|
||||
"tar-stream": "^3.1.6",
|
||||
"zigbee-herdsman": "^0.30.0"
|
||||
"iconv-lite": "^0.6.3",
|
||||
"semver": "^7.5.4",
|
||||
"tar-stream": "^3.1.7",
|
||||
"zigbee-herdsman": "^0.33.5"
|
||||
}
|
||||
},
|
||||
"node_modules/zigbee2mqtt-frontend": {
|
||||
"version": "0.6.150",
|
||||
"resolved": "https://registry.npmjs.org/zigbee2mqtt-frontend/-/zigbee2mqtt-frontend-0.6.150.tgz",
|
||||
"integrity": "sha512-+BGvDQcKC0XUtVLChwFc2kBJwQkC+SA/VAsAH8tzMwx5riVrflKOH0ewnUYamT/vAqQM0cxZB9Jfnip8mXds3Q==",
|
||||
"version": "0.6.152",
|
||||
"resolved": "https://registry.npmjs.org/zigbee2mqtt-frontend/-/zigbee2mqtt-frontend-0.6.152.tgz",
|
||||
"integrity": "sha512-Nl8E6e1DLlI+DpIlIKRsygs3cdEmTPSIvA/oH/JK3JJ4jGZcNnOGe3hBPL95jv1Z/ZPS2huSn0PX7fnxu8zT4g==",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
|
||||
+8
-7
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "zigbee2mqtt",
|
||||
"version": "1.35.0",
|
||||
"version": "1.35.2",
|
||||
"description": "Zigbee to MQTT bridge using Zigbee-herdsman",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
@@ -26,9 +26,7 @@
|
||||
"start": "node index.js",
|
||||
"test-with-coverage": "jest test --coverage",
|
||||
"test": "jest test",
|
||||
"test-watch": "jest test --watch",
|
||||
"clean": "rimraf coverage dist tsconfig.tsbuildinfo",
|
||||
"prepack": "npm run clean && npm run build"
|
||||
"test-watch": "jest test --watch"
|
||||
},
|
||||
"author": "Koen Kanters",
|
||||
"license": "GPL-3.0",
|
||||
@@ -61,9 +59,9 @@
|
||||
"winston-syslog": "^2.7.0",
|
||||
"winston-transport": "^4.6.0",
|
||||
"ws": "^8.16.0",
|
||||
"zigbee-herdsman": "0.30.0",
|
||||
"zigbee-herdsman-converters": "18.3.0",
|
||||
"zigbee2mqtt-frontend": "0.6.150"
|
||||
"zigbee-herdsman": "0.33.5",
|
||||
"zigbee-herdsman-converters": "18.25.1",
|
||||
"zigbee2mqtt-frontend": "0.6.152"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.7",
|
||||
@@ -111,5 +109,8 @@
|
||||
},
|
||||
"bin": {
|
||||
"zigbee2mqtt": "cli.js"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"sd-notify": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
{
|
||||
"packages": {
|
||||
".": {
|
||||
"changelog-path": "CHANGELOG.md",
|
||||
"release-type": "node",
|
||||
"bump-minor-pre-major": false,
|
||||
"bump-patch-for-minor-pre-major": false,
|
||||
"draft": false,
|
||||
"include-component-in-tag": false,
|
||||
"include-v-in-tag": false,
|
||||
"prerelease": true,
|
||||
"skip-github-release": false
|
||||
"draft": true
|
||||
}
|
||||
},
|
||||
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
|
||||
|
||||
+3
-1
@@ -36,10 +36,12 @@ Description=zigbee2mqtt
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/npm start
|
||||
Type=notify
|
||||
ExecStart=/usr/bin/node index.js
|
||||
WorkingDirectory=/opt/zigbee2mqtt
|
||||
StandardOutput=inherit
|
||||
StandardError=inherit
|
||||
WatchdogSec=10s
|
||||
Restart=always
|
||||
User=pi
|
||||
|
||||
|
||||
+6
-5
File diff suppressed because one or more lines are too long
@@ -176,11 +176,11 @@ describe('Configure', () => {
|
||||
});
|
||||
|
||||
it('Fail to configure via MQTT when device has no configure', async () => {
|
||||
await MQTT.events.message('zigbee2mqtt/bridge/request/device/configure', stringify({id: "0x90fd9ffffe4b64ax", transaction: 20}));
|
||||
await MQTT.events.message('zigbee2mqtt/bridge/request/device/configure', stringify({id: "0x0017880104e45521", transaction: 20}));
|
||||
await flushPromises();
|
||||
expect(MQTT.publish).toHaveBeenCalledWith(
|
||||
'zigbee2mqtt/bridge/response/device/configure',
|
||||
stringify({"data":{"id": "0x90fd9ffffe4b64ax"},"status":"error","error": "Device 'ZNLDP12LM' cannot be configured","transaction":20}),
|
||||
stringify({"data":{"id": "0x0017880104e45521"},"status":"error","error": "Device 'button_double_key' cannot be configured","transaction":20}),
|
||||
{retain: false, qos: 0}, expect.any(Function)
|
||||
);
|
||||
});
|
||||
@@ -200,9 +200,9 @@ describe('Configure', () => {
|
||||
});
|
||||
|
||||
it('Legacy api: Should skip reconfigure when device does not require this', async () => {
|
||||
await MQTT.events.message('zigbee2mqtt/bridge/configure', '0x90fd9ffffe4b64ax');
|
||||
await MQTT.events.message('zigbee2mqtt/bridge/configure', '0x0017880104e45521');
|
||||
await flushPromises();
|
||||
expect(logger.warn).toHaveBeenCalledWith(`Skipping configure of 'ZNLDP12LM', device does not require this.`)
|
||||
expect(logger.warn).toHaveBeenCalledWith(`Skipping configure of 'button_double_key', device does not require this.`)
|
||||
});
|
||||
|
||||
it('Should not configure when interview not completed', async () => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
process.env.NOTIFY_SOCKET = "mocked";
|
||||
const data = require('./stub/data');
|
||||
const logger = require('./stub/logger');
|
||||
const zigbeeHerdsman = require('./stub/zigbeeHerdsman');
|
||||
@@ -16,6 +17,16 @@ const mocksClear = [
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
jest.mock('sd-notify', () => {
|
||||
return {
|
||||
watchdogInterval: () => {return 3000;},
|
||||
startWatchdogMode: (interval) => {},
|
||||
stopWatchdogMode: () => {},
|
||||
ready: () => {},
|
||||
stopping: () => {},
|
||||
};
|
||||
}, {virtual: true});
|
||||
|
||||
describe('Controller', () => {
|
||||
let controller;
|
||||
let mockExit;
|
||||
@@ -730,4 +741,14 @@ describe('Controller', () => {
|
||||
await controller.stop();
|
||||
expect(controller.state.state[device.ieeeAddr]).toStrictEqual(undefined);
|
||||
});
|
||||
|
||||
it('EventBus should handle errors', async () => {
|
||||
const eventbus = controller.eventBus;
|
||||
const callback = jest.fn().mockImplementation(async () => {throw new Error('Whoops!')});
|
||||
eventbus.onStateChange('test', callback);
|
||||
eventbus.emitStateChange({});
|
||||
await flushPromises();
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(logger.error).toHaveBeenCalledWith(`EventBus error 'String/stateChange': Whoops!`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -67,6 +67,7 @@ jest.mock('https', () => ({
|
||||
mockHTTPS.variables.onRequest = onRequest;
|
||||
return mockHTTPS.implementation;
|
||||
}),
|
||||
Agent: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("connect-gzip-static", () =>
|
||||
|
||||
+117
-66
@@ -5,9 +5,8 @@ const logger = require('./stub/logger');
|
||||
const zigbeeHerdsman = require('./stub/zigbeeHerdsman');
|
||||
const flushPromises = require('./lib/flushPromises');
|
||||
const MQTT = require('./stub/mqtt');
|
||||
const sleep = require('./stub/sleep');
|
||||
const Controller = require('../lib/controller');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
describe('HomeAssistant extension', () => {
|
||||
let version;
|
||||
@@ -42,12 +41,14 @@ describe('HomeAssistant extension', () => {
|
||||
settings.reRead();
|
||||
data.writeEmptyState();
|
||||
MQTT.publish.mockClear();
|
||||
sleep.mock();
|
||||
controller = new Controller(false);
|
||||
await controller.start();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
jest.useRealTimers();
|
||||
sleep.restore();
|
||||
});
|
||||
|
||||
it('Should not have duplicate type/object_ids in a mapping', () => {
|
||||
@@ -170,8 +171,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -200,8 +201,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -229,8 +230,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -259,8 +260,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -290,8 +291,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -311,8 +312,8 @@ describe('HomeAssistant extension', () => {
|
||||
"identifiers":[
|
||||
"zigbee2mqtt_0x0017880104e45542"
|
||||
],
|
||||
"manufacturer":"Xiaomi",
|
||||
"model":"Aqara double key wired wall switch without neutral wire. Doesn't work as a router and doesn't support power meter (QBKG03LM)",
|
||||
"manufacturer":"Aqara",
|
||||
"model":"Smart wall switch (no neutral, double rocker) (QBKG03LM)",
|
||||
"name":"wall_switch_double",
|
||||
"sw_version": null,
|
||||
"via_device": "zigbee2mqtt_bridge_0x00124b00120144ae",
|
||||
@@ -342,8 +343,8 @@ describe('HomeAssistant extension', () => {
|
||||
"identifiers":[
|
||||
"zigbee2mqtt_0x0017880104e45542"
|
||||
],
|
||||
"manufacturer":"Xiaomi",
|
||||
"model":"Aqara double key wired wall switch without neutral wire. Doesn't work as a router and doesn't support power meter (QBKG03LM)",
|
||||
"manufacturer":"Aqara",
|
||||
"model":"Smart wall switch (no neutral, double rocker) (QBKG03LM)",
|
||||
"name":"wall_switch_double",
|
||||
"sw_version": null,
|
||||
"via_device": "zigbee2mqtt_bridge_0x00124b00120144ae",
|
||||
@@ -440,8 +441,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -469,8 +470,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -498,8 +499,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -521,7 +522,7 @@ describe('HomeAssistant extension', () => {
|
||||
temperature: {
|
||||
expire_after: 90,
|
||||
device: {
|
||||
manufacturer: 'From Xiaomi',
|
||||
manufacturer: 'From Aqara',
|
||||
sw_version: 'test'
|
||||
}
|
||||
},
|
||||
@@ -529,7 +530,7 @@ describe('HomeAssistant extension', () => {
|
||||
unique_id: null,
|
||||
},
|
||||
device: {
|
||||
manufacturer: 'Not from Xiaomi',
|
||||
manufacturer: 'Not from Aqara',
|
||||
model: 'custom model',
|
||||
},
|
||||
},
|
||||
@@ -558,7 +559,7 @@ describe('HomeAssistant extension', () => {
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': 'test',
|
||||
'model': 'custom model',
|
||||
'manufacturer': 'From Xiaomi',
|
||||
'manufacturer': 'From Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -586,7 +587,7 @@ describe('HomeAssistant extension', () => {
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'custom model',
|
||||
'manufacturer': 'Not from Xiaomi',
|
||||
'manufacturer': 'Not from Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'origin': origin,
|
||||
@@ -632,8 +633,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'Weather Sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -662,8 +663,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'Weather Sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -704,8 +705,8 @@ describe('HomeAssistant extension', () => {
|
||||
"identifiers": [
|
||||
"zigbee2mqtt_0x0017880104e45541"
|
||||
],
|
||||
"manufacturer": "Xiaomi",
|
||||
"model": "Aqara single key wired wall switch without neutral wire. Doesn't work as a router and doesn't support power meter (QBKG04LM)",
|
||||
"manufacturer": "Aqara",
|
||||
"model": "Smart wall switch (no neutral, single rocker) (QBKG04LM)",
|
||||
"name": "my_switch",
|
||||
"sw_version": null,
|
||||
"via_device": "zigbee2mqtt_bridge_0x00124b00120144ae",
|
||||
@@ -967,8 +968,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -1096,8 +1097,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -1234,8 +1235,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability_mode': 'all',
|
||||
@@ -1311,8 +1312,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor_renamed',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -1347,8 +1348,8 @@ describe('HomeAssistant extension', () => {
|
||||
],
|
||||
"name":"weather_sensor_renamed",
|
||||
"sw_version": null,
|
||||
"model":"Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)",
|
||||
"manufacturer":"Xiaomi",
|
||||
"model":"Temperature and humidity sensor (WSDCGQ11LM)",
|
||||
"manufacturer":"Aqara",
|
||||
"via_device": "zigbee2mqtt_bridge_0x00124b00120144ae",
|
||||
}
|
||||
}),
|
||||
@@ -1448,8 +1449,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor_renamed',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -1524,8 +1525,8 @@ describe('HomeAssistant extension', () => {
|
||||
],
|
||||
"name":"button",
|
||||
"sw_version": null,
|
||||
"model":"Aqara wireless switch (WXKG11LM)",
|
||||
"manufacturer":"Xiaomi",
|
||||
"model":"Wireless mini switch (WXKG11LM)",
|
||||
"manufacturer":"Aqara",
|
||||
"via_device": "zigbee2mqtt_bridge_0x00124b00120144ae",
|
||||
}
|
||||
};
|
||||
@@ -1550,8 +1551,8 @@ describe('HomeAssistant extension', () => {
|
||||
],
|
||||
"name":"button",
|
||||
"sw_version": null,
|
||||
"model":"Aqara wireless switch (WXKG11LM)",
|
||||
"manufacturer":"Xiaomi",
|
||||
"model":"Wireless mini switch (WXKG11LM)",
|
||||
"manufacturer":"Aqara",
|
||||
"via_device": "zigbee2mqtt_bridge_0x00124b00120144ae",
|
||||
}
|
||||
};
|
||||
@@ -1716,8 +1717,8 @@ describe('HomeAssistant extension', () => {
|
||||
],
|
||||
"name":"button",
|
||||
"sw_version": null,
|
||||
"model":"Aqara wireless switch (WXKG11LM)",
|
||||
"manufacturer":"Xiaomi",
|
||||
"model":"Wireless mini switch (WXKG11LM)",
|
||||
"manufacturer":"Aqara",
|
||||
"via_device": "zigbee2mqtt_bridge_0x00124b00120144ae",
|
||||
}
|
||||
};
|
||||
@@ -1751,7 +1752,7 @@ describe('HomeAssistant extension', () => {
|
||||
|
||||
await MQTT.events.message('zigbee2mqtt/U202DST600ZB/l2/set', stringify({state: 'ON', brightness: 20}));
|
||||
await flushPromises();
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/U202DST600ZB', stringify({state_l2:"ON", brightness_l2:20, linkquality: null, state_l1: null}), {"qos": 0, "retain": false}, expect.any(Function));
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/U202DST600ZB', stringify({state_l2:"ON", brightness_l2:20, linkquality: null, state_l1: null, power_on_behavior: null}), {"qos": 0, "retain": false}, expect.any(Function));
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/U202DST600ZB/l2', stringify({state:"ON", brightness:20}), {"qos": 0, "retain": false}, expect.any(Function));
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/U202DST600ZB/l1', stringify({state: null}), {"qos": 0, "retain": false}, expect.any(Function));
|
||||
});
|
||||
@@ -1891,8 +1892,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae'
|
||||
},
|
||||
'availability': [{topic: 'zigbee2mqtt/bridge/state'}],
|
||||
@@ -2136,8 +2137,8 @@ describe('HomeAssistant extension', () => {
|
||||
'identifiers': ['zigbee2mqtt_0x0017880104e45522'],
|
||||
'name': 'weather_sensor',
|
||||
'sw_version': null,
|
||||
'model': 'Aqara temperature, humidity and pressure sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Xiaomi',
|
||||
'model': 'Temperature and humidity sensor (WSDCGQ11LM)',
|
||||
'manufacturer': 'Aqara',
|
||||
'configuration_url': 'http://zigbee.mqtt/#/device/0x0017880104e45522/info',
|
||||
'via_device': 'zigbee2mqtt_bridge_0x00124b00120144ae',
|
||||
},
|
||||
@@ -2153,8 +2154,12 @@ describe('HomeAssistant extension', () => {
|
||||
});
|
||||
|
||||
it('Should rediscover scenes when a scene is changed', async () => {
|
||||
|
||||
// Device/endpoint scenes.
|
||||
const device = controller.zigbee.resolveEntity(zigbeeHerdsman.devices.bulb_color_2);
|
||||
|
||||
MQTT.publish.mockClear();
|
||||
controller.eventBus.emitScenesChanged();
|
||||
controller.eventBus.emitScenesChanged({entity: device});
|
||||
await flushPromises();
|
||||
|
||||
// Discovery messages for scenes have been purged.
|
||||
@@ -2164,12 +2169,6 @@ describe('HomeAssistant extension', () => {
|
||||
{retain: true, qos: 1},
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(MQTT.publish).toHaveBeenCalledWith(
|
||||
`homeassistant/scene/1221051039810110150109113116116_9/scene_4/config`,
|
||||
null,
|
||||
{retain: true, qos: 1},
|
||||
expect.any(Function),
|
||||
);
|
||||
jest.runOnlyPendingTimers();
|
||||
await flushPromises();
|
||||
|
||||
@@ -2197,6 +2196,24 @@ describe('HomeAssistant extension', () => {
|
||||
{retain: true, qos: 1},
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(MQTT.publish).toHaveBeenCalledTimes( 12 );
|
||||
|
||||
// Group scenes.
|
||||
const group = controller.zigbee.resolveEntity('ha_discovery_group');
|
||||
|
||||
MQTT.publish.mockClear();
|
||||
controller.eventBus.emitScenesChanged({entity: group});
|
||||
await flushPromises();
|
||||
|
||||
// Discovery messages for scenes have been purged.
|
||||
expect(MQTT.publish).toHaveBeenCalledWith(
|
||||
`homeassistant/scene/1221051039810110150109113116116_9/scene_4/config`,
|
||||
null,
|
||||
{retain: true, qos: 1},
|
||||
expect.any(Function),
|
||||
);
|
||||
jest.runOnlyPendingTimers();
|
||||
await flushPromises();
|
||||
|
||||
payload = {
|
||||
'name': 'Scene 4',
|
||||
@@ -2222,9 +2239,7 @@ describe('HomeAssistant extension', () => {
|
||||
{retain: true, qos: 1},
|
||||
expect.any(Function),
|
||||
);
|
||||
|
||||
// Only discovery entries for entities with scenes need to be republished.
|
||||
expect(MQTT.publish).toHaveBeenCalledTimes( 16 );
|
||||
expect(MQTT.publish).toHaveBeenCalledTimes( 6 );
|
||||
});
|
||||
|
||||
it('Should not clear bridge entities unnecessarily', async () => {
|
||||
@@ -2287,7 +2302,7 @@ describe('HomeAssistant extension', () => {
|
||||
'device_class': 'connectivity',
|
||||
'unique_id': 'bridge_0x00124b00120144ae_connection_state_zigbee2mqtt',
|
||||
'state_topic': 'zigbee2mqtt/bridge/state',
|
||||
'value_template': '{{ value_json.state }}',
|
||||
'value_template': '{{ value }}',
|
||||
'payload_on': 'online',
|
||||
'payload_off': 'offline',
|
||||
'origin': origin,
|
||||
@@ -2488,4 +2503,40 @@ describe('HomeAssistant extension', () => {
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it('Should publish discovery message when a converter announces changed exposes', async () => {
|
||||
MQTT.publish.mockClear();
|
||||
const device = zigbeeHerdsman.devices['BMCT-SLZ'];
|
||||
const data = {deviceMode: 0}
|
||||
const msg = {data, cluster: 'manuSpecificBosch10', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10};
|
||||
await zigbeeHerdsman.events.message(msg);
|
||||
const payload = {
|
||||
'availability':[{'topic':'zigbee2mqtt/bridge/state'}],
|
||||
'command_topic':'zigbee2mqtt/0x18fc26000000cafe/set/device_mode',
|
||||
'device':{
|
||||
'identifiers':['zigbee2mqtt_0x18fc26000000cafe'],
|
||||
'manufacturer':'Bosch',
|
||||
'model':'Light/shutter control unit II (BMCT-SLZ)',
|
||||
'name':'0x18fc26000000cafe',
|
||||
'sw_version':null,
|
||||
'via_device':'zigbee2mqtt_bridge_0x00124b00120144ae'
|
||||
},
|
||||
'entity_category':'config',
|
||||
'icon':'mdi:tune',
|
||||
'json_attributes_topic':'zigbee2mqtt/0x18fc26000000cafe',
|
||||
'name':'Device mode',
|
||||
'object_id':'0x18fc26000000cafe_device_mode',
|
||||
'options':['light','shutter','disabled'],
|
||||
'origin': origin,
|
||||
'state_topic':'zigbee2mqtt/0x18fc26000000cafe',
|
||||
'unique_id':'0x18fc26000000cafe_device_mode_zigbee2mqtt',
|
||||
'value_template':'{{ value_json.device_mode }}'
|
||||
}
|
||||
expect(MQTT.publish).toHaveBeenCalledWith(
|
||||
"homeassistant/select/0x18fc26000000cafe/device_mode/config",
|
||||
stringify(payload),
|
||||
{ retain: true, qos: 1 },
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ const flushPromises = require('./lib/flushPromises');
|
||||
const mocksClear = [MQTT.publish, logger.warn, logger.debug];
|
||||
const setTimeoutNative = setTimeout;
|
||||
|
||||
describe('Networkmap', () => {
|
||||
describe('onlythisNetworkmap', () => {
|
||||
let controller;
|
||||
|
||||
beforeAll(async () => {
|
||||
@@ -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, color_options, 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":{"description":"Automatically generated definition","model":"notSupportedModelID","supports":"linkquality","vendor":"Boef"},"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, color_options, 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":"Wireless remote switch (double rocker), 2016 model","model":"WXKG02LM_rev1","supports":"battery, action, voltage, power_outage_count, linkquality","vendor":"Aqara"},"friendlyName":"button_double_key","ieeeAddr":"0x0017880104e45521","lastSeen":1000,"modelID":"lumi.sensor_86sw2.es1","networkAddress":6538,"type":"EndDevice"},{"definition":{"description":"Automatically generated definition","model":"notSupportedModelID","supports":"linkquality","vendor":"Boef"},"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);
|
||||
|
||||
/**
|
||||
@@ -148,7 +148,7 @@ describe('Networkmap', () => {
|
||||
"0x000b57fffec6a5b3" [style="rounded, filled", fillcolor="#4ea3e0", fontcolor="#ffffff", label="{bulb_color|0x000b57fffec6a5b3 (0x9dcf)|Philips Hue Go (7146060PH)|unknown}"];
|
||||
"0x000b57fffec6a5b3" -> "0x00124b00120144ae" [penwidth=0.5, weight=0, color="#994444", label="120"]
|
||||
"0x000b57fffec6a5b3" -> "0x000b57fffec6a5b2" [penwidth=0.5, weight=0, color="#994444", label="110"]
|
||||
"0x0017880104e45521" [style="rounded, dashed, filled", fillcolor="#fff8ce", fontcolor="#000000", label="{button_double_key|0x0017880104e45521 (0x198a)|Xiaomi Aqara double key wireless wall switch (2016 model) (WXKG02LM_rev1)|9 seconds ago}"];
|
||||
"0x0017880104e45521" [style="rounded, dashed, filled", fillcolor="#fff8ce", fontcolor="#000000", label="{button_double_key|0x0017880104e45521 (0x198a)|Aqara Wireless remote switch (double rocker), 2016 model (WXKG02LM_rev1)|9 seconds ago}"];
|
||||
"0x0017880104e45521" -> "0x0017880104e45559" [penwidth=1, weight=0, color="#994444", label="130"]
|
||||
"0x0017880104e45525" [style="rounded, filled", fillcolor="#4ea3e0", fontcolor="#ffffff", label="{0x0017880104e45525|0x0017880104e45525 (0x1988)failed: lqi,routingTable|Boef Automatically generated definition (notSupportedModelID)|9 seconds ago}"];
|
||||
"0x0017880104e45559" [style="rounded, filled", fillcolor="#4ea3e0", fontcolor="#ffffff", label="{cc2530_router|0x0017880104e45559 (0x198c)|Custom devices (DiY) [CC2530 router](http://ptvo.info/cc2530-based-zigbee-coordinator-and-router-112/) (CC2530.ROUTER)|9 seconds ago}"];
|
||||
@@ -227,7 +227,7 @@ describe('Networkmap', () => {
|
||||
---
|
||||
0x0017880104e45521 (0x198a)
|
||||
---
|
||||
Xiaomi Aqara double key wireless wall switch (2016 model) (WXKG02LM_rev1)
|
||||
Aqara Wireless remote switch (double rocker), 2016 model (WXKG02LM_rev1)
|
||||
---
|
||||
9 seconds ago
|
||||
]
|
||||
@@ -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, color_options, 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":{"description":"Automatically generated definition","model":"notSupportedModelID","supports":"linkquality","vendor":"Boef"},"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, color_options, 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":"Wireless remote switch (double rocker), 2016 model","model":"WXKG02LM_rev1","supports":"battery, action, voltage, power_outage_count, linkquality","vendor":"Aqara"},"friendlyName":"button_double_key","ieeeAddr":"0x0017880104e45521","lastSeen":1000,"modelID":"lumi.sensor_86sw2.es1","networkAddress":6538,"type":"EndDevice"},{"definition":{"description":"Automatically generated definition","model":"notSupportedModelID","supports":"linkquality","vendor":"Boef"},"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);
|
||||
});
|
||||
@@ -303,7 +303,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":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":{"description":"Automatically generated definition","model":"notSupportedModelID","supports":"linkquality","vendor":"Boef"},"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":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":"Wireless remote switch (double rocker), 2016 model","model":"WXKG02LM_rev1","supports":"battery, action, voltage, power_outage_count, linkquality","vendor":"Aqara"},"friendlyName":"button_double_key","ieeeAddr":"0x0017880104e45521","lastSeen":1000,"modelID":"lumi.sensor_86sw2.es1","networkAddress":6538,"type":"EndDevice"},{"definition":{"description":"Automatically generated definition","model":"notSupportedModelID","supports":"linkquality","vendor":"Boef"},"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);
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ const path = require('path');
|
||||
|
||||
const data = require('./stub/data');
|
||||
const logger = require('./stub/logger');
|
||||
const sleep = require('./stub/sleep');
|
||||
const zigbeeHerdsman = require('./stub/zigbeeHerdsman');
|
||||
const MQTT = require('./stub/mqtt');
|
||||
const settings = require('../lib/util/settings');
|
||||
@@ -35,6 +36,7 @@ describe('OTA update', () => {
|
||||
settings.reRead();
|
||||
jest.useFakeTimers();
|
||||
controller = new Controller(jest.fn(), jest.fn());
|
||||
sleep.mock();
|
||||
await controller.start();
|
||||
await jest.runOnlyPendingTimers();
|
||||
await flushPromises();
|
||||
@@ -47,6 +49,7 @@ describe('OTA update', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
jest.useRealTimers();
|
||||
sleep.restore();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -86,8 +89,8 @@ describe('OTA update', () => {
|
||||
expect(logger.info).toHaveBeenCalledWith(`Finished update of 'bulb'`);
|
||||
expect(logger.info).toHaveBeenCalledWith(`Device 'bulb' was updated from '{"dateCode":"20190101","softwareBuildID":1}' to '{"dateCode":"20190103","softwareBuildID":3}'`);
|
||||
expect(device.save).toHaveBeenCalledTimes(2);
|
||||
expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {'sendWhen': 'immediate'});
|
||||
expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {'sendWhen': 'active'});
|
||||
expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {'sendPolicy': 'immediate'});
|
||||
expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {});
|
||||
expect(MQTT.publish).toHaveBeenCalledWith(
|
||||
'zigbee2mqtt/bulb',
|
||||
stringify({"update_available":false,"update":{"state":"updating","progress":0}}),
|
||||
@@ -389,7 +392,7 @@ describe('OTA update', () => {
|
||||
expect(logger.info).toHaveBeenCalledWith(`Device 'bulb' was updated from '{"dateCode":"20190101","softwareBuildID":1}' to '{"dateCode":"20190103","softwareBuildID":3}'`);
|
||||
expect(logger.error).toHaveBeenCalledTimes(0);
|
||||
expect(device.save).toHaveBeenCalledTimes(2);
|
||||
expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {'sendWhen': 'immediate'});
|
||||
expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {'sendPolicy': 'immediate'});
|
||||
});
|
||||
|
||||
it('Legacy api: Should handle when OTA update fails', async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const data = require('./stub/data');
|
||||
const sleep = require('./stub/sleep');
|
||||
const logger = require('./stub/logger');
|
||||
const zigbeeHerdsman = require('./stub/zigbeeHerdsman');
|
||||
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
|
||||
@@ -30,6 +31,7 @@ describe('Publish', () => {
|
||||
jest.useFakeTimers();
|
||||
data.writeEmptyState();
|
||||
controller = new Controller(jest.fn(), jest.fn());
|
||||
sleep.mock();
|
||||
await controller.start();
|
||||
await flushPromises();
|
||||
});
|
||||
@@ -56,6 +58,7 @@ describe('Publish', () => {
|
||||
afterAll(async () => {
|
||||
jest.runOnlyPendingTimers();
|
||||
jest.useRealTimers();
|
||||
sleep.restore();
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee devices', async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const data = require('./stub/data');
|
||||
const sleep = require('./stub/sleep');
|
||||
const logger = require('./stub/logger');
|
||||
const stringify = require('json-stable-stringify-without-jsonify');
|
||||
const zigbeeHerdsman = require('./stub/zigbeeHerdsman');
|
||||
@@ -15,6 +16,7 @@ describe('Receive', () => {
|
||||
beforeAll(async () => {
|
||||
jest.useFakeTimers();
|
||||
controller = new Controller(jest.fn(), jest.fn());
|
||||
sleep.mock();
|
||||
await controller.start();
|
||||
await jest.runOnlyPendingTimers();
|
||||
await flushPromises();
|
||||
@@ -30,6 +32,7 @@ describe('Receive', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
jest.useRealTimers();
|
||||
sleep.restore();
|
||||
});
|
||||
|
||||
it('Should handle a zigbee message', async () => {
|
||||
@@ -464,4 +467,11 @@ describe('Receive', () => {
|
||||
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/SP600_OLD');
|
||||
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({energy: 6.65, power: 496});
|
||||
});
|
||||
it('Should emit DevicesChanged event when a converter announces changed exposes', async () => {
|
||||
const device = zigbeeHerdsman.devices['BMCT-SLZ'];
|
||||
const data = {deviceMode: 0}
|
||||
const payload = {data, cluster: 'manuSpecificBosch10', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10};
|
||||
await zigbeeHerdsman.events.message(payload);
|
||||
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual("zigbee2mqtt/bridge/devices");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
const utils = require('../../lib/util/utils');
|
||||
const spy = jest.spyOn(utils.default, 'sleep');
|
||||
|
||||
export function mock() {
|
||||
spy.mockImplementation(() => {});
|
||||
}
|
||||
|
||||
export function restore() {
|
||||
spy.mockRestore();
|
||||
}
|
||||
@@ -204,6 +204,8 @@ const devices = {
|
||||
'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'),
|
||||
'BMCT-SLZ': new Device('Router', '0x18fc26000000cafe', 6546,4617, [new Endpoint(1, [0,3,4,5,258,1794,2820,2821,64672], [10,25], '0x18fc26000000cafe')], true, "Mains (single phase)", 'RBSH-MMS-ZB-EU'),
|
||||
|
||||
}
|
||||
|
||||
const mock = {
|
||||
|
||||
+1
-2
@@ -16,8 +16,7 @@
|
||||
"rootDir": "lib",
|
||||
"inlineSourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"experimentalDecorators": true,
|
||||
"incremental": true
|
||||
"experimentalDecorators": true
|
||||
},
|
||||
"include": [
|
||||
"lib/**/*",
|
||||
|
||||
Reference in New Issue
Block a user