From 0bbdaf908357e9bec23552f8befe792beac61dae Mon Sep 17 00:00:00 2001 From: Vuong Hoang Date: Fri, 4 Sep 2026 09:57:02 -0700 Subject: [PATCH] =?UTF-8?q?fix(esh):=20correct=20the=20SLZB-MR1U=20MAC=20f?= =?UTF-8?q?raming=20=E2=80=94=20derived=20ESP32=20address,=20not=20fragile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I described ea:f6:0a:ca:f5:b4 as "locally administered, no OUI" and treated it as the class of MAC that may regenerate at boot. ha-dev corrected it and the correction verifies: the device advertises e8:f6:0a:ca:f5:b4 over mDNS, which differs in exactly the locally-administered bit, and E8:F6:0A is registered to Espressif Inc. in the IEEE registry while EA:F6:0A resolves to nothing. That is the standard ESP32 pattern — one factory base MAC in eFuse, sibling interface MACs derived deterministically — so the reservation is keyed correctly and cannot drift on its own. The PoE-cycle test still stands and is now corroborating evidence rather than the only evidence. The residual risk narrows to a firmware change to the derivation scheme. Also from ha-dev: tcp/7638 is open alongside 6638; mDNS crosses the VLAN boundary so HA rediscovers without help; and HA's pending smlight config flow is keyed on the mDNS service name, which did not change, so a stale flow may still hold the dead 10.0.10.58 and should be dismissed rather than confirmed. ha-dev declined the dns: resolver fix on their stack — configuring by IP costs them nothing and the entry would couple HA name resolution to AdGuard uptime for no present benefit. --- docs/runbooks/slzb-mr1u-zigbee-coordinator.md | 54 ++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/docs/runbooks/slzb-mr1u-zigbee-coordinator.md b/docs/runbooks/slzb-mr1u-zigbee-coordinator.md index 7bb3e95..933f84b 100644 --- a/docs/runbooks/slzb-mr1u-zigbee-coordinator.md +++ b/docs/runbooks/slzb-mr1u-zigbee-coordinator.md @@ -6,7 +6,7 @@ Moved onto the IoT VLAN 2026-09-04 and handed to Home Assistant. 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 + zigbee tcp/6638 web UI tcp/80 also open: tcp/7638 consumer Home Assistant container at 10.0.50.46 (esh-docker-vm, macvlan on VLAN 50) ## The shape, and why it is this shape @@ -21,20 +21,31 @@ nothing about its own address. 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 +## The MAC is a derived ESP32 interface address — stable, not fragile - ea:f6:0a:ca:f5:b4 no OUI, LAA bit set + ethernet (what DHCP sees) ea:f6:0a:ca:f5:b4 LA bit SET + base (what mDNS advertises) e8:f6:0a:ca:f5:b4 Espressif Inc. (verified against IEEE) -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. +⚠ **An earlier version of this runbook called the MAC "locally administered, no +OUI" and treated it as the kind that may regenerate at boot. That framing was +wrong and ha-dev corrected it.** The two addresses differ in exactly one bit — +the locally-administered bit — which is the standard ESP32 pattern: one factory +base MAC in eFuse, sibling interface MACs derived from it deterministically. The +Ethernet interface gets the derived `ea:` variant; mDNS advertises the base +`e8:`. `E8:F6:0A` resolves to **Espressif Inc.** in the IEEE registry and +`EA:F6:0A` correctly resolves to nothing, which is what confirms the two are the +same address wearing different bits rather than two unrelated MACs. -**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.40–250`. +So the reservation is keyed on the right address and the derivation cannot drift +on its own. Independently consistent with the test below. + +**Tested anyway, and it was free:** the PoE power-cycle needed to make the device +re-DHCP onto the new VLAN is also a reboot. It came back on **exactly +10.0.90.10** — which only happens if the reservation matched. + +The residual risk is real but narrow: only a firmware update that changed the +derivation scheme would move it. Symptom if that ever happens — the coordinator +reappears somewhere in `10.0.90.40–250`. ## ⚠ port_overrides is a WHOLE-ARRAY PUT @@ -87,3 +98,22 @@ 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`. + +## mDNS crosses the VLAN boundary — and that has one sharp edge + +`esh-iot` has `mdns_enabled: true`, so the coordinator's advert reaches the +Home Assistant container across VLANs and HA rediscovers it without help. + +⚠ **HA's pending `smlight` config flow is keyed on the mDNS service name, which +did NOT change across the move — so the same flow id survived and may still hold +the dead 10.0.10.58.** Dismiss and re-discover rather than confirming the stale +flow. This is the kind of thing that makes a device look broken after a clean +network change. (Reported by ha-dev, 2026-09-04.) + +## Resolver: ha-dev declined the `dns:` fix, deliberately + +Offered and turned down: pointing the homeassistant service at `10.0.50.45` +would couple HA's name resolution to AdGuard's uptime for a benefit they do not +currently need, since configuring by IP costs them nothing. Recorded on their +side as a standing foot-gun with the fix written down. Revisit only if something +inside the container actually needs a name.