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 diff --git a/plugwise_usb/network/cache.py b/plugwise_usb/network/cache.py index 504a89014..3f6d4a3f8 100644 --- a/plugwise_usb/network/cache.py +++ b/plugwise_usb/network/cache.py @@ -26,12 +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(): - 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: 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, rewrite=True) # Make sure the cache-contents is actual async def clear_cache(self) -> None: """Clear current cache.""" @@ -44,13 +43,18 @@ 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).upper() + node_type = NodeType.__members__.get(key) # e.g., "CIRCLE" + if node_type is None: 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) + _LOGGER.warning("Invalid NodeType in cache for mac %s: %s", mac, node_value) continue self._nodetypes[mac] = node_type _LOGGER.debug( @@ -86,5 +90,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() diff --git a/tests/test_usb.py b/tests/test_usb.py index 0d452a2c4..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) @@ -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 == {