Observed (2026-08-22, live broker capture)
With adaptive lighting enabled in Apple Home on ~8 bridged lights, Apple re-asserts every light's full colour state in a round-robin sweep every ~15–20 s, continuously — observed at 21:45 BST and also running at 02:24 (caught by z2m-plugin broker-down warnings logging identical payload pairs). Per light, per cycle:
zigbee2mqtt/<light>/set {"brightness": <N>} # N = that light's current/target level, 0–255
zigbee2mqtt/<light>/set {"color_temp": 400} # same circadian mired for all; ramps 363→400 across the evening
zigbee2mqtt/<light>/set {"color":{"r":0,"g":0,"b":0}} # some lights also get black RGB
Steady-state load: ~60 commands/min across the fleet, 24/7.
Why this is serious
This is the standing background load that turned two otherwise-survivable faults into coordinator meltdowns (2026-08-20 and 2026-08-22): group /set = broadcast, the coordinator allows ~15 broadcasts per ~9 s network-wide, and the sweep permanently consumes a large share. Any additional retry loop or conflict tips the mesh into Failed to send with status=BUSY for everything.
A healthy adaptive-lighting accessory receives occasional CT updates (minutes-scale ramp). A tight re-assert loop means Apple believes its writes are not taking effect — i.e. the attribute state echoed back through the bridge does not match what Apple wrote.
Attribution is solid
- HomeKitLink is not registered with Apple Home and the HA HomeKit bridge is off — Apple reaches these lights only via this bridge.
- Payload shape (separate single-property messages) identifies the autolog z2m plugin as publisher, i.e. the commands arrive as Indigo device commands.
- No Indigo schedules/triggers/action groups were firing during capture windows (event log checked).
- Control experiment: turning adaptive lighting OFF for one light (Kitchen cabinet strip) removed exactly that light from the sweep within seconds (0 commands in 45 s, previously ~3/45 s). The rest continued.
Hypotheses (in rough order)
- Level/CT round-trip mismatch: Apple writes
CurrentLevel/ColorTemperatureMireds; the dispatch lands in Indigo (percent brightness, Kelvin whiteTemperature); the state echo converts back with rounding (0–255 ↔ 0–100 %, mired ↔ K) or clamping (device Kelvin min/max) that yields a value ≠ what Apple wrote → subscription report shows a mismatch → Apple re-asserts → loop.
- Off-light level assertion: several swept lights are OFF; Apple asserts a remembered level (including 0) while the bridge reports the off-state level differently (e.g. CurrentLevel frozen at last-on value vs 0) → permanent mismatch.
- Stale/slow state pipeline: during the sweep the plugin logs
unmatched response (set_state dev …) every ~2 s — the bridge node acks state pushes late (or they time out), so attribute state lags and subscription reports carry stale values, feeding the loop. (Possibly the same family as the Alexa stale-subscription findings.)
Observability gap to fix as part of this
ExportBridge.on_command → _apply_command logs nothing on successful dispatch — only failures. Tonight that silence was misread as "Apple is not commanding" and cost an hour of misattribution. A DEBUG line per dispatched ecosystem command (device, command, args) would have identified this loop in one grep.
Suggested diagnostics
- Add the DEBUG dispatch logging above; capture one sweep cycle end-to-end.
- For one adaptive light, log the Matter attribute values the bridge holds immediately after the state echo of an Apple write, and diff against the written values (level and mireds).
- Check whether the ~15–20 s cadence matches the fabric's subscription report interval.
- Single-light A/B: adaptive on for exactly one light, everything else off — is the loop per-light independent or fleet-synchronised?
Observed (2026-08-22, live broker capture)
With adaptive lighting enabled in Apple Home on ~8 bridged lights, Apple re-asserts every light's full colour state in a round-robin sweep every ~15–20 s, continuously — observed at 21:45 BST and also running at 02:24 (caught by z2m-plugin broker-down warnings logging identical payload pairs). Per light, per cycle:
Steady-state load: ~60 commands/min across the fleet, 24/7.
Why this is serious
This is the standing background load that turned two otherwise-survivable faults into coordinator meltdowns (2026-08-20 and 2026-08-22): group /set = broadcast, the coordinator allows ~15 broadcasts per ~9 s network-wide, and the sweep permanently consumes a large share. Any additional retry loop or conflict tips the mesh into
Failed to send with status=BUSYfor everything.A healthy adaptive-lighting accessory receives occasional CT updates (minutes-scale ramp). A tight re-assert loop means Apple believes its writes are not taking effect — i.e. the attribute state echoed back through the bridge does not match what Apple wrote.
Attribution is solid
Hypotheses (in rough order)
CurrentLevel/ColorTemperatureMireds; the dispatch lands in Indigo (percent brightness, Kelvin whiteTemperature); the state echo converts back with rounding (0–255 ↔ 0–100 %, mired ↔ K) or clamping (device Kelvin min/max) that yields a value ≠ what Apple wrote → subscription report shows a mismatch → Apple re-asserts → loop.unmatched response (set_state dev …)every ~2 s — the bridge node acks state pushes late (or they time out), so attribute state lags and subscription reports carry stale values, feeding the loop. (Possibly the same family as the Alexa stale-subscription findings.)Observability gap to fix as part of this
ExportBridge.on_command→_apply_commandlogs nothing on successful dispatch — only failures. Tonight that silence was misread as "Apple is not commanding" and cost an hour of misattribution. A DEBUG line per dispatched ecosystem command (device, command, args) would have identified this loop in one grep.Suggested diagnostics