Zigbee2MQTT deployment for no-re-pair ZHA migration #364

Merged
k.renner merged 2 commits from claude-bot/zha-to-zigbee2mqtt into master 2026-07-23 10:02:18 +00:00
Member

What & why

Lays down Zigbee2MQTT (Z2M) in the home-assistant namespace as the eventual replacement for the ZHA integration. Z2M is wired to drive the same coordinator ZHA uses today — SMLIGHT SLZB-06 / TI CC2652 (zstack/zigpy-znp) at tcp://slzb-zigbee.renner.uno:6638.

No re-pairing. Devices are joined to the network stored on the coordinator chip. If Z2M starts configured with the existing network parameters (pan_id, ext_pan_id, network_key, channel), zigbee-herdsman adopts that network instead of forming a new one — every device stays joined. Getting those parameters wrong (or leaving them default) makes Z2M form a new network and drop every device; two interlocks prevent that (below).

Safe to merge — ships inert

  • The Deployment is replicas: 0. Reconciling this PR starts nothing and does not touch the running Zigbee network.
  • The ZHA network parameters come from the zigbee2mqtt-network ExternalSecret (OpenBao), populated only at cutover. Until then it's NotReady, the Secret is absent, and the pod cannot start — so it can never accidentally form a new network.

Going live is a manual, documented, reversible procedure: see zigbee2mqtt-migration-runbook.md.

Contents

File Purpose
zigbee2mqtt-deployment.yaml Z2M @ 2.12.1, replicas: 0. Init container renders /app/data/secret.yaml from Secrets each start and seeds configuration.yaml once.
zigbee2mqtt-config.yaml Seed-only config template. Secrets pulled via Z2M !secret → the network key never touches git or the ConfigMap.
zigbee2mqtt-pvc.yaml / -service.yaml 1Gi RWO state PVC; ClusterIP Service on 8080 (frontend).
zigbee2mqtt-network-externalsecret.yaml OpenBao-backed network params, populated at cutover from a ZHA network backup.
mosquitto-bootstrap.yaml / mosquitto-deployment.yaml New zigbee2mqtt broker user (bootstrap Job + passwd/ACL/env), scoped to zigbee2mqtt/# + write homeassistant/# for HA MQTT discovery.
zigbee2mqtt-migration-runbook.md Cutover + rollback procedure.

Notes / decisions

  • No new egress CiliumNetworkPolicy. The namespace-wide default-deny policy already grants every pod same-namespace (mosquitto), DNS, and world (the IoT-VLAN coordinator). A scoped policy would be documentation only (Cilium is additive).
  • Secrets via !secret, not ZIGBEE2MQTT_CONFIG_* env overrides — the env path mis-splits keys that contain underscores (network_key, ext_pan_id), which is exactly where a silent mismatch → network re-form would hurt.
  • Validated: kubectl kustomize builds; all new objects pass kubectl apply --dry-run=server.

Follow-ups (not blocking)

  • homeassistant repo PR — re-point automations/dashboards/scripts from ZHA entity IDs (*_texas_instruments_coordinator_*) to the new Z2M MQTT-discovery entities. This is the real bulk of the migration effort (new unique_ids ⇒ new entities). Precedent: the prior ZHA→Matter cover migration.
  • Gated ingress for the frontend (Authentik outpost, like esphome/shelly-manager); Flux image-automation policy for the tag.

🤖 Generated with Claude Code

## What & why Lays down **Zigbee2MQTT (Z2M)** in the `home-assistant` namespace as the eventual replacement for the **ZHA** integration. Z2M is wired to drive the **same coordinator ZHA uses today** — SMLIGHT SLZB-06 / TI CC2652 (`zstack`/`zigpy-znp`) at `tcp://slzb-zigbee.renner.uno:6638`. **No re-pairing.** Devices are joined to the network stored on the coordinator chip. If Z2M starts configured with the *existing* network parameters (`pan_id`, `ext_pan_id`, `network_key`, `channel`), `zigbee-herdsman` **adopts** that network instead of forming a new one — every device stays joined. Getting those parameters wrong (or leaving them default) makes Z2M **form a new network** and drop every device; two interlocks prevent that (below). ## Safe to merge — ships inert - The Deployment is **`replicas: 0`**. Reconciling this PR starts nothing and does not touch the running Zigbee network. - The ZHA network parameters come from the `zigbee2mqtt-network` **ExternalSecret** (OpenBao), populated **only at cutover**. Until then it's NotReady, the Secret is absent, and the pod **cannot** start — so it can never accidentally form a new network. Going live is a **manual, documented, reversible** procedure: see `zigbee2mqtt-migration-runbook.md`. ## Contents | File | Purpose | |---|---| | `zigbee2mqtt-deployment.yaml` | Z2M @ `2.12.1`, `replicas: 0`. Init container renders `/app/data/secret.yaml` from Secrets each start and seeds `configuration.yaml` once. | | `zigbee2mqtt-config.yaml` | Seed-only config template. Secrets pulled via Z2M `!secret` → the network key never touches git or the ConfigMap. | | `zigbee2mqtt-pvc.yaml` / `-service.yaml` | 1Gi RWO state PVC; ClusterIP Service on 8080 (frontend). | | `zigbee2mqtt-network-externalsecret.yaml` | OpenBao-backed network params, populated at cutover from a ZHA network backup. | | `mosquitto-bootstrap.yaml` / `mosquitto-deployment.yaml` | New `zigbee2mqtt` broker user (bootstrap Job + passwd/ACL/env), scoped to `zigbee2mqtt/#` + write `homeassistant/#` for HA MQTT discovery. | | `zigbee2mqtt-migration-runbook.md` | Cutover + rollback procedure. | ## Notes / decisions - **No new egress CiliumNetworkPolicy.** The namespace-wide default-deny policy already grants every pod same-namespace (mosquitto), DNS, and `world` (the IoT-VLAN coordinator). A scoped policy would be documentation only (Cilium is additive). - **Secrets via `!secret`, not `ZIGBEE2MQTT_CONFIG_*` env overrides** — the env path mis-splits keys that contain underscores (`network_key`, `ext_pan_id`), which is exactly where a silent mismatch → network re-form would hurt. - Validated: `kubectl kustomize` builds; all new objects pass `kubectl apply --dry-run=server`. ## Follow-ups (not blocking) - **`homeassistant` repo PR** — re-point automations/dashboards/scripts from ZHA entity IDs (`*_texas_instruments_coordinator_*`) to the new Z2M MQTT-discovery entities. This is the real bulk of the migration effort (new `unique_id`s ⇒ new entities). Precedent: the prior ZHA→Matter cover migration. - Gated ingress for the frontend (Authentik outpost, like `esphome`/`shelly-manager`); Flux image-automation policy for the tag. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude-bot added 1 commit 2026-07-23 09:10:56 +00:00
Lay down Zigbee2MQTT (Z2M) in the home-assistant namespace as the eventual
replacement for the ZHA integration, wired to drive the SAME coordinator ZHA
uses today (SMLIGHT SLZB-06 / TI CC2652, tcp://slzb-zigbee.renner.uno:6638).

Devices are joined to the network on the coordinator chip, so if Z2M comes up
with the existing network parameters (pan_id, ext_pan_id, network_key, channel)
zigbee-herdsman ADOPTS that network instead of forming a new one — every device
stays joined, no re-pairing.

Ships INERT and safe to merge:
  - Deployment is replicas: 0. Reconciling this PR starts nothing.
  - The ZHA network params come from the `zigbee2mqtt-network` ExternalSecret
    (OpenBao), populated only at cutover. Until then the ExternalSecret is
    NotReady and the pod cannot start, so it can never accidentally form a new
    network (which would drop every device).
The cutover is a manual, documented, reversible procedure — see
zigbee2mqtt-migration-runbook.md.

Contents:
  - zigbee2mqtt-{pvc,config,deployment,service}.yaml — the app. Config template
    is seeded to the PVC once; secrets (mqtt password + ZHA network params) are
    injected via /app/data/secret.yaml (rendered each start by an init
    container) and referenced with Z2M `!secret`, keeping the network key out
    of git and out of the ConfigMap.
  - zigbee2mqtt-network-externalsecret.yaml — OpenBao-backed network params,
    populated at cutover from a ZHA network backup.
  - New `zigbee2mqtt` Mosquitto broker user: bootstrap Job
    (mosquitto-bootstrap.yaml) + passwd/ACL/env (mosquitto-deployment.yaml),
    scoped to zigbee2mqtt/# plus write homeassistant/# for HA MQTT discovery.
  - zigbee2mqtt-migration-runbook.md — the cutover + rollback procedure.

No new egress CiliumNetworkPolicy is needed: the namespace-wide default-deny
policy already grants same-namespace (mosquitto), DNS, and world (the IoT-VLAN
coordinator) to every pod.

Follow-up (separate homeassistant-repo PR): re-point automations/dashboards
from ZHA entity ids to the new Z2M MQTT-discovery entities.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
claude-bot marked the pull request as ready for review 2026-07-23 09:49:56 +00:00
claude-bot added 1 commit 2026-07-23 09:57:17 +00:00
Pull the live ZHA device registry (31 devices + coordinator) and pre-seed each
device's friendly_name in the Z2M config, keyed by IEEE. Devices then come up as
"EG Küche Tischlampe Oben" instead of "0x001788010856bb17" the moment Z2M
re-interviews them on the adopted network — which is what keeps the HA-side
entity reconciliation small and mechanical. Two devices that were both bare
"Deckenlampe" in ZHA are disambiguated by area (Z2M requires unique friendly
names): EG Galerie (Hue LTC001) and DG Lager (LUMI N1 switch).

Add zigbee2mqtt-entity-reconciliation.md: an audit of exactly which ZHA entities
the git-tracked config references, so the cutover knows what must be re-pointed.
Key result — the HA-side change is FAR smaller than "rewire everything":

  - 216 ZHA entities exist, but only 16 distinct entity_ids are referenced in
    the repo (200 are unreferenced diagnostics/config entities).
  - 14 of the 16 are physical-device entities, all mapping cleanly into the
    31-device inventory (no orphans).
  - The remaining 2 are the `light.texas_instruments_coordinator_*` entities —
    now identified as ZHA *groups* on the coordinator (not physical devices),
    accounting for 14 references. These don't come from Z2M device discovery and
    must be re-created as Z2M groups and re-pointed by hand.

Scope note captured in the doc: only git-tracked YAML/JSON was audited; live
.storage Lovelace dashboards and UI-created automations/helpers must be
reconciled separately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
k.renner merged commit 8d840b0c55 into master 2026-07-23 10:02:18 +00:00
Sign in to join this conversation.