From dd8f9bf2bbd46d189f4941a88e5b8e29a480ffad Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Wed, 29 May 2024 15:55:03 +0200 Subject: [PATCH] Only Poll individual attributes in custom Eve cluster (#724) --- matter_server/common/custom_clusters.py | 18 ++++++++---- matter_server/server/device_controller.py | 36 +++++++++++------------ 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/matter_server/common/custom_clusters.py b/matter_server/common/custom_clusters.py index 94c02517..c8a49bfb 100644 --- a/matter_server/common/custom_clusters.py +++ b/matter_server/common/custom_clusters.py @@ -60,7 +60,6 @@ class EveCluster(Cluster, CustomClusterMixin): """Custom (vendor-specific) cluster for Eve - Vendor ID 4874 (0x130a).""" id: ClassVar[int] = 0x130AFC01 - should_poll = True @ChipUtility.classproperty def descriptor(cls) -> ClusterObjectDescriptor: @@ -98,6 +97,8 @@ class Attributes: class Watt(ClusterAttributeDescriptor, CustomClusterAttributeMixin): """Watt Attribute within the Eve Cluster.""" + should_poll = True + @ChipUtility.classproperty def cluster_id(cls) -> int: """Return cluster id.""" @@ -119,6 +120,8 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: class WattAccumulated(ClusterAttributeDescriptor, CustomClusterAttributeMixin): """WattAccumulated Attribute within the Eve Cluster.""" + should_poll = True + @ChipUtility.classproperty def cluster_id(cls) -> int: """Return cluster id.""" @@ -137,11 +140,13 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: float32 = 0 @dataclass - class wattAccumulatedControlPoint( + class WattAccumulatedControlPoint( ClusterAttributeDescriptor, CustomClusterAttributeMixin ): """wattAccumulatedControlPoint Attribute within the Eve Cluster.""" + should_poll = True + @ChipUtility.classproperty def cluster_id(cls) -> int: """Return cluster id.""" @@ -163,6 +168,8 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: class Voltage(ClusterAttributeDescriptor, CustomClusterAttributeMixin): """Voltage Attribute within the Eve Cluster.""" + should_poll = True + @ChipUtility.classproperty def cluster_id(cls) -> int: """Return cluster id.""" @@ -184,6 +191,8 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: class Current(ClusterAttributeDescriptor, CustomClusterAttributeMixin): """Current Attribute within the Eve Cluster.""" + should_poll = True + @ChipUtility.classproperty def cluster_id(cls) -> int: """Return cluster id.""" @@ -213,9 +222,8 @@ def check_polled_attributes(node_data: MatterNodeData) -> set[str]: # the entire cluster needs to be polled attributes_to_poll.add(f"{endpoint_id}/{cluster_id}/*") continue - if ( - custom_attribute := ALL_CUSTOM_ATTRIBUTES[cluster_id].get(attribute_id) - ) and custom_attribute.should_poll: + custom_attribute = ALL_CUSTOM_ATTRIBUTES[cluster_id].get(attribute_id) + if custom_attribute and custom_attribute.should_poll: # this attribute needs to be polled attributes_to_poll.add(attr_path) return attributes_to_poll diff --git a/matter_server/server/device_controller.py b/matter_server/server/device_controller.py index 981e4fc4..94e99b33 100644 --- a/matter_server/server/device_controller.py +++ b/matter_server/server/device_controller.py @@ -1404,25 +1404,23 @@ async def _custom_attributes_poller(self) -> None: node = self._nodes[node_id] if not node.available: continue - for attribute_path in self._polled_attributes[node_id].copy(): - try: - # try to read the attribute(s) - this will fire an event if the value changed - await self.read_attribute( - node_id, attribute_path, fabric_filtered=False - ) - except (ChipStackError, NodeNotReady) as err: - LOGGER.warning( - "Polling custom attribute %s for node %s failed: %s", - attribute_path, - node_id, - str(err) or err.__class__.__name__, - # log full stack trace if verbose logging is enabled - exc_info=err - if LOGGER.isEnabledFor(VERBOSE_LOG_LEVEL) - else None, - ) - # polling attributes is heavy on network traffic, so we throttle it a bit - await asyncio.sleep(2) + attribute_paths = list(self._polled_attributes[node_id]) + try: + # try to read the attribute(s) - this will fire an event if the value changed + await self.read_attribute( + node_id, attribute_paths, fabric_filtered=False + ) + except (ChipStackError, NodeNotReady) as err: + LOGGER.warning( + "Polling custom attribute(s) %s for node %s failed: %s", + ",".join(attribute_paths), + node_id, + str(err) or err.__class__.__name__, + # log full stack trace if verbose logging is enabled + exc_info=err if LOGGER.isEnabledFor(VERBOSE_LOG_LEVEL) else None, + ) + # polling attributes is heavy on network traffic, so we throttle it a bit + await asyncio.sleep(2) # reschedule self to run at next interval self._schedule_custom_attributes_poller()