Skip to content

Commit 686cb6c

Browse files
authored
Throw an explicit error about NVRAM corruption when it is detected (#218)
1 parent e3a2ba5 commit 686cb6c

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

tests/api/test_network_state.py

+32
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
from unittest import mock
33

44
import pytest
5+
from zigpy.exceptions import FormationFailure
56

67
import zigpy_znp.types as t
8+
import zigpy_znp.commands as c
79
from zigpy_znp.types.nvids import ExNvIds, OsalNvIds
810

911
from ..conftest import (
@@ -114,3 +116,33 @@ async def test_write_settings_fast(device, make_connected_znp):
114116

115117
# We don't waste time writing device info
116118
assert len(mock_write_devices.mock_awaits) == 0
119+
120+
121+
@pytest.mark.parametrize("device", FORMED_DEVICES)
122+
async def test_formation_failure_on_corrupted_nvram(device, make_connected_znp):
123+
formed_znp, _ = await make_connected_znp(server_cls=FormedLaunchpadCC26X2R1)
124+
await formed_znp.load_network_info()
125+
formed_znp.close()
126+
127+
znp, znp_server = await make_connected_znp(server_cls=device)
128+
129+
# Instead of accepting the write, fail
130+
write_reset_rsp = znp_server.reply_once_to(
131+
request=c.SYS.OSALNVWriteExt.Req(
132+
Id=OsalNvIds.STARTUP_OPTION,
133+
Offset=0,
134+
Value=t.ShortBytes(
135+
(t.StartupOptions.ClearState | t.StartupOptions.ClearConfig).serialize()
136+
),
137+
),
138+
responses=[c.SYS.OSALNVWriteExt.Rsp(Status=t.Status.NV_OPER_FAILED)],
139+
override=True,
140+
)
141+
142+
with pytest.raises(FormationFailure):
143+
await znp.write_network_info(
144+
network_info=formed_znp.network_info,
145+
node_info=formed_znp.node_info,
146+
)
147+
148+
await write_reset_rsp

zigpy_znp/api.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,19 @@ async def write_network_info(
344344
"""
345345
from zigpy_znp.znp import security
346346

347-
if not network_info.stack_specific.get("form_quickly", False):
348-
await self.reset_network_info()
347+
try:
348+
if not network_info.stack_specific.get("form_quickly", False):
349+
await self.reset_network_info()
350+
except InvalidCommandResponse as rsp:
351+
if rsp.response.Status != t.Status.NV_OPER_FAILED:
352+
raise
353+
354+
# Sonoff Zigbee 3.0 USB Dongle Plus coordinators randomly fail with NVRAM
355+
# corruption. This seemingly can only be fixed by re-flashing the firmware.
356+
raise zigpy.exceptions.FormationFailure(
357+
"Network formation failed: NVRAM is corrupted, re-flash your adapter's"
358+
" firmware."
359+
)
349360

350361
# Form a network with completely random settings to get NVRAM to a known state
351362
for item, value in {

0 commit comments

Comments
 (0)