Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw an explicit error about NVRAM corruption when it is detected #218

Merged
merged 1 commit into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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