Files
esh-pfi-infrastructure/stacks/zigbee2mqtt
vh 0b8632a7ed fix(esh-docker-vm): /32 route to Home Assistant over macvlan-shim
The shim holds 10.0.50.47/24, which gives two equal connected 10.0.50.0/24 routes,
and ens18's wins. Host-to-HA traffic therefore left via the macvlan parent and was
dropped. HA lost MQTT to the broker on this host on 2026-08-19, 2026-09-21 and
2026-09-25 (the last lasted two days). This adds an ifupdown if-up.d hook that
routes 10.0.50.46/32 via macvlan-shim; /etc/network/interfaces is not edited.
Verified: the route resolves via the shim, the host pings HA, HA reaches :1883,
and HA reconnected to the broker. Diagnosis by ha-dev.

Also corrects the zigbee2mqtt acceptance note, which had wrongly reported HA as
connected.
2026-09-27 12:50:05 -07:00
..

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, and a wrong password is refused. ⚠ Correction (1250): I first reported HA's MQTT client as connected. It was not. HA had lost the broker at 2026-09-25 06:13, because host→HA traffic left via ens18 instead of the macvlan shim (ha-dev diagnosed it). The third "client" I counted was my own probe. Fixed by playbooks/esh-docker-vm-macvlan-shim-route.yaml, a /32 route to 10.0.50.46 over macvlan-shim. HA reconnected at 1249. 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.