From 5723d8c47cfc3a1637de082151d0d3cd51f5e8ba Mon Sep 17 00:00:00 2001 From: Patrick Elsasser Date: Thu, 14 Aug 2025 09:46:20 +0200 Subject: [PATCH] switch: tolerate missing 'type' in device info for legacy v1 firmware; use .get for version/mac/type; add test; update changelog (refs home-assistant/core#150264) --- CHANGELOG.md | 2 ++ pymystrom/switch.py | 7 +++--- tests/test_switch_missing_type.py | 37 +++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 tests/test_switch_missing_type.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a33a23..3ff3790 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - Add boot_id, energy_since_boot and time_since_boot to switch (thanks @slyoldfox) - Expose `device_type` property on switches +- Fix: Tolerate missing 'type' in device info for legacy myStrom v1 switches, preventing KeyError during get_state (related to home-assistant/core#150264) + ## 2.2.0 (2023-05-21) diff --git a/pymystrom/switch.py b/pymystrom/switch.py index d83b088..bda3373 100644 --- a/pymystrom/switch.py +++ b/pymystrom/switch.py @@ -87,9 +87,10 @@ async def get_state(self) -> None: url = URL(self.uri).join(URL("info.json")) response = await request(self, uri=url) - self._firmware = response["version"] - self._mac = response["mac"] - self._device_type = response["type"] + # Tolerate missing keys on legacy firmware (e.g., v1 devices) + self._firmware = response.get("version") + self._mac = response.get("mac") + self._device_type = response.get("type") @property def device_type(self) -> Optional[str]: diff --git a/tests/test_switch_missing_type.py b/tests/test_switch_missing_type.py new file mode 100644 index 0000000..53ef50d --- /dev/null +++ b/tests/test_switch_missing_type.py @@ -0,0 +1,37 @@ +import asyncio + +from pymystrom.switch import MyStromSwitch +import pymystrom.switch as switch_module + + +async def _fake_request(self, uri, method="GET", data=None, json_data=None, params=None): + uri_str = str(uri) + if uri_str.endswith("/report"): + return {"relay": True, "power": 1.23, "Ws": 0.5} + if uri_str.endswith("/api/v1/info"): + # Legacy v1 firmware without 'type' + return {"version": "2.68.10", "mac": "AA:BB:CC:DD:EE:FF"} + if uri_str.endswith("/info.json"): + return {"version": "2.68.10", "mac": "AA:BB:CC:DD:EE:FF"} + return {} + + +def test_get_state_missing_type(): + # Patch the request function used by MyStromSwitch + original_request = switch_module.request + switch_module.request = _fake_request + try: + sw = MyStromSwitch("127.0.0.1") + asyncio.run(sw.get_state()) + + assert sw.relay is True + assert sw.consumption == 1.2 + assert sw.consumedWs == 0.5 + assert sw.firmware == "2.68.10" + assert sw.mac == "AA:BB:CC:DD:EE:FF" + # Missing 'type' should be tolerated and map to None + assert sw.device_type is None + finally: + # Restore original request function + switch_module.request = original_request +