From fbed4d2952b6a402f24be4befb9c928b79eae42e Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:25:33 -0400 Subject: [PATCH 1/3] Explicitly disable source routing if it is not enabled --- bellows/ezsp/__init__.py | 12 +++++++++--- bellows/types/named.py | 8 ++++++++ bellows/zigbee/application.py | 4 +++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/bellows/ezsp/__init__.py b/bellows/ezsp/__init__.py index 2f367812..6892a646 100644 --- a/bellows/ezsp/__init__.py +++ b/bellows/ezsp/__init__.py @@ -532,10 +532,10 @@ def handle_callback(self, *args): except Exception as e: LOGGER.exception("Exception running handler", exc_info=e) - async def set_source_routing(self) -> None: + async def set_source_routing(self, enabled: bool) -> None: """Enable source routing on NCP.""" res = await self.setConcentrator( - on=True, + on=enabled, concentratorType=t.EmberConcentratorType.HIGH_RAM_CONCENTRATOR, minTime=MTOR_MIN_INTERVAL, maxTime=MTOR_MAX_INTERVAL, @@ -548,7 +548,13 @@ async def set_source_routing(self) -> None: LOGGER.warning("Couldn't set concentrator type %s: %s", True, res) if self._ezsp_version >= 8: - await self.setSourceRouteDiscoveryMode(mode=1) + await self.setSourceRouteDiscoveryMode( + mode=( + t.SourceRouteDiscoveryMode.ON + if enabled + else t.SourceRouteDiscoveryMode.OFF + ) + ) def start_ezsp(self): """Mark EZSP as running.""" diff --git a/bellows/types/named.py b/bellows/types/named.py index 83a8cb84..f2a7e897 100644 --- a/bellows/types/named.py +++ b/bellows/types/named.py @@ -2646,3 +2646,11 @@ class SecurityManagerDerivedKeyTypeV13(basic.enum16): # For a TC using hashed link keys, hashed the root key against the supplied EUI in # context. TC_HASHED_LINK_KEY = 5 + + +class SourceRouteDiscoveryMode(basic.enum8): + """Source route discovery mode.""" + + OFF = 0 + ON = 1 + RESCHEDULE = 2 diff --git a/bellows/zigbee/application.py b/bellows/zigbee/application.py index da0a9551..268bce28 100644 --- a/bellows/zigbee/application.py +++ b/bellows/zigbee/application.py @@ -196,7 +196,9 @@ async def start_network(self): await self._ensure_network_running() if self.config[zigpy.config.CONF_SOURCE_ROUTING]: - await ezsp.set_source_routing() + await ezsp.set_source_routing(enabled=True) + else: + await ezsp.set_source_routing(enabled=False) await ezsp._protocol.update_policies(self.config[CONF_EZSP_POLICIES]) await self.load_network_info(load_devices=False) From ae8f515057890f1624762f16ddb0e9ab8121f311 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:33:16 -0400 Subject: [PATCH 2/3] Add a unit test --- tests/test_ezsp.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/tests/test_ezsp.py b/tests/test_ezsp.py index e95abe63..a99bee79 100644 --- a/tests/test_ezsp.py +++ b/tests/test_ezsp.py @@ -407,14 +407,32 @@ async def replacement(command_name, tokenId=None, valueId=None): assert (mfg, brd, ver) == expected -async def test_set_source_routing(ezsp_f): +async def test_set_enable_source_routing(ezsp_f): """Test enabling source routing.""" ezsp_f.setConcentrator = AsyncMock(return_value=(t.EmberStatus.SUCCESS,)) ezsp_f.setSourceRouteDiscoveryMode = AsyncMock() - await ezsp_f.set_source_routing() + await ezsp_f.set_source_routing(enabled=True) assert len(ezsp_f.setSourceRouteDiscoveryMode.mock_calls) == 1 + assert ( + ezsp_f.setSourceRouteDiscoveryMode.mock_calls[0].kwargs["mode"] + == t.SourceRouteDiscoveryMode.ON + ) + + +async def test_set_disable_source_routing(ezsp_f): + """Test disabling source routing.""" + + ezsp_f.setConcentrator = AsyncMock(return_value=(t.EmberStatus.SUCCESS,)) + ezsp_f.setSourceRouteDiscoveryMode = AsyncMock() + + await ezsp_f.set_source_routing(enabled=False) + assert len(ezsp_f.setSourceRouteDiscoveryMode.mock_calls) == 1 + assert ( + ezsp_f.setSourceRouteDiscoveryMode.mock_calls[0].kwargs["mode"] + == t.SourceRouteDiscoveryMode.OFF + ) async def test_leave_network_error(ezsp_f): From 96260a9ec20730554a69d0cc44ed636f8f7d24b2 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:36:53 -0400 Subject: [PATCH 3/3] Fix unit tests --- tests/test_application.py | 4 ++++ tests/test_ezsp.py | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_application.py b/tests/test_application.py index bd96a2e7..51d0e299 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -280,6 +280,10 @@ async def mock_leave(*args, **kwargs): t.EmberMulticastTableEntry(multicastId=0x0000, endpoint=0, networkIndex=0), ) proto.setMulticastTableEntry.return_value = [t.EmberStatus.SUCCESS] + proto.setConcentrator.return_value = [t.EmberStatus.SUCCESS] + + if ezsp_version >= 8: + proto.setSourceRouteDiscoveryMode.return_value = [12345] return ezsp_mock diff --git a/tests/test_ezsp.py b/tests/test_ezsp.py index a99bee79..61db3a31 100644 --- a/tests/test_ezsp.py +++ b/tests/test_ezsp.py @@ -409,7 +409,6 @@ async def replacement(command_name, tokenId=None, valueId=None): async def test_set_enable_source_routing(ezsp_f): """Test enabling source routing.""" - ezsp_f.setConcentrator = AsyncMock(return_value=(t.EmberStatus.SUCCESS,)) ezsp_f.setSourceRouteDiscoveryMode = AsyncMock() @@ -423,7 +422,6 @@ async def test_set_enable_source_routing(ezsp_f): async def test_set_disable_source_routing(ezsp_f): """Test disabling source routing.""" - ezsp_f.setConcentrator = AsyncMock(return_value=(t.EmberStatus.SUCCESS,)) ezsp_f.setSourceRouteDiscoveryMode = AsyncMock()