feat(esh): move SLZB-MR1U Zigbee coordinator to the IoT VLAN for Home Assistant

The coordinator arrived on esh-userland (VLAN 10) at a DHCP-assigned
10.0.10.58. It now sits on esh-iot (VLAN 90) at 10.0.90.10, reserved on
the UDM and named slzb-mr1u.esh.internal.

Address on the network side, not the device — the pfi-gx10 ruling: a
reservation moves with the hardware, a device-side static goes stale.
10.0.90.10 is below the 10.0.90.40-250 pool so it cannot be handed out.

The MAC is locally administered (ea:f6:0a:ca:f5:b4, no OUI), which is
exactly the case where a reservation can silently stop matching. The
PoE power-cycle that makes the device re-DHCP is also the stability
test, so it cost nothing: it rebooted and came back on exactly
10.0.90.10, which only happens if the MAC held.

ESH-Media carried 8 port_overrides and that PUT is a whole-array
replace, so the array was diffed to prove exactly one field on one port
changed before sending, and read back after.

Inter-VLAN reachability needed no firewall work and was proven from
inside the HA container before the move, against existing IoT devices.
Testing from the Docker host would have proven the wrong thing — HA
runs on a macvlan address, 10.0.50.46, not the host's 10.0.50.45.

Documented but NOT fixed: the HA container cannot resolve any
.internal name (its resolver is Docker's 127.0.0.11, upstream excludes
the fleet AdGuard). Pre-existing, verified against names that predate
this change. HA should be configured with the IP; changing the DNS of
a live home-automation stack is ha-dev's call.
This commit is contained in:
2026-09-04 09:50:31 -07:00
parent dae77ee118
commit fed29be04e
2 changed files with 90 additions and 0 deletions
+1
View File
@@ -100,6 +100,7 @@ hosts:
- {name: plex, site: esh, v4: 10.0.50.56, note: media server}
- {name: jellyfin, site: esh, v4: 10.0.50.57, note: media server}
- {name: brother, site: esh, v4: 10.0.90.125, note: Brother printer}
- {name: slzb-mr1u, site: esh, v4: 10.0.90.10, note: SMLIGHT SLZB-MR1U Zigbee/Thread coordinator (esh-iot VLAN 90, PoE on ESH-Media p4); Home Assistant at 10.0.50.46 connects to tcp/6638}
# Service aliases — a name that points at whatever host currently runs it, so
# consumers reference the SERVICE rather than the box. Changing where something
@@ -0,0 +1,89 @@
# SLZB-MR1U Zigbee/Thread coordinator — ESH IoT VLAN
Moved onto the IoT VLAN 2026-09-04 and handed to Home Assistant.
device SMLIGHT SLZB-MR1U ("SLZB OS", firmware build Jan 27 2026 11:19:04)
address 10.0.90.10 slzb-mr1u.esh.internal
network esh-iot, VLAN 90, 10.0.90.0/24
switch USW Pro XG 10 PoE - ESH-Media (10.0.250.164), port 4, PoE ~1.0-1.5 W
zigbee tcp/6638 web UI tcp/80
consumer Home Assistant container at 10.0.50.46 (esh-docker-vm, macvlan on VLAN 50)
## The shape, and why it is this shape
**The address lives on the UDM as a DHCP reservation, not on the device.** Same
ruling as pfi-gx10: a reservation moves with the hardware, a device-side static
goes stale the moment anything changes. The device stays on DHCP and knows
nothing about its own address.
`10.0.90.10` sits deliberately **below** the esh-iot DHCP pool
(`10.0.90.40250`), so the pool can never hand it to something else. Note the
one pre-existing reservation on this network — the Brother printer at
`10.0.90.125` — is *inside* the pool; the out-of-pool convention starts here.
## ⚠ The MAC is locally administered, and that was worth checking
ea:f6:0a:ca:f5:b4 no OUI, LAA bit set
A DHCP reservation keys on the MAC. A device that regenerates its MAC at boot
would silently miss the reservation, land on a pool address, and take the DNS
record stale with it — long after anyone remembers this change.
**Tested rather than assumed, and free:** the PoE power-cycle needed to make the
device re-DHCP onto the new VLAN is also the MAC-stability test. It rebooted
(client uptime reset to 66 s) and came back on **exactly 10.0.90.10** — which
only happens if the reservation matched, i.e. the MAC survived. If a future
firmware changes that behaviour, the symptom is the device appearing somewhere in
`10.0.90.40250`.
## ⚠ port_overrides is a WHOLE-ARRAY PUT
ESH-Media carried 8 port overrides. Anything omitted from the PUT is deleted, so
the array was read, backed up, modified in exactly one field, diffed to prove
only that field changed, and written back. Read-back confirmed 8 in, 8 out, ports
2/3/5/6/8/9 still on esh-userland and port 7 still locked down.
## ⚠ UniFi's client record lies during the transition — do not read it as breakage
While the port was cycling, `stat/sta` reported the client on **the UDM's own
SFP+ uplink** with its old VLAN-10 address and a frozen uptime, and `port_table`
showed ESH-Media port 4 down at 0 W. Both were transitional artifacts. The
authoritative check is the device itself: the page served at the new address was
**byte-identical** (same 25,413 bytes, same `ETag: "Jan 27 2026 11:19:04"`) to the
one captured before the move. Fingerprint the endpoint; do not trust the
controller's cache mid-change.
## ⚠ Home Assistant CANNOT resolve `.internal` — give it the IP
Verified from inside the container, and it is **pre-existing, not caused by this
change**:
slzb-mr1u.esh.internal FAIL homepage.esh.internal FAIL
esh-docker-vm.esh.internal FAIL google.com OK
The container's resolver is Docker's embedded `127.0.0.11`, whose upstream does
not include the fleet AdGuard at `10.0.50.45`. Public DNS resolves, so it is
reaching *an* upstream — just not ours. **Configure HA against `10.0.90.10`.**
The fix, if wanted, is a `dns:` entry on the HA service pointing at `10.0.50.45`
plus a container restart — a change to a live home-automation stack, so it is
ha-dev's call, not an incidental edit.
Separately, note `esh-iot` itself hands out `1.1.1.1` / `8.8.8.8` by DHCP, so
devices *on* VLAN 90 cannot resolve `.internal` either. Irrelevant here — the
coordinator never initiates — but relevant to anything on that VLAN that does.
## Reachability is already open, and was proven before the move
VLAN 50 → VLAN 90 needed no firewall work. Confirmed from the actual consumer —
`docker exec homeassistant` — against pre-existing IoT devices (the printer and a
Tasmota plug) *before* touching anything, then against the coordinator after.
Testing from the Docker **host** would have proven the wrong thing: HA runs on a
macvlan interface with its own address, not the host's.
## Rollback
Backups of both mutated objects are transient (session scratch), so the durable
path is: set ESH-Media port 4's `native_networkconf_id` back to
`687985eae5d15b673cef1a73` (esh-userland), clear `use_fixedip` on the client, and
drop the `slzb-mr1u` line from `dns/internal.yaml` + re-run `scripts/dns-sync.py`.