Files
esh-pfi-infrastructure/stacks/zigbee2mqtt/README.md
T
vh c7b32418e1 feat(zigbee2mqtt): Zigbee2MQTT 2.14.1 on esh-docker-vm, replacing HA's ZHA
Requested by ha-dev; approved by Prime in this session. Radio: SLZB-MR1U chip 0
(EFR32MG21, EmberZNet 8.0.2) at tcp://10.0.90.10:6638, adapter ember. A fresh
network was formed on channel 25, PAN 0xCFF4. The broker is reached as mosquitto
user zigbee2mqtt, with HA discovery on homeassistant/. The frontend on :8099 is
token-protected.

State and the network key stay host-only in /opt/docker/data/zigbee2mqtt
(root 0700, restic). The repo carries only compose, .env.example and the README.
configuration.yaml refers to the secrets as !secret.yaml, and those references
survived Z2M's v4->v5 settings migration.
2026-09-27 12:43:49 -07:00

4.1 KiB

zigbee2mqtt

The house Zigbee stack on esh-docker-vm, replacing Home Assistant's ZHA. It was requested by ha-dev and approved by Prime on 2026-09-27. It started greenfield: the Zigbee network had no devices, so nothing was migrated.

Frontend http://10.0.50.45:8099, protected by an auth token (vault esh-docker-vm/zigbee2mqtt-frontend-token)
Image koenkk/zigbee2mqtt:2.14.1@sha256:fef0de76… (.env IMAGE, digest-pinned)
Radio SLZB-MR1U 10.0.90.10 (VLAN 90), chip 0 = EFR32MG21 / EmberZNet 8.0.2, tcp://10.0.90.10:6638, adapter ember. Chip 1 (CC2652P7, :6639) is unused.
Network channel 25, PAN ID 0xCFF4 (53236), extended PAN ID 0xd0cbe1735919b497, coordinator IEEE 0x187a3efffe99a487. Formed fresh on 2026-09-27 (the EFR32 left the abandoned ZHA network: channel 25, PAN 0xF09F).
MQTT mqtt://mosquitto:1883 over traefik-net, as broker user zigbee2mqtt (vault esh-docker-vm/zigbee2mqtt-mqtt-password). Base topic zigbee2mqtt, HA discovery on homeassistant/.
State /opt/docker/data/zigbee2mqtt (root 0700): configuration.yaml, secret.yaml, coordinator_backup.json, database.db. Backed up by the host's restic (/opt/docker).

⚠ The network key

secret.yaml holds the Zigbee network key, which encrypts the whole mesh. The same key is in the vault as esh-docker-vm/zigbee2mqtt-network-key. If it is lost, every device must be re-paired. It must never be in git. That is why this repo holds only compose.yaml, .env.example and this README; the data dir is host-only and deploy-stack.sh never touches it. configuration.yaml refers to the secrets as '!secret.yaml <key>'.

Notes

  • One client per radio socket. HA's ZHA must stay disabled or deleted while Z2M owns 6638.
  • Configured by IP. Containers here cannot resolve *.internal. The SLZB's mDNS TXT record advertises radio_type znp for 6638, which is wrong: 6638 speaks EZSP/Ember.
  • Pairing is timed. Z2M 2.x has no permit_join setting. Joining is opened from the frontend or over MQTT, and closes on a timer.
  • The broker user was added with mosquitto_passwd + SIGHUP; the password file's owner and mode are unchanged (1883, 0600). The broker still has allow_anonymous true, a pre-existing setting that is not this stack's to change.

Acceptance (2026-09-27, first start at 1240)

  • Z2M 2.14.1 on EmberZNet 8.0.2 (EZSP 14). herdsman reported "Adapter network does not match config. Leaving network...", found no backup, and formed a new network on channel 25: PAN 0xCFF4. It wrote coordinator_backup.json.
  • zigbee2mqtt/bridge/state = {"state":"online"}, and the bridge's 8 HA discovery configs are retained under homeassistant/+/1221051039810110150109113116116_0x187a3efffe99a487/…. Whether the device shows up in HA is ha-dev's to confirm.
  • On startup Z2M migrated the settings to version: 5. All three !secret.yaml references survived the rewrite, so no key is in plaintext in configuration.yaml. The pre-migration file is kept as configuration_backup_v4.yaml.
  • Frontend: HTTP 200. The websocket accepts the vault token, and closes with 4401 Unauthorized on a wrong token or no token.
  • Broker: the new user is accepted, a wrong password is refused, and the reload disconnected no one. Afterwards 3 clients were connected (HA, the denspots Tasmota, Z2M). The Tasmotas consoletree, fireplacetree and mantlelights show LWT Offline, but they have not connected at any point in the broker's current log (back to 2026-09-09), so that predates this change.

Deploy

scripts/deploy-stack.sh esh-docker-vm zigbee2mqtt --compose
# on the host, first time only:
# /opt/docker/compose/zigbee2mqtt is lkraven:docker 2755, so infra-ops cannot `cp` into it
cd /opt/docker/compose/zigbee2mqtt && sudo -n install -o lkraven -g docker -m 644 .env.example .env \
  && docker compose config -q && docker compose up -d

To upgrade, change IMAGE in the host .env to a new tag@digest, then run docker compose up -d. Read the release notes first: an adapter or firmware change can require re-pairing.