From 97c0bbee6068518f4713151cf75a2c5adeb02df1 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Sat, 3 Oct 2026 12:24:40 +0000 Subject: [PATCH] Do not fail the whole device on a Wi-Fi still connecting A real TIME, still (re)connecting to its Wi-Fi network, answered without active, ip and netmask, and with mac and ssid as null. That made the whole device fail to parse, taking the display, audio and everything else down with it until the next poll. Those Wi-Fi fields are optional now, so only the Wi-Fi details are missing while the device connects. --- src/demetriek/models.py | 13 +++-- tests/fixtures/device_wifi_connecting.json | 67 ++++++++++++++++++++++ tests/test_device.py | 27 +++++++++ 3 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 tests/fixtures/device_wifi_connecting.json diff --git a/src/demetriek/models.py b/src/demetriek/models.py index 642f5b2f..eefa1e72 100644 --- a/src/demetriek/models.py +++ b/src/demetriek/models.py @@ -177,15 +177,18 @@ class Config(BaseConfig): class Wifi(DataClassORJSONMixin): """Object holding the Wi-Fi state of an LaMetric device.""" - active: bool available: bool encryption: str | None = None - ip: IPv4Address - mac: str mode: WifiMode - netmask: str rssi: int | None = None - ssid: str + + # A device that is (re)connecting to its Wi-Fi network leaves these out, + # or reports them as null. Seen on a real TIME, home-assistant/core#97575. + active: bool | None = None + ip: IPv4Address | None = None + mac: str | None = None + netmask: str | None = None + ssid: str | None = None @dataclass(kw_only=True) diff --git a/tests/fixtures/device_wifi_connecting.json b/tests/fixtures/device_wifi_connecting.json new file mode 100644 index 00000000..269c9fe8 --- /dev/null +++ b/tests/fixtures/device_wifi_connecting.json @@ -0,0 +1,67 @@ +{ + "audio": { + "volume": 46, + "volume_limit": { + "max": 100, + "min": 0 + }, + "volume_range": { + "max": 100, + "min": 0 + } + }, + "bluetooth": { + "active": false, + "address": "AA:BB:CC:DD:EE:FF", + "available": true, + "discoverable": true, + "low_energy": { + "active": true, + "advertising": true, + "connectable": true + }, + "name": "LM1234", + "pairable": true + }, + "display": { + "brightness": 100, + "brightness_limit": { + "max": 100, + "min": 2 + }, + "brightness_mode": "auto", + "brightness_range": { + "max": 100, + "min": 0 + }, + "height": 8, + "screensaver": { + "enabled": true, + "modes": { + "time_based": { + "enabled": false + }, + "when_dark": { + "enabled": true + } + }, + "widget": "08b8eac21074f8f7e5a29f2855ba8060" + }, + "type": "mixed", + "width": 37 + }, + "id": "12345", + "mode": "manual", + "model": "LM 37X8", + "name": "Living room", + "os_version": "2.3.9", + "serial_number": "SA000000000000W00BS9", + "wifi": { + "address": null, + "available": true, + "encryption": "WPA", + "essid": null, + "mode": "dhcp", + "strength": 18 + } +} diff --git a/tests/test_device.py b/tests/test_device.py index ca22ec8b..47b03579 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -136,6 +136,33 @@ async def test_get_device_wifi_not_an_object( await device.device() +async def test_get_device_wifi_connecting( + responses: aioresponses, device: LaMetricDevice +) -> None: + """Test a device still connecting to its Wi-Fi does not fail the update. + + A real TIME answered like this in home-assistant/core#97575. Only the + Wi-Fi details are missing, the rest of the device is still there. + """ + responses.get( + f"{DEVICE_URL}/api/v2/device", + status=200, + body=load_fixture("device_wifi_connecting.json"), + ) + + result = await device.device() + + assert result.wifi.available is True + assert result.wifi.rssi == 18 + assert result.wifi.active is None + assert result.wifi.ip is None + assert result.wifi.mac is None + assert result.wifi.netmask is None + assert result.wifi.ssid is None + assert result.display.brightness is not None + assert result.audio is not None + + async def test_get_device_update( responses: aioresponses, device: LaMetricDevice ) -> None: