From 05780f4c1c98e8f7546cf5f9f237e47fb43ee0b9 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 14 Sep 2025 19:59:18 +0200 Subject: [PATCH 1/7] Update node_type cache: - Save NodeType name to file - Read all previously used string-formats from cache-file - Fix CIRCLE_PLUS not appearing in cache-file - Make sure to rewrite the full contents at every write-to-file --- plugwise_usb/network/cache.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/plugwise_usb/network/cache.py b/plugwise_usb/network/cache.py index 504a89014..84980d01d 100644 --- a/plugwise_usb/network/cache.py +++ b/plugwise_usb/network/cache.py @@ -28,10 +28,11 @@ async def save_cache(self) -> None: """Save the node information to file.""" cache_data_to_save: dict[str, str] = {} for mac, node_type in self._nodetypes.items(): - node_value = str(node_type) - cache_data_to_save[mac] = node_value - _LOGGER.debug("Save NodeTypes %s", str(len(cache_data_to_save))) - await self.write_cache(cache_data_to_save) + cache_data_to_save[mac] = node_type.name + _LOGGER.debug("Save NodeTypes for %s Nodes", str(len(cache_data_to_save))) + await self.write_cache( + cache_data_to_save, True + ) # rewrite set to True is required async def clear_cache(self) -> None: """Clear current cache.""" @@ -44,11 +45,16 @@ async def restore_cache(self) -> None: self._nodetypes = {} for mac, node_value in data.items(): node_type: NodeType | None = None - if len(node_value) >= 10: + # Backward-compatible parsing: support full enums, enum names, or numeric values + val = node_value.strip() + key = val.split(".", 1)[1] if val.startswith("NodeType.") else val + node_type = NodeType.__members__.get(key) # e.g., "CIRCLE" + if node_type is None and val.isdigit(): # e.g., "2" try: - node_type = NodeType[node_value[9:]] - except KeyError: + node_type = NodeType(int(val)) + except ValueError: node_type = None + if node_type is None: _LOGGER.warning("Invalid NodeType in cache: %s", node_value) continue From 0ae8172d017696f1241e859dd0782cc5caffbb24 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 14 Sep 2025 20:02:17 +0200 Subject: [PATCH 2/7] Update related test-asserts --- tests/test_usb.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_usb.py b/tests/test_usb.py index 0d452a2c4..2241296dc 100644 --- a/tests/test_usb.py +++ b/tests/test_usb.py @@ -1733,10 +1733,10 @@ async def makedirs(cache_dir: str, exist_ok: bool) -> None: ) mock_file_stream.writelines.assert_called_with( [ - "0123456789ABCDEF;NodeType.CIRCLE_PLUS\n", - "FEDCBA9876543210;NodeType.CIRCLE\n", - "1298347650AFBECD;NodeType.SCAN\n", - "1234ABCD4321FEDC;NodeType.STEALTH\n", + "0123456789ABCDEF;CIRCLE_PLUS\n", + "FEDCBA9876543210;CIRCLE\n", + "1298347650AFBECD;SCAN\n", + "1234ABCD4321FEDC;STEALTH\n", ] ) assert pw_nw_cache.nodetypes == { From 1d1d02f9adbae6422aff3e059f8bd3e4118d5565 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 14 Sep 2025 20:11:40 +0200 Subject: [PATCH 3/7] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f78f298df..e714cd0f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Ongoing + +- PR [342](https://github.com/plugwise/python-plugwise-usb/pull/342): Improve node_type chaching. + ## 0.46.0 - 2025-09-12 - PR [338](https://github.com/plugwise/python-plugwise-usb/pull/338): Append report interval to Sense node configuration From cca403e52514413eb4b572ff8892ef6b35c6e315 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 14 Sep 2025 20:20:31 +0200 Subject: [PATCH 4/7] Extend to all node_type formats used --- tests/test_usb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_usb.py b/tests/test_usb.py index 2241296dc..af5cbdffe 100644 --- a/tests/test_usb.py +++ b/tests/test_usb.py @@ -1712,9 +1712,9 @@ async def makedirs(cache_dir: str, exist_ok: bool) -> None: # test with valid data mock_read_data = [ - "0123456789ABCDEF;NodeType.CIRCLE_PLUS", + "0123456789ABCDEF;CIRCLE_PLUS", "FEDCBA9876543210;NodeType.CIRCLE", - "1298347650AFBECD;NodeType.SCAN", + "1298347650AFBECD;6", ] file_chunks_iter = iter(mock_read_data) mock_file_stream = MagicMock(readlines=lambda *args, **kwargs: file_chunks_iter) From 58c7931f3030867e04ada3f80c32a2185cd5dccd Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 14 Sep 2025 20:35:41 +0200 Subject: [PATCH 5/7] Implement CRAI suggestions --- plugwise_usb/network/cache.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugwise_usb/network/cache.py b/plugwise_usb/network/cache.py index 84980d01d..cef04bde6 100644 --- a/plugwise_usb/network/cache.py +++ b/plugwise_usb/network/cache.py @@ -29,7 +29,7 @@ async def save_cache(self) -> None: cache_data_to_save: dict[str, str] = {} for mac, node_type in self._nodetypes.items(): cache_data_to_save[mac] = node_type.name - _LOGGER.debug("Save NodeTypes for %s Nodes", str(len(cache_data_to_save))) + _LOGGER.debug("Save NodeTypes for %s Nodes", (len(cache_data_to_save))) await self.write_cache( cache_data_to_save, True ) # rewrite set to True is required @@ -47,9 +47,9 @@ async def restore_cache(self) -> None: node_type: NodeType | None = None # Backward-compatible parsing: support full enums, enum names, or numeric values val = node_value.strip() - key = val.split(".", 1)[1] if val.startswith("NodeType.") else val + key = (val.split(".", 1)[1] if val.startswith("NodeType.") else val).upper() node_type = NodeType.__members__.get(key) # e.g., "CIRCLE" - if node_type is None and val.isdigit(): # e.g., "2" + if node_type is None: try: node_type = NodeType(int(val)) except ValueError: @@ -92,5 +92,9 @@ async def prune_cache(self, registry: list[str]) -> None: continue if (node_type := self.get_nodetype(mac)) is not None: new_nodetypes[mac] = node_type + + if new_nodetypes == self._nodetypes: + _LOGGER.debug("prune_cache: no changes; skipping save") + return self._nodetypes = new_nodetypes await self.save_cache() From 147a7ce8922841c094cc65c8422260f13df0ecfb Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 15 Sep 2025 09:01:25 +0200 Subject: [PATCH 6/7] Optimize, improve comment --- plugwise_usb/network/cache.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugwise_usb/network/cache.py b/plugwise_usb/network/cache.py index cef04bde6..9b67d15c6 100644 --- a/plugwise_usb/network/cache.py +++ b/plugwise_usb/network/cache.py @@ -29,10 +29,10 @@ async def save_cache(self) -> None: cache_data_to_save: dict[str, str] = {} for mac, node_type in self._nodetypes.items(): cache_data_to_save[mac] = node_type.name - _LOGGER.debug("Save NodeTypes for %s Nodes", (len(cache_data_to_save))) + _LOGGER.debug("Save NodeTypes for %s Nodes", len(cache_data_to_save)) await self.write_cache( cache_data_to_save, True - ) # rewrite set to True is required + ) # rewrite set to True to make sure the cache-contents is actual async def clear_cache(self) -> None: """Clear current cache.""" From 0ffd05c4039ad58da30c29f2a65a0ba4f04febf5 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 15 Sep 2025 09:13:01 +0200 Subject: [PATCH 7/7] More CRAI suggestions --- plugwise_usb/network/cache.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/plugwise_usb/network/cache.py b/plugwise_usb/network/cache.py index 9b67d15c6..3f6d4a3f8 100644 --- a/plugwise_usb/network/cache.py +++ b/plugwise_usb/network/cache.py @@ -26,13 +26,11 @@ def nodetypes(self) -> dict[str, NodeType]: async def save_cache(self) -> None: """Save the node information to file.""" - cache_data_to_save: dict[str, str] = {} - for mac, node_type in self._nodetypes.items(): - cache_data_to_save[mac] = node_type.name + cache_data_to_save: dict[str, str] = { + mac: node_type.name for mac, node_type in self._nodetypes.items() + } _LOGGER.debug("Save NodeTypes for %s Nodes", len(cache_data_to_save)) - await self.write_cache( - cache_data_to_save, True - ) # rewrite set to True to make sure the cache-contents is actual + await self.write_cache(cache_data_to_save, rewrite=True) # Make sure the cache-contents is actual async def clear_cache(self) -> None: """Clear current cache.""" @@ -56,7 +54,7 @@ async def restore_cache(self) -> None: node_type = None if node_type is None: - _LOGGER.warning("Invalid NodeType in cache: %s", node_value) + _LOGGER.warning("Invalid NodeType in cache for mac %s: %s", mac, node_value) continue self._nodetypes[mac] = node_type _LOGGER.debug(