From 4d56aed5798cb019e73808f8e0f164a28f444c8b Mon Sep 17 00:00:00 2001 From: TheJulianJES Date: Mon, 4 May 2026 07:33:17 +0200 Subject: [PATCH] Also enable AODV route discovery on source-routed unicasts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When `CONF_SOURCE_ROUTING` is enabled, bellows previously set only `APS_OPTION_ENABLE_ADDRESS_DISCOVERY` on outgoing unicasts. The two APS option flags are independent in the stack: - `ENABLE_ADDRESS_DISCOVERY` triggers a network-broadcast address resolution if the destination NWK isn't known. - `ENABLE_ROUTE_DISCOVERY` initiates AODV route discovery if no route exists. If a packet is sent to a destination that isn't yet in the NCP's source-route table (e.g. immediately after startup, before MTORR has propagated), `ADDRESS_DISCOVERY` alone is not enough — the delivery falls back to whatever default the stack chooses. Setting both flags lets AODV act as a transparent fallback. zigbee-herdsman's ember adapter applies both flags to all unicasts for this reason — its `DEFAULT_APS_OPTIONS` in `emberAdapter.ts` includes them together with the comment "Removing `ENABLE_ROUTE_DISCOVERY` leads to devices that won't reconnect/go offline, and various other issues." The non-source-routing path is untouched: it already includes `ENABLE_ROUTE_DISCOVERY`, and the explicit `FORCE_ROUTE_DISCOVERY` caller-override path also stays as-is. --- bellows/zigbee/application.py | 11 +++++++++-- tests/test_application.py | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/bellows/zigbee/application.py b/bellows/zigbee/application.py index 1bd0271c..45ee6af7 100644 --- a/bellows/zigbee/application.py +++ b/bellows/zigbee/application.py @@ -991,8 +991,15 @@ async def send_packet(self, packet: zigpy.types.ZigbeePacket) -> None: aps_frame.groupId = t.uint16_t(0x0000) if self.config[zigpy.config.CONF_SOURCE_ROUTING]: - # Source routing uses address discovery to discover routes - aps_frame.options |= t.EmberApsOption.APS_OPTION_ENABLE_ADDRESS_DISCOVERY + # Concentrator/source-routing uses address discovery; also keep AODV + # route discovery as a fallback for destinations that aren't yet in + # the NCP's source-route table (e.g. immediately after startup, + # before the first MTORR has propagated). Mirrors what + # zigbee-herdsman's ember adapter does for the same reason. + aps_frame.options |= ( + t.EmberApsOption.APS_OPTION_ENABLE_ADDRESS_DISCOVERY + | t.EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY + ) elif zigpy.types.TransmitOptions.FORCE_ROUTE_DISCOVERY in packet.tx_options: # Forcing route discovery requires retrying aps_frame.options |= t.EmberApsOption.APS_OPTION_FORCE_ROUTE_DISCOVERY diff --git a/tests/test_application.py b/tests/test_application.py index 018dd632..861ef4cf 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -879,6 +879,7 @@ async def test_send_packet_unicast_source_route(make_app, packet): options=( t.EmberApsOption.APS_OPTION_RETRY | t.EmberApsOption.APS_OPTION_ENABLE_ADDRESS_DISCOVERY + | t.EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY ), ) @@ -909,6 +910,7 @@ async def test_send_packet_unicast_manual_source_route(make_app, packet): options=( t.EmberApsOption.APS_OPTION_RETRY | t.EmberApsOption.APS_OPTION_ENABLE_ADDRESS_DISCOVERY + | t.EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY ), )