Skip to content

Commit

Permalink
Throw an explicit error about NVRAM corruption when it is detected (#218
Browse files Browse the repository at this point in the history
)
  • Loading branch information
puddly committed Jul 6, 2023
1 parent e3a2ba5 commit 686cb6c
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 2 deletions.
32 changes: 32 additions & 0 deletions tests/api/test_network_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
from unittest import mock

import pytest
from zigpy.exceptions import FormationFailure

import zigpy_znp.types as t
import zigpy_znp.commands as c
from zigpy_znp.types.nvids import ExNvIds, OsalNvIds

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

# We don't waste time writing device info
assert len(mock_write_devices.mock_awaits) == 0


@pytest.mark.parametrize("device", FORMED_DEVICES)
async def test_formation_failure_on_corrupted_nvram(device, make_connected_znp):
formed_znp, _ = await make_connected_znp(server_cls=FormedLaunchpadCC26X2R1)
await formed_znp.load_network_info()
formed_znp.close()

znp, znp_server = await make_connected_znp(server_cls=device)

# Instead of accepting the write, fail
write_reset_rsp = znp_server.reply_once_to(
request=c.SYS.OSALNVWriteExt.Req(
Id=OsalNvIds.STARTUP_OPTION,
Offset=0,
Value=t.ShortBytes(
(t.StartupOptions.ClearState | t.StartupOptions.ClearConfig).serialize()
),
),
responses=[c.SYS.OSALNVWriteExt.Rsp(Status=t.Status.NV_OPER_FAILED)],
override=True,
)

with pytest.raises(FormationFailure):
await znp.write_network_info(
network_info=formed_znp.network_info,
node_info=formed_znp.node_info,
)

await write_reset_rsp
15 changes: 13 additions & 2 deletions zigpy_znp/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,19 @@ async def write_network_info(
"""
from zigpy_znp.znp import security

if not network_info.stack_specific.get("form_quickly", False):
await self.reset_network_info()
try:
if not network_info.stack_specific.get("form_quickly", False):
await self.reset_network_info()
except InvalidCommandResponse as rsp:
if rsp.response.Status != t.Status.NV_OPER_FAILED:
raise

# Sonoff Zigbee 3.0 USB Dongle Plus coordinators randomly fail with NVRAM
# corruption. This seemingly can only be fixed by re-flashing the firmware.
raise zigpy.exceptions.FormationFailure(
"Network formation failed: NVRAM is corrupted, re-flash your adapter's"
" firmware."
)

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

0 comments on commit 686cb6c

Please sign in to comment.