You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a Home Assistant scene or automation activates multiple Z-Wave devices to the same state, the zwave_js integration emits one unicast command frame per device. Z-Wave supports multicast group addressing: one unacknowledged frame that all addressed nodes receive and act on simultaneously. The zwave_js integration already exposes this capability via the zwave_js.multicast_set_value service, but the scene and automation activation paths never call it.
Root Cause
The scene activation path flows through homeassistant/components/switch/reproduce_state.py and homeassistant/components/light/reproduce_state.py. Both call asyncio.gather() with one turn_on/turn_off service call per entity:
These N concurrent HA-level calls produce N individual WebSocket messages to zwave-js-server, which serializes them as N unicast Z-Wave frames. The reproduce_state infrastructure has no platform-level batching hook — the domain-level files (switch/, light/) have no way to delegate to the underlying entity platform before individual service calls fire.
Existing Infrastructure
The zwave_js integration already implements multicast_set_value in services.py, wrapping the multicast_group.set_value driver command. It is exposed for direct automation use, but the scene activation and service dispatch paths never call it. The batching capability exists at the driver layer; the gap is at the HA dispatch layer.
Proposed Approach
Option 1 — Service-layer interceptor within zwave_js (no HA core changes required)
Register a higher-priority service handler that buffers switch.turn_on/off and light.turn_on/off calls sharing the same context.id within a short window (≤50ms). On flush:
Identify entities on the zwave_js platform via the entity registry
Group by (service, target value, security class, node capability)
For qualifying groups of 2+ nodes: emit one multicast_group.set_value call
For singletons or excluded nodes: pass through to the original service handler unchanged
This covers all call paths: scenes, automations, scripts, voice assistants, and the dashboard.
Option 2 — Platform batching hook in reproduce_state infrastructure (requires HA core changes)
Introduce an optional async_batch_reproduce_states(hass, states, context) protocol in homeassistant/helpers/state.py. Platforms that implement it receive all states at once before individual service calls fire. The zwave_js entity platform would implement it to emit a single multicast call for qualifying groups — making scene batching deterministic with no timing window.
The two approaches are complementary. Option 1 covers all call paths with no core changes. Option 2 makes the scene path fully deterministic if a core protocol is eventually introduced.
Z-Wave unicast requires the controller to transmit a frame, wait for an acknowledgment, then move to the next node. At the RF layer, frames are serialized regardless of how many HA service calls are issued concurrently. A 15-node scene activating switches to the same state takes approximately 450ms under ideal conditions and 3–4 seconds with normal routing and retry overhead (per Z-Wave 700/800-series frame timing: 10–20ms transmission + 10ms ACK per hop). A single multicast frame covers all 15 nodes in ~20ms with no ACK wait.
N sequential frames during scene activation also flood the 868/915 MHz mesh in a predictable burst, degrading mesh performance for unrelated devices during and after activation.
Scene size and network density scale the problem directly. A 30-node evening routine (lights, switches, locks) can take 6–9 seconds to activate under current behavior. The same routine with multicast completes in under 100ms.
Any user with more than a handful of Z-Wave devices benefits from this. The improvement is automatic — existing scenes, automations, and scripts require no changes.
Anything else?
Implementation Constraints
Any production implementation must handle:
Z-Wave LR exclusion — Check isLongRange on each node before including it in a multicast group.
Security class bucketing — Nodes at different security classes cannot share a multicast frame. Split groups by matching class.
FLiRS/battery device exclusion — Fall these nodes back to unicast; they may miss unacknowledged frames.
Post-multicast verification — Multicast is unacknowledged. Follow up with a polling pass to detect non-responsive nodes and issue corrective unicast retries.
Optimistic state writes — Issue optimistic state updates after the multicast call to prevent the UI showing stale state for all N nodes.
zwave-js-server version gate — Check server version and degrade gracefully on older deployments that lack multicast_group.set_value.
Opt-in toggle — Expose a toggle in the integration options flow for users on atypical network topologies.
Proof of Concept
A custom component implementing Option 1 (service interceptor) was tested on HA 2026.4.x with a mains-powered Z-Wave network of mixed security classes:
All service calls from a single scene activation share the same context.id and arrive within ~3ms — well within the 50ms buffer window.
The multicast_set_value service updates HA entity state correctly via optimistic writes or unsolicited node reports.
The 50ms window produces zero false-positive batches across automations firing in normal sequence (each invocation receives a unique context.id).
Fail-open: on any multicast error, all buffered entities fall through to their original unicast handlers.
The prototype satisfies constraints 1–3 and 5–7. Post-multicast verification polling (constraint 4) remains as a follow-up.
References
Z-Wave Specification SDS11064: Group 2 multicast addressing (unacknowledged broadcast)
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Describe the enhancement
When a Home Assistant scene or automation activates multiple Z-Wave devices to the same state, the
zwave_jsintegration emits one unicast command frame per device. Z-Wave supports multicast group addressing: one unacknowledged frame that all addressed nodes receive and act on simultaneously. Thezwave_jsintegration already exposes this capability via thezwave_js.multicast_set_valueservice, but the scene and automation activation paths never call it.Root Cause
The scene activation path flows through
homeassistant/components/switch/reproduce_state.pyandhomeassistant/components/light/reproduce_state.py. Both callasyncio.gather()with oneturn_on/turn_offservice call per entity:These N concurrent HA-level calls produce N individual WebSocket messages to
zwave-js-server, which serializes them as N unicast Z-Wave frames. Thereproduce_stateinfrastructure has no platform-level batching hook — the domain-level files (switch/,light/) have no way to delegate to the underlying entity platform before individual service calls fire.Existing Infrastructure
The
zwave_jsintegration already implementsmulticast_set_valueinservices.py, wrapping themulticast_group.set_valuedriver command. It is exposed for direct automation use, but the scene activation and service dispatch paths never call it. The batching capability exists at the driver layer; the gap is at the HA dispatch layer.Proposed Approach
Option 1 — Service-layer interceptor within
zwave_js(no HA core changes required)Register a higher-priority service handler that buffers
switch.turn_on/offandlight.turn_on/offcalls sharing the samecontext.idwithin a short window (≤50ms). On flush:zwave_jsplatform via the entity registrymulticast_group.set_valuecallThis covers all call paths: scenes, automations, scripts, voice assistants, and the dashboard.
Option 2 — Platform batching hook in
reproduce_stateinfrastructure (requires HA core changes)Introduce an optional
async_batch_reproduce_states(hass, states, context)protocol inhomeassistant/helpers/state.py. Platforms that implement it receive all states at once before individual service calls fire. Thezwave_jsentity platform would implement it to emit a single multicast call for qualifying groups — making scene batching deterministic with no timing window.The two approaches are complementary. Option 1 covers all call paths with no core changes. Option 2 makes the scene path fully deterministic if a core protocol is eventually introduced.
Device information
Use cases
Z-Wave unicast requires the controller to transmit a frame, wait for an acknowledgment, then move to the next node. At the RF layer, frames are serialized regardless of how many HA service calls are issued concurrently. A 15-node scene activating switches to the same state takes approximately 450ms under ideal conditions and 3–4 seconds with normal routing and retry overhead (per Z-Wave 700/800-series frame timing: 10–20ms transmission + 10ms ACK per hop). A single multicast frame covers all 15 nodes in ~20ms with no ACK wait.
N sequential frames during scene activation also flood the 868/915 MHz mesh in a predictable burst, degrading mesh performance for unrelated devices during and after activation.
Scene size and network density scale the problem directly. A 30-node evening routine (lights, switches, locks) can take 6–9 seconds to activate under current behavior. The same routine with multicast completes in under 100ms.
Any user with more than a handful of Z-Wave devices benefits from this. The improvement is automatic — existing scenes, automations, and scripts require no changes.
Anything else?
Implementation Constraints
Any production implementation must handle:
isLongRangeon each node before including it in a multicast group.multicast_group.set_value.Proof of Concept
A custom component implementing Option 1 (service interceptor) was tested on HA 2026.4.x with a mains-powered Z-Wave network of mixed security classes:
context.idand arrive within ~3ms — well within the 50ms buffer window.multicast_set_valueservice updates HA entity state correctly via optimistic writes or unsolicited node reports.context.id).The prototype satisfies constraints 1–3 and 5–7. Post-multicast verification polling (constraint 4) remains as a follow-up.
References
homeassistant/components/zwave_js/services.py— existingmulticast_set_valueimplementationhomeassistant/components/switch/reproduce_state.py— current per-entity scene dispatchhomeassistant/components/light/reproduce_state.py— current per-entity scene dispatchhomeassistant/helpers/state.py—async_reproduce_state, dispatches per domain with no platform batching hookMulticastGroupAPI:setValue,getDefinedValueIDsBeta Was this translation helpful? Give feedback.
All reactions