diff --git a/bellows/cli/backup.py b/bellows/cli/backup.py index e1f20789..2c1a0cb2 100644 --- a/bellows/cli/backup.py +++ b/bellows/cli/backup.py @@ -44,7 +44,7 @@ ATTR_KEY_FRAME_COUNTER_OUT: cv_hex, ATTR_KEY_FRAME_COUNTER_IN: cv_hex, ATTR_KEY_SEQ: cv_hex, - ATTR_KEY_PARTNER: vol.All(str, t.EmberEUI64.convert), + ATTR_KEY_PARTNER: vol.All(str, t.EUI64.convert), } ) SCHEMA_BAK = vol.Schema( @@ -52,7 +52,7 @@ ATTR_CHANNELS: cv_hex, ATTR_NODE_TYPE: cv_hex, ATTR_NODE_ID: cv_hex, - ATTR_NODE_EUI64: vol.All(str, t.EmberEUI64.convert), + ATTR_NODE_EUI64: vol.All(str, t.EUI64.convert), ATTR_NWK_UPDATE_ID: cv_hex, ATTR_PAN_ID: cv_hex, ATTR_RADIO_CHANNEL: cv_hex, @@ -214,7 +214,7 @@ async def _restore( return if update_eui64_token: - ncp_eui64 = t.EmberEUI64(backup_data[ATTR_NODE_EUI64]).serialize() + ncp_eui64 = t.EUI64(backup_data[ATTR_NODE_EUI64]).serialize() (status,) = await ezsp.setMfgToken( t.EzspMfgTokenId.MFG_CUSTOM_EUI_64, ncp_eui64 ) @@ -244,7 +244,7 @@ async def _restore( init_sec_state.bitmask |= ( t.EmberInitialSecurityBitmask.TRUST_CENTER_USES_HASHED_LINK_KEY ) - init_sec_state.preconfiguredKey = t.EmberKeyData(os.urandom(16)) + init_sec_state.preconfiguredKey = t.KeyData(os.urandom(16)) (status,) = await ezsp.setInitialSecurityState(init_sec_state) LOGGER.debug("Set initial security state: %s", status) @@ -344,5 +344,5 @@ async def _update_nwk_id(ezsp, nwk_update_id): def is_well_known_key(tc_link_key): """Return True if this is a well known key.""" - well_known_key = t.EmberKeyData.deserialize(b"ZigBeeAlliance09")[0] + well_known_key = t.KeyData.deserialize(b"ZigBeeAlliance09")[0] return tc_link_key == well_known_key diff --git a/bellows/cli/util.py b/bellows/cli/util.py index fdf89e62..bcb9e0b7 100644 --- a/bellows/cli/util.py +++ b/bellows/cli/util.py @@ -29,7 +29,7 @@ class ZigbeeNodeParamType(click.ParamType): def convert(self, value, param, ctx): if ":" not in value or len(value) != 23: self.fail("Node format should be a 8 byte hex string separated by ':'") - return t.EmberEUI64.convert(value) + return t.EUI64.convert(value) def background(f): diff --git a/bellows/ezsp/__init__.py b/bellows/ezsp/__init__.py index 3052ec66..fa4aab0b 100644 --- a/bellows/ezsp/__init__.py +++ b/bellows/ezsp/__init__.py @@ -27,9 +27,9 @@ import bellows.types as t import bellows.uart -from . import v4, v5, v6, v7, v8, v9, v10, v11, v12 +from . import v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 -EZSP_LATEST = v12.EZSPv12.VERSION +EZSP_LATEST = v13.EZSPv13.VERSION LOGGER = logging.getLogger(__name__) MTOR_MIN_INTERVAL = 60 MTOR_MAX_INTERVAL = 3600 @@ -55,6 +55,7 @@ class EZSP: v10.EZSPv10.VERSION: v10.EZSPv10, v11.EZSPv11.VERSION: v11.EZSPv11, v12.EZSPv12.VERSION: v12.EZSPv12, + v13.EZSPv13.VERSION: v13.EZSPv13, } def __init__(self, device_config: dict): @@ -154,20 +155,19 @@ async def reset(self): self.start_ezsp() def _switch_protocol_version(self, version: int) -> None: + LOGGER.debug("Switching to EZSP protocol version %d", version) self._ezsp_version = version - LOGGER.debug("Switching to EZSP protocol version %d", self.ezsp_version) - try: - protcol_cls = self._BY_VERSION[version] - except KeyError: + if version not in self._BY_VERSION: LOGGER.warning( "Protocol version %s is not supported, using version %s instead", version, EZSP_LATEST, ) - protcol_cls = self._BY_VERSION[EZSP_LATEST] + # We replace the protocol object but keep the version correct + version = EZSP_LATEST - self._protocol = protcol_cls(self.handle_callback, self._gw) + self._protocol = self._BY_VERSION[version](self.handle_callback, self._gw) async def version(self): ver, stack_type, stack_version = await self._command( @@ -386,14 +386,14 @@ async def _get_nv3_restored_eui64_key(self) -> t.NV3KeyId | None: return None if status == t.EmberStatus.SUCCESS: - nv3_restored_eui64, _ = t.EmberEUI64.deserialize(data) + nv3_restored_eui64, _ = t.EUI64.deserialize(data) LOGGER.debug("NV3 restored EUI64: %s=%s", key, nv3_restored_eui64) return key return None - async def _get_mfg_custom_eui_64(self) -> t.EmberEUI64 | None: + async def _get_mfg_custom_eui_64(self) -> t.EUI64 | None: """Get the custom EUI 64 manufacturing token, if it has a valid value.""" (data,) = await self.getMfgToken(t.EzspMfgTokenId.MFG_CUSTOM_EUI_64) @@ -401,9 +401,9 @@ async def _get_mfg_custom_eui_64(self) -> t.EmberEUI64 | None: if not data: raise ValueError("Firmware does not support MFG_CUSTOM_EUI_64 token") - mfg_custom_eui64, _ = t.EmberEUI64.deserialize(data) + mfg_custom_eui64, _ = t.EUI64.deserialize(data) - if mfg_custom_eui64 == t.EmberEUI64.convert("FF:FF:FF:FF:FF:FF:FF:FF"): + if mfg_custom_eui64 == t.EUI64.convert("FF:FF:FF:FF:FF:FF:FF:FF"): return None return mfg_custom_eui64 @@ -429,7 +429,7 @@ async def reset_custom_eui64(self) -> None: (status,) = await self.setTokenData( nv3_eui64_key, 0, - t.LVBytes32(t.EmberEUI64.convert("FF:FF:FF:FF:FF:FF:FF:FF").serialize()), + t.LVBytes32(t.EUI64.convert("FF:FF:FF:FF:FF:FF:FF:FF").serialize()), ) assert status == t.EmberStatus.SUCCESS diff --git a/bellows/ezsp/config.py b/bellows/ezsp/config.py index 5280fbd3..052e12e2 100644 --- a/bellows/ezsp/config.py +++ b/bellows/ezsp/config.py @@ -130,4 +130,5 @@ class ValueConfig: 10: DEFAULT_CONFIG_NEW, 11: DEFAULT_CONFIG_NEW, 12: DEFAULT_CONFIG_NEW, + 13: DEFAULT_CONFIG_NEW, } diff --git a/bellows/ezsp/protocol.py b/bellows/ezsp/protocol.py index fe1e82d6..c7b08054 100644 --- a/bellows/ezsp/protocol.py +++ b/bellows/ezsp/protocol.py @@ -13,6 +13,7 @@ from bellows.config import CONF_EZSP_POLICIES from bellows.exception import InvalidCommandError +import bellows.types as t from bellows.typing import GatewayType LOGGER = logging.getLogger(__name__) @@ -54,6 +55,11 @@ def _ezsp_frame_tx(self, name: str) -> bytes: async def pre_permit(self, time_s: int) -> None: """Schedule task before allowing new joins.""" + async def add_transient_link_key( + self, ieee: t.EUI64, key: t.KeyData + ) -> t.EmberStatus: + """Add a transient link key.""" + async def command(self, name, *args) -> Any: """Serialize command and send it.""" LOGGER.debug("Send command %s: %s", name, args) @@ -103,6 +109,9 @@ def __call__(self, data: bytes) -> None: LOGGER.debug("Application frame received %s: %s", frame_name, result) + if data: + LOGGER.debug("Frame contains trailing data: %s", data) + if sequence in self._awaiting: expected_id, schema, future = self._awaiting.pop(sequence) try: diff --git a/bellows/ezsp/v10/commands.py b/bellows/ezsp/v10/commands.py index 726e5a41..0fd70340 100644 --- a/bellows/ezsp/v10/commands.py +++ b/bellows/ezsp/v10/commands.py @@ -65,7 +65,7 @@ "getXncpInfo": (0x0013, (), (t.EmberStatus, t.uint16_t, t.uint16_t)), "customFrame": (0x0047, (t.LVBytes,), (t.EmberStatus, t.LVBytes)), "customFrameHandler": (0x0054, (), (t.LVBytes,)), - "getEui64": (0x0026, (), (t.EmberEUI64,)), + "getEui64": (0x0026, (), (t.EUI64,)), "getNodeId": (0x0027, (), (t.EmberNodeId,)), "getPhyInterfaceCount": (0x00FC, (), (t.uint8_t,)), "getTrueRandomEntropySource": (0x004F, (), (t.EmberEntropySource,)), @@ -103,7 +103,7 @@ "childJoinHandler": ( 0x0023, (), - (t.uint8_t, t.Bool, t.EmberNodeId, t.EmberEUI64, t.EmberNodeType), + (t.uint8_t, t.Bool, t.EmberNodeId, t.EUI64, t.EmberNodeType), ), "energyScanRequest": ( 0x009C, @@ -120,7 +120,7 @@ (t.uint8_t,), (t.EmberStatus, t.EmberNodeType, t.EmberNetworkParameters), ), - "getParentChildParameters": (0x0029, (), (t.uint8_t, t.EmberEUI64, t.EmberNodeId)), + "getParentChildParameters": (0x0029, (), (t.uint8_t, t.EUI64, t.EmberNodeId)), "getChildData": ( 0x004A, (t.uint8_t,), @@ -128,8 +128,8 @@ ), "setChildData": ( 0x00AC, - (t.uint8_t,), - (t.EmberStatus, t.EmberChildData), + (t.uint8_t, t.EmberChildData), + (t.EmberStatus,), ), "getSourceRouteTableTotalSize": (0x00C3, (), (t.uint8_t,)), "getSourceRouteTableFilledSize": (0x00C2, (), (t.uint8_t,)), @@ -139,8 +139,8 @@ (t.EmberStatus, t.EmberNodeId, t.uint8_t), ), "getNeighbor": (0x0079, (t.uint8_t,), (t.EmberStatus, t.EmberNeighborTableEntry)), - "getNeighborFrameCounter": (0x003E, (t.EmberEUI64,), (t.EmberStatus, t.uint32_t)), - "setNeighborFrameCounter": (0x00AD, (t.EmberEUI64,), (t.EmberStatus, t.uint32_t)), + "getNeighborFrameCounter": (0x003E, (t.EUI64,), (t.EmberStatus, t.uint32_t)), + "setNeighborFrameCounter": (0x00AD, (t.EUI64,), (t.EmberStatus, t.uint32_t)), "setRoutingShortcutThreshold": (0x00D0, (t.uint8_t,), (t.EmberStatus,)), "getRoutingShortcutThreshold": (0x00D1, (), (t.uint8_t,)), "neighborCount": (0x007A, (), (t.uint8_t,)), @@ -288,7 +288,7 @@ ), "pollCompleteHandler": (0x0043, (), (t.EmberStatus,)), "pollHandler": (0x0044, (), (t.EmberNodeId,)), - "incomingSenderEui64Handler": (0x0062, (), (t.EmberEUI64,)), + "incomingSenderEui64Handler": (0x0062, (), (t.EUI64,)), "incomingMessageHandler": ( 0x0045, (), @@ -306,39 +306,44 @@ "incomingRouteRecordHandler": ( 0x0059, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), + (t.EmberNodeId, t.EUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), ), "incomingNetworkStatusHandler": ( 0x00C4, (), tuple({"errorCode": t.EmberStackError, "target": t.EmberNodeId}.values()), ), + "setSourceRoute": ( + 0x00AE, + (t.EmberNodeId, t.LVList(t.EmberNodeId)), + (t.EmberStatus,), + ), "setSourceRouteDiscoveryMode": (0x005A, (t.uint8_t,), (t.uint32_t,)), "incomingManyToOneRouteRequestHandler": ( 0x007D, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t), + (t.EmberNodeId, t.EUI64, t.uint8_t), ), "incomingRouteErrorHandler": (0x0080, (), (t.EmberStatus, t.EmberNodeId)), "unicastCurrentNetworkKey": ( 0x0050, - (t.EmberNodeId, t.EmberEUI64, t.EmberNodeId), + (t.EmberNodeId, t.EUI64, t.EmberNodeId), (t.EmberStatus,), ), "addressTableEntryIsActive": (0x005B, (t.uint8_t,), (t.Bool,)), - "setAddressTableRemoteEui64": (0x005C, (t.uint8_t, t.EmberEUI64), (t.EmberStatus,)), + "setAddressTableRemoteEui64": (0x005C, (t.uint8_t, t.EUI64), (t.EmberStatus,)), "setAddressTableRemoteNodeId": (0x005D, (t.uint8_t, t.EmberNodeId), ()), - "getAddressTableRemoteEui64": (0x005E, (t.uint8_t,), (t.EmberEUI64,)), + "getAddressTableRemoteEui64": (0x005E, (t.uint8_t,), (t.EUI64,)), "getAddressTableRemoteNodeId": (0x005F, (t.uint8_t,), (t.EmberNodeId,)), - "setExtendedTimeout": (0x007E, (t.EmberEUI64, t.Bool), ()), - "getExtendedTimeout": (0x007F, (t.EmberEUI64,), (t.Bool,)), + "setExtendedTimeout": (0x007E, (t.EUI64, t.Bool), ()), + "getExtendedTimeout": (0x007F, (t.EUI64,), (t.Bool,)), "replaceAddressTableEntry": ( 0x0082, - (t.uint8_t, t.EmberEUI64, t.EmberNodeId, t.Bool), - (t.EmberStatus, t.EmberEUI64, t.EmberNodeId, t.Bool), + (t.uint8_t, t.EUI64, t.EmberNodeId, t.Bool), + (t.EmberStatus, t.EUI64, t.EmberNodeId, t.Bool), ), - "lookupNodeIdByEui64": (0x0060, (t.EmberEUI64,), (t.EmberNodeId,)), - "lookupEui64ByNodeId": (0x0061, (t.EmberNodeId,), (t.EmberStatus, t.EmberEUI64)), + "lookupNodeIdByEui64": (0x0060, (t.EUI64,), (t.EmberNodeId,)), + "lookupEui64ByNodeId": (0x0061, (t.EmberNodeId,), (t.EmberStatus, t.EUI64)), "getMulticastTableEntry": ( 0x0063, (t.uint8_t,), @@ -395,26 +400,26 @@ "getKeyTableEntry": (0x0071, (t.uint8_t,), (t.EmberStatus, t.EmberKeyStruct)), "setKeyTableEntry": ( 0x0072, - (t.uint8_t, t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.uint8_t, t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "findKeyTableEntry": (0x0075, (t.EmberEUI64, t.Bool), (t.uint8_t,)), + "findKeyTableEntry": (0x0075, (t.EUI64, t.Bool), (t.uint8_t,)), "addOrUpdateKeyTableEntry": ( 0x0066, - (t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "sendTrustCenterLinkKey": (0x0067, (t.EmberNodeId, t.EmberEUI64), (t.EmberStatus,)), + "sendTrustCenterLinkKey": (0x0067, (t.EmberNodeId, t.EUI64), (t.EmberStatus,)), "eraseKeyTableEntry": (0x0076, (t.uint8_t,), (t.EmberStatus,)), "clearKeyTable": (0x00B1, (), (t.EmberStatus,)), - "requestLinkKey": (0x0014, (t.EmberEUI64,), (t.EmberStatus,)), + "requestLinkKey": (0x0014, (t.EUI64,), (t.EmberStatus,)), "updateTcLinkKey": (0x006C, (t.uint8_t,), (t.EmberStatus,)), - "zigbeeKeyEstablishmentHandler": (0x009B, (), (t.EmberEUI64, t.EmberKeyStatus)), - "addTransientLinkKey": (0x00AF, (t.EmberEUI64, t.EmberKeyData), (t.EmberStatus,)), + "zigbeeKeyEstablishmentHandler": (0x009B, (), (t.EUI64, t.EmberKeyStatus)), + "addTransientLinkKey": (0x00AF, (t.EUI64, t.KeyData), (t.EmberStatus,)), "clearTransientLinkKeys": (0x006B, (), ()), "getTransientLinkKey": ( 0x00CE, - (t.EmberEUI64,), + (t.EUI64,), (t.EmberStatus, t.EmberTransientKeyData), ), "getTransientKeyTableEntry": ( @@ -428,15 +433,15 @@ (), ( t.EmberNodeId, - t.EmberEUI64, + t.EUI64, t.EmberDeviceUpdate, t.EmberJoinDecision, t.EmberNodeId, ), ), - "broadcastNextNetworkKey": (0x0073, (t.EmberKeyData,), (t.EmberStatus,)), + "broadcastNextNetworkKey": (0x0073, (t.KeyData,), (t.EmberStatus,)), "broadcastNetworkKeySwitch": (0x0074, (), (t.EmberStatus,)), - "becomeTrustCenter": (0x0077, (t.EmberKeyData,), (t.EmberStatus,)), + "becomeTrustCenter": (0x0077, (t.KeyData,), (t.EmberStatus,)), "aesMmoHash": ( 0x006F, (t.EmberAesMmoHashContext, t.Bool, t.LVBytes), @@ -444,12 +449,12 @@ ), "removeDevice": ( 0x00A8, - (t.EmberNodeId, t.EmberEUI64, t.EmberEUI64), + (t.EmberNodeId, t.EUI64, t.EUI64), (t.EmberStatus,), ), "unicastNwkKeyUpdate": ( 0x00A9, - (t.EmberNodeId, t.EmberEUI64, t.EmberKeyData), + (t.EmberNodeId, t.EUI64, t.KeyData), (t.EmberStatus,), ), # 11. Certificate Based Key Exchange (CBKE) Frames @@ -529,7 +534,7 @@ "launchStandaloneBootloader": (0x008F, (t.uint8_t,), (t.EmberStatus,)), "sendBootloadMessage": ( 0x0090, - (t.Bool, t.EmberEUI64, t.LVBytes), + (t.Bool, t.EUI64, t.LVBytes), (t.EmberStatus,), ), "getStandaloneBootloaderVersionPlatMicroPhy": ( @@ -540,7 +545,7 @@ "incomingBootloadMessageHandler": ( 0x0092, (), - (t.EmberEUI64, t.uint8_t, t.int8s, t.LVBytes), + (t.EUI64, t.uint8_t, t.int8s, t.LVBytes), ), "bootloadTransmitCompleteHandler": (0x0093, (), (t.EmberStatus, t.LVBytes)), "aesEncrypt": ( @@ -556,7 +561,7 @@ ), "zllSetInitialSecurityState": ( 0x00B3, - (t.EmberKeyData, t.EmberZllInitialSecurityState), + (t.KeyData, t.EmberZllInitialSecurityState), (t.EmberStatus,), ), "zllSetSecurityStateWithoutKey": ( @@ -613,8 +618,8 @@ t.uint16_t, t.uint16_t, t.uint16_t, - t.EmberEUI64, - t.EmberKeyData, + t.EUI64, + t.KeyData, ), (), ), @@ -670,7 +675,7 @@ # 17 Secure EZSP Frames "setSecurityKey": ( 0x00CA, - (t.EmberKeyData, t.SecureEzspSecurityType), + (t.KeyData, t.SecureEzspSecurityType), (t.EzspStatus,), ), "setSecurityParameters": ( diff --git a/bellows/ezsp/v10/types/named.py b/bellows/ezsp/v10/types/named.py index 828d89ef..72e735de 100644 --- a/bellows/ezsp/v10/types/named.py +++ b/bellows/ezsp/v10/types/named.py @@ -2,6 +2,7 @@ import bellows.types.basic as basic from bellows.types.named import ( # noqa: F401, F403 + EUI64, Bool, Channels, EmberApsOption, @@ -11,14 +12,12 @@ EmberConcentratorType, EmberConfigTxPowerMode, EmberCurrentSecurityBitmask, - EmberEUI64, EmberEventUnits, EmberGpKeyType, EmberGpSecurityLevel, EmberIncomingMessageType, EmberInitialSecurityBitmask, EmberJoinDecision, - EmberKeyData, EmberKeyStatus, EmberKeyStructBitmask, EmberLibraryId, @@ -51,6 +50,7 @@ EzspSourceRouteOverheadInformation, EzspStatus, EzspZllNetworkOperation, + KeyData, sl_Status, ) diff --git a/bellows/ezsp/v10/types/struct.py b/bellows/ezsp/v10/types/struct.py index af81ec8a..65329a12 100644 --- a/bellows/ezsp/v10/types/struct.py +++ b/bellows/ezsp/v10/types/struct.py @@ -92,7 +92,7 @@ class EmberKeyStruct(EzspStruct): # The type of the key. type: named.EmberKeyType # The actual key data. - key: named.EmberKeyData + key: named.KeyData # The outgoing frame counter associated with the key. outgoingFrameCounter: basic.uint32_t # The frame counter of the partner device associated with the key. @@ -100,7 +100,7 @@ class EmberKeyStruct(EzspStruct): # The sequence number associated with the key. sequenceNumber: basic.uint8_t # The IEEE address of the partner device also in possession of the key. - partnerEUI64: named.EmberEUI64 + partnerEUI64: named.EUI64 @classmethod def deserialize(cls, data: bytes) -> tuple[named.EmberKeyStruct, bytes]: @@ -116,7 +116,7 @@ class EmberGpSinkListEntry(EzspStruct): # The sink list type. type: basic.uint8_t # The EUI64 of the target sink. - sinkEUI: named.EmberEUI64 + sinkEUI: named.EUI64 # The short address of the target sink. sinkNodeId: named.EmberNodeId @@ -125,7 +125,7 @@ class EmberGpProxyTableEntry(EzspStruct): """The internal representation of a proxy table entry.""" # The link key to be used to secure this pairing link. - securityLinkKey: named.EmberKeyData + securityLinkKey: named.KeyData # Internal status of the proxy table entry. status: named.EmberGpProxyTableEntryStatus # The tunneling options @@ -170,7 +170,7 @@ class EmberGpSinkTableEntry(EzspStruct): # The security frame counter of the GPD. gpdSecurityFrameCounter: named.EmberGpSecurityFrameCounter # The key to use for GPD. - gpdKey: named.EmberKeyData + gpdKey: named.KeyData class EmberDutyCycleLimits(EzspStruct): @@ -204,9 +204,9 @@ class EmberTransientKeyData(EzspStruct): """The transient key data structure. Added in ver. 5. Revised in ver 8""" # The IEEE address paired with the transient link key. - eui64: named.EmberEUI64 + eui64: named.EUI64 # The key data structure matching the transient key. - keyData: named.EmberKeyData + keyData: named.KeyData # This bitmask indicates whether various fields in the structure contain valid data. bitmask: named.EmberKeyStructBitmask # The number of seconds remaining before the key is automatically timed out of the @@ -218,7 +218,7 @@ class EmberChildData(EzspStruct): """A structure containing a child node's data.""" # The EUI64 of the child - eui64: named.EmberEUI64 + eui64: named.EUI64 # The node type of the child type: named.EmberNodeType # The short address of the child @@ -229,8 +229,9 @@ class EmberChildData(EzspStruct): power: basic.uint8_t # The timeout of the child timeout: basic.uint8_t + timeout_remaining: basic.uint32_t # The GPD's EUI64. - # gpdIeeeAddress: named.EmberEUI64 + # gpdIeeeAddress: named.EUI64 # The GPD's source ID. # sourceId: basic.uint32_t diff --git a/bellows/ezsp/v12/commands.py b/bellows/ezsp/v12/commands.py index d1962e86..96522a56 100644 --- a/bellows/ezsp/v12/commands.py +++ b/bellows/ezsp/v12/commands.py @@ -1,4 +1,4 @@ -from bellows.types import EmberKeyData +from bellows.types import KeyData from . import types as t from ..v11.commands import COMMANDS as COMMANDS_v11 @@ -95,7 +95,7 @@ ), tuple( { - "key": EmberKeyData, + "key": KeyData, "status": t.sl_Status, }.values() ), @@ -104,12 +104,12 @@ 0x010D, tuple( { - "eui64": t.EmberEUI64, + "eui64": t.EUI64, }.values() ), tuple( { - "plaintext_key": EmberKeyData, + "plaintext_key": KeyData, "index": t.uint8_t, "key_data": t.sl_zb_sec_man_aps_key_metadata_t, "status": t.sl_Status, @@ -125,8 +125,8 @@ ), tuple( { - "eui64": t.EmberEUI64, - "plaintext_key": EmberKeyData, + "eui64": t.EUI64, + "plaintext_key": KeyData, "key_data": t.sl_zb_sec_man_aps_key_metadata_t, "status": t.sl_Status, }.values() @@ -136,13 +136,13 @@ 0x0113, tuple( { - "eui64": t.EmberEUI64, + "eui64": t.EUI64, }.values() ), tuple( { "context": t.sl_zb_sec_man_context_t, - "plaintext_key": EmberKeyData, + "plaintext_key": KeyData, "key_data": t.sl_zb_sec_man_aps_key_metadata_t, "status": t.sl_Status, }.values() @@ -158,7 +158,7 @@ tuple( { "context": t.sl_zb_sec_man_context_t, - "plaintext_key": EmberKeyData, + "plaintext_key": KeyData, "key_data": t.sl_zb_sec_man_aps_key_metadata_t, "status": t.sl_Status, }.values() @@ -173,7 +173,7 @@ ), tuple( { - "eui": t.EmberEUI64, + "eui": t.EUI64, "key_data": t.sl_zb_sec_man_aps_key_metadata_t, "status": t.sl_Status, }.values() @@ -205,7 +205,7 @@ tuple( { "context": t.sl_zb_sec_man_context_t, - "key": EmberKeyData, + "key": KeyData, }.values() ), tuple( @@ -219,8 +219,8 @@ tuple( { "index": t.uint8_t, - "address": t.EmberEUI64, - "key": EmberKeyData, + "address": t.EUI64, + "key": KeyData, }.values() ), tuple( @@ -233,8 +233,8 @@ 0x0111, tuple( { - "eui64": t.EmberEUI64, - "plaintext_key": EmberKeyData, + "eui64": t.EUI64, + "plaintext_key": KeyData, "flags": t.sl_zb_sec_man_flags_t, }.values() ), diff --git a/bellows/ezsp/v12/types/struct.py b/bellows/ezsp/v12/types/struct.py index eb7626fd..d1c09d3f 100644 --- a/bellows/ezsp/v12/types/struct.py +++ b/bellows/ezsp/v12/types/struct.py @@ -17,7 +17,7 @@ class sl_zb_sec_man_context_t(EzspStruct): # The type of key derivation operation to perform on a key. derived_type: named.sl_zb_sec_man_derived_key_type_t # The EUI64 associated with this key. - eui64: t.EmberEUI64 + eui64: t.EUI64 # Multi-network index. multi_network_index: t.uint8_t # Flag bitmask. diff --git a/bellows/ezsp/v13/__init__.py b/bellows/ezsp/v13/__init__.py new file mode 100644 index 00000000..73979b41 --- /dev/null +++ b/bellows/ezsp/v13/__init__.py @@ -0,0 +1,33 @@ +""""EZSP Protocol version 13 protocol handler.""" +from __future__ import annotations + +import voluptuous as vol + +import bellows.config +import bellows.types as t + +from . import commands, config, types as v13_types +from ..v12 import EZSPv12 + + +class EZSPv13(EZSPv12): + """EZSP Version 13 Protocol version handler.""" + + VERSION = 13 + 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), + } + types = v13_types + + async def add_transient_link_key( + self, ieee: t.EUI64, key: t.KeyData + ) -> t.EmberStatus: + (status,) = await self.importTransientKey( + ieee, + key, + v13_types.sl_zb_sec_man_flags_t.NONE, + ) + + return status diff --git a/bellows/ezsp/v13/commands.py b/bellows/ezsp/v13/commands.py new file mode 100644 index 00000000..8e9d8559 --- /dev/null +++ b/bellows/ezsp/v13/commands.py @@ -0,0 +1,129 @@ +from . import types as t +from ..v12.commands import COMMANDS as COMMANDS_v12 + +COMMANDS = { + **COMMANDS_v12, + "getNetworkKeyInfo": ( + 0x0116, + (), + tuple( + { + "status": t.sl_Status, + "bogus": t.uint16_t, + "network_key_info": t.sl_zb_sec_man_network_key_info_t, + }.values() + ), + ), + "gpSecurityTestVectors": ( + 0x0117, + (), + tuple( + { + "status": t.EmberStatus, + }.values() + ), + ), + "tokenFactoryReset": ( + 0x0077, + tuple({"excludeOutgoingFC": t.Bool, "excludeBootCounter": t.Bool}.values()), + (), + ), + "gpSinkTableGetNumberOfActiveEntries": ( + 0x0118, + (), + tuple( + { + "number_of_entries": t.uint8_t, + }.values() + ), + ), + # The following commands are redefined because `sl_zb_sec_man_context_t` changed + "exportKey": ( + 0x0114, + tuple( + { + "context": t.sl_zb_sec_man_context_t, + }.values() + ), + tuple( + { + "key": t.KeyData, + "status": t.sl_Status, + }.values() + ), + ), + "exportTransientKeyByEui": ( + 0x0113, + tuple( + { + "eui64": t.EUI64, + }.values() + ), + tuple( + { + "context": t.sl_zb_sec_man_context_t, + "plaintext_key": t.KeyData, + "key_data": t.sl_zb_sec_man_aps_key_metadata_t, + "status": t.sl_Status, + }.values() + ), + ), + "exportTransientKeyByIndex": ( + 0x0112, + tuple( + { + "index": t.uint8_t, + }.values() + ), + tuple( + { + "context": t.sl_zb_sec_man_context_t, + "plaintext_key": t.KeyData, + "key_data": t.sl_zb_sec_man_aps_key_metadata_t, + "status": t.sl_Status, + }.values() + ), + ), + "getApsKeyInfo": ( + 0x010C, + tuple( + { + "context_in": t.sl_zb_sec_man_context_t, + }.values() + ), + tuple( + { + "eui": t.EUI64, + "key_data": t.sl_zb_sec_man_aps_key_metadata_t, + "status": t.sl_Status, + }.values() + ), + ), + "importKey": ( + 0x0115, + tuple( + { + "context": t.sl_zb_sec_man_context_t, + "key": t.KeyData, + }.values() + ), + tuple( + { + "status": t.sl_Status, + }.values() + ), + ), +} + +del COMMANDS["becomeTrustCenter"] # this one was likely removed earlier +del COMMANDS["getKey"] +del COMMANDS["getKeyTableEntry"] +del COMMANDS["setKeyTableEntry"] +del COMMANDS["addOrUpdateKeyTableEntry"] +del COMMANDS["addTransientLinkKey"] +del COMMANDS["getTransientLinkKey"] +del COMMANDS["getTransientKeyTableEntry"] +del COMMANDS["setSecurityKey"] +del COMMANDS["setSecurityParameters"] +del COMMANDS["resetToFactoryDefaults"] +del COMMANDS["getSecurityKeyStatus"] diff --git a/bellows/ezsp/v13/config.py b/bellows/ezsp/v13/config.py new file mode 100644 index 00000000..8b0be575 --- /dev/null +++ b/bellows/ezsp/v13/config.py @@ -0,0 +1,16 @@ +import voluptuous as vol + +from bellows.config import cv_uint16 + +from ..v4.config import EZSP_POLICIES_SHARED +from ..v12 import config as v12_config +from .types import EzspPolicyId + +EZSP_SCHEMA = { + **v12_config.EZSP_SCHEMA, +} + +EZSP_POLICIES_SCH = { + **EZSP_POLICIES_SHARED, + **{vol.Optional(policy.name): cv_uint16 for policy in EzspPolicyId}, +} diff --git a/bellows/ezsp/v13/types/__init__.py b/bellows/ezsp/v13/types/__init__.py new file mode 100644 index 00000000..77e247c3 --- /dev/null +++ b/bellows/ezsp/v13/types/__init__.py @@ -0,0 +1,3 @@ +from bellows.ezsp.v12.types import * # noqa: F401, F403 +from bellows.ezsp.v13.types.named import * # noqa: F401, F403 +from bellows.ezsp.v13.types.struct import * # noqa: F401, F403 diff --git a/bellows/ezsp/v13/types/named.py b/bellows/ezsp/v13/types/named.py new file mode 100644 index 00000000..4c88fb36 --- /dev/null +++ b/bellows/ezsp/v13/types/named.py @@ -0,0 +1,161 @@ +from bellows.ezsp.v12.types.named import * # noqa: F401, F403 +import bellows.types as t + + +class sl_zb_sec_man_derived_key_type_t(t.enum16): + """Derived keys are calculated when performing Zigbee crypto operations. + The stack makes use of these derivations. + """ + + # Perform no derivation; use the key as is. + NONE = 0 + # Perform the Key-Transport-Key hash. + KEY_TRANSPORT_KEY = 1 + # Perform the Key-Load-Key hash. + KEY_LOAD_KEY = 2 + # Perform the Verify Key hash. + VERIFY_KEY = 3 + # Perform a simple AES hash of the key for TC backup. + TC_SWAP_OUT_KEY = 4 + # For a TC using hashed link keys, hashed the root key against the supplied EUI in + # context. + TC_HASHED_LINK_KEY = 5 + + +class EzspValueId(t.enum8): + # Identifies a value. + + # The contents of the node data stack token. + VALUE_TOKEN_STACK_NODE_DATA = 0x00 + # The types of MAC passthrough messages that the host wishes to receive. + VALUE_MAC_PASSTHROUGH_FLAGS = 0x01 + # The source address used to filter legacy EmberNet messages when the + # MAC_PASSTHROUGH_EMBERNET_SOURCE flag is set in VALUE_MAC_PASSTHROUGH_FLAGS. + VALUE_EMBERNET_PASSTHROUGH_SOURCE_ADDRESS = 0x02 + # The number of available message buffers. + VALUE_FREE_BUFFERS = 0x03 + # Selects sending synchronous callbacks in ezsp-uart. + VALUE_UART_SYNCH_CALLBACKS = 0x04 + # The maximum incoming transfer size for the local node. + VALUE_MAXIMUM_INCOMING_TRANSFER_SIZE = 0x05 + # The maximum outgoing transfer size for the local node. + VALUE_MAXIMUM_OUTGOING_TRANSFER_SIZE = 0x06 + # A boolean indicating whether stack tokens are written to persistent + # storage as they change. + VALUE_STACK_TOKEN_WRITING = 0x07 + # A read-only value indicating whether the stack is currently performing a rejoin. + VALUE_STACK_IS_PERFORMING_REJOIN = 0x08 + # A list of EmberMacFilterMatchData values. + VALUE_MAC_FILTER_LIST = 0x09 + # The Ember Extended Security Bitmask. + VALUE_EXTENDED_SECURITY_BITMASK = 0x0A + # The node short ID. + VALUE_NODE_SHORT_ID = 0x0B + # The descriptor capability of the local node. + VALUE_DESCRIPTOR_CAPABILITY = 0x0C + # The stack device request sequence number of the local node. + VALUE_STACK_DEVICE_REQUEST_SEQUENCE_NUMBER = 0x0D + # Enable or disable radio hold-off. + VALUE_RADIO_HOLD_OFF = 0x0E + # The flags field associated with the endpoint data. + VALUE_ENDPOINT_FLAGS = 0x0F + # Enable/disable the Mfg security config key settings. + VALUE_MFG_SECURITY_CONFIG = 0x10 + # Retrieves the version information from the stack on the NCP. + VALUE_VERSION_INFO = 0x11 + # This will get/set the rejoin reason noted by the host for a subsequent call to + # emberFindAndRejoinNetwork(). After a call to emberFindAndRejoinNetwork() the + # host's rejoin reason will be set to REJOIN_REASON_NONE. The NCP will store the + # rejoin reason used by the call to emberFindAndRejoinNetwork() + VALUE_NEXT_HOST_REJOIN_REASON = 0x12 + # This is the reason that the last rejoin took place. This value may only be + # retrieved, not set. The rejoin may have been initiated by the stack (NCP) or the + # application (host). If a host initiated a rejoin the reason will be set by default + # to REJOIN_DUE_TO_APP_EVENT_1. If the application wishes to denote its own rejoin + # reasons it can do so by calling ezspSetValue(VALUE_HOST_REJOIN_REASON, + # REJOIN_DUE_TO_APP_EVENT_X). X is a number corresponding to one of the app events + # defined. If the NCP initiated a rejoin it will record this value internally for + # retrieval by ezspGetValue(VALUE_REAL_REJOIN_REASON). + VALUE_LAST_REJOIN_REASON = 0x13 + # The next ZigBee sequence number. + VALUE_NEXT_ZIGBEE_SEQUENCE_NUMBER = 0x14 + # CCA energy detect threshold for radio. + VALUE_CCA_THRESHOLD = 0x15 + # The threshold value for a counter + VALUE_SET_COUNTER_THRESHOLD = 0x17 + # Resets all counters thresholds to 0xFF + VALUE_RESET_COUNTER_THRESHOLDS = 0x18 + # Clears all the counters + VALUE_CLEAR_COUNTERS = 0x19 + # The node's new certificate signed by the CA. + EZSP_VALUE_CERTIFICATE_283K1 = 0x1A + # The Certificate Authority's public key. + EZSP_VALUE_PUBLIC_KEY_283K1 = 0x1B + # The node's new static private key. + EZSP_VALUE_PRIVATE_KEY_283K1 = 0x1C + # The NWK layer security frame counter value + VALUE_NWK_FRAME_COUNTER = 0x23 + # The APS layer security frame counter value + VALUE_APS_FRAME_COUNTER = 0x24 + # Sets the device type to use on the next rejoin using device type + VALUE_RETRY_DEVICE_TYPE = 0x25 + # Setting this byte enables R21 behavior on the NCP. + VALUE_ENABLE_R21_BEHAVIOR = 0x29 + # Configure the antenna mode(0-primary,1-secondary,2- toggle on tx ack fail). + VALUE_ANTENNA_MODE = 0x30 + # Enable or disable packet traffic arbitration. + VALUE_ENABLE_PTA = 0x31 + # Set packet traffic arbitration configuration options. + VALUE_PTA_OPTIONS = 0x32 + # Configure manufacturing library options(0-non-CSMA transmits,1-CSMA transmits). + VALUE_MFGLIB_OPTIONS = 0x33 + # Sets the flag to use either negotiated power by link power delta (LPD) or fixed + # power value provided by user while forming/joining a network for packet + # transmissions on subghz interface. This is mainly for testing purposes. + VALUE_USE_NEGOTIATED_POWER_BY_LPD = 0x34 + # Set packet traffic arbitration configuration PWM options. + VALUE_PTA_PWM_OPTIONS = 0x35 + # Set packet traffic arbitration directional priority pulse width in microseconds. + VALUE_PTA_DIRECTIONAL_PRIORITY_PULSE_WIDTH = 0x36 + # Set packet traffic arbitration phy select timeout(ms) + VALUE_PTA_PHY_SELECT_TIMEOUT = 0x37 + # Configure the RX antenna mode: (0-do not switch; 1- primary; 2-secondary; + # 3-RX antenna diversity). + VALUE_ANTENNA_RX_MODE = 0x38 + # Configure the timeout to wait for the network key before failing a join. + VALUE_NWK_KEY_TIMEOUT = 0x39 + # The number of failed CSMA attempts due to failed CCA made by the MAC before + # continuing transmission with CCA disabled. This is the same as calling the + # emberForceTxAfterFailedCca(uint8_t csmaAttempts) API. A value of 0 disables the + # feature + VALUE_FORCE_TX_AFTER_FAILED_CCA_ATTEMPTS = 0x3A + # The length of time, in seconds, that a trust center will store a transient link + # key that a device can use to join its network. A transient key is added with a + # call to emberAddTransientLinkKey. After the transient key is added, it will be + # removed once this amount of time has passed. A joining device will not be able to + # use that key to join until it is added again on the trust center. The default + # value is 300 seconds (5 minutes). + VALUE_TRANSIENT_KEY_TIMEOUT_S = 0x3B + # Cumulative energy usage metric since the last value reset of the coulomb counter + # plugin. Setting this value will reset the coulomb counter. + VALUE_COULOMB_COUNTER_USAGE = 0x3C + # When scanning, configure the maximum number of beacons to store in cache. Each + # beacon consumes one packet buffer in RAM. + VALUE_MAX_BEACONS_TO_STORE = 0x3D + # Set the mask to filter out unacceptable child timeout options on a router. + VALUE_END_DEVICE_TIMEOUT_OPTIONS_MASK = 0x3E + # The end device keep alive mode supported by the parent. + VALUE_END_DEVICE_KEEP_ALIVE_SUPPORT_MODE = 0x3F + # Return the active radio config. + VALUE_ACTIVE_RADIO_CONFIG = 0x41 + # Timeout in milliseconds to store entries in the transient device table. + # If the devices are not authenticated before the timeout, the entry shall be + # purged. + VALUE_TRANSIENT_DEVICE_TIMEOUT = 0x43 + # Return information about the key storage on an NCP. + # Returns 0 if keys are in classic key storage, and 1 if they + # are located in PSA key storage. Read only. + VALUE_KEY_STORAGE_VERSION = 0x44 + # Return activation state about TC Delayed Join on an NCP. A return value of + # 0 indicates that the feature is not activated. + VALUE_DELAYED_JOIN_ACTIVATION = 0x45 diff --git a/bellows/ezsp/v13/types/struct.py b/bellows/ezsp/v13/types/struct.py new file mode 100644 index 00000000..c2ddd82c --- /dev/null +++ b/bellows/ezsp/v13/types/struct.py @@ -0,0 +1,37 @@ +"""Protocol version 13 specific structs.""" + +from __future__ import annotations + +from bellows.ezsp.v12.types.struct import * # noqa: F401, F403 +from bellows.ezsp.v13.types import named +import bellows.types as t +from bellows.types.struct import EzspStruct + + +class sl_zb_sec_man_context_t(EzspStruct): + """Context for Zigbee Security Manager operations.""" + + # The type of key being referenced. + core_key_type: named.sl_zb_sec_man_key_type_t + # The index of the referenced key. + key_index: t.uint8_t + # The type of key derivation operation to perform on a key. + derived_type: named.sl_zb_sec_man_derived_key_type_t + # The EUI64 associated with this key. + eui64: t.EUI64 + # Multi-network index. + multi_network_index: t.uint8_t + # Flag bitmask. + flags: named.sl_zb_sec_man_flags_t + # Algorithm to use with this key (for PSA APIs) + psa_key_alg_permission: t.uint32_t + + +class sl_zb_sec_man_network_key_info_t(EzspStruct): + """The metadata pertaining to an network key.""" + + network_key_set: t.Bool + alternate_network_key_set: t.Bool + network_key_sequence_number: t.uint8_t + alt_network_key_sequence_number: t.uint8_t + network_key_frame_counter: t.uint32_t diff --git a/bellows/ezsp/v4/commands.py b/bellows/ezsp/v4/commands.py index 29074ea0..c5086f56 100644 --- a/bellows/ezsp/v4/commands.py +++ b/bellows/ezsp/v4/commands.py @@ -77,7 +77,7 @@ "getXncpInfo": (0x13, (), (t.EmberStatus, t.uint16_t, t.uint16_t)), "customFrame": (0x47, (t.LVBytes,), (t.EmberStatus, t.LVBytes)), "customFrameHandler": (0x54, (), (t.LVBytes,)), - "getEui64": (0x26, (), (t.EmberEUI64,)), + "getEui64": (0x26, (), (t.EUI64,)), "getNodeId": (0x27, (), (t.EmberNodeId,)), "networkInit": (0x17, (), (t.EmberStatus,)), # 6. Networking Frames @@ -107,7 +107,7 @@ "childJoinHandler": ( 0x23, (), - (t.uint8_t, t.Bool, t.EmberNodeId, t.EmberEUI64, t.EmberNodeType), + (t.uint8_t, t.Bool, t.EmberNodeId, t.EUI64, t.EmberNodeType), ), "energyScanRequest": ( 0x9C, @@ -119,11 +119,11 @@ (), (t.EmberStatus, t.EmberNodeType, t.EmberNetworkParameters), ), - "getParentChildParameters": (0x29, (), (t.uint8_t, t.EmberEUI64, t.EmberNodeId)), + "getParentChildParameters": (0x29, (), (t.uint8_t, t.EUI64, t.EmberNodeId)), "getChildData": ( 0x4A, (t.uint8_t,), - (t.EmberStatus, t.EmberNodeId, t.EmberEUI64, t.EmberNodeType), + (t.EmberStatus, t.EmberNodeId, t.EUI64, t.EmberNodeType), ), "getNeighbor": (0x79, (t.uint8_t,), (t.EmberStatus, t.EmberNeighborTableEntry)), "neighborCount": (0x7A, (), (t.uint8_t,)), @@ -202,7 +202,7 @@ "pollForData": (0x42, (t.uint16_t, t.EmberEventUnits, t.uint8_t), (t.EmberStatus,)), "pollCompleteHandler": (0x43, (), (t.EmberStatus,)), "pollHandler": (0x44, (), (t.EmberNodeId,)), - "incomingSenderEui64Handler": (0x62, (), (t.EmberEUI64,)), + "incomingSenderEui64Handler": (0x62, (), (t.EUI64,)), "incomingMessageHandler": ( 0x45, (), @@ -220,7 +220,7 @@ "incomingRouteRecordHandler": ( 0x59, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), + (t.EmberNodeId, t.EUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), ), "setSourceRoute": ( 0x5A, @@ -230,23 +230,23 @@ "incomingManyToOneRouteRequestHandler": ( 0x7D, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t), + (t.EmberNodeId, t.EUI64, t.uint8_t), ), "incomingRouteErrorHandler": (0x80, (), (t.EmberStatus, t.EmberNodeId)), "addressTableEntryIsActive": (0x5B, (t.uint8_t,), (t.Bool,)), - "setAddressTableRemoteEui64": (0x5C, (t.uint8_t, t.EmberEUI64), (t.EmberStatus,)), + "setAddressTableRemoteEui64": (0x5C, (t.uint8_t, t.EUI64), (t.EmberStatus,)), "setAddressTableRemoteNodeId": (0x5D, (t.uint8_t, t.EmberNodeId), ()), - "getAddressTableRemoteEui64": (0x5E, (t.uint8_t,), (t.EmberEUI64,)), + "getAddressTableRemoteEui64": (0x5E, (t.uint8_t,), (t.EUI64,)), "getAddressTableRemoteNodeId": (0x5F, (t.uint8_t,), (t.EmberNodeId,)), - "setExtendedTimeout": (0x7E, (t.EmberEUI64, t.Bool), ()), - "getExtendedTimeout": (0x7F, (t.EmberEUI64,), (t.Bool,)), + "setExtendedTimeout": (0x7E, (t.EUI64, t.Bool), ()), + "getExtendedTimeout": (0x7F, (t.EUI64,), (t.Bool,)), "replaceAddressTableEntry": ( 0x82, - (t.uint8_t, t.EmberEUI64, t.EmberNodeId, t.Bool), - (t.EmberStatus, t.EmberEUI64, t.EmberNodeId, t.Bool), + (t.uint8_t, t.EUI64, t.EmberNodeId, t.Bool), + (t.EmberStatus, t.EUI64, t.EmberNodeId, t.Bool), ), - "lookupNodeIdByEui64": (0x60, (t.EmberEUI64,), (t.EmberNodeId,)), - "lookupEui64ByNodeId": (0x61, (t.EmberNodeId,), (t.EmberStatus, t.EmberEUI64)), + "lookupNodeIdByEui64": (0x60, (t.EUI64,), (t.EmberNodeId,)), + "lookupEui64ByNodeId": (0x61, (t.EmberNodeId,), (t.EmberStatus, t.EUI64)), "getMulticastTableEntry": ( 0x63, (t.uint8_t,), @@ -278,20 +278,20 @@ "getKeyTableEntry": (0x71, (t.uint8_t,), (t.EmberStatus, t.EmberKeyStruct)), "setKeyTableEntry": ( 0x72, - (t.uint8_t, t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.uint8_t, t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "findKeyTableEntry": (0x75, (t.EmberEUI64, t.Bool), (t.uint8_t,)), + "findKeyTableEntry": (0x75, (t.EUI64, t.Bool), (t.uint8_t,)), "addOrUpdateKeyTableEntry": ( 0x66, - (t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), "eraseKeyTableEntry": (0x76, (t.uint8_t,), (t.EmberStatus,)), "clearKeyTable": (0xB1, (), (t.EmberStatus,)), - "requestLinkKey": (0x14, (t.EmberEUI64,), (t.EmberStatus,)), - "zigbeeKeyEstablishmentHandler": (0x9B, (), (t.EmberEUI64, t.EmberKeyStatus)), - "addTransientLinkKey": (0xAF, (t.EmberEUI64, t.EmberKeyData), (t.EmberStatus,)), + "requestLinkKey": (0x14, (t.EUI64,), (t.EmberStatus,)), + "zigbeeKeyEstablishmentHandler": (0x9B, (), (t.EUI64, t.EmberKeyStatus)), + "addTransientLinkKey": (0xAF, (t.EUI64, t.KeyData), (t.EmberStatus,)), "clearTransientLinkKeys": (0x6B, (), ()), # 10. Trust Center Frames "trustCenterJoinHandler": ( @@ -299,15 +299,15 @@ (), ( t.EmberNodeId, - t.EmberEUI64, + t.EUI64, t.EmberDeviceUpdate, t.EmberJoinDecision, t.EmberNodeId, ), ), - "broadcastNextNetworkKey": (0x73, (t.EmberKeyData,), (t.EmberStatus,)), + "broadcastNextNetworkKey": (0x73, (t.KeyData,), (t.EmberStatus,)), "broadcastNetworkKeySwitch": (0x74, (), (t.EmberStatus,)), - "becomeTrustCenter": (0x77, (t.EmberKeyData,), (t.EmberStatus,)), + "becomeTrustCenter": (0x77, (t.KeyData,), (t.EmberStatus,)), "aesMmoHash": ( 0x6F, (t.EmberAesMmoHashContext, t.Bool, t.LVBytes), @@ -315,12 +315,12 @@ ), "removeDevice": ( 0xA8, - (t.EmberNodeId, t.EmberEUI64, t.EmberEUI64), + (t.EmberNodeId, t.EUI64, t.EUI64), (t.EmberStatus,), ), "unicastNwkKeyUpdate": ( 0xA9, - (t.EmberNodeId, t.EmberEUI64, t.EmberKeyData), + (t.EmberNodeId, t.EUI64, t.KeyData), (t.EmberStatus,), ), # 11. Certificate Based Key Exchange (CBKE) Frames @@ -398,7 +398,7 @@ "mfglibRxHandler": (0x8E, (), (t.uint8_t, t.int8s, t.LVBytes)), # 13. Bootloader Frames "launchStandaloneBootloader": (0x8F, (t.uint8_t,), (t.EmberStatus,)), - "sendBootloadMessage": (0x90, (t.Bool, t.EmberEUI64, t.LVBytes), (t.EmberStatus,)), + "sendBootloadMessage": (0x90, (t.Bool, t.EUI64, t.LVBytes), (t.EmberStatus,)), "getStandaloneBootloaderVersionPlatMicroPhy": ( 0x91, (), @@ -407,7 +407,7 @@ "incomingBootloadMessageHandler": ( 0x92, (), - (t.EmberEUI64, t.uint8_t, t.int8s, t.LVBytes), + (t.EUI64, t.uint8_t, t.int8s, t.LVBytes), ), "bootloadTransmitCompleteHandler": (0x93, (), (t.EmberStatus, t.LVBytes)), "aesEncrypt": ( @@ -424,7 +424,7 @@ ), "zllSetInitialSecurityState": ( 0xB3, - (t.EmberKeyData, t.EmberZllInitialSecurityState), + (t.KeyData, t.EmberZllInitialSecurityState), (t.EmberStatus,), ), "zllStartScan": (0xB4, (t.Channels, t.int8s, t.EmberNodeType), (t.EmberStatus,)), @@ -463,7 +463,7 @@ (t.EmberStatus, t.EmberRf4cePairingTableEntry), ), "rf4ceDeletePairingTableEntry": (0xD2, (t.uint8_t,), (t.EmberStatus,)), - "rf4ceKeyUpdate": (0xD3, (t.uint8_t, t.EmberKeyData), (t.EmberStatus,)), + "rf4ceKeyUpdate": (0xD3, (t.uint8_t, t.KeyData), (t.EmberStatus,)), "rf4ceSend": ( 0xD4, (t.uint8_t, t.uint8_t, t.uint16_t, t.EmberRf4ceTxOption, t.uint8_t, t.LVBytes), @@ -510,7 +510,7 @@ 0xDB, (), ( - t.EmberEUI64, + t.EUI64, t.uint8_t, t.EmberRf4ceVendorInfo, t.EmberRf4ceApplicationInfo, @@ -525,7 +525,7 @@ t.Bool, t.uint8_t, t.EmberPanId, - t.EmberEUI64, + t.EUI64, t.uint8_t, t.EmberRf4ceVendorInfo, t.EmberRf4ceApplicationInfo, @@ -539,7 +539,7 @@ (), ( t.EmberStatus, - t.EmberEUI64, + t.EUI64, t.uint8_t, t.EmberRf4ceVendorInfo, t.EmberRf4ceApplicationInfo, @@ -548,7 +548,7 @@ ), "rf4cePair": ( 0xDF, - (t.uint8_t, t.EmberPanId, t.EmberEUI64, t.uint8_t), + (t.uint8_t, t.EmberPanId, t.EUI64, t.uint8_t), (t.EmberStatus,), ), "rf4cePairCompleteHandler": ( @@ -562,7 +562,7 @@ ( t.EmberStatus, t.uint8_t, - t.EmberEUI64, + t.EUI64, t.uint8_t, t.EmberRf4ceVendorInfo, t.EmberRf4ceApplicationInfo, @@ -596,8 +596,8 @@ t.uint16_t, t.uint16_t, t.uint16_t, - t.EmberEUI64, - t.EmberKeyData, + t.EUI64, + t.KeyData, ), (), ), diff --git a/bellows/ezsp/v4/types/named.py b/bellows/ezsp/v4/types/named.py index 8c789378..dc05d1ef 100644 --- a/bellows/ezsp/v4/types/named.py +++ b/bellows/ezsp/v4/types/named.py @@ -2,6 +2,7 @@ import bellows.types.basic as basic from bellows.types.named import ( # noqa: F401, F403 + EUI64, Bool, Channels, EmberApsOption, @@ -11,7 +12,6 @@ EmberConcentratorType, EmberConfigTxPowerMode, EmberCurrentSecurityBitmask, - EmberEUI64, EmberEventUnits, EmberGpKeyType, EmberGpSecurityLevel, @@ -19,7 +19,6 @@ EmberInitialSecurityBitmask, EmberJoinDecision, EmberJoinMethod, - EmberKeyData, EmberKeyStatus, EmberKeyStructBitmask, EmberLibraryStatus, @@ -50,6 +49,7 @@ EzspSourceRouteOverheadInformation, EzspStatus, EzspZllNetworkOperation, + KeyData, ) diff --git a/bellows/ezsp/v4/types/struct.py b/bellows/ezsp/v4/types/struct.py index 9b96ef14..e9b04ccf 100644 --- a/bellows/ezsp/v4/types/struct.py +++ b/bellows/ezsp/v4/types/struct.py @@ -35,7 +35,7 @@ class EmberKeyStruct(EzspStruct): # The type of the key. type: named.EmberKeyType # The actual key data. - key: named.EmberKeyData + key: named.KeyData # The outgoing frame counter associated with the key. outgoingFrameCounter: basic.uint32_t # The frame counter of the partner device associated with the key. @@ -43,7 +43,7 @@ class EmberKeyStruct(EzspStruct): # The sequence number associated with the key. sequenceNumber: basic.uint8_t # The IEEE address of the partner device also in possession of the key. - partnerEUI64: named.EmberEUI64 + partnerEUI64: named.EUI64 class EmberRf4ceVendorInfo(EzspStruct): @@ -74,9 +74,9 @@ class EmberRf4ceApplicationInfo(EzspStruct): class EmberRf4cePairingTableEntry(EzspStruct): # The internal representation of an RF4CE pairing table entry. # The link key to be used to secure this pairing link. - securityLinkKey: named.EmberKeyData + securityLinkKey: named.KeyData # The IEEE address of the destination device. - destLongId: named.EmberEUI64 + destLongId: named.EUI64 # The frame counter last received from the recipient node. frameCounter: basic.uint32_t # The network address to be assumed by the source device. @@ -106,6 +106,6 @@ class EmberGpSinkListEntry(EzspStruct): # The sink list type. type: basic.uint8_t # The EUI64 of the target sink. - sinkEUI: named.EmberEUI64 + sinkEUI: named.EUI64 # The short address of the target sink. sinkNodeId: named.EmberNodeId diff --git a/bellows/ezsp/v5/__init__.py b/bellows/ezsp/v5/__init__.py index e6856cd9..01d286a6 100644 --- a/bellows/ezsp/v5/__init__.py +++ b/bellows/ezsp/v5/__init__.py @@ -1,10 +1,12 @@ """"EZSP Protocol version 5 protocol handler.""" +from __future__ import annotations + import logging -from typing import Tuple import voluptuous import bellows.config +import bellows.types as t from . import commands, config, types as v5_types from ..v4 import EZSPv4 @@ -29,12 +31,18 @@ def _ezsp_frame_tx(self, name: str) -> bytes: frame = [self._seq, 0x00, 0xFF, 0x00, cmd_id] return bytes(frame) - def _ezsp_frame_rx(self, data: bytes) -> Tuple[int, int, bytes]: + def _ezsp_frame_rx(self, data: bytes) -> tuple[int, int, bytes]: """Handler for received data frame.""" return data[0], data[4], data[5:] + async def add_transient_link_key( + self, ieee: t.EUI64, key: t.KeyData + ) -> t.EmberStatus: + (status,) = await self.addTransientLinkKey(ieee, key) + return status + async def pre_permit(self, time_s: int) -> None: """Add pre-shared TC Link key.""" - wild_card_ieee = v5_types.EmberEUI64([0xFF] * 8) - tc_link_key = v5_types.EmberKeyData(b"ZigBeeAlliance09") - await self.addTransientLinkKey(wild_card_ieee, tc_link_key) + wild_card_ieee = v5_types.EUI64([0xFF] * 8) + tc_link_key = v5_types.KeyData(b"ZigBeeAlliance09") + await self.add_transient_link_key(wild_card_ieee, tc_link_key) diff --git a/bellows/ezsp/v5/commands.py b/bellows/ezsp/v5/commands.py index e349233b..211cf5ac 100644 --- a/bellows/ezsp/v5/commands.py +++ b/bellows/ezsp/v5/commands.py @@ -78,7 +78,7 @@ "getXncpInfo": (0x13, (), (t.EmberStatus, t.uint16_t, t.uint16_t)), "customFrame": (0x47, (t.LVBytes,), (t.EmberStatus, t.LVBytes)), "customFrameHandler": (0x54, (), (t.LVBytes,)), - "getEui64": (0x26, (), (t.EmberEUI64,)), + "getEui64": (0x26, (), (t.EUI64,)), "getNodeId": (0x27, (), (t.EmberNodeId,)), "networkInit": (0x17, (), (t.EmberStatus,)), # 6. Networking Frames @@ -108,7 +108,7 @@ "childJoinHandler": ( 0x23, (), - (t.uint8_t, t.Bool, t.EmberNodeId, t.EmberEUI64, t.EmberNodeType), + (t.uint8_t, t.Bool, t.EmberNodeId, t.EUI64, t.EmberNodeType), ), "energyScanRequest": ( 0x9C, @@ -120,11 +120,11 @@ (), (t.EmberStatus, t.EmberNodeType, t.EmberNetworkParameters), ), - "getParentChildParameters": (0x29, (), (t.uint8_t, t.EmberEUI64, t.EmberNodeId)), + "getParentChildParameters": (0x29, (), (t.uint8_t, t.EUI64, t.EmberNodeId)), "getChildData": ( 0x4A, (t.uint8_t,), - (t.EmberStatus, t.EmberNodeId, t.EmberEUI64, t.EmberNodeType), + (t.EmberStatus, t.EmberNodeId, t.EUI64, t.EmberNodeType), ), "getNeighbor": (0x79, (t.uint8_t,), (t.EmberStatus, t.EmberNeighborTableEntry)), "neighborCount": (0x7A, (), (t.uint8_t,)), @@ -203,7 +203,7 @@ "pollForData": (0x42, (t.uint16_t, t.EmberEventUnits, t.uint8_t), (t.EmberStatus,)), "pollCompleteHandler": (0x43, (), (t.EmberStatus,)), "pollHandler": (0x44, (), (t.EmberNodeId,)), - "incomingSenderEui64Handler": (0x62, (), (t.EmberEUI64,)), + "incomingSenderEui64Handler": (0x62, (), (t.EUI64,)), "incomingMessageHandler": ( 0x45, (), @@ -221,7 +221,7 @@ "incomingRouteRecordHandler": ( 0x59, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), + (t.EmberNodeId, t.EUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), ), "changeSourceRouteHandler": (0xC4, (), (t.EmberNodeId, t.EmberNodeId, t.Bool)), "setSourceRoute": ( @@ -232,23 +232,23 @@ "incomingManyToOneRouteRequestHandler": ( 0x7D, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t), + (t.EmberNodeId, t.EUI64, t.uint8_t), ), "incomingRouteErrorHandler": (0x80, (), (t.EmberStatus, t.EmberNodeId)), "addressTableEntryIsActive": (0x5B, (t.uint8_t,), (t.Bool,)), - "setAddressTableRemoteEui64": (0x5C, (t.uint8_t, t.EmberEUI64), (t.EmberStatus,)), + "setAddressTableRemoteEui64": (0x5C, (t.uint8_t, t.EUI64), (t.EmberStatus,)), "setAddressTableRemoteNodeId": (0x5D, (t.uint8_t, t.EmberNodeId), ()), - "getAddressTableRemoteEui64": (0x5E, (t.uint8_t,), (t.EmberEUI64,)), + "getAddressTableRemoteEui64": (0x5E, (t.uint8_t,), (t.EUI64,)), "getAddressTableRemoteNodeId": (0x5F, (t.uint8_t,), (t.EmberNodeId,)), - "setExtendedTimeout": (0x7E, (t.EmberEUI64, t.Bool), ()), - "getExtendedTimeout": (0x7F, (t.EmberEUI64,), (t.Bool,)), + "setExtendedTimeout": (0x7E, (t.EUI64, t.Bool), ()), + "getExtendedTimeout": (0x7F, (t.EUI64,), (t.Bool,)), "replaceAddressTableEntry": ( 0x82, - (t.uint8_t, t.EmberEUI64, t.EmberNodeId, t.Bool), - (t.EmberStatus, t.EmberEUI64, t.EmberNodeId, t.Bool), + (t.uint8_t, t.EUI64, t.EmberNodeId, t.Bool), + (t.EmberStatus, t.EUI64, t.EmberNodeId, t.Bool), ), - "lookupNodeIdByEui64": (0x60, (t.EmberEUI64,), (t.EmberNodeId,)), - "lookupEui64ByNodeId": (0x61, (t.EmberNodeId,), (t.EmberStatus, t.EmberEUI64)), + "lookupNodeIdByEui64": (0x60, (t.EUI64,), (t.EmberNodeId,)), + "lookupEui64ByNodeId": (0x61, (t.EmberNodeId,), (t.EmberStatus, t.EUI64)), "getMulticastTableEntry": ( 0x63, (t.uint8_t,), @@ -280,24 +280,24 @@ "getKeyTableEntry": (0x71, (t.uint8_t,), (t.EmberStatus, t.EmberKeyStruct)), "setKeyTableEntry": ( 0x72, - (t.uint8_t, t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.uint8_t, t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "findKeyTableEntry": (0x75, (t.EmberEUI64, t.Bool), (t.uint8_t,)), + "findKeyTableEntry": (0x75, (t.EUI64, t.Bool), (t.uint8_t,)), "addOrUpdateKeyTableEntry": ( 0x66, - (t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), "eraseKeyTableEntry": (0x76, (t.uint8_t,), (t.EmberStatus,)), "clearKeyTable": (0xB1, (), (t.EmberStatus,)), - "requestLinkKey": (0x14, (t.EmberEUI64,), (t.EmberStatus,)), - "zigbeeKeyEstablishmentHandler": (0x9B, (), (t.EmberEUI64, t.EmberKeyStatus)), - "addTransientLinkKey": (0xAF, (t.EmberEUI64, t.EmberKeyData), (t.EmberStatus,)), + "requestLinkKey": (0x14, (t.EUI64,), (t.EmberStatus,)), + "zigbeeKeyEstablishmentHandler": (0x9B, (), (t.EUI64, t.EmberKeyStatus)), + "addTransientLinkKey": (0xAF, (t.EUI64, t.KeyData), (t.EmberStatus,)), "clearTransientLinkKeys": (0x6B, (), ()), "getTransientLinkKey": ( 0xCE, - (t.EmberEUI64,), + (t.EUI64,), (t.EmberStatus, t.EmberTransientKeyData), ), # 10. Trust Center Frames @@ -306,15 +306,15 @@ (), ( t.EmberNodeId, - t.EmberEUI64, + t.EUI64, t.EmberDeviceUpdate, t.EmberJoinDecision, t.EmberNodeId, ), ), - "broadcastNextNetworkKey": (0x73, (t.EmberKeyData,), (t.EmberStatus,)), + "broadcastNextNetworkKey": (0x73, (t.KeyData,), (t.EmberStatus,)), "broadcastNetworkKeySwitch": (0x74, (), (t.EmberStatus,)), - "becomeTrustCenter": (0x77, (t.EmberKeyData,), (t.EmberStatus,)), + "becomeTrustCenter": (0x77, (t.KeyData,), (t.EmberStatus,)), "aesMmoHash": ( 0x6F, (t.EmberAesMmoHashContext, t.Bool, t.LVBytes), @@ -322,12 +322,12 @@ ), "removeDevice": ( 0xA8, - (t.EmberNodeId, t.EmberEUI64, t.EmberEUI64), + (t.EmberNodeId, t.EUI64, t.EUI64), (t.EmberStatus,), ), "unicastNwkKeyUpdate": ( 0xA9, - (t.EmberNodeId, t.EmberEUI64, t.EmberKeyData), + (t.EmberNodeId, t.EUI64, t.KeyData), (t.EmberStatus,), ), # 11. Certificate Based Key Exchange (CBKE) Frames @@ -405,7 +405,7 @@ "mfglibRxHandler": (0x8E, (), (t.uint8_t, t.int8s, t.LVBytes)), # 13. Bootloader Frames "launchStandaloneBootloader": (0x8F, (t.uint8_t,), (t.EmberStatus,)), - "sendBootloadMessage": (0x90, (t.Bool, t.EmberEUI64, t.LVBytes), (t.EmberStatus,)), + "sendBootloadMessage": (0x90, (t.Bool, t.EUI64, t.LVBytes), (t.EmberStatus,)), "getStandaloneBootloaderVersionPlatMicroPhy": ( 0x91, (), @@ -414,7 +414,7 @@ "incomingBootloadMessageHandler": ( 0x92, (), - (t.EmberEUI64, t.uint8_t, t.int8s, t.LVBytes), + (t.EUI64, t.uint8_t, t.int8s, t.LVBytes), ), "bootloadTransmitCompleteHandler": (0x93, (), (t.EmberStatus, t.LVBytes)), "aesEncrypt": ( @@ -431,7 +431,7 @@ ), "zllSetInitialSecurityState": ( 0xB3, - (t.EmberKeyData, t.EmberZllInitialSecurityState), + (t.KeyData, t.EmberZllInitialSecurityState), (t.EmberStatus,), ), "zllStartScan": (0xB4, (t.Channels, t.int8s, t.EmberNodeType), (t.EmberStatus,)), @@ -470,7 +470,7 @@ (t.EmberStatus, t.EmberRf4cePairingTableEntry), ), "rf4ceDeletePairingTableEntry": (0xD2, (t.uint8_t,), (t.EmberStatus,)), - "rf4ceKeyUpdate": (0xD3, (t.uint8_t, t.EmberKeyData), (t.EmberStatus,)), + "rf4ceKeyUpdate": (0xD3, (t.uint8_t, t.KeyData), (t.EmberStatus,)), "rf4ceSend": ( 0xD4, (t.uint8_t, t.uint8_t, t.uint16_t, t.EmberRf4ceTxOption, t.uint8_t, t.LVBytes), @@ -517,7 +517,7 @@ 0xDB, (), ( - t.EmberEUI64, + t.EUI64, t.uint8_t, t.EmberRf4ceVendorInfo, t.EmberRf4ceApplicationInfo, @@ -532,7 +532,7 @@ t.Bool, t.uint8_t, t.EmberPanId, - t.EmberEUI64, + t.EUI64, t.uint8_t, t.EmberRf4ceVendorInfo, t.EmberRf4ceApplicationInfo, @@ -546,7 +546,7 @@ (), ( t.EmberStatus, - t.EmberEUI64, + t.EUI64, t.uint8_t, t.EmberRf4ceVendorInfo, t.EmberRf4ceApplicationInfo, @@ -555,7 +555,7 @@ ), "rf4cePair": ( 0xDF, - (t.uint8_t, t.EmberPanId, t.EmberEUI64, t.uint8_t), + (t.uint8_t, t.EmberPanId, t.EUI64, t.uint8_t), (t.EmberStatus,), ), "rf4cePairCompleteHandler": ( @@ -569,7 +569,7 @@ ( t.EmberStatus, t.uint8_t, - t.EmberEUI64, + t.EUI64, t.uint8_t, t.EmberRf4ceVendorInfo, t.EmberRf4ceApplicationInfo, @@ -603,8 +603,8 @@ t.uint16_t, t.uint16_t, t.uint16_t, - t.EmberEUI64, - t.EmberKeyData, + t.EUI64, + t.KeyData, ), (), ), @@ -638,7 +638,7 @@ ), "setSecurityKey": ( 0xCA, - (t.EmberKeyData, t.SecureEzspSecurityType), + (t.KeyData, t.SecureEzspSecurityType), (t.EzspStatus,), ), "setSecurityParameters": ( diff --git a/bellows/ezsp/v5/types/named.py b/bellows/ezsp/v5/types/named.py index fb366df5..aa63a9a1 100644 --- a/bellows/ezsp/v5/types/named.py +++ b/bellows/ezsp/v5/types/named.py @@ -2,6 +2,7 @@ import bellows.types.basic as basic from bellows.types.named import ( # noqa: F401, F403 + EUI64, Bool, Channels, EmberApsOption, @@ -11,7 +12,6 @@ EmberConcentratorType, EmberConfigTxPowerMode, EmberCurrentSecurityBitmask, - EmberEUI64, EmberEventUnits, EmberGpKeyType, EmberGpSecurityLevel, @@ -19,7 +19,6 @@ EmberInitialSecurityBitmask, EmberJoinDecision, EmberJoinMethod, - EmberKeyData, EmberKeyStatus, EmberKeyStructBitmask, EmberLibraryStatus, @@ -50,6 +49,7 @@ EzspSourceRouteOverheadInformation, EzspStatus, EzspZllNetworkOperation, + KeyData, ) diff --git a/bellows/ezsp/v5/types/struct.py b/bellows/ezsp/v5/types/struct.py index dfca4d1f..8e2147e2 100644 --- a/bellows/ezsp/v5/types/struct.py +++ b/bellows/ezsp/v5/types/struct.py @@ -35,7 +35,7 @@ class EmberKeyStruct(EzspStruct): # The type of the key. type: named.EmberKeyType # The actual key data. - key: named.EmberKeyData + key: named.KeyData # The outgoing frame counter associated with the key. outgoingFrameCounter: basic.uint32_t # The frame counter of the partner device associated with the key. @@ -43,7 +43,7 @@ class EmberKeyStruct(EzspStruct): # The sequence number associated with the key. sequenceNumber: basic.uint8_t # The IEEE address of the partner device also in possession of the key. - partnerEUI64: named.EmberEUI64 + partnerEUI64: named.EUI64 class EmberRf4ceVendorInfo(EzspStruct): @@ -74,9 +74,9 @@ class EmberRf4ceApplicationInfo(EzspStruct): class EmberRf4cePairingTableEntry(EzspStruct): # The internal representation of an RF4CE pairing table entry. # The link key to be used to secure this pairing link. - securityLinkKey: named.EmberKeyData + securityLinkKey: named.KeyData # The IEEE address of the destination device. - destLongId: named.EmberEUI64 + destLongId: named.EUI64 # The frame counter last received from the recipient node. frameCounter: basic.uint32_t # The network address to be assumed by the source device. @@ -106,6 +106,6 @@ class EmberGpSinkListEntry(EzspStruct): # The sink list type. type: basic.uint8_t # The EUI64 of the target sink. - sinkEUI: named.EmberEUI64 + sinkEUI: named.EUI64 # The short address of the target sink. sinkNodeId: named.EmberNodeId diff --git a/bellows/ezsp/v6/commands.py b/bellows/ezsp/v6/commands.py index bf2c6701..72c15135 100644 --- a/bellows/ezsp/v6/commands.py +++ b/bellows/ezsp/v6/commands.py @@ -77,7 +77,7 @@ "getXncpInfo": (0x13, (), (t.EmberStatus, t.uint16_t, t.uint16_t)), "customFrame": (0x47, (t.LVBytes,), (t.EmberStatus, t.LVBytes)), "customFrameHandler": (0x54, (), (t.LVBytes,)), - "getEui64": (0x26, (), (t.EmberEUI64,)), + "getEui64": (0x26, (), (t.EUI64,)), "getNodeId": (0x27, (), (t.EmberNodeId,)), "getPhyInterfaceCount": (0xFC, (), (t.uint8_t,)), "networkInit": (0x17, (t.EmberNetworkInitStruct,), (t.EmberStatus,)), @@ -109,7 +109,7 @@ "childJoinHandler": ( 0x23, (), - (t.uint8_t, t.Bool, t.EmberNodeId, t.EmberEUI64, t.EmberNodeType), + (t.uint8_t, t.Bool, t.EmberNodeId, t.EUI64, t.EmberNodeType), ), "energyScanRequest": ( 0x9C, @@ -126,11 +126,11 @@ (t.uint8_t,), (t.EmberStatus, t.EmberNodeType, t.EmberNetworkParameters), ), - "getParentChildParameters": (0x29, (), (t.uint8_t, t.EmberEUI64, t.EmberNodeId)), + "getParentChildParameters": (0x29, (), (t.uint8_t, t.EUI64, t.EmberNodeId)), "getChildData": ( 0x4A, (t.uint8_t,), - (t.EmberStatus, t.EmberNodeId, t.EmberEUI64, t.EmberNodeType), + (t.EmberStatus, t.EmberNodeId, t.EUI64, t.EmberNodeType), ), "getSourceRouteTableTotalSize": (0xC3, (), (t.uint8_t,)), "getSourceRouteTableFilledSize": (0xC2, (), (t.uint8_t,)), @@ -268,7 +268,7 @@ "pollForData": (0x42, (t.uint16_t, t.EmberEventUnits, t.uint8_t), (t.EmberStatus,)), "pollCompleteHandler": (0x43, (), (t.EmberStatus,)), "pollHandler": (0x44, (), (t.EmberNodeId,)), - "incomingSenderEui64Handler": (0x62, (), (t.EmberEUI64,)), + "incomingSenderEui64Handler": (0x62, (), (t.EUI64,)), "incomingMessageHandler": ( 0x45, (), @@ -286,7 +286,7 @@ "incomingRouteRecordHandler": ( 0x59, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), + (t.EmberNodeId, t.EUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), ), "changeSourceRouteHandler": (0xC4, (), (t.EmberNodeId, t.EmberNodeId, t.Bool)), "setSourceRoute": ( @@ -297,23 +297,23 @@ "incomingManyToOneRouteRequestHandler": ( 0x7D, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t), + (t.EmberNodeId, t.EUI64, t.uint8_t), ), "incomingRouteErrorHandler": (0x80, (), (t.EmberStatus, t.EmberNodeId)), "addressTableEntryIsActive": (0x5B, (t.uint8_t,), (t.Bool,)), - "setAddressTableRemoteEui64": (0x5C, (t.uint8_t, t.EmberEUI64), (t.EmberStatus,)), + "setAddressTableRemoteEui64": (0x5C, (t.uint8_t, t.EUI64), (t.EmberStatus,)), "setAddressTableRemoteNodeId": (0x5D, (t.uint8_t, t.EmberNodeId), ()), - "getAddressTableRemoteEui64": (0x5E, (t.uint8_t,), (t.EmberEUI64,)), + "getAddressTableRemoteEui64": (0x5E, (t.uint8_t,), (t.EUI64,)), "getAddressTableRemoteNodeId": (0x5F, (t.uint8_t,), (t.EmberNodeId,)), - "setExtendedTimeout": (0x7E, (t.EmberEUI64, t.Bool), ()), - "getExtendedTimeout": (0x7F, (t.EmberEUI64,), (t.Bool,)), + "setExtendedTimeout": (0x7E, (t.EUI64, t.Bool), ()), + "getExtendedTimeout": (0x7F, (t.EUI64,), (t.Bool,)), "replaceAddressTableEntry": ( 0x82, - (t.uint8_t, t.EmberEUI64, t.EmberNodeId, t.Bool), - (t.EmberStatus, t.EmberEUI64, t.EmberNodeId, t.Bool), + (t.uint8_t, t.EUI64, t.EmberNodeId, t.Bool), + (t.EmberStatus, t.EUI64, t.EmberNodeId, t.Bool), ), - "lookupNodeIdByEui64": (0x60, (t.EmberEUI64,), (t.EmberNodeId,)), - "lookupEui64ByNodeId": (0x61, (t.EmberNodeId,), (t.EmberStatus, t.EmberEUI64)), + "lookupNodeIdByEui64": (0x60, (t.EUI64,), (t.EmberNodeId,)), + "lookupEui64ByNodeId": (0x61, (t.EmberNodeId,), (t.EmberStatus, t.EUI64)), "getMulticastTableEntry": ( 0x63, (t.uint8_t,), @@ -346,25 +346,25 @@ "getKeyTableEntry": (0x71, (t.uint8_t,), (t.EmberStatus, t.EmberKeyStruct)), "setKeyTableEntry": ( 0x72, - (t.uint8_t, t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.uint8_t, t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "findKeyTableEntry": (0x75, (t.EmberEUI64, t.Bool), (t.uint8_t,)), + "findKeyTableEntry": (0x75, (t.EUI64, t.Bool), (t.uint8_t,)), "addOrUpdateKeyTableEntry": ( 0x66, - (t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "sendTrustCenterLinkKey": (0x67, (t.EmberNodeId, t.EmberEUI64), (t.EmberStatus,)), + "sendTrustCenterLinkKey": (0x67, (t.EmberNodeId, t.EUI64), (t.EmberStatus,)), "eraseKeyTableEntry": (0x76, (t.uint8_t,), (t.EmberStatus,)), "clearKeyTable": (0xB1, (), (t.EmberStatus,)), - "requestLinkKey": (0x14, (t.EmberEUI64,), (t.EmberStatus,)), - "zigbeeKeyEstablishmentHandler": (0x9B, (), (t.EmberEUI64, t.EmberKeyStatus)), - "addTransientLinkKey": (0xAF, (t.EmberEUI64, t.EmberKeyData), (t.EmberStatus,)), + "requestLinkKey": (0x14, (t.EUI64,), (t.EmberStatus,)), + "zigbeeKeyEstablishmentHandler": (0x9B, (), (t.EUI64, t.EmberKeyStatus)), + "addTransientLinkKey": (0xAF, (t.EUI64, t.KeyData), (t.EmberStatus,)), "clearTransientLinkKeys": (0x6B, (), ()), "getTransientLinkKey": ( 0xCE, - (t.EmberEUI64,), + (t.EUI64,), (t.EmberStatus, t.EmberTransientKeyData), ), # 10. Trust Center Frames @@ -373,15 +373,15 @@ (), ( t.EmberNodeId, - t.EmberEUI64, + t.EUI64, t.EmberDeviceUpdate, t.EmberJoinDecision, t.EmberNodeId, ), ), - "broadcastNextNetworkKey": (0x73, (t.EmberKeyData,), (t.EmberStatus,)), + "broadcastNextNetworkKey": (0x73, (t.KeyData,), (t.EmberStatus,)), "broadcastNetworkKeySwitch": (0x74, (), (t.EmberStatus,)), - "becomeTrustCenter": (0x77, (t.EmberKeyData,), (t.EmberStatus,)), + "becomeTrustCenter": (0x77, (t.KeyData,), (t.EmberStatus,)), "aesMmoHash": ( 0x6F, (t.EmberAesMmoHashContext, t.Bool, t.LVBytes), @@ -389,12 +389,12 @@ ), "removeDevice": ( 0xA8, - (t.EmberNodeId, t.EmberEUI64, t.EmberEUI64), + (t.EmberNodeId, t.EUI64, t.EUI64), (t.EmberStatus,), ), "unicastNwkKeyUpdate": ( 0xA9, - (t.EmberNodeId, t.EmberEUI64, t.EmberKeyData), + (t.EmberNodeId, t.EUI64, t.KeyData), (t.EmberStatus,), ), # 11. Certificate Based Key Exchange (CBKE) Frames @@ -472,7 +472,7 @@ "mfglibRxHandler": (0x8E, (), (t.uint8_t, t.int8s, t.LVBytes)), # 13. Bootloader Frames "launchStandaloneBootloader": (0x8F, (t.uint8_t,), (t.EmberStatus,)), - "sendBootloadMessage": (0x90, (t.Bool, t.EmberEUI64, t.LVBytes), (t.EmberStatus,)), + "sendBootloadMessage": (0x90, (t.Bool, t.EUI64, t.LVBytes), (t.EmberStatus,)), "getStandaloneBootloaderVersionPlatMicroPhy": ( 0x91, (), @@ -481,7 +481,7 @@ "incomingBootloadMessageHandler": ( 0x92, (), - (t.EmberEUI64, t.uint8_t, t.int8s, t.LVBytes), + (t.EUI64, t.uint8_t, t.int8s, t.LVBytes), ), "bootloadTransmitCompleteHandler": (0x93, (), (t.EmberStatus, t.LVBytes)), "aesEncrypt": ( @@ -498,7 +498,7 @@ ), "zllSetInitialSecurityState": ( 0xB3, - (t.EmberKeyData, t.EmberZllInitialSecurityState), + (t.KeyData, t.EmberZllInitialSecurityState), (t.EmberStatus,), ), "zllSetSecurityStateWithoutKey": ( @@ -549,8 +549,8 @@ t.uint16_t, t.uint16_t, t.uint16_t, - t.EmberEUI64, - t.EmberKeyData, + t.EUI64, + t.KeyData, ), (), ), @@ -605,7 +605,7 @@ # 16 Secure EZSP Frames "setSecurityKey": ( 0xCA, - (t.EmberKeyData, t.SecureEzspSecurityType), + (t.KeyData, t.SecureEzspSecurityType), (t.EzspStatus,), ), "setSecurityParameters": ( diff --git a/bellows/ezsp/v6/types/named.py b/bellows/ezsp/v6/types/named.py index c6ffa969..ac7223c1 100644 --- a/bellows/ezsp/v6/types/named.py +++ b/bellows/ezsp/v6/types/named.py @@ -2,6 +2,7 @@ import bellows.types.basic as basic from bellows.types.named import ( # noqa: F401, F403 + EUI64, Bool, Channels, EmberApsOption, @@ -11,7 +12,6 @@ EmberConcentratorType, EmberConfigTxPowerMode, EmberCurrentSecurityBitmask, - EmberEUI64, EmberEventUnits, EmberGpKeyType, EmberGpSecurityLevel, @@ -19,7 +19,6 @@ EmberInitialSecurityBitmask, EmberJoinDecision, EmberJoinMethod, - EmberKeyData, EmberKeyStatus, EmberKeyStructBitmask, EmberLibraryStatus, @@ -50,6 +49,7 @@ EzspSourceRouteOverheadInformation, EzspStatus, EzspZllNetworkOperation, + KeyData, ) diff --git a/bellows/ezsp/v6/types/struct.py b/bellows/ezsp/v6/types/struct.py index 5ed6f73a..dcc2bf30 100644 --- a/bellows/ezsp/v6/types/struct.py +++ b/bellows/ezsp/v6/types/struct.py @@ -35,7 +35,7 @@ class EmberKeyStruct(EzspStruct): # The type of the key. type: named.EmberKeyType # The actual key data. - key: named.EmberKeyData + key: named.KeyData # The outgoing frame counter associated with the key. outgoingFrameCounter: basic.uint32_t # The frame counter of the partner device associated with the key. @@ -43,7 +43,7 @@ class EmberKeyStruct(EzspStruct): # The sequence number associated with the key. sequenceNumber: basic.uint8_t # The IEEE address of the partner device also in possession of the key. - partnerEUI64: named.EmberEUI64 + partnerEUI64: named.EUI64 class EmberGpSinkListEntry(EzspStruct): @@ -51,7 +51,7 @@ class EmberGpSinkListEntry(EzspStruct): # The sink list type. type: basic.uint8_t # The EUI64 of the target sink. - sinkEUI: named.EmberEUI64 + sinkEUI: named.EUI64 # The short address of the target sink. sinkNodeId: named.EmberNodeId @@ -60,7 +60,7 @@ class EmberGpProxyTableEntry(EzspStruct): """The internal representation of a proxy table entry.""" # The link key to be used to secure this pairing link. - securityLinkKey: named.EmberKeyData + securityLinkKey: named.KeyData # Internal status of the proxy table entry. status: named.EmberGpProxyTableEntryStatus # The tunneling options @@ -75,7 +75,7 @@ class EmberGpProxyTableEntry(EzspStruct): # The security frame counter of the GPD. gpdSecurityFrameCounter: named.EmberGpSecurityFrameCounter # The key to use for GPD. - gpdKey: named.EmberKeyData + gpdKey: named.KeyData # The list of sinks (hardcoded to 2 which is the spec minimum). sinkList: basic.fixed_list(2, EmberGpSinkListEntry) # The groupcast radius. @@ -107,7 +107,7 @@ class EmberGpSinkTableEntry(EzspStruct): # The security frame counter of the GPD. gpdSecurityFrameCounter: named.EmberGpSecurityFrameCounter # The key to use for GPD. - gpdKey: named.EmberKeyData + gpdKey: named.KeyData class EmberDutyCycleLimits(EzspStruct): diff --git a/bellows/ezsp/v7/commands.py b/bellows/ezsp/v7/commands.py index dc9c901a..98eaf15b 100644 --- a/bellows/ezsp/v7/commands.py +++ b/bellows/ezsp/v7/commands.py @@ -78,7 +78,7 @@ "getXncpInfo": (0x13, (), (t.EmberStatus, t.uint16_t, t.uint16_t)), "customFrame": (0x47, (t.LVBytes,), (t.EmberStatus, t.LVBytes)), "customFrameHandler": (0x54, (), (t.LVBytes,)), - "getEui64": (0x26, (), (t.EmberEUI64,)), + "getEui64": (0x26, (), (t.EUI64,)), "getNodeId": (0x27, (), (t.EmberNodeId,)), "getPhyInterfaceCount": (0xFC, (), (t.uint8_t,)), "getTrueRandomEntropySource": (0x4F, (), (t.EmberEntropySource,)), @@ -116,7 +116,7 @@ "childJoinHandler": ( 0x23, (), - (t.uint8_t, t.Bool, t.EmberNodeId, t.EmberEUI64, t.EmberNodeType), + (t.uint8_t, t.Bool, t.EmberNodeId, t.EUI64, t.EmberNodeType), ), "energyScanRequest": ( 0x9C, @@ -133,7 +133,7 @@ (t.uint8_t,), (t.EmberStatus, t.EmberNodeType, t.EmberNetworkParameters), ), - "getParentChildParameters": (0x29, (), (t.uint8_t, t.EmberEUI64, t.EmberNodeId)), + "getParentChildParameters": (0x29, (), (t.uint8_t, t.EUI64, t.EmberNodeId)), "getChildData": ( 0x4A, (t.uint8_t,), @@ -279,7 +279,7 @@ "pollForData": (0x42, (t.uint16_t, t.EmberEventUnits, t.uint8_t), (t.EmberStatus,)), "pollCompleteHandler": (0x43, (), (t.EmberStatus,)), "pollHandler": (0x44, (), (t.EmberNodeId,)), - "incomingSenderEui64Handler": (0x62, (), (t.EmberEUI64,)), + "incomingSenderEui64Handler": (0x62, (), (t.EUI64,)), "incomingMessageHandler": ( 0x45, (), @@ -297,7 +297,7 @@ "incomingRouteRecordHandler": ( 0x59, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), + (t.EmberNodeId, t.EUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), ), "changeSourceRouteHandler": (0xC4, (), (t.EmberNodeId, t.EmberNodeId, t.Bool)), "setSourceRoute": ( @@ -308,28 +308,28 @@ "incomingManyToOneRouteRequestHandler": ( 0x7D, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t), + (t.EmberNodeId, t.EUI64, t.uint8_t), ), "incomingRouteErrorHandler": (0x80, (), (t.EmberStatus, t.EmberNodeId)), "unicastCurrentNetworkKey": ( 0x50, - (t.EmberNodeId, t.EmberEUI64, t.EmberNodeId), + (t.EmberNodeId, t.EUI64, t.EmberNodeId), (t.EmberStatus,), ), "addressTableEntryIsActive": (0x5B, (t.uint8_t,), (t.Bool,)), - "setAddressTableRemoteEui64": (0x5C, (t.uint8_t, t.EmberEUI64), (t.EmberStatus,)), + "setAddressTableRemoteEui64": (0x5C, (t.uint8_t, t.EUI64), (t.EmberStatus,)), "setAddressTableRemoteNodeId": (0x5D, (t.uint8_t, t.EmberNodeId), ()), - "getAddressTableRemoteEui64": (0x5E, (t.uint8_t,), (t.EmberEUI64,)), + "getAddressTableRemoteEui64": (0x5E, (t.uint8_t,), (t.EUI64,)), "getAddressTableRemoteNodeId": (0x5F, (t.uint8_t,), (t.EmberNodeId,)), - "setExtendedTimeout": (0x7E, (t.EmberEUI64, t.Bool), ()), - "getExtendedTimeout": (0x7F, (t.EmberEUI64,), (t.Bool,)), + "setExtendedTimeout": (0x7E, (t.EUI64, t.Bool), ()), + "getExtendedTimeout": (0x7F, (t.EUI64,), (t.Bool,)), "replaceAddressTableEntry": ( 0x82, - (t.uint8_t, t.EmberEUI64, t.EmberNodeId, t.Bool), - (t.EmberStatus, t.EmberEUI64, t.EmberNodeId, t.Bool), + (t.uint8_t, t.EUI64, t.EmberNodeId, t.Bool), + (t.EmberStatus, t.EUI64, t.EmberNodeId, t.Bool), ), - "lookupNodeIdByEui64": (0x60, (t.EmberEUI64,), (t.EmberNodeId,)), - "lookupEui64ByNodeId": (0x61, (t.EmberNodeId,), (t.EmberStatus, t.EmberEUI64)), + "lookupNodeIdByEui64": (0x60, (t.EUI64,), (t.EmberNodeId,)), + "lookupEui64ByNodeId": (0x61, (t.EmberNodeId,), (t.EmberStatus, t.EUI64)), "getMulticastTableEntry": ( 0x63, (t.uint8_t,), @@ -373,26 +373,26 @@ "getKeyTableEntry": (0x71, (t.uint8_t,), (t.EmberStatus, t.EmberKeyStruct)), "setKeyTableEntry": ( 0x72, - (t.uint8_t, t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.uint8_t, t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "findKeyTableEntry": (0x75, (t.EmberEUI64, t.Bool), (t.uint8_t,)), + "findKeyTableEntry": (0x75, (t.EUI64, t.Bool), (t.uint8_t,)), "addOrUpdateKeyTableEntry": ( 0x66, - (t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "sendTrustCenterLinkKey": (0x67, (t.EmberNodeId, t.EmberEUI64), (t.EmberStatus,)), + "sendTrustCenterLinkKey": (0x67, (t.EmberNodeId, t.EUI64), (t.EmberStatus,)), "eraseKeyTableEntry": (0x76, (t.uint8_t,), (t.EmberStatus,)), "clearKeyTable": (0xB1, (), (t.EmberStatus,)), - "requestLinkKey": (0x14, (t.EmberEUI64,), (t.EmberStatus,)), + "requestLinkKey": (0x14, (t.EUI64,), (t.EmberStatus,)), "updateTcLinkKey": (0x6C, (t.uint8_t,), (t.EmberStatus,)), - "zigbeeKeyEstablishmentHandler": (0x9B, (), (t.EmberEUI64, t.EmberKeyStatus)), - "addTransientLinkKey": (0xAF, (t.EmberEUI64, t.EmberKeyData), (t.EmberStatus,)), + "zigbeeKeyEstablishmentHandler": (0x9B, (), (t.EUI64, t.EmberKeyStatus)), + "addTransientLinkKey": (0xAF, (t.EUI64, t.KeyData), (t.EmberStatus,)), "clearTransientLinkKeys": (0x6B, (), ()), "getTransientLinkKey": ( 0xCE, - (t.EmberEUI64,), + (t.EUI64,), (t.EmberStatus, t.EmberTransientKeyData), ), "getTransientKeyTableEntry": ( @@ -406,15 +406,15 @@ (), ( t.EmberNodeId, - t.EmberEUI64, + t.EUI64, t.EmberDeviceUpdate, t.EmberJoinDecision, t.EmberNodeId, ), ), - "broadcastNextNetworkKey": (0x73, (t.EmberKeyData,), (t.EmberStatus,)), + "broadcastNextNetworkKey": (0x73, (t.KeyData,), (t.EmberStatus,)), "broadcastNetworkKeySwitch": (0x74, (), (t.EmberStatus,)), - "becomeTrustCenter": (0x77, (t.EmberKeyData,), (t.EmberStatus,)), + "becomeTrustCenter": (0x77, (t.KeyData,), (t.EmberStatus,)), "aesMmoHash": ( 0x6F, (t.EmberAesMmoHashContext, t.Bool, t.LVBytes), @@ -422,12 +422,12 @@ ), "removeDevice": ( 0xA8, - (t.EmberNodeId, t.EmberEUI64, t.EmberEUI64), + (t.EmberNodeId, t.EUI64, t.EUI64), (t.EmberStatus,), ), "unicastNwkKeyUpdate": ( 0xA9, - (t.EmberNodeId, t.EmberEUI64, t.EmberKeyData), + (t.EmberNodeId, t.EUI64, t.KeyData), (t.EmberStatus,), ), # 11. Certificate Based Key Exchange (CBKE) Frames @@ -505,7 +505,7 @@ "mfglibRxHandler": (0x8E, (), (t.uint8_t, t.int8s, t.LVBytes)), # 13. Bootloader Frames "launchStandaloneBootloader": (0x8F, (t.uint8_t,), (t.EmberStatus,)), - "sendBootloadMessage": (0x90, (t.Bool, t.EmberEUI64, t.LVBytes), (t.EmberStatus,)), + "sendBootloadMessage": (0x90, (t.Bool, t.EUI64, t.LVBytes), (t.EmberStatus,)), "getStandaloneBootloaderVersionPlatMicroPhy": ( 0x91, (), @@ -514,7 +514,7 @@ "incomingBootloadMessageHandler": ( 0x92, (), - (t.EmberEUI64, t.uint8_t, t.int8s, t.LVBytes), + (t.EUI64, t.uint8_t, t.int8s, t.LVBytes), ), "bootloadTransmitCompleteHandler": (0x93, (), (t.EmberStatus, t.LVBytes)), "aesEncrypt": ( @@ -531,7 +531,7 @@ ), "zllSetInitialSecurityState": ( 0xB3, - (t.EmberKeyData, t.EmberZllInitialSecurityState), + (t.KeyData, t.EmberZllInitialSecurityState), (t.EmberStatus,), ), "zllSetSecurityStateWithoutKey": ( @@ -590,8 +590,8 @@ t.uint16_t, t.uint16_t, t.uint16_t, - t.EmberEUI64, - t.EmberKeyData, + t.EUI64, + t.KeyData, ), (), ), @@ -647,7 +647,7 @@ # 16 Secure EZSP Frames "setSecurityKey": ( 0xCA, - (t.EmberKeyData, t.SecureEzspSecurityType), + (t.KeyData, t.SecureEzspSecurityType), (t.EzspStatus,), ), "setSecurityParameters": ( diff --git a/bellows/ezsp/v7/types/named.py b/bellows/ezsp/v7/types/named.py index 00e24e97..0885316f 100644 --- a/bellows/ezsp/v7/types/named.py +++ b/bellows/ezsp/v7/types/named.py @@ -2,6 +2,7 @@ import bellows.types.basic as basic from bellows.types.named import ( # noqa: F401, F403 + EUI64, Bool, Channels, EmberApsOption, @@ -11,14 +12,12 @@ EmberConcentratorType, EmberConfigTxPowerMode, EmberCurrentSecurityBitmask, - EmberEUI64, EmberEventUnits, EmberGpKeyType, EmberGpSecurityLevel, EmberIncomingMessageType, EmberInitialSecurityBitmask, EmberJoinDecision, - EmberKeyData, EmberKeyStatus, EmberKeyStructBitmask, EmberLibraryStatus, @@ -49,6 +48,7 @@ EzspSourceRouteOverheadInformation, EzspStatus, EzspZllNetworkOperation, + KeyData, ) diff --git a/bellows/ezsp/v7/types/struct.py b/bellows/ezsp/v7/types/struct.py index be0259dc..a370dae3 100644 --- a/bellows/ezsp/v7/types/struct.py +++ b/bellows/ezsp/v7/types/struct.py @@ -89,7 +89,7 @@ class EmberKeyStruct(EzspStruct): # The type of the key. type: named.EmberKeyType # The actual key data. - key: named.EmberKeyData + key: named.KeyData # The outgoing frame counter associated with the key. outgoingFrameCounter: basic.uint32_t # The frame counter of the partner device associated with the key. @@ -97,7 +97,7 @@ class EmberKeyStruct(EzspStruct): # The sequence number associated with the key. sequenceNumber: basic.uint8_t # The IEEE address of the partner device also in possession of the key. - partnerEUI64: named.EmberEUI64 + partnerEUI64: named.EUI64 class EmberGpSinkListEntry(EzspStruct): @@ -105,7 +105,7 @@ class EmberGpSinkListEntry(EzspStruct): # The sink list type. type: basic.uint8_t # The EUI64 of the target sink. - sinkEUI: named.EmberEUI64 + sinkEUI: named.EUI64 # The short address of the target sink. sinkNodeId: named.EmberNodeId @@ -114,7 +114,7 @@ class EmberGpProxyTableEntry(EzspStruct): """The internal representation of a proxy table entry.""" # The link key to be used to secure this pairing link. - securityLinkKey: named.EmberKeyData + securityLinkKey: named.KeyData # Internal status of the proxy table entry. status: named.EmberGpProxyTableEntryStatus # The tunneling options @@ -129,7 +129,7 @@ class EmberGpProxyTableEntry(EzspStruct): # The security frame counter of the GPD. gpdSecurityFrameCounter: named.EmberGpSecurityFrameCounter # The key to use for GPD. - gpdKey: named.EmberKeyData + gpdKey: named.KeyData # The list of sinks (hardcoded to 2 which is the spec minimum). sinkList: basic.fixed_list(2, EmberGpSinkListEntry) # The groupcast radius. @@ -161,7 +161,7 @@ class EmberGpSinkTableEntry(EzspStruct): # The security frame counter of the GPD. gpdSecurityFrameCounter: named.EmberGpSecurityFrameCounter # The key to use for GPD. - gpdKey: named.EmberKeyData + gpdKey: named.KeyData class EmberDutyCycleLimits(EzspStruct): @@ -195,7 +195,7 @@ class EmberChildData(EzspStruct): """A structure containing a child node's data.""" # The EUI64 of the child - eui64: named.EmberEUI64 + eui64: named.EUI64 # The node type of the child type: named.EmberNodeType # The short address of the child @@ -208,6 +208,6 @@ class EmberChildData(EzspStruct): timeout: basic.uint8_t # The GPD's EUI64. - # gpdIeeeAddress: named.EmberEUI64 + # gpdIeeeAddress: named.EUI64 # The GPD's source ID. # sourceId: basic.uint32_t diff --git a/bellows/ezsp/v8/commands.py b/bellows/ezsp/v8/commands.py index 25d0c295..35a4940b 100644 --- a/bellows/ezsp/v8/commands.py +++ b/bellows/ezsp/v8/commands.py @@ -75,7 +75,7 @@ "getXncpInfo": (0x0013, (), (t.EmberStatus, t.uint16_t, t.uint16_t)), "customFrame": (0x0047, (t.LVBytes,), (t.EmberStatus, t.LVBytes)), "customFrameHandler": (0x0054, (), (t.LVBytes,)), - "getEui64": (0x0026, (), (t.EmberEUI64,)), + "getEui64": (0x0026, (), (t.EUI64,)), "getNodeId": (0x0027, (), (t.EmberNodeId,)), "getPhyInterfaceCount": (0x00FC, (), (t.uint8_t,)), "getTrueRandomEntropySource": (0x004F, (), (t.EmberEntropySource,)), @@ -113,7 +113,7 @@ "childJoinHandler": ( 0x0023, (), - (t.uint8_t, t.Bool, t.EmberNodeId, t.EmberEUI64, t.EmberNodeType), + (t.uint8_t, t.Bool, t.EmberNodeId, t.EUI64, t.EmberNodeType), ), "energyScanRequest": ( 0x009C, @@ -130,7 +130,7 @@ (t.uint8_t,), (t.EmberStatus, t.EmberNodeType, t.EmberNetworkParameters), ), - "getParentChildParameters": (0x0029, (), (t.uint8_t, t.EmberEUI64, t.EmberNodeId)), + "getParentChildParameters": (0x0029, (), (t.uint8_t, t.EUI64, t.EmberNodeId)), "getChildData": ( 0x004A, (t.uint8_t,), @@ -144,7 +144,7 @@ (t.EmberStatus, t.EmberNodeId, t.uint8_t), ), "getNeighbor": (0x0079, (t.uint8_t,), (t.EmberStatus, t.EmberNeighborTableEntry)), - "getNeighborFrameCounter": (0x003E, (t.EmberEUI64,), (t.EmberStatus, t.uint32_t)), + "getNeighborFrameCounter": (0x003E, (t.EUI64,), (t.EmberStatus, t.uint32_t)), "setRoutingShortcutThreshold": (0x00D0, (t.uint8_t,), (t.EmberStatus,)), "getRoutingShortcutThreshold": (0x00D1, (), (t.uint8_t,)), "neighborCount": (0x007A, (), (t.uint8_t,)), @@ -291,7 +291,7 @@ ), "pollCompleteHandler": (0x0043, (), (t.EmberStatus,)), "pollHandler": (0x0044, (), (t.EmberNodeId,)), - "incomingSenderEui64Handler": (0x0062, (), (t.EmberEUI64,)), + "incomingSenderEui64Handler": (0x0062, (), (t.EUI64,)), "incomingMessageHandler": ( 0x0045, (), @@ -309,35 +309,40 @@ "incomingRouteRecordHandler": ( 0x0059, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), + (t.EmberNodeId, t.EUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), ), "changeSourceRouteHandler": (0x00C4, (), (t.EmberNodeId, t.EmberNodeId, t.Bool)), + "setSourceRoute": ( + 0x00AE, + (t.EmberNodeId, t.LVList(t.EmberNodeId)), + (t.EmberStatus,), + ), "setSourceRouteDiscoveryMode": (0x005A, (t.uint8_t,), (t.uint32_t,)), "incomingManyToOneRouteRequestHandler": ( 0x007D, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t), + (t.EmberNodeId, t.EUI64, t.uint8_t), ), "incomingRouteErrorHandler": (0x0080, (), (t.EmberStatus, t.EmberNodeId)), "unicastCurrentNetworkKey": ( 0x0050, - (t.EmberNodeId, t.EmberEUI64, t.EmberNodeId), + (t.EmberNodeId, t.EUI64, t.EmberNodeId), (t.EmberStatus,), ), "addressTableEntryIsActive": (0x005B, (t.uint8_t,), (t.Bool,)), - "setAddressTableRemoteEui64": (0x005C, (t.uint8_t, t.EmberEUI64), (t.EmberStatus,)), + "setAddressTableRemoteEui64": (0x005C, (t.uint8_t, t.EUI64), (t.EmberStatus,)), "setAddressTableRemoteNodeId": (0x005D, (t.uint8_t, t.EmberNodeId), ()), - "getAddressTableRemoteEui64": (0x005E, (t.uint8_t,), (t.EmberEUI64,)), + "getAddressTableRemoteEui64": (0x005E, (t.uint8_t,), (t.EUI64,)), "getAddressTableRemoteNodeId": (0x005F, (t.uint8_t,), (t.EmberNodeId,)), - "setExtendedTimeout": (0x007E, (t.EmberEUI64, t.Bool), ()), - "getExtendedTimeout": (0x007F, (t.EmberEUI64,), (t.Bool,)), + "setExtendedTimeout": (0x007E, (t.EUI64, t.Bool), ()), + "getExtendedTimeout": (0x007F, (t.EUI64,), (t.Bool,)), "replaceAddressTableEntry": ( 0x0082, - (t.uint8_t, t.EmberEUI64, t.EmberNodeId, t.Bool), - (t.EmberStatus, t.EmberEUI64, t.EmberNodeId, t.Bool), + (t.uint8_t, t.EUI64, t.EmberNodeId, t.Bool), + (t.EmberStatus, t.EUI64, t.EmberNodeId, t.Bool), ), - "lookupNodeIdByEui64": (0x0060, (t.EmberEUI64,), (t.EmberNodeId,)), - "lookupEui64ByNodeId": (0x0061, (t.EmberNodeId,), (t.EmberStatus, t.EmberEUI64)), + "lookupNodeIdByEui64": (0x0060, (t.EUI64,), (t.EmberNodeId,)), + "lookupEui64ByNodeId": (0x0061, (t.EmberNodeId,), (t.EmberStatus, t.EUI64)), "getMulticastTableEntry": ( 0x0063, (t.uint8_t,), @@ -394,26 +399,26 @@ "getKeyTableEntry": (0x0071, (t.uint8_t,), (t.EmberStatus, t.EmberKeyStruct)), "setKeyTableEntry": ( 0x0072, - (t.uint8_t, t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.uint8_t, t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "findKeyTableEntry": (0x0075, (t.EmberEUI64, t.Bool), (t.uint8_t,)), + "findKeyTableEntry": (0x0075, (t.EUI64, t.Bool), (t.uint8_t,)), "addOrUpdateKeyTableEntry": ( 0x0066, - (t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "sendTrustCenterLinkKey": (0x0067, (t.EmberNodeId, t.EmberEUI64), (t.EmberStatus,)), + "sendTrustCenterLinkKey": (0x0067, (t.EmberNodeId, t.EUI64), (t.EmberStatus,)), "eraseKeyTableEntry": (0x0076, (t.uint8_t,), (t.EmberStatus,)), "clearKeyTable": (0x00B1, (), (t.EmberStatus,)), - "requestLinkKey": (0x0014, (t.EmberEUI64,), (t.EmberStatus,)), + "requestLinkKey": (0x0014, (t.EUI64,), (t.EmberStatus,)), "updateTcLinkKey": (0x006C, (t.uint8_t,), (t.EmberStatus,)), - "zigbeeKeyEstablishmentHandler": (0x009B, (), (t.EmberEUI64, t.EmberKeyStatus)), - "addTransientLinkKey": (0x00AF, (t.EmberEUI64, t.EmberKeyData), (t.EmberStatus,)), + "zigbeeKeyEstablishmentHandler": (0x009B, (), (t.EUI64, t.EmberKeyStatus)), + "addTransientLinkKey": (0x00AF, (t.EUI64, t.KeyData), (t.EmberStatus,)), "clearTransientLinkKeys": (0x006B, (), ()), "getTransientLinkKey": ( 0x00CE, - (t.EmberEUI64,), + (t.EUI64,), (t.EmberStatus, t.EmberTransientKeyData), ), "getTransientKeyTableEntry": ( @@ -427,15 +432,15 @@ (), ( t.EmberNodeId, - t.EmberEUI64, + t.EUI64, t.EmberDeviceUpdate, t.EmberJoinDecision, t.EmberNodeId, ), ), - "broadcastNextNetworkKey": (0x0073, (t.EmberKeyData,), (t.EmberStatus,)), + "broadcastNextNetworkKey": (0x0073, (t.KeyData,), (t.EmberStatus,)), "broadcastNetworkKeySwitch": (0x0074, (), (t.EmberStatus,)), - "becomeTrustCenter": (0x0077, (t.EmberKeyData,), (t.EmberStatus,)), + "becomeTrustCenter": (0x0077, (t.KeyData,), (t.EmberStatus,)), "aesMmoHash": ( 0x006F, (t.EmberAesMmoHashContext, t.Bool, t.LVBytes), @@ -443,12 +448,12 @@ ), "removeDevice": ( 0x00A8, - (t.EmberNodeId, t.EmberEUI64, t.EmberEUI64), + (t.EmberNodeId, t.EUI64, t.EUI64), (t.EmberStatus,), ), "unicastNwkKeyUpdate": ( 0x00A9, - (t.EmberNodeId, t.EmberEUI64, t.EmberKeyData), + (t.EmberNodeId, t.EUI64, t.KeyData), (t.EmberStatus,), ), # 11. Certificate Based Key Exchange (CBKE) Frames @@ -528,7 +533,7 @@ "launchStandaloneBootloader": (0x008F, (t.uint8_t,), (t.EmberStatus,)), "sendBootloadMessage": ( 0x0090, - (t.Bool, t.EmberEUI64, t.LVBytes), + (t.Bool, t.EUI64, t.LVBytes), (t.EmberStatus,), ), "getStandaloneBootloaderVersionPlatMicroPhy": ( @@ -539,7 +544,7 @@ "incomingBootloadMessageHandler": ( 0x0092, (), - (t.EmberEUI64, t.uint8_t, t.int8s, t.LVBytes), + (t.EUI64, t.uint8_t, t.int8s, t.LVBytes), ), "bootloadTransmitCompleteHandler": (0x0093, (), (t.EmberStatus, t.LVBytes)), "aesEncrypt": ( @@ -556,7 +561,7 @@ ), "zllSetInitialSecurityState": ( 0x00B3, - (t.EmberKeyData, t.EmberZllInitialSecurityState), + (t.KeyData, t.EmberZllInitialSecurityState), (t.EmberStatus,), ), "zllSetSecurityStateWithoutKey": ( @@ -613,8 +618,8 @@ t.uint16_t, t.uint16_t, t.uint16_t, - t.EmberEUI64, - t.EmberKeyData, + t.EUI64, + t.KeyData, ), (), ), @@ -670,7 +675,7 @@ # 16 Secure EZSP Frames "setSecurityKey": ( 0x00CA, - (t.EmberKeyData, t.SecureEzspSecurityType), + (t.KeyData, t.SecureEzspSecurityType), (t.EzspStatus,), ), "setSecurityParameters": ( diff --git a/bellows/ezsp/v8/types/named.py b/bellows/ezsp/v8/types/named.py index 9a3a946a..b8a4e61c 100644 --- a/bellows/ezsp/v8/types/named.py +++ b/bellows/ezsp/v8/types/named.py @@ -2,6 +2,7 @@ import bellows.types.basic as basic from bellows.types.named import ( # noqa: F401, F403 + EUI64, Bool, Channels, EmberApsOption, @@ -11,14 +12,12 @@ EmberConcentratorType, EmberConfigTxPowerMode, EmberCurrentSecurityBitmask, - EmberEUI64, EmberEventUnits, EmberGpKeyType, EmberGpSecurityLevel, EmberIncomingMessageType, EmberInitialSecurityBitmask, EmberJoinDecision, - EmberKeyData, EmberKeyStatus, EmberKeyStructBitmask, EmberLibraryStatus, @@ -49,6 +48,7 @@ EzspSourceRouteOverheadInformation, EzspStatus, EzspZllNetworkOperation, + KeyData, ) diff --git a/bellows/ezsp/v8/types/struct.py b/bellows/ezsp/v8/types/struct.py index f1a56628..f10daa0e 100644 --- a/bellows/ezsp/v8/types/struct.py +++ b/bellows/ezsp/v8/types/struct.py @@ -88,7 +88,7 @@ class EmberKeyStruct(EzspStruct): # The type of the key. type: named.EmberKeyType # The actual key data. - key: named.EmberKeyData + key: named.KeyData # The outgoing frame counter associated with the key. outgoingFrameCounter: basic.uint32_t # The frame counter of the partner device associated with the key. @@ -96,7 +96,7 @@ class EmberKeyStruct(EzspStruct): # The sequence number associated with the key. sequenceNumber: basic.uint8_t # The IEEE address of the partner device also in possession of the key. - partnerEUI64: named.EmberEUI64 + partnerEUI64: named.EUI64 class EmberGpSinkListEntry(EzspStruct): @@ -104,7 +104,7 @@ class EmberGpSinkListEntry(EzspStruct): # The sink list type. type: basic.uint8_t # The EUI64 of the target sink. - sinkEUI: named.EmberEUI64 + sinkEUI: named.EUI64 # The short address of the target sink. sinkNodeId: named.EmberNodeId @@ -113,7 +113,7 @@ class EmberGpProxyTableEntry(EzspStruct): """The internal representation of a proxy table entry.""" # The link key to be used to secure this pairing link. - securityLinkKey: named.EmberKeyData + securityLinkKey: named.KeyData # Internal status of the proxy table entry. status: named.EmberGpProxyTableEntryStatus # The tunneling options @@ -128,7 +128,7 @@ class EmberGpProxyTableEntry(EzspStruct): # The security frame counter of the GPD. gpdSecurityFrameCounter: named.EmberGpSecurityFrameCounter # The key to use for GPD. - gpdKey: named.EmberKeyData + gpdKey: named.KeyData # The list of sinks (hardcoded to 2 which is the spec minimum). sinkList: basic.fixed_list(2, EmberGpSinkListEntry) # The groupcast radius. @@ -160,7 +160,7 @@ class EmberGpSinkTableEntry(EzspStruct): # The security frame counter of the GPD. gpdSecurityFrameCounter: named.EmberGpSecurityFrameCounter # The key to use for GPD. - gpdKey: named.EmberKeyData + gpdKey: named.KeyData class EmberDutyCycleLimits(EzspStruct): @@ -194,9 +194,9 @@ class EmberTransientKeyData(EzspStruct): """The transient key data structure. Added in ver. 5. Revised in ver 8""" # The IEEE address paired with the transient link key. - eui64: named.EmberEUI64 + eui64: named.EUI64 # The key data structure matching the transient key. - keyData: named.EmberKeyData + keyData: named.KeyData # This bitmask indicates whether various fields in the structure contain valid data. bitmask: named.EmberKeyStructBitmask # The number of seconds remaining before the key is automatically timed out of the @@ -208,7 +208,7 @@ class EmberChildData(EzspStruct): """A structure containing a child node's data.""" # The EUI64 of the child - eui64: named.EmberEUI64 + eui64: named.EUI64 # The node type of the child type: named.EmberNodeType # The short address of the child @@ -221,6 +221,6 @@ class EmberChildData(EzspStruct): timeout: basic.uint8_t # The GPD's EUI64. - # gpdIeeeAddress: named.EmberEUI64 + # gpdIeeeAddress: named.EUI64 # The GPD's source ID. # sourceId: basic.uint32_t diff --git a/bellows/ezsp/v9/commands.py b/bellows/ezsp/v9/commands.py index 4ecbdd2f..ada069f2 100644 --- a/bellows/ezsp/v9/commands.py +++ b/bellows/ezsp/v9/commands.py @@ -65,7 +65,7 @@ "getXncpInfo": (0x0013, (), (t.EmberStatus, t.uint16_t, t.uint16_t)), "customFrame": (0x0047, (t.LVBytes,), (t.EmberStatus, t.LVBytes)), "customFrameHandler": (0x0054, (), (t.LVBytes,)), - "getEui64": (0x0026, (), (t.EmberEUI64,)), + "getEui64": (0x0026, (), (t.EUI64,)), "getNodeId": (0x0027, (), (t.EmberNodeId,)), "getPhyInterfaceCount": (0x00FC, (), (t.uint8_t,)), "getTrueRandomEntropySource": (0x004F, (), (t.EmberEntropySource,)), @@ -103,7 +103,7 @@ "childJoinHandler": ( 0x0023, (), - (t.uint8_t, t.Bool, t.EmberNodeId, t.EmberEUI64, t.EmberNodeType), + (t.uint8_t, t.Bool, t.EmberNodeId, t.EUI64, t.EmberNodeType), ), "energyScanRequest": ( 0x009C, @@ -120,7 +120,7 @@ (t.uint8_t,), (t.EmberStatus, t.EmberNodeType, t.EmberNetworkParameters), ), - "getParentChildParameters": (0x0029, (), (t.uint8_t, t.EmberEUI64, t.EmberNodeId)), + "getParentChildParameters": (0x0029, (), (t.uint8_t, t.EUI64, t.EmberNodeId)), "getChildData": ( 0x004A, (t.uint8_t,), @@ -128,8 +128,8 @@ ), "setChildData": ( 0x00AC, - (t.uint8_t,), - (t.EmberStatus, t.EmberChildData), + (t.uint8_t, t.EmberChildData), + (t.EmberStatus,), ), "getSourceRouteTableTotalSize": (0x00C3, (), (t.uint8_t,)), "getSourceRouteTableFilledSize": (0x00C2, (), (t.uint8_t,)), @@ -139,8 +139,8 @@ (t.EmberStatus, t.EmberNodeId, t.uint8_t), ), "getNeighbor": (0x0079, (t.uint8_t,), (t.EmberStatus, t.EmberNeighborTableEntry)), - "getNeighborFrameCounter": (0x003E, (t.EmberEUI64,), (t.EmberStatus, t.uint32_t)), - "setNeighborFrameCounter": (0x00AD, (t.EmberEUI64,), (t.EmberStatus, t.uint32_t)), + "getNeighborFrameCounter": (0x003E, (t.EUI64,), (t.EmberStatus, t.uint32_t)), + "setNeighborFrameCounter": (0x00AD, (t.EUI64,), (t.EmberStatus, t.uint32_t)), "setRoutingShortcutThreshold": (0x00D0, (t.uint8_t,), (t.EmberStatus,)), "getRoutingShortcutThreshold": (0x00D1, (), (t.uint8_t,)), "neighborCount": (0x007A, (), (t.uint8_t,)), @@ -288,7 +288,7 @@ ), "pollCompleteHandler": (0x0043, (), (t.EmberStatus,)), "pollHandler": (0x0044, (), (t.EmberNodeId,)), - "incomingSenderEui64Handler": (0x0062, (), (t.EmberEUI64,)), + "incomingSenderEui64Handler": (0x0062, (), (t.EUI64,)), "incomingMessageHandler": ( 0x0045, (), @@ -306,35 +306,40 @@ "incomingRouteRecordHandler": ( 0x0059, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), + (t.EmberNodeId, t.EUI64, t.uint8_t, t.int8s, t.LVList(t.EmberNodeId)), ), "changeSourceRouteHandler": (0x00C4, (), (t.EmberNodeId, t.EmberNodeId, t.Bool)), + "setSourceRoute": ( + 0x00AE, + (t.EmberNodeId, t.LVList(t.EmberNodeId)), + (t.EmberStatus,), + ), "setSourceRouteDiscoveryMode": (0x005A, (t.uint8_t,), (t.uint32_t,)), "incomingManyToOneRouteRequestHandler": ( 0x007D, (), - (t.EmberNodeId, t.EmberEUI64, t.uint8_t), + (t.EmberNodeId, t.EUI64, t.uint8_t), ), "incomingRouteErrorHandler": (0x0080, (), (t.EmberStatus, t.EmberNodeId)), "unicastCurrentNetworkKey": ( 0x0050, - (t.EmberNodeId, t.EmberEUI64, t.EmberNodeId), + (t.EmberNodeId, t.EUI64, t.EmberNodeId), (t.EmberStatus,), ), "addressTableEntryIsActive": (0x005B, (t.uint8_t,), (t.Bool,)), - "setAddressTableRemoteEui64": (0x005C, (t.uint8_t, t.EmberEUI64), (t.EmberStatus,)), + "setAddressTableRemoteEui64": (0x005C, (t.uint8_t, t.EUI64), (t.EmberStatus,)), "setAddressTableRemoteNodeId": (0x005D, (t.uint8_t, t.EmberNodeId), ()), - "getAddressTableRemoteEui64": (0x005E, (t.uint8_t,), (t.EmberEUI64,)), + "getAddressTableRemoteEui64": (0x005E, (t.uint8_t,), (t.EUI64,)), "getAddressTableRemoteNodeId": (0x005F, (t.uint8_t,), (t.EmberNodeId,)), - "setExtendedTimeout": (0x007E, (t.EmberEUI64, t.Bool), ()), - "getExtendedTimeout": (0x007F, (t.EmberEUI64,), (t.Bool,)), + "setExtendedTimeout": (0x007E, (t.EUI64, t.Bool), ()), + "getExtendedTimeout": (0x007F, (t.EUI64,), (t.Bool,)), "replaceAddressTableEntry": ( 0x0082, - (t.uint8_t, t.EmberEUI64, t.EmberNodeId, t.Bool), - (t.EmberStatus, t.EmberEUI64, t.EmberNodeId, t.Bool), + (t.uint8_t, t.EUI64, t.EmberNodeId, t.Bool), + (t.EmberStatus, t.EUI64, t.EmberNodeId, t.Bool), ), - "lookupNodeIdByEui64": (0x0060, (t.EmberEUI64,), (t.EmberNodeId,)), - "lookupEui64ByNodeId": (0x0061, (t.EmberNodeId,), (t.EmberStatus, t.EmberEUI64)), + "lookupNodeIdByEui64": (0x0060, (t.EUI64,), (t.EmberNodeId,)), + "lookupEui64ByNodeId": (0x0061, (t.EmberNodeId,), (t.EmberStatus, t.EUI64)), "getMulticastTableEntry": ( 0x0063, (t.uint8_t,), @@ -391,26 +396,26 @@ "getKeyTableEntry": (0x0071, (t.uint8_t,), (t.EmberStatus, t.EmberKeyStruct)), "setKeyTableEntry": ( 0x0072, - (t.uint8_t, t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.uint8_t, t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "findKeyTableEntry": (0x0075, (t.EmberEUI64, t.Bool), (t.uint8_t,)), + "findKeyTableEntry": (0x0075, (t.EUI64, t.Bool), (t.uint8_t,)), "addOrUpdateKeyTableEntry": ( 0x0066, - (t.EmberEUI64, t.Bool, t.EmberKeyData), + (t.EUI64, t.Bool, t.KeyData), (t.EmberStatus,), ), - "sendTrustCenterLinkKey": (0x0067, (t.EmberNodeId, t.EmberEUI64), (t.EmberStatus,)), + "sendTrustCenterLinkKey": (0x0067, (t.EmberNodeId, t.EUI64), (t.EmberStatus,)), "eraseKeyTableEntry": (0x0076, (t.uint8_t,), (t.EmberStatus,)), "clearKeyTable": (0x00B1, (), (t.EmberStatus,)), - "requestLinkKey": (0x0014, (t.EmberEUI64,), (t.EmberStatus,)), + "requestLinkKey": (0x0014, (t.EUI64,), (t.EmberStatus,)), "updateTcLinkKey": (0x006C, (t.uint8_t,), (t.EmberStatus,)), - "zigbeeKeyEstablishmentHandler": (0x009B, (), (t.EmberEUI64, t.EmberKeyStatus)), - "addTransientLinkKey": (0x00AF, (t.EmberEUI64, t.EmberKeyData), (t.EmberStatus,)), + "zigbeeKeyEstablishmentHandler": (0x009B, (), (t.EUI64, t.EmberKeyStatus)), + "addTransientLinkKey": (0x00AF, (t.EUI64, t.KeyData), (t.EmberStatus,)), "clearTransientLinkKeys": (0x006B, (), ()), "getTransientLinkKey": ( 0x00CE, - (t.EmberEUI64,), + (t.EUI64,), (t.EmberStatus, t.EmberTransientKeyData), ), "getTransientKeyTableEntry": ( @@ -424,15 +429,15 @@ (), ( t.EmberNodeId, - t.EmberEUI64, + t.EUI64, t.EmberDeviceUpdate, t.EmberJoinDecision, t.EmberNodeId, ), ), - "broadcastNextNetworkKey": (0x0073, (t.EmberKeyData,), (t.EmberStatus,)), + "broadcastNextNetworkKey": (0x0073, (t.KeyData,), (t.EmberStatus,)), "broadcastNetworkKeySwitch": (0x0074, (), (t.EmberStatus,)), - "becomeTrustCenter": (0x0077, (t.EmberKeyData,), (t.EmberStatus,)), + "becomeTrustCenter": (0x0077, (t.KeyData,), (t.EmberStatus,)), "aesMmoHash": ( 0x006F, (t.EmberAesMmoHashContext, t.Bool, t.LVBytes), @@ -440,12 +445,12 @@ ), "removeDevice": ( 0x00A8, - (t.EmberNodeId, t.EmberEUI64, t.EmberEUI64), + (t.EmberNodeId, t.EUI64, t.EUI64), (t.EmberStatus,), ), "unicastNwkKeyUpdate": ( 0x00A9, - (t.EmberNodeId, t.EmberEUI64, t.EmberKeyData), + (t.EmberNodeId, t.EUI64, t.KeyData), (t.EmberStatus,), ), # 11. Certificate Based Key Exchange (CBKE) Frames @@ -525,7 +530,7 @@ "launchStandaloneBootloader": (0x008F, (t.uint8_t,), (t.EmberStatus,)), "sendBootloadMessage": ( 0x0090, - (t.Bool, t.EmberEUI64, t.LVBytes), + (t.Bool, t.EUI64, t.LVBytes), (t.EmberStatus,), ), "getStandaloneBootloaderVersionPlatMicroPhy": ( @@ -536,7 +541,7 @@ "incomingBootloadMessageHandler": ( 0x0092, (), - (t.EmberEUI64, t.uint8_t, t.int8s, t.LVBytes), + (t.EUI64, t.uint8_t, t.int8s, t.LVBytes), ), "bootloadTransmitCompleteHandler": (0x0093, (), (t.EmberStatus, t.LVBytes)), "aesEncrypt": ( @@ -552,7 +557,7 @@ ), "zllSetInitialSecurityState": ( 0x00B3, - (t.EmberKeyData, t.EmberZllInitialSecurityState), + (t.KeyData, t.EmberZllInitialSecurityState), (t.EmberStatus,), ), "zllSetSecurityStateWithoutKey": ( @@ -609,8 +614,8 @@ t.uint16_t, t.uint16_t, t.uint16_t, - t.EmberEUI64, - t.EmberKeyData, + t.EUI64, + t.KeyData, ), (), ), @@ -666,7 +671,7 @@ # 17 Secure EZSP Frames "setSecurityKey": ( 0x00CA, - (t.EmberKeyData, t.SecureEzspSecurityType), + (t.KeyData, t.SecureEzspSecurityType), (t.EzspStatus,), ), "setSecurityParameters": ( diff --git a/bellows/ezsp/v9/types/named.py b/bellows/ezsp/v9/types/named.py index e727ca7d..b3a6e43f 100644 --- a/bellows/ezsp/v9/types/named.py +++ b/bellows/ezsp/v9/types/named.py @@ -2,6 +2,7 @@ import bellows.types.basic as basic from bellows.types.named import ( # noqa: F401, F403 + EUI64, Bool, Channels, EmberApsOption, @@ -11,14 +12,12 @@ EmberConcentratorType, EmberConfigTxPowerMode, EmberCurrentSecurityBitmask, - EmberEUI64, EmberEventUnits, EmberGpKeyType, EmberGpSecurityLevel, EmberIncomingMessageType, EmberInitialSecurityBitmask, EmberJoinDecision, - EmberKeyData, EmberKeyStatus, EmberKeyStructBitmask, EmberLibraryId, @@ -50,6 +49,7 @@ EzspSourceRouteOverheadInformation, EzspStatus, EzspZllNetworkOperation, + KeyData, sl_Status, ) diff --git a/bellows/ezsp/v9/types/struct.py b/bellows/ezsp/v9/types/struct.py index af81ec8a..b575ff9f 100644 --- a/bellows/ezsp/v9/types/struct.py +++ b/bellows/ezsp/v9/types/struct.py @@ -92,7 +92,7 @@ class EmberKeyStruct(EzspStruct): # The type of the key. type: named.EmberKeyType # The actual key data. - key: named.EmberKeyData + key: named.KeyData # The outgoing frame counter associated with the key. outgoingFrameCounter: basic.uint32_t # The frame counter of the partner device associated with the key. @@ -100,7 +100,7 @@ class EmberKeyStruct(EzspStruct): # The sequence number associated with the key. sequenceNumber: basic.uint8_t # The IEEE address of the partner device also in possession of the key. - partnerEUI64: named.EmberEUI64 + partnerEUI64: named.EUI64 @classmethod def deserialize(cls, data: bytes) -> tuple[named.EmberKeyStruct, bytes]: @@ -116,7 +116,7 @@ class EmberGpSinkListEntry(EzspStruct): # The sink list type. type: basic.uint8_t # The EUI64 of the target sink. - sinkEUI: named.EmberEUI64 + sinkEUI: named.EUI64 # The short address of the target sink. sinkNodeId: named.EmberNodeId @@ -125,7 +125,7 @@ class EmberGpProxyTableEntry(EzspStruct): """The internal representation of a proxy table entry.""" # The link key to be used to secure this pairing link. - securityLinkKey: named.EmberKeyData + securityLinkKey: named.KeyData # Internal status of the proxy table entry. status: named.EmberGpProxyTableEntryStatus # The tunneling options @@ -170,7 +170,7 @@ class EmberGpSinkTableEntry(EzspStruct): # The security frame counter of the GPD. gpdSecurityFrameCounter: named.EmberGpSecurityFrameCounter # The key to use for GPD. - gpdKey: named.EmberKeyData + gpdKey: named.KeyData class EmberDutyCycleLimits(EzspStruct): @@ -204,9 +204,9 @@ class EmberTransientKeyData(EzspStruct): """The transient key data structure. Added in ver. 5. Revised in ver 8""" # The IEEE address paired with the transient link key. - eui64: named.EmberEUI64 + eui64: named.EUI64 # The key data structure matching the transient key. - keyData: named.EmberKeyData + keyData: named.KeyData # This bitmask indicates whether various fields in the structure contain valid data. bitmask: named.EmberKeyStructBitmask # The number of seconds remaining before the key is automatically timed out of the @@ -218,7 +218,7 @@ class EmberChildData(EzspStruct): """A structure containing a child node's data.""" # The EUI64 of the child - eui64: named.EmberEUI64 + eui64: named.EUI64 # The node type of the child type: named.EmberNodeType # The short address of the child @@ -231,6 +231,6 @@ class EmberChildData(EzspStruct): timeout: basic.uint8_t # The GPD's EUI64. - # gpdIeeeAddress: named.EmberEUI64 + # gpdIeeeAddress: named.EUI64 # The GPD's source ID. # sourceId: basic.uint32_t diff --git a/bellows/types/named.py b/bellows/types/named.py index 7d3ed6f4..ae8522a5 100644 --- a/bellows/types/named.py +++ b/bellows/types/named.py @@ -5,6 +5,7 @@ Channels = ztypes.Channels EmberEUI64 = ztypes.EUI64 +EUI64 = ztypes.EUI64 class NcpResetCode(basic.enum8): @@ -1239,6 +1240,7 @@ class EzspSourceRouteOverheadInformation(basic.enum8): EmberKeyData = ztypes.KeyData +KeyData = ztypes.KeyData class EmberCertificateData(basic.fixed_list(48, basic.uint8_t)): diff --git a/bellows/types/struct.py b/bellows/types/struct.py index a56c3793..83d91e03 100644 --- a/bellows/types/struct.py +++ b/bellows/types/struct.py @@ -82,7 +82,7 @@ class EmberBindingTableEntry(EzspStruct): remote: basic.uint8_t # A 64-bit identifier. This is either the destination EUI64 (for # unicasts) or the 64-bit group address (for multicasts). - identifier: named.EmberEUI64 + identifier: named.EUI64 # The index of the network the binding belongs to. networkIndex: basic.uint8_t @@ -103,9 +103,9 @@ class EmberMulticastTableEntry(EzspStruct): class EmberTransientKeyData(EzspStruct): # The transient key data structure. Added in ver. 5 # The IEEE address paired with the transient link key. - eui64: named.EmberEUI64 + eui64: named.EUI64 # The key data structure matching the transient key. - keyData: named.EmberKeyData + keyData: named.KeyData # The incoming frame counter associated with this key. incomingFrameCounter: basic.uint32_t # The number of milliseconds remaining before the key @@ -142,7 +142,7 @@ class EmberNeighborTableEntry(EzspStruct): # last received from this neighbor. The aging period is 16 seconds. age: basic.uint8_t # The 8 byte EUI64 of the neighbor. - longId: named.EmberEUI64 + longId: named.EUI64 class EmberRouteTableEntry(EzspStruct): @@ -179,12 +179,12 @@ class EmberInitialSecurityState(EzspStruct): # joining the network. The security bitmask must be set with the # HAVE_PRECONFIGURED_KEY bit to indicate that the key contains valid # data. - preconfiguredKey: named.EmberKeyData + preconfiguredKey: named.KeyData # The Network Key that should be used by the Trust Center when it forms # the network, or the Network Key currently in use by a joined device. # The security bitmask must be set with HAVE_NETWORK_KEY to indicate # that the key contains valid data. - networkKey: named.EmberKeyData + networkKey: named.KeyData # The sequence number associated with the network key. This is only # valid if the HAVE_NETWORK_KEY has been set in the security bitmask. networkKeySequenceNumber: basic.uint8_t @@ -195,7 +195,7 @@ class EmberInitialSecurityState(EzspStruct): # EmberInitialSecurityState::bitmask. Most devices should clear that # bit and leave this field alone. This field must be set when using # commissioning mode. - preconfiguredTrustCenterEui64: named.EmberEUI64 + preconfiguredTrustCenterEui64: named.EUI64 class EmberCurrentSecurityState(EzspStruct): @@ -204,7 +204,7 @@ class EmberCurrentSecurityState(EzspStruct): # device joined in the network. bitmask: named.EmberCurrentSecurityBitmask # The IEEE Address of the Trust Center device. - trustCenterLongAddress: named.EmberEUI64 + trustCenterLongAddress: named.EUI64 class EmberZllSecurityAlgorithmData(EzspStruct): @@ -224,7 +224,7 @@ class EmberZllNetwork(EzspStruct): # Data associated with the ZLL security algorithm. securityAlgorithm: EmberZllSecurityAlgorithmData # Associated EUI64. - eui64: named.EmberEUI64 + eui64: named.EUI64 # The node id. nodeId: named.EmberNodeId # The ZLL state. @@ -247,16 +247,16 @@ class EmberZllInitialSecurityState(EzspStruct): # The key encryption algorithm advertised by the application. keyIndex: named.EmberZllKeyIndex # The encryption key for use by algorithms that require it. - encryptionKey: named.EmberKeyData + encryptionKey: named.KeyData # The pre-configured link key used during classical ZigBee # commissioning. - preconfiguredKey: named.EmberKeyData + preconfiguredKey: named.KeyData class EmberZllDeviceInfoRecord(EzspStruct): # Information about a specific ZLL Device. # EUI64 associated with the device. - ieeeAddress: named.EmberEUI64 + ieeeAddress: named.EUI64 # Endpoint id. endpointId: basic.uint8_t # Profile id. @@ -334,15 +334,15 @@ class EmberTokTypeStackZllSecurity(EzspStruct): # Key index. keyIndex: basic.uint8_t # Encryption key. - encryptionKey: named.EmberKeyData + encryptionKey: named.KeyData # Preconfigured key. - preconfiguredKey: named.EmberKeyData + preconfiguredKey: named.KeyData class EmberGpAddress(EzspStruct): # A GP address structure. # The GPD's EUI64. - gpdIeeeAddress: named.EmberEUI64 + gpdIeeeAddress: named.EUI64 # The GPD's source ID. sourceId: basic.uint32_t # The GPD Application ID. @@ -355,5 +355,5 @@ class NV3StackTrustCenterToken(EzspStruct): """NV3 stack trust center token value.""" mode: basic.uint16_t - eui64: named.EmberEUI64 - key: named.EmberKeyData + eui64: named.EUI64 + key: named.KeyData diff --git a/bellows/zigbee/application.py b/bellows/zigbee/application.py index 7c85e8ec..d486ff05 100644 --- a/bellows/zigbee/application.py +++ b/bellows/zigbee/application.py @@ -119,7 +119,7 @@ async def add_endpoint(self, descriptor: zdo_t.SimpleDescriptor) -> None: if status != t.EmberStatus.SUCCESS: raise StackAlreadyRunning() - async def cleanup_tc_link_key(self, ieee: t.EmberEUI64) -> None: + async def cleanup_tc_link_key(self, ieee: t.EUI64) -> None: """Remove tc link_key for the given device.""" (index,) = await self._ezsp.findKeyTableEntry(ieee, True) if index != 0xFF: @@ -195,12 +195,6 @@ async def start_network(self): for cnt_group in self.state.counters: cnt_group.reset() - # Device relays are cleared on startup when "source routing" on newer EmberZNet - # to enable route discovery when first sending requests - if self.config[zigpy.config.CONF_SOURCE_ROUTING] and ezsp.ezsp_version >= 8: - for device in self.devices.values(): - device.relays = None - ezsp.add_callback(self.ezsp_callback_handler) self.controller_event.set() @@ -260,16 +254,58 @@ async def load_network_info(self, *, load_devices=False) -> None: assert status == t.EmberStatus.SUCCESS security_level = zigpy.types.uint8_t(security_level) - (status, network_key) = await ezsp.getKey( - ezsp.types.EmberKeyType.CURRENT_NETWORK_KEY - ) - assert status == t.EmberStatus.SUCCESS + if ezsp.ezsp_version < 13: + (status, ezsp_network_key) = await ezsp.getKey( + ezsp.types.EmberKeyType.CURRENT_NETWORK_KEY + ) + assert status == t.EmberStatus.SUCCESS + network_key = util.ezsp_key_to_zigpy_key(ezsp_network_key, ezsp) - (status, ezsp_tc_link_key) = await ezsp.getKey( - ezsp.types.EmberKeyType.TRUST_CENTER_LINK_KEY - ) - assert status == t.EmberStatus.SUCCESS - tc_link_key = util.ezsp_key_to_zigpy_key(ezsp_tc_link_key, ezsp) + (status, ezsp_tc_link_key) = await ezsp.getKey( + ezsp.types.EmberKeyType.TRUST_CENTER_LINK_KEY + ) + assert status == t.EmberStatus.SUCCESS + tc_link_key = util.ezsp_key_to_zigpy_key(ezsp_tc_link_key, ezsp) + else: + (network_key_data, status) = await ezsp.exportKey( + ezsp.types.sl_zb_sec_man_context_t( + core_key_type=ezsp.types.sl_zb_sec_man_key_type_t.NETWORK, + key_index=0, + derived_type=ezsp.types.sl_zb_sec_man_derived_key_type_t.NONE, + eui64=t.EUI64.convert("00:00:00:00:00:00:00:00"), + multi_network_index=0, + flags=ezsp.types.sl_zb_sec_man_flags_t.NONE, + psa_key_alg_permission=0, + ) + ) + assert status == t.EmberStatus.SUCCESS + + (status, _, network_key_info) = await ezsp.getNetworkKeyInfo() + assert status == t.EmberStatus.SUCCESS + + if not network_key_info.network_key_set: + raise NetworkNotFormed("Network key is not set") + + network_key = zigpy.state.Key( + key=network_key_data, + tx_counter=network_key_info.network_key_frame_counter, + seq=network_key_info.network_key_sequence_number, + ) + + (tc_link_key_data, status) = await ezsp.exportKey( + ezsp.types.sl_zb_sec_man_context_t( + core_key_type=ezsp.types.sl_zb_sec_man_key_type_t.TC_LINK, + key_index=0, + derived_type=ezsp.types.sl_zb_sec_man_derived_key_type_t.NONE, + eui64=t.EUI64.convert("00:00:00:00:00:00:00:00"), + multi_network_index=0, + flags=ezsp.types.sl_zb_sec_man_flags_t.NONE, + psa_key_alg_permission=0, + ) + ) + assert status == t.EmberStatus.SUCCESS + + tc_link_key = zigpy.state.Key(key=tc_link_key_data) (status, state) = await ezsp.getCurrentSecurityState() assert status == t.EmberStatus.SUCCESS @@ -299,7 +335,7 @@ async def load_network_info(self, *, load_devices=False) -> None: channel=zigpy.types.uint8_t(nwk_params.radioChannel), channel_mask=zigpy.types.Channels(nwk_params.channels), security_level=zigpy.types.uint8_t(security_level), - network_key=util.ezsp_key_to_zigpy_key(network_key, ezsp), + network_key=network_key, tc_link_key=tc_link_key, key_table=[], children=[], @@ -317,19 +353,46 @@ async def load_network_info(self, *, load_devices=False) -> None: if not load_devices: return - for idx in range(0, 192): - (status, key) = await ezsp.getKeyTableEntry(idx) + (status, key_table_size) = await ezsp.getConfigurationValue( + ezsp.types.EzspConfigId.CONFIG_KEY_TABLE_SIZE + ) - if status == t.EmberStatus.INDEX_OUT_OF_RANGE: - break - elif status in (t.EmberStatus.TABLE_ENTRY_ERASED, t.EmberStatus.NOT_FOUND): - continue + if ezsp.ezsp_version < 13: + for index in range(key_table_size): + (status, key) = await ezsp.getKeyTableEntry(index) - assert status == t.EmberStatus.SUCCESS + if status == t.EmberStatus.INDEX_OUT_OF_RANGE: + break + elif status in ( + t.EmberStatus.TABLE_ENTRY_ERASED, + t.EmberStatus.NOT_FOUND, + ): + continue - self.state.network_info.key_table.append( - util.ezsp_key_to_zigpy_key(key, ezsp) - ) + assert status == t.EmberStatus.SUCCESS + + self.state.network_info.key_table.append( + util.ezsp_key_to_zigpy_key(key, ezsp) + ) + else: + for index in range(key_table_size): + ( + eui64, + plaintext_key, + key_data, + status, + ) = await ezsp.exportLinkKeyByIndex(index) + if status != t.sl_Status.SL_STATUS_OK: + continue + + self.state.network_info.key_table.append( + zigpy.state.Key( + key=plaintext_key, + tx_counter=key_data.outgoing_frame_counter, + rx_counter=key_data.incoming_frame_counter, + partner_ieee=eui64, + ) + ) for idx in range(0, 255 + 1): (status, *rsp) = await ezsp.getChildData(idx) @@ -349,22 +412,25 @@ async def load_network_info(self, *, load_devices=False) -> None: # v4 can crash when getAddressTableRemoteNodeId(32) is received # Error code: undefined_0x8a - if ezsp.ezsp_version == 4: - return + if ezsp.ezsp_version > 4: + (status, addr_table_size) = await ezsp.getConfigurationValue( + ezsp.types.EzspConfigId.CONFIG_ADDRESS_TABLE_SIZE + ) - for idx in range(0, 255 + 1): - (nwk,) = await ezsp.getAddressTableRemoteNodeId(idx) - (eui64,) = await ezsp.getAddressTableRemoteEui64(idx) + for idx in range(addr_table_size): + (nwk,) = await ezsp.getAddressTableRemoteNodeId(idx) - # Ignore invalid NWK entries - if nwk in t.EmberDistinguishedNodeId.__members__.values(): - continue - elif eui64 == t.EmberEUI64.convert("00:00:00:00:00:00:00:00"): - continue + # Ignore invalid NWK entries + if nwk in t.EmberDistinguishedNodeId.__members__.values(): + continue - self.state.network_info.nwk_addresses[ - zigpy.types.EUI64(eui64) - ] = zigpy.types.NWK(nwk) + (eui64,) = await ezsp.getAddressTableRemoteEui64(idx) + if eui64 == t.EUI64.convert("00:00:00:00:00:00:00:00"): + continue + + self.state.network_info.nwk_addresses[ + zigpy.types.EUI64(eui64) + ] = zigpy.types.NWK(nwk) async def write_network_info( self, *, network_info: zigpy.state.NetworkInfo, node_info: zigpy.state.NodeInfo @@ -410,6 +476,25 @@ async def write_network_info( node_info.ieee = current_eui64 network_info.tc_link_key.partner_ieee = current_eui64 + if ezsp.ezsp_version > 4: + # Frame counters can only be set *before* we have joined a network + (state,) = await self._ezsp.networkState() + assert state == ezsp.types.EmberNetworkStatus.NO_NETWORK + + # Set NWK frame counter + (status,) = await ezsp.setValue( + ezsp.types.EzspValueId.VALUE_NWK_FRAME_COUNTER, + t.uint32_t(network_info.network_key.tx_counter).serialize(), + ) + assert status == t.EmberStatus.SUCCESS + + # Set APS frame counter + (status,) = await ezsp.setValue( + ezsp.types.EzspValueId.VALUE_APS_FRAME_COUNTER, + t.uint32_t(network_info.tc_link_key.tx_counter).serialize(), + ) + assert status == t.EmberStatus.SUCCESS + use_hashed_tclk = ezsp.ezsp_version > 4 if use_hashed_tclk and not stack_specific.get("hashed_tclk"): @@ -426,35 +511,45 @@ async def write_network_info( assert status == t.EmberStatus.SUCCESS # Write APS link keys - for key in network_info.key_table: - ember_key = util.zigpy_key_to_ezsp_key(key, ezsp) + for index, key in enumerate(network_info.key_table): + if ezsp.ezsp_version < 13: + # XXX: is there no way to set the outgoing frame counter or seq? + (status,) = await ezsp.addOrUpdateKeyTableEntry( + key.partner_ieee, True, key.key + ) + else: + (status,) = await ezsp.importLinkKey(index, key.partner_ieee, key.key) - # XXX: is there no way to set the outgoing frame counter or seq? - (status,) = await ezsp.addOrUpdateKeyTableEntry( - ember_key.partnerEUI64, True, ember_key.key - ) if status != t.EmberStatus.SUCCESS: LOGGER.warning("Couldn't add %s key: %s", key, status) - if ezsp.ezsp_version > 4: - # Set NWK frame counter - (status,) = await ezsp.setValue( - ezsp.types.EzspValueId.VALUE_NWK_FRAME_COUNTER, - t.uint32_t(network_info.network_key.tx_counter).serialize(), - ) - assert status == t.EmberStatus.SUCCESS - - # Set APS frame counter - (status,) = await ezsp.setValue( - ezsp.types.EzspValueId.VALUE_APS_FRAME_COUNTER, - t.uint32_t(network_info.tc_link_key.tx_counter).serialize(), - ) - assert status == t.EmberStatus.SUCCESS + # Write the child table + if ezsp.ezsp_version >= 9: + index = 0 + + for child_eui64 in network_info.children: + if child_eui64 not in network_info.nwk_addresses: + continue + + await ezsp.setChildData( + index, + ezsp.types.EmberChildData( + eui64=child_eui64, + type=t.EmberNodeType.SLEEPY_END_DEVICE, + id=network_info.nwk_addresses[child_eui64], + # The rest are unused when setting child data + phy=0, + power=0, + timeout=0, + **({"timeout_remaining": 0} if ezsp.ezsp_version >= 10 else {}), + ), + ) + index += 1 # Set the network settings parameters = t.EmberNetworkParameters() parameters.panId = t.EmberPanId(network_info.pan_id) - parameters.extendedPanId = t.EmberEUI64(network_info.extended_pan_id) + parameters.extendedPanId = t.EUI64(network_info.extended_pan_id) parameters.radioTxPower = t.uint8_t(8) parameters.radioChannel = t.uint8_t(network_info.channel) parameters.joinMethod = t.EmberJoinMethod.USE_MAC_ASSOCIATION @@ -631,7 +726,7 @@ async def _handle_no_such_device(self, sender: int) -> None: def _handle_tc_join_handler( self, nwk: t.EmberNodeId, - ieee: t.EmberEUI64, + ieee: t.EUI64, device_update_status: EmberDeviceUpdate, decision: t.EmberJoinDecision, parent_nwk: t.EmberNodeId, @@ -665,16 +760,6 @@ async def _reset_mfg_id(self, mfg_id: int) -> None: async def _set_source_route( self, nwk: zigpy.types.NWK, relays: list[zigpy.types.NWK] ) -> bool: - if self._ezsp.ezsp_version >= 8: - # Pretend EmberZNet knows about the device's relays if they are set (i.e. we - # did not receive a routing error) - try: - device = self.get_device(nwk=nwk) - except KeyError: - return False - else: - return device.relays is not None - (res,) = await self._ezsp.setSourceRoute(nwk, relays) return res == t.EmberStatus.SUCCESS @@ -845,10 +930,10 @@ async def permit_with_link_key( ) -> None: """Permits a new device to join with the given IEEE and link key.""" - v = await self._ezsp.addTransientLinkKey(node, link_key) + status = await self._ezsp.add_transient_link_key(node, link_key) - if v[0] != t.EmberStatus.SUCCESS: - raise Exception("Failed to set link key") + if status != t.EmberStatus.SUCCESS: + raise ControllerError("Failed to set link key") if self._ezsp.ezsp_version >= 8: await self._ezsp.setPolicy( @@ -938,7 +1023,7 @@ async def _get_free_buffers(self) -> int | None: def handle_route_record( self, nwk: t.EmberNodeId, - ieee: t.EmberEUI64, + ieee: t.EUI64, lqi: t.uint8_t, rssi: t.int8s, relays: t.LVList(t.EmberNodeId), diff --git a/bellows/zigbee/util.py b/bellows/zigbee/util.py index 38ff9b25..2aa5c0c6 100644 --- a/bellows/zigbee/util.py +++ b/bellows/zigbee/util.py @@ -29,30 +29,29 @@ def zha_security( | t.EmberInitialSecurityBitmask.REQUIRE_ENCRYPTED_KEY | t.EmberInitialSecurityBitmask.TRUST_CENTER_GLOBAL_LINK_KEY | t.EmberInitialSecurityBitmask.HAVE_NETWORK_KEY + | t.EmberInitialSecurityBitmask.NO_FRAME_COUNTER_RESET ) - isc.networkKey = t.EmberKeyData(network_info.network_key.key) + isc.networkKey = t.KeyData(network_info.network_key.key) isc.networkKeySequenceNumber = t.uint8_t(network_info.network_key.seq) if network_info.tc_link_key.partner_ieee != zigpy_t.EUI64.UNKNOWN: isc.bitmask |= t.EmberInitialSecurityBitmask.HAVE_TRUST_CENTER_EUI64 - isc.preconfiguredTrustCenterEui64 = t.EmberEUI64( + isc.preconfiguredTrustCenterEui64 = t.EUI64( network_info.tc_link_key.partner_ieee ) else: - isc.preconfiguredTrustCenterEui64 = t.EmberEUI64.convert( - "00:00:00:00:00:00:00:00" - ) + isc.preconfiguredTrustCenterEui64 = t.EUI64.convert("00:00:00:00:00:00:00:00") if use_hashed_tclk: if network_info.tc_link_key.key != zigpy_t.KeyData(b"ZigBeeAlliance09"): LOGGER.warning("Only the well-known TC Link Key is supported") isc.bitmask |= t.EmberInitialSecurityBitmask.TRUST_CENTER_USES_HASHED_LINK_KEY - isc.preconfiguredKey, _ = t.EmberKeyData.deserialize( + isc.preconfiguredKey, _ = t.KeyData.deserialize( bytes.fromhex(network_info.stack_specific["ezsp"]["hashed_tclk"]) ) else: - isc.preconfiguredKey = t.EmberKeyData(network_info.tc_link_key.key) + isc.preconfiguredKey = t.KeyData(network_info.tc_link_key.key) return isc @@ -80,7 +79,7 @@ def ezsp_key_to_zigpy_key(key, ezsp) -> zigpy.state.Key: def zigpy_key_to_ezsp_key(zigpy_key: zigpy.state.Key, ezsp): """Convert a zigpy `Key` into a `EmberKeyStruct`.""" key = ezsp.types.EmberKeyStruct() - key.key = ezsp.types.EmberKeyData(zigpy_key.key) + key.key = ezsp.types.KeyData(zigpy_key.key) key.bitmask = ezsp.types.EmberKeyStructBitmask(0) if zigpy_key.seq is not None: @@ -96,7 +95,7 @@ def zigpy_key_to_ezsp_key(zigpy_key: zigpy.state.Key, ezsp): key.bitmask |= ezsp.types.EmberKeyStructBitmask.KEY_HAS_INCOMING_FRAME_COUNTER if zigpy_key.partner_ieee is not None: - key.partnerEUI64 = t.EmberEUI64(zigpy_key.partner_ieee) + key.partnerEUI64 = t.EUI64(zigpy_key.partner_ieee) key.bitmask |= ezsp.types.EmberKeyStructBitmask.KEY_HAS_PARTNER_EUI64 return key diff --git a/tests/test_application.py b/tests/test_application.py index 46640247..aceeabb3 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -35,7 +35,7 @@ @pytest.fixture def ieee(init=0): - return t.EmberEUI64(map(t.uint8_t, range(init, init + 8))) + return t.EUI64(map(t.uint8_t, range(init, init + 8))) @pytest.fixture @@ -71,6 +71,7 @@ def ezsp_mock(ieee): mock_ezsp.wait_for_stack_status.return_value.__enter__ = AsyncMock( return_value=t.EmberStatus.NETWORK_UP ) + mock_ezsp.add_transient_link_key = AsyncMock(return_value=t.EmberStatus.SUCCESS) mock_ezsp._protocol = AsyncMock() type(mock_ezsp).types = ezsp_t7 @@ -183,11 +184,11 @@ async def mock_leave(*args, **kwargs): bitmask=t.EmberKeyStructBitmask.KEY_HAS_SEQUENCE_NUMBER | t.EmberKeyStructBitmask.KEY_HAS_OUTGOING_FRAME_COUNTER, type=t.EmberKeyType.CURRENT_NETWORK_KEY, - key=t.EmberKeyData(b"ActualNetworkKey"), + key=t.KeyData(b"ActualNetworkKey"), outgoingFrameCounter=t.uint32_t(0x12345678), incomingFrameCounter=t.uint32_t(0x00000000), sequenceNumber=t.uint8_t(1), - partnerEUI64=t.EmberEUI64.convert("ff:ff:ff:ff:ff:ff:ff:ff"), + partnerEUI64=t.EUI64.convert("ff:ff:ff:ff:ff:ff:ff:ff"), ), ] ) @@ -261,7 +262,7 @@ async def test_startup_ezsp_ver7(app, ieee): async def test_startup_ezsp_ver8(app, ieee): app.state.counters["ezsp_counters"] = MagicMock() - ieee_1 = t.EmberEUI64.convert("11:22:33:44:55:66:77:88") + ieee_1 = t.EUI64.convert("11:22:33:44:55:66:77:88") dev_1 = app.add_device(ieee_1, 0x1234) dev_1.relays = [ t.EmberNodeId(0x2222), @@ -615,49 +616,33 @@ async def test_permit_ncp(app): assert app._ezsp.permitJoining.call_count == 1 -@pytest.mark.parametrize( - "version, tc_policy_count, ezsp_types", - ((4, 0, t), (5, 0, ezsp_t5), (6, 0, ezsp_t6), (7, 0, ezsp_t7), (8, 1, ezsp_t8)), -) -async def test_permit_with_link_key_ieee( - app, ieee, version, tc_policy_count, ezsp_types -): - p1 = patch("zigpy.application.ControllerApplication.permit") - p2 = patch.object(app._ezsp, "types", ezsp_types) - - with patch.object(app._ezsp, "ezsp_version", version), p1 as permit_mock, p2: +async def test_permit_with_link_key(app, ieee): + with patch("zigpy.application.ControllerApplication.permit") as permit_mock: await app.permit_with_link_key( ieee, - zigpy_t.KeyData.convert("11:22:33:44:55:66:77:88:11:22:33:44:55:66:77:88:"), + zigpy_t.KeyData.convert("11:22:33:44:55:66:77:88:11:22:33:44:55:66:77:88"), 60, ) - assert app._ezsp.addTransientLinkKey.await_count == 1 assert permit_mock.await_count == 1 - assert app._ezsp.setPolicy.await_count == tc_policy_count + assert app._ezsp.add_transient_link_key.await_count == 1 -async def test_permit_with_link_key_failed_add_key(app, ieee): - app._ezsp.addTransientLinkKey = AsyncMock(return_value=[1, 1]) +async def test_permit_with_link_key_failure(app, ieee): + app._ezsp.add_transient_link_key.return_value = t.EmberStatus.ERR_FATAL - with pytest.raises(Exception): - await app.permit_with_link_key( - ieee, - zigpy_t.KeyData.convert("11:22:33:44:55:66:77:88:11:22:33:44:55:66:77:88:"), - 60, - ) + with patch("zigpy.application.ControllerApplication.permit") as permit_mock: + with pytest.raises(ControllerError): + await app.permit_with_link_key( + ieee, + zigpy_t.KeyData.convert( + "11:22:33:44:55:66:77:88:11:22:33:44:55:66:77:88" + ), + 60, + ) - -async def test_permit_with_link_key_failed_set_policy(app, ieee): - app._ezsp.addTransientLinkKey = AsyncMock(return_value=[0]) - app._ezsp.setPolicy = AsyncMock(return_value=[1]) - - with pytest.raises(Exception): - await app.permit_with_link_key( - ieee, - zigpy_t.KeyData.convert("11:22:33:44:55:66:77:88:11:22:33:44:55:66:77:88:"), - 60, - ) + assert permit_mock.await_count == 0 + assert app._ezsp.add_transient_link_key.await_count == 1 @pytest.fixture @@ -775,33 +760,6 @@ async def test_send_packet_unicast_source_route_ezsp7(make_app, packet): ) -async def test_send_packet_unicast_source_route_ezsp8_have_relays(make_app, packet): - app = make_app({zigpy.config.CONF_SOURCE_ROUTING: True}) - app._ezsp.ezsp_version = 8 - - device = MagicMock() - device.relays = [0x0003] - - app.get_device = MagicMock(return_value=device) - - packet.source_route = [0x0001, 0x0002] - await _test_send_packet_unicast(app, packet) - - aps_frame = app._ezsp.sendUnicast.mock_calls[0].args[2] - assert t.EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY not in aps_frame.options - - -async def test_send_packet_unicast_source_route_ezsp8_no_relays(make_app, packet): - app = make_app({zigpy.config.CONF_SOURCE_ROUTING: True}) - app._ezsp.ezsp_version = 8 - - packet.source_route = [0x0001, 0x0002] - await _test_send_packet_unicast(app, packet) - - aps_frame = app._ezsp.sendUnicast.mock_calls[0].args[2] - assert t.EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY in aps_frame.options - - async def test_send_packet_unicast_retries_success(app, packet): await _test_send_packet_unicast( app, @@ -1470,7 +1428,7 @@ async def test_set_mfg_id(ieee, expected_mfg_id, app, ezsp_mock): "trustCenterJoinHandler", [ 1, - t.EmberEUI64.convert(ieee), + t.EUI64.convert(ieee), t.EmberDeviceUpdate.STANDARD_SECURITY_UNSECURED_JOIN, t.EmberJoinDecision.NO_ACTION, sentinel.parent, @@ -1481,7 +1439,7 @@ async def test_set_mfg_id(ieee, expected_mfg_id, app, ezsp_mock): "trustCenterJoinHandler", [ 1, - t.EmberEUI64.convert(ieee), + t.EUI64.convert(ieee), t.EmberDeviceUpdate.STANDARD_SECURITY_UNSECURED_JOIN, t.EmberJoinDecision.NO_ACTION, sentinel.parent, @@ -1585,32 +1543,6 @@ async def test_startup_new_coordinator_no_groups_joined(app, ieee): p2.assert_not_called() -@pytest.mark.parametrize("enable_source_routing", [True, False]) -async def test_startup_source_routing(make_app, ieee, enable_source_routing): - """Existing relays are cleared on startup.""" - - app = make_app({zigpy.config.CONF_SOURCE_ROUTING: enable_source_routing}) - - app._ezsp.ezsp_version = 9 - app._ezsp.update_policies = AsyncMock() - - app._ensure_network_running = AsyncMock() - app.load_network_info = AsyncMock() - app.state.node_info.ieee = ieee - - mock_device = MagicMock() - mock_device.relays = sentinel.relays - mock_device.initialize = AsyncMock() - app.devices[0xABCD] = mock_device - - await app.start_network() - - if enable_source_routing: - assert mock_device.relays is None - else: - assert mock_device.relays is sentinel.relays - - @pytest.mark.parametrize( "scan_results", [ diff --git a/tests/test_application_network_state.py b/tests/test_application_network_state.py index d2342bb4..1c33deea 100644 --- a/tests/test_application_network_state.py +++ b/tests/test_application_network_state.py @@ -1,11 +1,13 @@ import importlib.metadata import pytest +import zigpy.exceptions import zigpy.state import zigpy.types as zigpy_t import zigpy.zdo.types as zdo_t from bellows.exception import EzspError +from bellows.ezsp import EZSP import bellows.types as t from tests.async_mock import AsyncMock, PropertyMock @@ -64,7 +66,9 @@ def network_info(node_info): partner_ieee=zigpy_t.EUI64.convert("EC:1B:BD:FF:FE:2F:41:A4"), ), ], - children=[zigpy_t.EUI64.convert("00:0B:57:FF:FE:2B:D4:57")], + children=[ + zigpy_t.EUI64.convert("00:0B:57:FF:FE:2B:D4:57"), + ], # If exposed by the stack, NWK addresses of other connected devices on the network nwk_addresses={ # Two routers @@ -78,9 +82,11 @@ def network_info(node_info): ) -def _mock_app_for_load(app): +def _mock_app_for_load(app, ezsp_ver=7): """Mock methods on the application and EZSP objects to run network state code.""" ezsp = app._ezsp + ezsp.ezsp_version = ezsp_ver + type(ezsp).types = EZSP._BY_VERSION[ezsp_ver].types app._ensure_network_running = AsyncMock() ezsp.getNetworkParameters = AsyncMock( @@ -101,10 +107,34 @@ def _mock_app_for_load(app): ) ezsp.getNodeId = AsyncMock(return_value=[t.EmberNodeId(0x0000)]) - ezsp.getEui64 = AsyncMock( - return_value=[t.EmberEUI64.convert("00:12:4b:00:1c:a1:b8:46")] + ezsp.getEui64 = AsyncMock(return_value=[t.EUI64.convert("00:12:4b:00:1c:a1:b8:46")]) + + def get_configuration_value(config_id): + size = { + app._ezsp.types.EzspConfigId.CONFIG_ADDRESS_TABLE_SIZE: t.uint8_t(20), + app._ezsp.types.EzspConfigId.CONFIG_KEY_TABLE_SIZE: t.uint8_t(13), + app._ezsp.types.EzspConfigId.CONFIG_SECURITY_LEVEL: t.uint8_t(5), + }[config_id] + + return [app._ezsp.types.EmberStatus.SUCCESS, size] + + ezsp.getConfigurationValue = AsyncMock(side_effect=get_configuration_value) + + ezsp.getCurrentSecurityState = AsyncMock( + return_value=( + t.EmberStatus.SUCCESS, + ezsp.types.EmberCurrentSecurityState( + bitmask=( + t.EmberCurrentSecurityBitmask.TRUST_CENTER_USES_HASHED_LINK_KEY + | 64 + | 32 + | t.EmberCurrentSecurityBitmask.HAVE_TRUST_CENTER_LINK_KEY + | t.EmberCurrentSecurityBitmask.GLOBAL_LINK_KEY + ), + trustCenterLongAddress=t.EUI64.convert("00:12:4b:00:1c:a1:b8:46"), + ), + ) ) - ezsp.getConfigurationValue = AsyncMock(return_value=[t.EmberStatus.SUCCESS, 5]) def get_key(key_type): key = { @@ -114,11 +144,11 @@ def get_key(key_type): | t.EmberKeyStructBitmask.KEY_HAS_SEQUENCE_NUMBER ), type=ezsp.types.EmberKeyType.CURRENT_NETWORK_KEY, - key=t.EmberKeyData(bytes.fromhex("2ccade06b3090c310315b3d574d3c85a")), + key=t.KeyData.convert("2ccade06b3090c310315b3d574d3c85a"), outgoingFrameCounter=118785, incomingFrameCounter=0, sequenceNumber=108, - partnerEUI64=t.EmberEUI64.convert("00:00:00:00:00:00:00:00"), + partnerEUI64=t.EUI64.convert("00:00:00:00:00:00:00:00"), ), ezsp.types.EmberKeyType.TRUST_CENTER_LINK_KEY: ezsp.types.EmberKeyStruct( bitmask=( @@ -127,32 +157,46 @@ def get_key(key_type): | t.EmberKeyStructBitmask.KEY_HAS_OUTGOING_FRAME_COUNTER ), type=ezsp.types.EmberKeyType.TRUST_CENTER_LINK_KEY, - key=t.EmberKeyData(bytes.fromhex("abcdabcdabcdabcdabcdabcdabcdabcd")), + key=t.KeyData.convert("abcdabcdabcdabcdabcdabcdabcdabcd"), outgoingFrameCounter=8712428, incomingFrameCounter=0, sequenceNumber=0, - partnerEUI64=t.EmberEUI64.convert("00:12:4b:00:1c:a1:b8:46"), + partnerEUI64=t.EUI64.convert("00:12:4b:00:1c:a1:b8:46"), ), }[key_type] return (t.EmberStatus.SUCCESS, key) ezsp.getKey = AsyncMock(side_effect=get_key) - ezsp.getCurrentSecurityState = AsyncMock( - return_value=( - t.EmberStatus.SUCCESS, - ezsp.types.EmberCurrentSecurityState( - bitmask=( - t.EmberCurrentSecurityBitmask.TRUST_CENTER_USES_HASHED_LINK_KEY - | 64 - | 32 - | t.EmberCurrentSecurityBitmask.HAVE_TRUST_CENTER_LINK_KEY - | t.EmberCurrentSecurityBitmask.GLOBAL_LINK_KEY + + if ezsp_ver >= 13: + + def export_key(security_context): + key = { + ezsp.types.sl_zb_sec_man_key_type_t.NETWORK: t.KeyData.convert( + "2ccade06b3090c310315b3d574d3c85a" ), - trustCenterLongAddress=t.EmberEUI64.convert("00:12:4b:00:1c:a1:b8:46"), - ), + ezsp.types.sl_zb_sec_man_key_type_t.TC_LINK: t.KeyData.convert( + "abcdabcdabcdabcdabcdabcdabcdabcd" + ), + }[security_context.core_key_type] + + return (key, t.EmberStatus.SUCCESS) + + ezsp.exportKey = AsyncMock(side_effect=export_key) + ezsp.getNetworkKeyInfo = AsyncMock( + return_value=[ + ezsp.types.sl_Status.SL_STATUS_OK, + 0x1234, + ezsp.types.sl_zb_sec_man_network_key_info_t( + network_key_set=True, + alternate_network_key_set=False, + network_key_sequence_number=108, + alt_network_key_sequence_number=0, + network_key_frame_counter=118785, + ), + ] ) - ) async def test_load_network_info_no_devices(app, network_info, node_info): @@ -170,10 +214,32 @@ async def test_load_network_info_no_devices(app, network_info, node_info): ) -@pytest.mark.parametrize("ezsp_ver", [4, 6, 7]) +async def test_load_network_info_no_key_set(app, network_info, node_info): + """Test loading network info in v13+ when no network key is set.""" + _mock_app_for_load(app, ezsp_ver=13) + + app._ezsp.getNetworkKeyInfo = AsyncMock( + return_value=[ + app._ezsp.types.sl_Status.SL_STATUS_OK, + 0x1234, + app._ezsp.types.sl_zb_sec_man_network_key_info_t( + network_key_set=False, # Not set + alternate_network_key_set=False, + network_key_sequence_number=108, + alt_network_key_sequence_number=0, + network_key_frame_counter=118785, + ), + ] + ) + + with pytest.raises(zigpy.exceptions.NetworkNotFormed): + await app.load_network_info(load_devices=False) + + +@pytest.mark.parametrize("ezsp_ver", [4, 6, 7, 13]) async def test_load_network_info_with_devices(app, network_info, node_info, ezsp_ver): """Test `load_network_info(load_devices=True)`""" - _mock_app_for_load(app) + _mock_app_for_load(app, ezsp_ver) def get_child_data_v6(index): if index == 0: @@ -184,7 +250,7 @@ def get_child_data_v6(index): return ( status, t.EmberNodeId(0xC06B), - t.EmberEUI64.convert("00:0b:57:ff:fe:2b:d4:57"), + t.EUI64.convert("00:0b:57:ff:fe:2b:d4:57"), t.EmberNodeType.SLEEPY_END_DEVICE, ) @@ -197,7 +263,7 @@ def get_child_data_v7(index): return ( status, app._ezsp.types.EmberChildData( - eui64=t.EmberEUI64.convert("00:0b:57:ff:fe:2b:d4:57"), + eui64=t.EUI64.convert("00:0b:57:ff:fe:2b:d4:57"), type=t.EmberNodeType.SLEEPY_END_DEVICE, id=t.EmberNodeId(0xC06B), phy=0, @@ -209,72 +275,122 @@ def get_child_data_v7(index): app._ezsp.ezsp_version = ezsp_ver app._ezsp.getChildData = AsyncMock( side_effect={ + 13: get_child_data_v7, 7: get_child_data_v7, 6: get_child_data_v6, 4: get_child_data_v6, }[ezsp_ver] ) - def get_key_table_entry(index): - if index == 0: - return ( - t.EmberStatus.SUCCESS, - app._ezsp.types.EmberKeyStruct( - bitmask=( - t.EmberKeyStructBitmask.KEY_IS_AUTHORIZED - | t.EmberKeyStructBitmask.KEY_HAS_PARTNER_EUI64 - | t.EmberKeyStructBitmask.KEY_HAS_INCOMING_FRAME_COUNTER - | t.EmberKeyStructBitmask.KEY_HAS_OUTGOING_FRAME_COUNTER + if ezsp_ver < 13: + + def get_key_table_entry(index): + if index == 0: + return ( + t.EmberStatus.SUCCESS, + app._ezsp.types.EmberKeyStruct( + bitmask=( + t.EmberKeyStructBitmask.KEY_IS_AUTHORIZED + | t.EmberKeyStructBitmask.KEY_HAS_PARTNER_EUI64 + | t.EmberKeyStructBitmask.KEY_HAS_INCOMING_FRAME_COUNTER + | t.EmberKeyStructBitmask.KEY_HAS_OUTGOING_FRAME_COUNTER + ), + type=app._ezsp.types.EmberKeyType.APPLICATION_LINK_KEY, + key=t.KeyData.convert("857C05003E761AF9689A49416A605C76"), + outgoingFrameCounter=3792973670, + incomingFrameCounter=1083290572, + sequenceNumber=147, + partnerEUI64=t.EUI64.convert("CC:CC:CC:FF:FE:E6:8E:CA"), ), - type=app._ezsp.types.EmberKeyType.APPLICATION_LINK_KEY, - key=t.EmberKeyData( - bytes.fromhex("857C05003E761AF9689A49416A605C76") + ) + elif index == 1: + return ( + t.EmberStatus.SUCCESS, + app._ezsp.types.EmberKeyStruct( + bitmask=( + t.EmberKeyStructBitmask.KEY_IS_AUTHORIZED + | t.EmberKeyStructBitmask.KEY_HAS_PARTNER_EUI64 + | t.EmberKeyStructBitmask.KEY_HAS_INCOMING_FRAME_COUNTER + | t.EmberKeyStructBitmask.KEY_HAS_OUTGOING_FRAME_COUNTER + ), + type=app._ezsp.types.EmberKeyType.APPLICATION_LINK_KEY, + key=t.KeyData.convert("CA02E8BB757C94F89339D39CB3CDA7BE"), + outgoingFrameCounter=2597245184, + incomingFrameCounter=824424412, + sequenceNumber=19, + partnerEUI64=t.EUI64.convert("EC:1B:BD:FF:FE:2F:41:A4"), ), - outgoingFrameCounter=3792973670, - incomingFrameCounter=1083290572, - sequenceNumber=147, - partnerEUI64=t.EmberEUI64.convert("CC:CC:CC:FF:FE:E6:8E:CA"), - ), - ) - elif index == 1: + ) + elif index >= 12: + status = t.EmberStatus.INDEX_OUT_OF_RANGE + else: + status = t.EmberStatus.TABLE_ENTRY_ERASED + return ( - t.EmberStatus.SUCCESS, + status, app._ezsp.types.EmberKeyStruct( - bitmask=( - t.EmberKeyStructBitmask.KEY_IS_AUTHORIZED - | t.EmberKeyStructBitmask.KEY_HAS_PARTNER_EUI64 - | t.EmberKeyStructBitmask.KEY_HAS_INCOMING_FRAME_COUNTER - | t.EmberKeyStructBitmask.KEY_HAS_OUTGOING_FRAME_COUNTER + bitmask=t.EmberKeyStructBitmask(244), + type=app._ezsp.types.EmberKeyType(0x46), + key=t.KeyData.convert("b8a11c004b1200cdabcdabcdabcdabcd"), + outgoingFrameCounter=8192, + incomingFrameCounter=0, + sequenceNumber=0, + partnerEUI64=t.EUI64.convert("00:12:4b:00:1c:a1:b8:46"), + ), + ) + + app._ezsp.getKeyTableEntry = AsyncMock(side_effect=get_key_table_entry) + else: + + def export_link_key_by_index(index): + if index == 0: + return ( + t.EUI64.convert("CC:CC:CC:FF:FE:E6:8E:CA"), + t.KeyData.convert("857C05003E761AF9689A49416A605C76"), + app._ezsp.types.sl_zb_sec_man_aps_key_metadata_t( + bitmask=( + t.EmberKeyStructBitmask.KEY_IS_AUTHORIZED + | t.EmberKeyStructBitmask.KEY_HAS_PARTNER_EUI64 + | t.EmberKeyStructBitmask.KEY_HAS_INCOMING_FRAME_COUNTER + | t.EmberKeyStructBitmask.KEY_HAS_OUTGOING_FRAME_COUNTER + ), + outgoing_frame_counter=3792973670, + incoming_frame_counter=1083290572, + ttl_in_seconds=0, ), - type=app._ezsp.types.EmberKeyType.APPLICATION_LINK_KEY, - key=t.EmberKeyData( - bytes.fromhex("CA02E8BB757C94F89339D39CB3CDA7BE") + app._ezsp.types.sl_Status.SL_STATUS_OK, + ) + elif index == 1: + return ( + t.EUI64.convert("EC:1B:BD:FF:FE:2F:41:A4"), + t.KeyData.convert("CA02E8BB757C94F89339D39CB3CDA7BE"), + app._ezsp.types.sl_zb_sec_man_aps_key_metadata_t( + bitmask=( + t.EmberKeyStructBitmask.KEY_IS_AUTHORIZED + | t.EmberKeyStructBitmask.KEY_HAS_PARTNER_EUI64 + | t.EmberKeyStructBitmask.KEY_HAS_INCOMING_FRAME_COUNTER + | t.EmberKeyStructBitmask.KEY_HAS_OUTGOING_FRAME_COUNTER + ), + outgoing_frame_counter=2597245184, + incoming_frame_counter=824424412, + ttl_in_seconds=0, ), - outgoingFrameCounter=2597245184, - incomingFrameCounter=824424412, - sequenceNumber=19, - partnerEUI64=t.EmberEUI64.convert("EC:1B:BD:FF:FE:2F:41:A4"), + app._ezsp.types.sl_Status.SL_STATUS_OK, + ) + + return ( + t.EUI64.convert("7f:c9:35:e1:b0:00:00:00"), + t.KeyData.convert("80:45:38:73:55:00:00:00:08:e4:35:c9:7f:00:00:00"), + app._ezsp.types.sl_zb_sec_man_aps_key_metadata_t( + bitmask=t.EmberKeyStructBitmask(43976), + outgoing_frame_counter=85, + incoming_frame_counter=0, + ttl_in_seconds=0, ), + app._ezsp.types.sl_Status.SL_STATUS_NOT_FOUND, ) - elif index >= 12: - status = t.EmberStatus.INDEX_OUT_OF_RANGE - else: - status = t.EmberStatus.TABLE_ENTRY_ERASED - return ( - status, - app._ezsp.types.EmberKeyStruct( - bitmask=t.EmberKeyStructBitmask(244), - type=app._ezsp.types.EmberKeyType(0x46), - key=t.EmberKeyData(bytes.fromhex("b8a11c004b1200cdabcdabcdabcdabcd")), - outgoingFrameCounter=8192, - incomingFrameCounter=0, - sequenceNumber=0, - partnerEUI64=t.EmberEUI64.convert("00:12:4b:00:1c:a1:b8:46"), - ), - ) - - app._ezsp.getKeyTableEntry = AsyncMock(side_effect=get_key_table_entry) + app._ezsp.exportLinkKeyByIndex = AsyncMock(side_effect=export_link_key_by_index) def get_addr_table_node_id(index): return ( @@ -291,17 +407,17 @@ def get_addr_table_node_id(index): def get_addr_table_eui64(index): if index < 16: - return (t.EmberEUI64.convert("ff:ff:ff:ff:ff:ff:ff:ff"),) + return (t.EUI64.convert("ff:ff:ff:ff:ff:ff:ff:ff"),) elif 16 <= index <= 18: return ( { - 16: t.EmberEUI64.convert("cc:cc:cc:ff:fe:e6:8e:ca"), - 17: t.EmberEUI64.convert("ec:1b:bd:ff:fe:2f:41:a4"), - 18: t.EmberEUI64.convert("00:00:00:00:00:00:00:00"), + 16: t.EUI64.convert("cc:cc:cc:ff:fe:e6:8e:ca"), + 17: t.EUI64.convert("ec:1b:bd:ff:fe:2f:41:a4"), + 18: t.EUI64.convert("00:00:00:00:00:00:00:00"), }[index], ) else: - return (t.EmberEUI64.convert("00:00:00:00:00:00:00:00"),) + return (t.EUI64.convert("00:00:00:00:00:00:00:00"),) app._ezsp.getAddressTableRemoteEui64 = AsyncMock(side_effect=get_addr_table_eui64) @@ -325,6 +441,10 @@ def get_addr_table_eui64(index): key_table=[key.replace(seq=0) for key in network_info.key_table], nwk_addresses=nwk_addresses, metadata=app.state.network_info.metadata, + # TC link key does not have a TX counter + tc_link_key=network_info.tc_link_key.replace( + tx_counter=app.state.network_info.tc_link_key.tx_counter + ), ) assert app.state.node_info == node_info @@ -334,52 +454,89 @@ def get_addr_table_eui64(index): app._ezsp.getAddressTableRemoteEui64.assert_not_called() -def _mock_app_for_write(app, network_info, node_info, ezsp_ver=None): +def _mock_app_for_write(app, network_info, node_info, ezsp_ver=7): ezsp = app._ezsp - ezsp.networkState = AsyncMock( - return_value=[ezsp.types.EmberNetworkStatus.JOINED_NETWORK] - ) - ezsp.leaveNetwork = AsyncMock(return_value=[t.EmberStatus.NETWORK_DOWN]) - ezsp.getEui64 = AsyncMock( - return_value=[t.EmberEUI64.convert("00:12:4b:00:1c:a1:b8:46")] - ) + ezsp.ezsp_version = ezsp_ver + type(ezsp).types = EZSP._BY_VERSION[ezsp_ver].types + + network_state = ezsp.types.EmberNetworkStatus.JOINED_NETWORK + ezsp.networkState = AsyncMock(side_effect=lambda: [network_state]) + + def leave_network(): + nonlocal network_state + network_state = ezsp.types.EmberNetworkStatus.NO_NETWORK + + return [t.EmberStatus.NETWORK_DOWN] + + def form_network(params): + nonlocal network_state + network_state = ezsp.types.EmberNetworkStatus.JOINED_NETWORK + + return [t.EmberStatus.SUCCESS] + + ezsp.leaveNetwork = AsyncMock(side_effect=leave_network) + ezsp.formNetwork = AsyncMock(side_effect=form_network) + + ezsp.getEui64 = AsyncMock(return_value=[t.EUI64.convert("00:12:4b:00:1c:a1:b8:46")]) ezsp.setInitialSecurityState = AsyncMock(return_value=[t.EmberStatus.SUCCESS]) ezsp.clearKeyTable = AsyncMock(return_value=[t.EmberStatus.SUCCESS]) ezsp.getConfigurationValue = AsyncMock( return_value=[t.EmberStatus.SUCCESS, t.uint8_t(200)] ) - ezsp.addOrUpdateKeyTableEntry = AsyncMock( - side_effect=[ - # Only the first one succeeds - (t.EmberStatus.SUCCESS,), - ] - + [ - # The rest will fail - (t.EmberStatus.TABLE_FULL,), - ] - * 20 - ) - if ezsp_ver is not None: - ezsp.ezsp_version = ezsp_ver + if ezsp_ver >= 13: + ezsp.importLinkKey = AsyncMock( + side_effect=[ + # Only the first one succeeds + (t.EmberStatus.SUCCESS,), + ] + + [ + # The rest will fail + (t.EmberStatus.TABLE_FULL,), + ] + * 20 + ) + else: + ezsp.addOrUpdateKeyTableEntry = AsyncMock( + side_effect=[ + # Only the first one succeeds + (t.EmberStatus.SUCCESS,), + ] + + [ + # The rest will fail + (t.EmberStatus.TABLE_FULL,), + ] + * 20 + ) + + if ezsp_ver == 4: + ezsp.setValue = AsyncMock(return_value=[t.EmberStatus.BAD_ARGUMENT]) + else: + ezsp.setValue = AsyncMock(return_value=[t.EmberStatus.SUCCESS]) - if ezsp_ver == 4: - ezsp.setValue = AsyncMock(return_value=[t.EmberStatus.BAD_ARGUMENT]) - else: - ezsp.setValue = AsyncMock(return_value=[t.EmberStatus.SUCCESS]) + if ezsp_ver >= 9: + ezsp.setChildData = AsyncMock(return_value=[t.EmberStatus.SUCCESS]) - ezsp.formNetwork = AsyncMock(return_value=[t.EmberStatus.SUCCESS]) ezsp.setValue = AsyncMock(return_value=[t.EmberStatus.SUCCESS]) ezsp.setMfgToken = AsyncMock(return_value=[t.EmberStatus.SUCCESS]) ezsp.getTokenData = AsyncMock(return_value=[t.EmberStatus.LIBRARY_NOT_PRESENT, b""]) -@pytest.mark.parametrize("ezsp_ver", [4, 7]) +@pytest.mark.parametrize("ezsp_ver", [4, 7, 13]) async def test_write_network_info(app, network_info, node_info, ezsp_ver): _mock_app_for_write(app, network_info, node_info, ezsp_ver) - await app.write_network_info(network_info=network_info, node_info=node_info) + await app.write_network_info( + network_info=network_info.replace( + children=network_info.children + + [ + # Bogus child that can't be restored + zigpy_t.EUI64.convert("FF:FF:57:FF:FE:2B:D4:57") + ] + ), + node_info=node_info, + ) @pytest.mark.parametrize("can_burn", [True, False]) @@ -391,7 +548,7 @@ async def test_write_network_info_write_eui64( _mock_app_for_write(app, network_info, node_info) # Differs from what is in `node_info` - app._ezsp.getEui64.return_value = [t.EmberEUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA")] + app._ezsp.getEui64.return_value = [t.EUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA")] app._ezsp.can_burn_userdata_custom_eui64 = AsyncMock(return_value=can_burn) app._ezsp.can_rewrite_custom_eui64 = AsyncMock(return_value=can_rewrite) diff --git a/tests/test_ezsp.py b/tests/test_ezsp.py index 6b5c1e96..5c2933eb 100644 --- a/tests/test_ezsp.py +++ b/tests/test_ezsp.py @@ -545,8 +545,8 @@ async def test_can_rewrite_custom_eui64_old_ezsp(ezsp_f): async def test_write_custom_eui64(ezsp_f): """Test writing a custom EUI64.""" - old_eui64 = t.EmberEUI64.convert("AA" * 8) - new_eui64 = t.EmberEUI64.convert("BB" * 8) + old_eui64 = t.EUI64.convert("AA" * 8) + new_eui64 = t.EUI64.convert("BB" * 8) ezsp_f.getEui64 = AsyncMock(return_value=[old_eui64]) ezsp_f.setMfgToken = AsyncMock(return_value=[t.EmberStatus.SUCCESS]) @@ -614,8 +614,8 @@ async def test_write_custom_eui64(ezsp_f): async def test_write_custom_eui64_rcp(ezsp_f): """Test writing a custom EUI64 with RPC firmware.""" - old_eui64 = t.EmberEUI64.convert("AA" * 8) - new_eui64 = t.EmberEUI64.convert("BB" * 8) + old_eui64 = t.EUI64.convert("AA" * 8) + new_eui64 = t.EUI64.convert("BB" * 8) ezsp_f.getEui64 = AsyncMock(return_value=[old_eui64]) ezsp_f.setMfgToken = AsyncMock(return_value=[t.EmberStatus.INVALID_CALL]) diff --git a/tests/test_ezsp_v10.py b/tests/test_ezsp_v10.py index bcf6a983..6b8ffdf1 100644 --- a/tests/test_ezsp_v10.py +++ b/tests/test_ezsp_v10.py @@ -28,7 +28,11 @@ def test_ezsp_frame_rx(ezsp_f): async def test_pre_permit(ezsp_f): """Test pre permit.""" p1 = patch.object(ezsp_f, "setPolicy", new=AsyncMock()) - p2 = patch.object(ezsp_f, "addTransientLinkKey", new=AsyncMock()) + p2 = patch.object( + ezsp_f, + "addTransientLinkKey", + new=AsyncMock(return_value=[ezsp_f.types.EmberStatus.SUCCESS]), + ) with p1 as pre_permit_mock, p2 as tclk_mock: await ezsp_f.pre_permit(-1.9) assert pre_permit_mock.await_count == 2 @@ -266,6 +270,7 @@ def test_command_frames(ezsp_f): "setRoutingShortcutThreshold": 0x00D0, "setSecurityKey": 0x00CA, "setSecurityParameters": 0x00CB, + "setSourceRoute": 0x00AE, "setSourceRouteDiscoveryMode": 0x005A, "setTimer": 0x000E, "setToken": 0x0009, diff --git a/tests/test_ezsp_v11.py b/tests/test_ezsp_v11.py index 84f201c8..e387d491 100644 --- a/tests/test_ezsp_v11.py +++ b/tests/test_ezsp_v11.py @@ -28,7 +28,11 @@ def test_ezsp_frame_rx(ezsp_f): async def test_pre_permit(ezsp_f): """Test pre permit.""" p1 = patch.object(ezsp_f, "setPolicy", new=AsyncMock()) - p2 = patch.object(ezsp_f, "addTransientLinkKey", new=AsyncMock()) + p2 = patch.object( + ezsp_f, + "addTransientLinkKey", + new=AsyncMock(return_value=[ezsp_f.types.EmberStatus.SUCCESS]), + ) with p1 as pre_permit_mock, p2 as tclk_mock: await ezsp_f.pre_permit(-1.9) assert pre_permit_mock.await_count == 2 @@ -266,6 +270,7 @@ def test_command_frames(ezsp_f): "setRoutingShortcutThreshold": 0x00D0, "setSecurityKey": 0x00CA, "setSecurityParameters": 0x00CB, + "setSourceRoute": 0x00AE, "setSourceRouteDiscoveryMode": 0x005A, "setTimer": 0x000E, "setToken": 0x0009, diff --git a/tests/test_ezsp_v12.py b/tests/test_ezsp_v12.py index 871f2184..9bb9fe7b 100644 --- a/tests/test_ezsp_v12.py +++ b/tests/test_ezsp_v12.py @@ -28,7 +28,11 @@ def test_ezsp_frame_rx(ezsp_f): async def test_pre_permit(ezsp_f): """Test pre permit.""" p1 = patch.object(ezsp_f, "setPolicy", new=AsyncMock()) - p2 = patch.object(ezsp_f, "addTransientLinkKey", new=AsyncMock()) + p2 = patch.object( + ezsp_f, + "addTransientLinkKey", + new=AsyncMock(return_value=[ezsp_f.types.EmberStatus.SUCCESS]), + ) with p1 as pre_permit_mock, p2 as tclk_mock: await ezsp_f.pre_permit(-1.9) assert pre_permit_mock.await_count == 2 @@ -280,6 +284,7 @@ def test_command_frames(ezsp_f): "setRoutingShortcutThreshold": 0x00D0, "setSecurityKey": 0x00CA, "setSecurityParameters": 0x00CB, + "setSourceRoute": 0x00AE, "setSourceRouteDiscoveryMode": 0x005A, "setTimer": 0x000E, "setToken": 0x0009, diff --git a/tests/test_ezsp_v13.py b/tests/test_ezsp_v13.py new file mode 100644 index 00000000..407f620f --- /dev/null +++ b/tests/test_ezsp_v13.py @@ -0,0 +1,320 @@ +import pytest + +import bellows.ezsp.v13 + +from .async_mock import AsyncMock, MagicMock, patch + + +@pytest.fixture +def ezsp_f(): + """EZSP v13 protocol handler.""" + return bellows.ezsp.v13.EZSPv13(MagicMock(), MagicMock()) + + +def test_ezsp_frame(ezsp_f): + ezsp_f._seq = 0x22 + data = ezsp_f._ezsp_frame("version", 13) + assert data == b"\x22\x00\x01\x00\x00\x0d" + + +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] + + +async def test_pre_permit(ezsp_f): + """Test pre permit.""" + p1 = patch.object(ezsp_f, "setPolicy", new=AsyncMock()) + p2 = patch.object( + ezsp_f, + "importTransientKey", + new=AsyncMock(return_value=[ezsp_f.types.sl_Status.SL_STATUS_OK]), + ) + with p1 as pre_permit_mock, p2 as tclk_mock: + await ezsp_f.pre_permit(-1.9) + assert pre_permit_mock.await_count == 2 + assert tclk_mock.await_count == 1 + + +def test_command_frames(ezsp_f): + """Test alphabetical list of frames matches the commands.""" + assert set(ezsp_f.COMMANDS) == set(command_frames) + for name, frame_id in command_frames.items(): + assert ezsp_f.COMMANDS[name][0] == frame_id + assert ezsp_f.COMMANDS_BY_ID[frame_id][0] == name + + +command_frames = { + "addEndpoint": 0x0002, + "addressTableEntryIsActive": 0x005B, + "aesEncrypt": 0x0094, + "aesMmoHash": 0x006F, + "bindingIsActive": 0x002E, + "bootloadTransmitCompleteHandler": 0x0093, + "broadcastNetworkKeySwitch": 0x0074, + "broadcastNextNetworkKey": 0x0073, + "calculateSmacs": 0x009F, + "calculateSmacs283k1": 0x00EA, + "calculateSmacsHandler": 0x00A0, + "calculateSmacsHandler283k1": 0x00EB, + "callback": 0x0006, + "checkKeyContext": 0x0110, + "childId": 0x0106, + "childJoinHandler": 0x0023, + "clearBindingTable": 0x002A, + "clearKeyTable": 0x00B1, + "clearStoredBeacons": 0x003C, + "clearTemporaryDataMaybeStoreLinkKey": 0x00A1, + "clearTemporaryDataMaybeStoreLinkKey283k1": 0x00EE, + "clearTransientLinkKeys": 0x006B, + "counterRolloverHandler": 0x00F2, + "customFrame": 0x0047, + "customFrameHandler": 0x0054, + "debugWrite": 0x0012, + "delayTest": 0x009D, + "deleteBinding": 0x002D, + "dGpSend": 0x00C6, + "dGpSentHandler": 0x00C7, + "dsaSign": 0x00A6, + "dsaSignHandler": 0x00A7, + "dsaVerify": 0x00A3, + "dsaVerify283k1": 0x00B0, + "dsaVerifyHandler": 0x0078, + "dutyCycleHandler": 0x004D, + "echo": 0x0081, + "energyScanRequest": 0x009C, + "energyScanResultHandler": 0x0048, + "eraseKeyTableEntry": 0x0076, + "exportKey": 0x0114, + "exportLinkKeyByEui": 0x010D, + "exportLinkKeyByIndex": 0x010F, + "exportTransientKeyByEui": 0x0113, + "exportTransientKeyByIndex": 0x0112, + "findAndRejoinNetwork": 0x0021, + "findKeyTableEntry": 0x0075, + "findUnusedPanId": 0x00D3, + "formNetwork": 0x001E, + "generateCbkeKeys": 0x00A4, + "generateCbkeKeys283k1": 0x00E8, + "generateCbkeKeysHandler": 0x009E, + "generateCbkeKeysHandler283k1": 0x00E9, + "getAddressTableRemoteEui64": 0x005E, + "getAddressTableRemoteNodeId": 0x005F, + "getApsKeyInfo": 0x010C, + "getBeaconClassificationParams": 0x00F3, + "getBinding": 0x002C, + "getBindingRemoteNodeId": 0x002F, + "getCertificate": 0x00A5, + "getCertificate283k1": 0x00EC, + "getChildData": 0x004A, + "getConfigurationValue": 0x0052, + "getCurrentDutyCycle": 0x004C, + "getCurrentSecurityState": 0x0069, + "getDutyCycleLimits": 0x004B, + "getDutyCycleState": 0x0035, + "getEui64": 0x0026, + "getExtendedTimeout": 0x007F, + "getExtendedValue": 0x0003, + "getFirstBeacon": 0x003D, + "getLibraryStatus": 0x0001, + "getLogicalChannel": 0x00BA, + "getMfgToken": 0x000B, + "getMulticastTableEntry": 0x0063, + "getNeighbor": 0x0079, + "getNeighborFrameCounter": 0x003E, + "getNetworkKeyInfo": 0x0116, + "getNetworkParameters": 0x0028, + "getNextBeacon": 0x0004, + "getNodeId": 0x0027, + "getNumStoredBeacons": 0x0008, + "getParentChildParameters": 0x0029, + "getParentClassificationEnabled": 0x00F0, + "getPhyInterfaceCount": 0x00FC, + "getPolicy": 0x0056, + "getRadioParameters": 0x00FD, + "getRandomNumber": 0x0049, + "getRouteTableEntry": 0x007B, + "getRoutingShortcutThreshold": 0x00D1, + "getSourceRouteTableEntry": 0x00C1, + "getSourceRouteTableFilledSize": 0x00C2, + "getSourceRouteTableTotalSize": 0x00C3, + "getStandaloneBootloaderVersionPlatMicroPhy": 0x0091, + "getTimer": 0x004E, + "getToken": 0x000A, + "getTokenCount": 0x0100, + "getTokenData": 0x0102, + "getTokenInfo": 0x0101, + "getTrueRandomEntropySource": 0x004F, + "getValue": 0x00AA, + "getXncpInfo": 0x0013, + "getZllPrimaryChannelMask": 0x00D9, + "getZllSecondaryChannelMask": 0x00DA, + "gpepIncomingMessageHandler": 0x00C5, + "gpProxyTableGetEntry": 0x00C8, + "gpProxyTableLookup": 0x00C0, + "gpProxyTableProcessGpPairing": 0x00C9, + "gpSecurityTestVectors": 0x0117, + "gpSinkCommission": 0x010A, + "gpSinkTableClearAll": 0x00E2, + "gpSinkTableFindOrAllocateEntry": 0x00E1, + "gpSinkTableGetEntry": 0x00DD, + "gpSinkTableGetNumberOfActiveEntries": 0x0118, + "gpSinkTableInit": 0x0070, + "gpSinkTableLookup": 0x00DE, + "gpSinkTableRemoveEntry": 0x00E0, + "gpSinkTableSetEntry": 0x00DF, + "gpTranslationTableClear": 0x010B, + "idConflictHandler": 0x007C, + "importKey": 0x0115, + "importLinkKey": 0x010E, + "importTransientKey": 0x0111, + "incomingBootloadMessageHandler": 0x0092, + "incomingManyToOneRouteRequestHandler": 0x007D, + "incomingMessageHandler": 0x0045, + "incomingNetworkStatusHandler": 0x00C4, + "incomingRouteErrorHandler": 0x0080, + "incomingRouteRecordHandler": 0x0059, + "incomingSenderEui64Handler": 0x0062, + "invalidCommand": 0x0058, + "isHubConnected": 0x00E6, + "isUpTimeLong": 0x00E5, + "isZllNetwork": 0x00BE, + "joinNetwork": 0x001F, + "joinNetworkDirectly": 0x003B, + "launchStandaloneBootloader": 0x008F, + "leaveNetwork": 0x0020, + "lookupEui64ByNodeId": 0x0061, + "lookupNodeIdByEui64": 0x0060, + "macFilterMatchMessageHandler": 0x0046, + "macPassthroughMessageHandler": 0x0097, + "maximumPayloadLength": 0x0033, + "messageSentHandler": 0x003F, + "mfglibEnd": 0x0084, + "mfglibGetChannel": 0x008B, + "mfglibGetPower": 0x008D, + "mfglibRxHandler": 0x008E, + "mfglibSendPacket": 0x0089, + "mfglibSetChannel": 0x008A, + "mfglibSetPower": 0x008C, + "mfglibStart": 0x0083, + "mfglibStartStream": 0x0087, + "mfglibStartTone": 0x0085, + "mfglibStopStream": 0x0088, + "mfglibStopTone": 0x0086, + "multiPhySetRadioChannel": 0x00FB, + "multiPhySetRadioPower": 0x00FA, + "multiPhyStart": 0x00F8, + "multiPhyStop": 0x00F9, + "neighborCount": 0x007A, + "networkFoundHandler": 0x001B, + "networkInit": 0x0017, + "networkState": 0x0018, + "noCallbacks": 0x0007, + "nop": 0x0005, + "permitJoining": 0x0022, + "pollCompleteHandler": 0x0043, + "pollForData": 0x0042, + "pollHandler": 0x0044, + "proxyBroadcast": 0x0037, + "rawTransmitCompleteHandler": 0x0098, + "readAndClearCounters": 0x0065, + "readAttribute": 0x0108, + "readCounters": 0x00F1, + "remoteDeleteBindingHandler": 0x0032, + "remoteSetBindingHandler": 0x0031, + "removeDevice": 0x00A8, + "replaceAddressTableEntry": 0x0082, + "requestLinkKey": 0x0014, + "resetNode": 0x0104, + "scanCompleteHandler": 0x001C, + "sendBootloadMessage": 0x0090, + "sendBroadcast": 0x0036, + "sendLinkPowerDeltaRequest": 0x00F7, + "sendManyToOneRouteRequest": 0x0041, + "sendMulticast": 0x0038, + "sendMulticastWithAlias": 0x003A, + "sendPanIdUpdate": 0x0057, + "sendRawMessage": 0x0096, + "sendRawMessageExtended": 0x0051, + "sendReply": 0x0039, + "sendTrustCenterLinkKey": 0x0067, + "sendUnicast": 0x0034, + "setAddressTableRemoteEui64": 0x005C, + "setAddressTableRemoteNodeId": 0x005D, + "setBeaconClassificationParams": 0x00EF, + "setBinding": 0x002B, + "setBindingRemoteNodeId": 0x0030, + "setBrokenRouteErrorCode": 0x0011, + "setChildData": 0x00AC, + "setChildData": 0x00AC, + "setConcentrator": 0x0010, + "setConfigurationValue": 0x0053, + "setDutyCycleLimitsInStack": 0x0040, + "setExtendedTimeout": 0x007E, + "setHubConnectivity": 0x00E4, + "setInitialSecurityState": 0x0068, + "setLogicalAndRadioChannel": 0x00B9, + "setLongUpTime": 0x00E3, + "setMacPollFailureWaitTime": 0x00F4, + "setManufacturerCode": 0x0015, + "setMfgToken": 0x000C, + "setMulticastTableEntry": 0x0064, + "setNeighborFrameCounter": 0x00AD, + "setNeighborFrameCounter": 0x00AD, + "setParentClassificationEnabled": 0x00E7, + "setPassiveAckConfig": 0x0105, + "setPolicy": 0x0055, + "setPowerDescriptor": 0x0016, + "setPreinstalledCbkeData": 0x00A2, + "setPreinstalledCbkeData283k1": 0x00ED, + "setRadioChannel": 0x009A, + "setRadioIeee802154CcaMode": 0x0095, + "setRadioIeee802154CcaMode": 0x0095, + "setRadioPower": 0x0099, + "setRoutingShortcutThreshold": 0x00D0, + "setSourceRoute": 0x00AE, + "setSourceRouteDiscoveryMode": 0x005A, + "setTimer": 0x000E, + "setToken": 0x0009, + "setTokenData": 0x0103, + "setValue": 0x00AB, + "setZllAdditionalState": 0x00D6, + "setZllNodeType": 0x00D5, + "setZllPrimaryChannelMask": 0x00DB, + "setZllSecondaryChannelMask": 0x00DC, + "stackStatusHandler": 0x0019, + "stackTokenChangedHandler": 0x000D, + "startScan": 0x001A, + "stopScan": 0x001D, + "switchNetworkKeyHandler": 0x006E, + "timerHandler": 0x000F, + "tokenFactoryReset": 0x0077, + "trustCenterJoinHandler": 0x0024, + "unicastCurrentNetworkKey": 0x0050, + "unicastNwkKeyUpdate": 0x00A9, + "unusedPanIdFoundHandler": 0x00D2, + "updateTcLinkKey": 0x006C, + "version": 0x0000, + "writeAttribute": 0x0109, + "writeNodeData": 0x00FE, + "zigbeeKeyEstablishmentHandler": 0x009B, + "zllAddressAssignmentHandler": 0x00B8, + "zllClearTokens": 0x0025, + "zllGetTokens": 0x00BC, + "zllNetworkFoundHandler": 0x00B6, + "zllNetworkOps": 0x00B2, + "zllOperationInProgress": 0x00D7, + "zllRxOnWhenIdleGetActive": 0x00D8, + "zllScanCompleteHandler": 0x00B7, + "zllSetDataToken": 0x00BD, + "zllSetInitialSecurityState": 0x00B3, + "zllSetNonZllNetwork": 0x00BF, + "zllSetRadioIdleMode": 0x00D4, + "zllSetRxOnWhenIdle": 0x00B5, + "zllSetSecurityStateWithoutKey": 0x00CF, + "zllStartScan": 0x00B4, + "zllTouchLinkTargetHandler": 0x00BB, +} diff --git a/tests/test_ezsp_v5.py b/tests/test_ezsp_v5.py index 714bc25d..5f9b7b12 100644 --- a/tests/test_ezsp_v5.py +++ b/tests/test_ezsp_v5.py @@ -27,7 +27,11 @@ def test_ezsp_frame_rx(ezsp_f): async def test_pre_permit(ezsp_f): """Test pre permit.""" - p2 = patch.object(ezsp_f, "addTransientLinkKey", new=AsyncMock()) + p2 = patch.object( + ezsp_f, + "addTransientLinkKey", + new=AsyncMock(return_value=[ezsp_f.types.EmberStatus.SUCCESS]), + ) with p2 as tclk_mock: await ezsp_f.pre_permit(1) assert tclk_mock.await_count == 1 diff --git a/tests/test_ezsp_v8.py b/tests/test_ezsp_v8.py index 8d6c5c93..3a1c884d 100644 --- a/tests/test_ezsp_v8.py +++ b/tests/test_ezsp_v8.py @@ -28,7 +28,11 @@ def test_ezsp_frame_rx(ezsp_f): async def test_pre_permit(ezsp_f): """Test pre permit.""" p1 = patch.object(ezsp_f, "setPolicy", new=AsyncMock()) - p2 = patch.object(ezsp_f, "addTransientLinkKey", new=AsyncMock()) + p2 = patch.object( + ezsp_f, + "addTransientLinkKey", + new=AsyncMock(return_value=[ezsp_f.types.EmberStatus.SUCCESS]), + ) with p1 as pre_permit_mock, p2 as tclk_mock: await ezsp_f.pre_permit(-1.9) assert pre_permit_mock.await_count == 2 @@ -258,6 +262,7 @@ def test_command_frames(ezsp_f): "setRoutingShortcutThreshold": 0x00D0, "setSecurityKey": 0x00CA, "setSecurityParameters": 0x00CB, + "setSourceRoute": 0x00AE, "setSourceRouteDiscoveryMode": 0x005A, "setTimer": 0x000E, "setToken": 0x0009, diff --git a/tests/test_ezsp_v9.py b/tests/test_ezsp_v9.py index b9b5806d..df596923 100644 --- a/tests/test_ezsp_v9.py +++ b/tests/test_ezsp_v9.py @@ -28,7 +28,11 @@ def test_ezsp_frame_rx(ezsp_f): async def test_pre_permit(ezsp_f): """Test pre permit.""" p1 = patch.object(ezsp_f, "setPolicy", new=AsyncMock()) - p2 = patch.object(ezsp_f, "addTransientLinkKey", new=AsyncMock()) + p2 = patch.object( + ezsp_f, + "addTransientLinkKey", + new=AsyncMock(return_value=[ezsp_f.types.EmberStatus.SUCCESS]), + ) with p1 as pre_permit_mock, p2 as tclk_mock: await ezsp_f.pre_permit(-1.9) assert pre_permit_mock.await_count == 2 @@ -266,6 +270,7 @@ def test_command_frames(ezsp_f): "setRoutingShortcutThreshold": 0x00D0, "setSecurityKey": 0x00CA, "setSecurityParameters": 0x00CB, + "setSourceRoute": 0x00AE, "setSourceRouteDiscoveryMode": 0x005A, "setTimer": 0x000E, "setToken": 0x0009, diff --git a/tests/test_types.py b/tests/test_types.py index ba78f64a..98356c6e 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -77,7 +77,7 @@ def test_str(): def test_ember_eui64(): serialized = b"\x00\x01\x02\x03\x04\x05\x06\x07" - eui64, data = t.EmberEUI64.deserialize(serialized) + eui64, data = t.EUI64.deserialize(serialized) assert data == b"" assert eui64.serialize() == serialized diff --git a/tests/test_util.py b/tests/test_util.py index 16880dcb..f90e119c 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -30,11 +30,11 @@ def ezsp_key(ezsp_mock, network_info, node_info, zigpy_key): | ezsp.types.EmberKeyStructBitmask.KEY_HAS_INCOMING_FRAME_COUNTER | ezsp.types.EmberKeyStructBitmask.KEY_HAS_PARTNER_EUI64 ), - key=ezsp.types.EmberKeyData(network_info.network_key.key), + key=ezsp.types.KeyData(network_info.network_key.key), sequenceNumber=zigpy_key.seq, outgoingFrameCounter=zigpy_key.tx_counter, incomingFrameCounter=zigpy_key.rx_counter, - partnerEUI64=bellows_t.EmberEUI64(node_info.ieee), + partnerEUI64=bellows_t.EUI64(node_info.ieee), ) @@ -66,7 +66,7 @@ def test_zha_security_router_unknown_tclk_partner_ieee(network_info): ) # Not set, since we don't know it - assert security.preconfiguredTrustCenterEui64 == bellows_t.EmberEUI64([0x00] * 8) + assert security.preconfiguredTrustCenterEui64 == bellows_t.EUI64([0x00] * 8) assert ( bellows_t.EmberInitialSecurityBitmask.HAVE_TRUST_CENTER_EUI64 not in security.bitmask diff --git a/tests/test_zigbee_repairs.py b/tests/test_zigbee_repairs.py index 86548b9b..8ecc3b45 100644 --- a/tests/test_zigbee_repairs.py +++ b/tests/test_zigbee_repairs.py @@ -17,7 +17,7 @@ def ezsp_tclk_f(ezsp_f: EZSP) -> EZSP: """Mock an EZSP instance with a valid TCLK.""" ezsp_f.getEui64 = AsyncMock( - return_value=[t.EmberEUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA")] + return_value=[t.EUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA")] ) ezsp_f.getTokenData = AsyncMock(side_effect=InvalidCommandError()) ezsp_f.getCurrentSecurityState = AsyncMock( @@ -29,7 +29,7 @@ def ezsp_tclk_f(ezsp_f: EZSP) -> EZSP: | t.EmberCurrentSecurityBitmask.HAVE_TRUST_CENTER_LINK_KEY | 224 ), - trustCenterLongAddress=t.EmberEUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA"), + trustCenterLongAddress=t.EUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA"), ), ] ) @@ -39,12 +39,10 @@ def ezsp_tclk_f(ezsp_f: EZSP) -> EZSP: async def test_fix_invalid_tclk_noop(ezsp_tclk_f: EZSP, caplog) -> None: """Test that the TCLK is not rewritten unnecessarily.""" - ezsp_tclk_f.getEui64.return_value[0] = t.EmberEUI64.convert( - "AA:AA:AA:AA:AA:AA:AA:AA" - ) + ezsp_tclk_f.getEui64.return_value[0] = t.EUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA") ezsp_tclk_f.getCurrentSecurityState.return_value[ 1 - ].trustCenterLongAddress = t.EmberEUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA") + ].trustCenterLongAddress = t.EUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA") with caplog.at_level(logging.WARNING): assert await repairs.fix_invalid_tclk_partner_ieee(ezsp_tclk_f) is False @@ -56,12 +54,10 @@ async def test_fix_invalid_tclk_old_firmware(ezsp_tclk_f: EZSP, caplog) -> None: """Test that the TCLK is not rewritten when the firmware is too old.""" ezsp_tclk_f.getTokenData = AsyncMock(side_effect=InvalidCommandError()) - ezsp_tclk_f.getEui64.return_value[0] = t.EmberEUI64.convert( - "AA:AA:AA:AA:AA:AA:AA:AA" - ) + ezsp_tclk_f.getEui64.return_value[0] = t.EUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA") ezsp_tclk_f.getCurrentSecurityState.return_value[ 1 - ].trustCenterLongAddress = t.EmberEUI64.convert("BB:BB:BB:BB:BB:BB:BB:BB") + ].trustCenterLongAddress = t.EUI64.convert("BB:BB:BB:BB:BB:BB:BB:BB") with caplog.at_level(logging.WARNING): assert await repairs.fix_invalid_tclk_partner_ieee(ezsp_tclk_f) is False @@ -79,19 +75,17 @@ async def test_fix_invalid_tclk(ezsp_tclk_f: EZSP, caplog) -> None: t.EmberStatus.SUCCESS, t.NV3StackTrustCenterToken( mode=228, - eui64=t.EmberEUI64.convert("BB:BB:BB:BB:BB:BB:BB:BB"), - key=t.EmberKeyData.convert( + eui64=t.EUI64.convert("BB:BB:BB:BB:BB:BB:BB:BB"), + key=t.KeyData.convert( "21:8e:df:b8:50:a0:4a:b6:8b:c6:10:25:bc:4e:93:6a" ), ).serialize(), ] ) - ezsp_tclk_f.getEui64.return_value[0] = t.EmberEUI64.convert( - "AA:AA:AA:AA:AA:AA:AA:AA" - ) + ezsp_tclk_f.getEui64.return_value[0] = t.EUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA") ezsp_tclk_f.getCurrentSecurityState.return_value[ 1 - ].trustCenterLongAddress = t.EmberEUI64.convert("BB:BB:BB:BB:BB:BB:BB:BB") + ].trustCenterLongAddress = t.EUI64.convert("BB:BB:BB:BB:BB:BB:BB:BB") with caplog.at_level(logging.WARNING): assert await repairs.fix_invalid_tclk_partner_ieee(ezsp_tclk_f) is True @@ -105,8 +99,8 @@ async def test_fix_invalid_tclk(ezsp_tclk_f: EZSP, caplog) -> None: 0, t.NV3StackTrustCenterToken( mode=228, - eui64=t.EmberEUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA"), - key=t.EmberKeyData.convert( + eui64=t.EUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA"), + key=t.KeyData.convert( "21:8e:df:b8:50:a0:4a:b6:8b:c6:10:25:bc:4e:93:6a" ), ).serialize(), @@ -131,8 +125,8 @@ async def test_fix_invalid_tclk_all_versions( t.EmberStatus.SUCCESS, t.NV3StackTrustCenterToken( mode=228, - eui64=t.EmberEUI64.convert("BB:BB:BB:BB:BB:BB:BB:BB"), - key=t.EmberKeyData.convert( + eui64=t.EUI64.convert("BB:BB:BB:BB:BB:BB:BB:BB"), + key=t.KeyData.convert( "21:8e:df:b8:50:a0:4a:b6:8b:c6:10:25:bc:4e:93:6a" ), ).serialize(), @@ -146,10 +140,10 @@ async def test_fix_invalid_tclk_all_versions( ezsp.getEui64 = ezsp_tclk_f.getEui64 ezsp.getCurrentSecurityState = ezsp_tclk_f.getCurrentSecurityState - ezsp.getEui64.return_value[0] = t.EmberEUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA") + ezsp.getEui64.return_value[0] = t.EUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA") ezsp.getCurrentSecurityState.return_value[ 1 - ].trustCenterLongAddress = t.EmberEUI64.convert("BB:BB:BB:BB:BB:BB:BB:BB") + ].trustCenterLongAddress = t.EUI64.convert("BB:BB:BB:BB:BB:BB:BB:BB") with caplog.at_level(logging.WARNING): assert ( @@ -167,8 +161,8 @@ async def test_fix_invalid_tclk_all_versions( 0, t.NV3StackTrustCenterToken( mode=228, - eui64=t.EmberEUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA"), - key=t.EmberKeyData.convert( + eui64=t.EUI64.convert("AA:AA:AA:AA:AA:AA:AA:AA"), + key=t.KeyData.convert( "21:8e:df:b8:50:a0:4a:b6:8b:c6:10:25:bc:4e:93:6a" ), ).serialize(),