From 2a83395ac585731b976085f50f7ee144abc33025 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 17 Jun 2022 02:15:37 +0200 Subject: [PATCH 1/4] Synchronize attribute reads and subscriptions on startup Avoid multiple entites requesting reads and subscriptions of the same node. Nodes seem to be overwhelmed and return a BUSY error code, which isn't handled gracefully throughout the stack (it seems). --- custom_components/matter_experimental/entity.py | 13 +++++++++---- matter_server/client/model/node.py | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/custom_components/matter_experimental/entity.py b/custom_components/matter_experimental/entity.py index d46539a8..95c5b20d 100644 --- a/custom_components/matter_experimental/entity.py +++ b/custom_components/matter_experimental/entity.py @@ -30,10 +30,8 @@ def device_info(self) -> entity.DeviceInfo | None: """Return device info for device registry.""" return {"identifiers": {(DOMAIN, self._device.node.unique_id)}} - async def async_added_to_hass(self) -> None: - """Handle being added to Home Assistant.""" - await super().async_added_to_hass() - + async def init_matter_device(self) -> None: + """Initialize and subscribe device attributes.""" device_name = ( device_registry.async_get(self.hass) .async_get(self.registry_entry.device_id) @@ -80,6 +78,13 @@ async def async_added_to_hass(self) -> None: self._update_from_device() + async def async_added_to_hass(self) -> None: + """Handle being added to Home Assistant.""" + await super().async_added_to_hass() + + async with self._device.node.node_lock: + await self.init_matter_device() + async def async_will_remove_from_hass(self) -> None: """Run when entity will be removed from hass.""" if self._unsubscribe is not None: diff --git a/matter_server/client/model/node.py b/matter_server/client/model/node.py index 423f58e6..91584639 100644 --- a/matter_server/client/model/node.py +++ b/matter_server/client/model/node.py @@ -1,5 +1,6 @@ """Matter node.""" from __future__ import annotations +import asyncio from typing import TYPE_CHECKING @@ -16,6 +17,7 @@ class MatterNode: """Matter node.""" root_device: MatterDevice[device_types.RootNode] + node_lock = asyncio.Lock() def __init__(self, matter: Matter, node_info: dict) -> None: self.matter = matter From 4bfdc5bcda91fa268814b02ad3798c06eaa01411 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 16 Jun 2022 22:36:54 -0700 Subject: [PATCH 2/4] Store Node Lock in the HA Adapater --- custom_components/matter_experimental/adapter.py | 7 +++++++ custom_components/matter_experimental/entity.py | 2 +- matter_server/client/model/node.py | 1 - 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/custom_components/matter_experimental/adapter.py b/custom_components/matter_experimental/adapter.py index daa56eaf..1f3e502b 100644 --- a/custom_components/matter_experimental/adapter.py +++ b/custom_components/matter_experimental/adapter.py @@ -101,6 +101,7 @@ def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None: self._store = get_matter_store(hass, config_entry) self.platform_handlers: dict[Platform, AddEntitiesCallback] = {} self._platforms_set_up = asyncio.Event() + self._node_lock: dict[int, asyncio.Lock] = {} def register_platform_handler( self, platform: Platform, add_entities: AddEntitiesCallback @@ -130,6 +131,12 @@ def get_server_url(self) -> str: def get_client_session(self) -> aiohttp.ClientSession: return async_get_clientsession(self.hass) + def get_node_lock(self, nodeid) -> asyncio.Lock: + if nodeid not in self._node_lock: + self._node_lock[nodeid] = asyncio.Lock() + return self._node_lock[nodeid] + + async def setup_node(self, node: MatterNode) -> None: """Set up an node.""" await self._platforms_set_up.wait() diff --git a/custom_components/matter_experimental/entity.py b/custom_components/matter_experimental/entity.py index 95c5b20d..f983afcf 100644 --- a/custom_components/matter_experimental/entity.py +++ b/custom_components/matter_experimental/entity.py @@ -82,7 +82,7 @@ async def async_added_to_hass(self) -> None: """Handle being added to Home Assistant.""" await super().async_added_to_hass() - async with self._device.node.node_lock: + async with self._device.node.matter.adapter.get_node_lock(self._device.node.node_id): await self.init_matter_device() async def async_will_remove_from_hass(self) -> None: diff --git a/matter_server/client/model/node.py b/matter_server/client/model/node.py index 91584639..5c0fa282 100644 --- a/matter_server/client/model/node.py +++ b/matter_server/client/model/node.py @@ -17,7 +17,6 @@ class MatterNode: """Matter node.""" root_device: MatterDevice[device_types.RootNode] - node_lock = asyncio.Lock() def __init__(self, matter: Matter, node_info: dict) -> None: self.matter = matter From 56c1aafe83f7c15f2e83e53d91ecbe3b6c5410f3 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 16 Jun 2022 22:41:03 -0700 Subject: [PATCH 3/4] Address flake8 --- custom_components/matter_experimental/adapter.py | 1 - matter_server/client/model/node.py | 1 - 2 files changed, 2 deletions(-) diff --git a/custom_components/matter_experimental/adapter.py b/custom_components/matter_experimental/adapter.py index 1f3e502b..96eb9e7c 100644 --- a/custom_components/matter_experimental/adapter.py +++ b/custom_components/matter_experimental/adapter.py @@ -136,7 +136,6 @@ def get_node_lock(self, nodeid) -> asyncio.Lock: self._node_lock[nodeid] = asyncio.Lock() return self._node_lock[nodeid] - async def setup_node(self, node: MatterNode) -> None: """Set up an node.""" await self._platforms_set_up.wait() diff --git a/matter_server/client/model/node.py b/matter_server/client/model/node.py index 5c0fa282..423f58e6 100644 --- a/matter_server/client/model/node.py +++ b/matter_server/client/model/node.py @@ -1,6 +1,5 @@ """Matter node.""" from __future__ import annotations -import asyncio from typing import TYPE_CHECKING From 024e5f037941521266e8f0175a76a37d80ab3126 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 16 Jun 2022 22:42:26 -0700 Subject: [PATCH 4/4] Reformat using black --- custom_components/matter_experimental/entity.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/custom_components/matter_experimental/entity.py b/custom_components/matter_experimental/entity.py index f983afcf..545cb433 100644 --- a/custom_components/matter_experimental/entity.py +++ b/custom_components/matter_experimental/entity.py @@ -82,7 +82,9 @@ async def async_added_to_hass(self) -> None: """Handle being added to Home Assistant.""" await super().async_added_to_hass() - async with self._device.node.matter.adapter.get_node_lock(self._device.node.node_id): + async with self._device.node.matter.adapter.get_node_lock( + self._device.node.node_id + ): await self.init_matter_device() async def async_will_remove_from_hass(self) -> None: