From a48c598da61054009400354dab4a0c19e7f972ef Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Fri, 3 Apr 2020 10:56:09 -0400 Subject: [PATCH 1/4] add zigbee signature to zha device info --- .../components/zha/core/channels/__init__.py | 29 +++++++++++++++++++ homeassistant/components/zha/core/const.py | 5 ++++ homeassistant/components/zha/core/device.py | 12 ++++++++ 3 files changed, 46 insertions(+) diff --git a/homeassistant/components/zha/core/channels/__init__.py b/homeassistant/components/zha/core/channels/__init__.py index 91a23e17f12fa..dd41c6739b57e 100644 --- a/homeassistant/components/zha/core/channels/__init__.py +++ b/homeassistant/components/zha/core/channels/__init__.py @@ -153,6 +153,14 @@ def zha_send_event(self, event_data: Dict[str, Union[str, int]]) -> None: }, ) + @callback + def async_get_zigbee_signature(self): + """Get the zigbee signatures for the pools in channels.""" + return { + signature[0]: signature[1] + for signature in [pool.async_get_zigbee_signature() for pool in self.pools] + } + class ChannelPool: """All channels of an endpoint.""" @@ -340,3 +348,24 @@ def zha_send_event(self, event_data: Dict[str, Union[str, int]]) -> None: **event_data, } ) + + @callback + def async_get_zigbee_signature(self): + """Get the zigbee signature for the endpoint this pool represents.""" + return ( + self.endpoint.endpoint_id, + { + const.ATTR_PROFILE_ID: self.endpoint.profile_id, + const.ATTR_DEVICE_TYPE: f"0x{self.endpoint.device_type:04x}" + if self.endpoint.device_type is not None + else "", + const.ATTR_IN_CLUSTERS: [ + f"0x{cluster_id:04x}" + for cluster_id in self.endpoint.in_clusters.keys() + ], + const.ATTR_OUT_CLUSTERS: [ + f"0x{cluster_id:04x}" + for cluster_id in self.endpoint.out_clusters.keys() + ], + }, + ) diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index da151f67dbbbd..055b5627bb116 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -22,8 +22,10 @@ ATTR_COMMAND_TYPE = "command_type" ATTR_DEVICE_IEEE = "device_ieee" ATTR_DEVICE_TYPE = "device_type" +ATTR_ENDPOINTS = "endpoints" ATTR_ENDPOINT_ID = "endpoint_id" ATTR_IEEE = "ieee" +ATTR_IN_CLUSTERS = "in_clusters" ATTR_LAST_SEEN = "last_seen" ATTR_LEVEL = "level" ATTR_LQI = "lqi" @@ -32,8 +34,11 @@ ATTR_MEMBERS = "members" ATTR_MODEL = "model" ATTR_NAME = "name" +ATTR_NODE_DESCRIPTOR = "node_descriptor" ATTR_NWK = "nwk" +ATTR_OUT_CLUSTERS = "out_clusters" ATTR_POWER_SOURCE = "power_source" +ATTR_PROFILE_ID = "profile_id" ATTR_QUIRK_APPLIED = "quirk_applied" ATTR_QUIRK_CLASS = "quirk_class" ATTR_RSSI = "rssi" diff --git a/homeassistant/components/zha/core/device.py b/homeassistant/components/zha/core/device.py index ad3d1ff18adb6..0befe5a3cde76 100644 --- a/homeassistant/components/zha/core/device.py +++ b/homeassistant/components/zha/core/device.py @@ -31,6 +31,7 @@ ATTR_COMMAND_TYPE, ATTR_DEVICE_TYPE, ATTR_ENDPOINT_ID, + ATTR_ENDPOINTS, ATTR_IEEE, ATTR_LAST_SEEN, ATTR_LQI, @@ -38,11 +39,13 @@ ATTR_MANUFACTURER_CODE, ATTR_MODEL, ATTR_NAME, + ATTR_NODE_DESCRIPTOR, ATTR_NWK, ATTR_POWER_SOURCE, ATTR_QUIRK_APPLIED, ATTR_QUIRK_CLASS, ATTR_RSSI, + ATTR_SIGNATURE, ATTR_VALUE, CLUSTER_COMMAND_SERVER, CLUSTER_COMMANDS_CLIENT, @@ -366,6 +369,7 @@ def device_info(self): ATTR_LAST_SEEN: update_time, ATTR_AVAILABLE: self.available, ATTR_DEVICE_TYPE: self.device_type, + ATTR_SIGNATURE: self.async_get_zigbee_signature(), } async def async_configure(self): @@ -617,6 +621,14 @@ async def _async_group_binding_operation( fmt = log_msg[1] + " completed: %s" zdo.debug(fmt, *(log_msg[2] + (outcome,))) + @callback + def async_get_zigbee_signature(self): + """Get zigbee signature for this device.""" + return { + ATTR_NODE_DESCRIPTOR: str(self._zigpy_device.node_desc), + ATTR_ENDPOINTS: self._channels.async_get_zigbee_signature(), + } + def log(self, level, msg, *args): """Log a message.""" msg = f"[%s](%s): {msg}" From ab803d6ee1a64340817a33eecc212daffcf7e10f Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Fri, 3 Apr 2020 20:04:41 -0400 Subject: [PATCH 2/4] add typing --- homeassistant/components/zha/core/channels/__init__.py | 6 +++--- homeassistant/components/zha/core/device.py | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/zha/core/channels/__init__.py b/homeassistant/components/zha/core/channels/__init__.py index dd41c6739b57e..28123a1e1528c 100644 --- a/homeassistant/components/zha/core/channels/__init__.py +++ b/homeassistant/components/zha/core/channels/__init__.py @@ -1,7 +1,7 @@ """Channels module for Zigbee Home Automation.""" import asyncio import logging -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Tuple, Union from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_send @@ -154,7 +154,7 @@ def zha_send_event(self, event_data: Dict[str, Union[str, int]]) -> None: ) @callback - def async_get_zigbee_signature(self): + def async_get_zigbee_signature(self) -> Dict[int, Dict[str, Any]]: """Get the zigbee signatures for the pools in channels.""" return { signature[0]: signature[1] @@ -350,7 +350,7 @@ def zha_send_event(self, event_data: Dict[str, Union[str, int]]) -> None: ) @callback - def async_get_zigbee_signature(self): + def async_get_zigbee_signature(self) -> Tuple[int, Dict[str, Any]]: """Get the zigbee signature for the endpoint this pool represents.""" return ( self.endpoint.endpoint_id, diff --git a/homeassistant/components/zha/core/device.py b/homeassistant/components/zha/core/device.py index 0befe5a3cde76..a05f058264868 100644 --- a/homeassistant/components/zha/core/device.py +++ b/homeassistant/components/zha/core/device.py @@ -5,6 +5,7 @@ import logging import random import time +from typing import Any, Dict from zigpy import types import zigpy.exceptions @@ -622,7 +623,7 @@ async def _async_group_binding_operation( zdo.debug(fmt, *(log_msg[2] + (outcome,))) @callback - def async_get_zigbee_signature(self): + def async_get_zigbee_signature(self) -> Dict[str, Any]: """Get zigbee signature for this device.""" return { ATTR_NODE_DESCRIPTOR: str(self._zigpy_device.node_desc), From c8355f80e906c3ac8e166061e4f502c9654085d9 Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Fri, 3 Apr 2020 21:35:12 -0400 Subject: [PATCH 3/4] use props and sort clusters --- .../components/zha/core/channels/__init__.py | 58 +++++++++---------- homeassistant/components/zha/core/device.py | 18 +++--- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/homeassistant/components/zha/core/channels/__init__.py b/homeassistant/components/zha/core/channels/__init__.py index 28123a1e1528c..b732b9b15a5cd 100644 --- a/homeassistant/components/zha/core/channels/__init__.py +++ b/homeassistant/components/zha/core/channels/__init__.py @@ -92,6 +92,14 @@ def unique_id(self): """Return the unique id for this channel.""" return self._unique_id + @property + def zigbee_signature(self) -> Dict[int, Dict[str, Any]]: + """Get the zigbee signatures for the pools in channels.""" + return { + signature[0]: signature[1] + for signature in [pool.zigbee_signature for pool in self.pools] + } + @classmethod def new(cls, zha_device: zha_typing.ZhaDeviceType) -> "Channels": """Create new instance.""" @@ -153,14 +161,6 @@ def zha_send_event(self, event_data: Dict[str, Union[str, int]]) -> None: }, ) - @callback - def async_get_zigbee_signature(self) -> Dict[int, Dict[str, Any]]: - """Get the zigbee signatures for the pools in channels.""" - return { - signature[0]: signature[1] - for signature in [pool.async_get_zigbee_signature() for pool in self.pools] - } - class ChannelPool: """All channels of an endpoint.""" @@ -239,6 +239,27 @@ def unique_id(self): """Return the unique id for this channel.""" return self._unique_id + @property + def zigbee_signature(self) -> Tuple[int, Dict[str, Any]]: + """Get the zigbee signature for the endpoint this pool represents.""" + return ( + self.endpoint.endpoint_id, + { + const.ATTR_PROFILE_ID: self.endpoint.profile_id, + const.ATTR_DEVICE_TYPE: f"0x{self.endpoint.device_type:04x}" + if self.endpoint.device_type is not None + else "", + const.ATTR_IN_CLUSTERS: [ + f"0x{cluster_id:04x}" + for cluster_id in sorted(self.endpoint.in_clusters.keys()) + ], + const.ATTR_OUT_CLUSTERS: [ + f"0x{cluster_id:04x}" + for cluster_id in sorted(self.endpoint.out_clusters.keys()) + ], + }, + ) + @classmethod def new(cls, channels: Channels, ep_id: int) -> "ChannelPool": """Create new channels for an endpoint.""" @@ -348,24 +369,3 @@ def zha_send_event(self, event_data: Dict[str, Union[str, int]]) -> None: **event_data, } ) - - @callback - def async_get_zigbee_signature(self) -> Tuple[int, Dict[str, Any]]: - """Get the zigbee signature for the endpoint this pool represents.""" - return ( - self.endpoint.endpoint_id, - { - const.ATTR_PROFILE_ID: self.endpoint.profile_id, - const.ATTR_DEVICE_TYPE: f"0x{self.endpoint.device_type:04x}" - if self.endpoint.device_type is not None - else "", - const.ATTR_IN_CLUSTERS: [ - f"0x{cluster_id:04x}" - for cluster_id in self.endpoint.in_clusters.keys() - ], - const.ATTR_OUT_CLUSTERS: [ - f"0x{cluster_id:04x}" - for cluster_id in self.endpoint.out_clusters.keys() - ], - }, - ) diff --git a/homeassistant/components/zha/core/device.py b/homeassistant/components/zha/core/device.py index a05f058264868..716ed5040ae7c 100644 --- a/homeassistant/components/zha/core/device.py +++ b/homeassistant/components/zha/core/device.py @@ -271,6 +271,14 @@ def available(self): """Return True if sensor is available.""" return self._available + @property + def zigbee_signature(self) -> Dict[str, Any]: + """Get zigbee signature for this device.""" + return { + ATTR_NODE_DESCRIPTOR: str(self._zigpy_device.node_desc), + ATTR_ENDPOINTS: self._channels.zigbee_signature, + } + def set_available(self, available): """Set availability from restore and prevent signals.""" self._available = available @@ -370,7 +378,7 @@ def device_info(self): ATTR_LAST_SEEN: update_time, ATTR_AVAILABLE: self.available, ATTR_DEVICE_TYPE: self.device_type, - ATTR_SIGNATURE: self.async_get_zigbee_signature(), + ATTR_SIGNATURE: self.zigbee_signature, } async def async_configure(self): @@ -622,14 +630,6 @@ async def _async_group_binding_operation( fmt = log_msg[1] + " completed: %s" zdo.debug(fmt, *(log_msg[2] + (outcome,))) - @callback - def async_get_zigbee_signature(self) -> Dict[str, Any]: - """Get zigbee signature for this device.""" - return { - ATTR_NODE_DESCRIPTOR: str(self._zigpy_device.node_desc), - ATTR_ENDPOINTS: self._channels.async_get_zigbee_signature(), - } - def log(self, level, msg, *args): """Log a message.""" msg = f"[%s](%s): {msg}" From e46dc657044f5d3816bf95af8c254285c308bc12 Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Sat, 4 Apr 2020 07:59:16 -0400 Subject: [PATCH 4/4] review comment --- homeassistant/components/zha/core/channels/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/zha/core/channels/__init__.py b/homeassistant/components/zha/core/channels/__init__.py index b732b9b15a5cd..18eb2a6c1cc62 100644 --- a/homeassistant/components/zha/core/channels/__init__.py +++ b/homeassistant/components/zha/core/channels/__init__.py @@ -251,11 +251,11 @@ def zigbee_signature(self) -> Tuple[int, Dict[str, Any]]: else "", const.ATTR_IN_CLUSTERS: [ f"0x{cluster_id:04x}" - for cluster_id in sorted(self.endpoint.in_clusters.keys()) + for cluster_id in sorted(self.endpoint.in_clusters) ], const.ATTR_OUT_CLUSTERS: [ f"0x{cluster_id:04x}" - for cluster_id in sorted(self.endpoint.out_clusters.keys()) + for cluster_id in sorted(self.endpoint.out_clusters) ], }, )