From 98f3044ac7e48296811f89891ae4bb06a740cddc Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:25:37 -0400 Subject: [PATCH] Support EZSPv19 --- bellows/ezsp/__init__.py | 5 +++-- bellows/ezsp/config.py | 1 + bellows/ezsp/v19/__init__.py | 20 ++++++++++++++++++++ bellows/ezsp/v19/commands.py | 15 +++++++++++++++ bellows/ezsp/v19/config.py | 16 ++++++++++++++++ bellows/types/named.py | 3 +++ tests/test_ezsp_v19.py | 31 +++++++++++++++++++++++++++++++ 7 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 bellows/ezsp/v19/__init__.py create mode 100644 bellows/ezsp/v19/commands.py create mode 100644 bellows/ezsp/v19/config.py create mode 100644 tests/test_ezsp_v19.py diff --git a/bellows/ezsp/__init__.py b/bellows/ezsp/__init__.py index 29554c93..1ef25f56 100644 --- a/bellows/ezsp/__init__.py +++ b/bellows/ezsp/__init__.py @@ -29,11 +29,11 @@ import bellows.types as t import bellows.uart -from . import v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v16, v17, v18 +from . import v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v16, v17, v18, v19 RESET_ATTEMPTS = 3 -EZSP_LATEST = v18.EZSPv18.VERSION +EZSP_LATEST = v19.EZSPv19.VERSION LOGGER = logging.getLogger(__name__) MTOR_MIN_INTERVAL = 60 MTOR_MAX_INTERVAL = 3600 @@ -62,6 +62,7 @@ class EZSP: v16.EZSPv16.VERSION: v16.EZSPv16, v17.EZSPv17.VERSION: v17.EZSPv17, v18.EZSPv18.VERSION: v18.EZSPv18, + v19.EZSPv19.VERSION: v19.EZSPv19, } def __init__(self, device_config: dict, application: Any | None = None): diff --git a/bellows/ezsp/config.py b/bellows/ezsp/config.py index 61e485ce..f61280ea 100644 --- a/bellows/ezsp/config.py +++ b/bellows/ezsp/config.py @@ -130,4 +130,5 @@ class ValueConfig: 16: DEFAULT_CONFIG_NEW, 17: DEFAULT_CONFIG_NEW, 18: DEFAULT_CONFIG_NEW, + 19: DEFAULT_CONFIG_NEW, } diff --git a/bellows/ezsp/v19/__init__.py b/bellows/ezsp/v19/__init__.py new file mode 100644 index 00000000..93a14dd2 --- /dev/null +++ b/bellows/ezsp/v19/__init__.py @@ -0,0 +1,20 @@ +""""EZSP Protocol version 19 protocol handler.""" +from __future__ import annotations + +import voluptuous as vol + +import bellows.config + +from . import commands, config +from ..v18 import EZSPv18 + + +class EZSPv19(EZSPv18): + """EZSP Version 19 Protocol version handler.""" + + VERSION = 19 + COMMANDS = commands.COMMANDS + SCHEMAS = { + bellows.config.CONF_EZSP_CONFIG: vol.Schema(config.EZSP_SCHEMA), + bellows.config.CONF_EZSP_POLICIES: vol.Schema(config.EZSP_POLICIES_SCH), + } diff --git a/bellows/ezsp/v19/commands.py b/bellows/ezsp/v19/commands.py new file mode 100644 index 00000000..739c610b --- /dev/null +++ b/bellows/ezsp/v19/commands.py @@ -0,0 +1,15 @@ +import bellows.types as t + +from ..v18.commands import COMMANDS as COMMANDS_v18 + +COMMANDS = { + **COMMANDS_v18, + # Added in Simplicity SDK 2026.6.0 + "clearBindingTableOnLeave": ( + 0x006D, + { + "clear": t.Bool, + }, + {}, + ), +} diff --git a/bellows/ezsp/v19/config.py b/bellows/ezsp/v19/config.py new file mode 100644 index 00000000..87252f27 --- /dev/null +++ b/bellows/ezsp/v19/config.py @@ -0,0 +1,16 @@ +import voluptuous as vol + +from bellows.config import cv_uint16 +from bellows.types import EzspPolicyId + +from ..v4.config import EZSP_POLICIES_SHARED +from ..v18 import config as v18_config + +EZSP_SCHEMA = { + **v18_config.EZSP_SCHEMA, +} + +EZSP_POLICIES_SCH = { + **EZSP_POLICIES_SHARED, + **{vol.Optional(policy.name): cv_uint16 for policy in EzspPolicyId}, +} diff --git a/bellows/types/named.py b/bellows/types/named.py index 513a7cbf..996fc4af 100644 --- a/bellows/types/named.py +++ b/bellows/types/named.py @@ -118,6 +118,7 @@ class EzspMfgTokenId(basic.enum8): # Custom version (2 bytes). MFG_CUSTOM_VERSION = 0x00 # Manufacturing string (16 bytes). + # Deprecated in EZSPv19 (SSDK 2026.6.0): removed on Series 3 platforms. MFG_STRING = 0x01 # Board name (16 bytes). MFG_BOARD_NAME = 0x02 @@ -126,10 +127,12 @@ class EzspMfgTokenId(basic.enum8): # Radio configuration (2 bytes). MFG_PHY_CONFIG = 0x04 # Bootload AES key (16 bytes). + # Deprecated in EZSPv19 (SSDK 2026.6.0): removed on Series 3 platforms. MFG_BOOTLOAD_AES_KEY = 0x05 # ASH configuration (40 bytes). MFG_ASH_CONFIG = 0x06 # EZSP storage (8 bytes). + # Deprecated in EZSPv19 (SSDK 2026.6.0): removed on Series 3 platforms. MFG_STORAGE = 0x07 # Radio calibration data (64 bytes). 4 bytes are stored for each of the 16 # channels. This token is not stored in the Flash Information Area. It is diff --git a/tests/test_ezsp_v19.py b/tests/test_ezsp_v19.py new file mode 100644 index 00000000..e4229ae9 --- /dev/null +++ b/tests/test_ezsp_v19.py @@ -0,0 +1,31 @@ +from unittest.mock import MagicMock + +import pytest + +import bellows.ezsp.v19 +import bellows.types as t + +from tests.common import mock_ezsp_commands + + +@pytest.fixture +def ezsp_f(): + """EZSP v19 protocol handler.""" + ezsp = bellows.ezsp.v19.EZSPv19(MagicMock(), MagicMock()) + mock_ezsp_commands(ezsp) + + return ezsp + + +def test_ezsp_frame(ezsp_f): + ezsp_f._seq = 0x22 + data = ezsp_f._ezsp_frame("version", 19) + assert data == b"\x22\x00\x01\x00\x00\x13" + + +def test_ezsp_frame_rx(ezsp_f): + """Test receiving a version frame.""" + ezsp_f(b"\x01\x01\x80\x00\x00\x01\x02\x34\x12") + assert ezsp_f._handle_callback.call_count == 1 + assert ezsp_f._handle_callback.call_args[0][0] == "version" + assert ezsp_f._handle_callback.call_args[0][1] == [0x01, 0x02, 0x1234]