Skip to content

Commit 96b2572

Browse files
authored
Improved network reset, attempt 2 (#273)
* Write intentionally invalid network settings when resetting * Fix unit tests * Do not wait for CONNECTED state when resetting
1 parent 048965a commit 96b2572

File tree

3 files changed

+68
-12
lines changed

3 files changed

+68
-12
lines changed

tests/test_application.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -553,10 +553,20 @@ async def read_param(param_id, index):
553553

554554

555555
async def test_reset_network_info(app):
556-
app.form_network = AsyncMock()
556+
app.write_network_info = AsyncMock()
557557
await app.reset_network_info()
558558

559-
app.form_network.assert_called_once_with(fast=True)
559+
assert len(app.write_network_info.mock_calls) == 1
560+
network_info = app.write_network_info.mock_calls[0].kwargs["network_info"]
561+
node_info = app.write_network_info.mock_calls[0].kwargs["node_info"]
562+
563+
# Verify invalid network settings are written
564+
assert network_info.pan_id == 0xFFFF
565+
assert network_info.extended_pan_id == zigpy.types.EUI64.convert(
566+
"FF:FF:FF:FF:FF:FF:FF:FF"
567+
)
568+
assert network_info.channel is None
569+
assert node_info.nwk == 0xFFFF
560570

561571

562572
async def test_energy_scan_conbee_2(app):

tests/test_network_state.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import zigpy_deconz
1313
import zigpy_deconz.api
1414
import zigpy_deconz.exception
15+
import zigpy_deconz.types
1516
import zigpy_deconz.zigbee.application as application
1617

1718
from tests.async_mock import AsyncMock, patch
@@ -415,13 +416,20 @@ async def write_parameter(param, *args):
415416

416417
app._change_network_state = AsyncMock()
417418
app._api.write_parameter = AsyncMock(side_effect=write_parameter)
418-
app.backups = AsyncMock()
419-
app.backups.restore_backup = AsyncMock()
419+
app._api.read_parameter = AsyncMock(
420+
return_value=t.EUI64.convert("00:11:22:33:44:55:66:77")
421+
)
420422

421-
# Should not raise an error because reset_network_info calls form_network(fast=True)
423+
# Should not raise an error despite frame counter not being supported
422424
await app.reset_network_info()
423425

424-
# Verify that restore_backup was called once (via form_network)
425-
assert app.backups.restore_backup.mock_calls == [
426-
call(backup=ANY, counter_increment=0, allow_incomplete=True, create_new=False)
426+
# Verify that write_parameter was called (including the frame counter attempt)
427+
assert any(
428+
mock_call.args[0] == zigpy_deconz.api.NetworkParameter.nwk_frame_counter
429+
for mock_call in app._api.write_parameter.mock_calls
430+
)
431+
432+
# Verify network state changes were awaited
433+
assert app._change_network_state.mock_calls == [
434+
call(zigpy_deconz.api.NetworkState.OFFLINE)
427435
]

zigpy_deconz/zigbee/application.py

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,29 @@ async def change_loop():
180180

181181
async def reset_network_info(self):
182182
# TODO: There does not appear to be a way to factory reset a Conbee
183-
await self.form_network(fast=True)
183+
await self.write_network_info(
184+
network_info=zigpy.state.NetworkInfo(
185+
pan_id=0xFFFF,
186+
extended_pan_id=zigpy.types.EUI64.convert("FF:FF:FF:FF:FF:FF:FF:FF"),
187+
channel=None,
188+
channel_mask=zigpy.types.Channels(0),
189+
nwk_update_id=0,
190+
network_key=zigpy.state.Key(
191+
key=zigpy.types.KeyData.convert(
192+
"FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF"
193+
)
194+
),
195+
tc_link_key=zigpy.state.Key(
196+
key=zigpy.types.KeyData.convert(b"ZigBeeAlliance09".hex())
197+
),
198+
security_level=0x05,
199+
),
200+
node_info=zigpy.state.NodeInfo(
201+
logical_type=zdo_t.LogicalType.Coordinator,
202+
ieee=zigpy.types.EUI64.UNKNOWN,
203+
nwk=0xFFFF,
204+
),
205+
)
184206

185207
async def write_network_info(self, *, network_info, node_info):
186208
try:
@@ -291,6 +313,14 @@ async def write_network_info(self, *, network_info, node_info):
291313
# Note: Changed network configuration parameters become only affective after
292314
# sending a Leave Network Request followed by a Create or Join Network Request
293315
await self._change_network_state(NetworkState.OFFLINE)
316+
317+
if (
318+
network_info.pan_id == 0xFFFF
319+
or network_info.channel_mask == zigpy.types.Channels(0)
320+
):
321+
# Network is being reset, it will never enter the CONNECTED state
322+
return
323+
294324
await asyncio.sleep(CHANGE_NETWORK_STATE_DELAY)
295325
await self._change_network_state(NetworkState.CONNECTED)
296326

@@ -341,7 +371,7 @@ async def load_network_info(self, *, load_devices=False):
341371
NetworkParameter.aps_extended_panid
342372
)
343373

344-
if network_info.extended_pan_id == zigpy.types.EUI64.convert(
374+
if network_info.extended_pan_id == zigpy.types.ExtendedPanId.convert(
345375
"00:00:00:00:00:00:00:00"
346376
):
347377
network_info.extended_pan_id = await self._api.read_parameter(
@@ -358,8 +388,16 @@ async def load_network_info(self, *, load_devices=False):
358388
NetworkParameter.nwk_update_id
359389
)
360390

361-
if network_info.channel == 0:
362-
raise NetworkNotFormed("Network channel is zero")
391+
if (
392+
node_info.nwk == 0xFFFF
393+
or network_info.pan_id == 0xFFFF
394+
or (
395+
network_info.extended_pan_id
396+
== zigpy.types.ExtendedPanId.convert("FF:FF:FF:FF:FF:FF:FF:FF")
397+
)
398+
or network_info.channel == 0
399+
):
400+
raise NetworkNotFormed("Network is not formed")
363401

364402
indexed_key = await self._api.read_parameter(NetworkParameter.network_key, 0)
365403

0 commit comments

Comments
 (0)