From 43d2fef1c94c4aac9f4971949b15d25b5fa3b873 Mon Sep 17 00:00:00 2001 From: trip-g Date: Tue, 21 Jul 2026 16:31:40 -0400 Subject: [PATCH 1/2] Fix ScheduleType.schedule_sub_type reading the wrong JSON key Resideo's API returns "scheduleSubtype" (lowercase t) for both device and location responses, not "scheduleSubType". Found while auditing device.py for the same class of field-name mismatch fixed in the priority endpoint (#165). Not currently consumed anywhere in Home Assistant's lyric integration, so this was never visibly broken, but the fixtures encoded the same wrong key the code was reading, so the existing tests passed without ever catching it against a real response. --- aiolyric/objects/device.py | 2 +- tests/__init__.py | 4 ++-- tests/objects/test_device.py | 2 +- tests/objects/test_location.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aiolyric/objects/device.py b/aiolyric/objects/device.py index 113c73e..363a590 100644 --- a/aiolyric/objects/device.py +++ b/aiolyric/objects/device.py @@ -51,7 +51,7 @@ def schedule_type(self): @property def schedule_sub_type(self): """Return the schedule sub type.""" - return self.attributes.get("scheduleSubType", None) + return self.attributes.get("scheduleSubtype", None) class SettingsHardwareSettings(LyricBaseObject): diff --git a/tests/__init__.py b/tests/__init__.py index ee93752..053b571 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -14,7 +14,7 @@ "availableScheduleTypes": ["None", "Geofenced", "TimedEmea"], "schedulableFan": False, }, - "scheduleType": {"scheduleType": "Timed", "scheduleSubType": "EMEA"}, + "scheduleType": {"scheduleType": "Timed", "scheduleSubtype": "EMEA"}, "scheduleStatus": "Resume", "allowedTimeIncrements": 10, "settings": { @@ -80,7 +80,7 @@ "availableScheduleTypes": ["None", "Geofenced", "TimedEmea"], "schedulableFan": False, }, - "scheduleType": {"scheduleType": "Timed", "scheduleSubType": "EMEA"}, + "scheduleType": {"scheduleType": "Timed", "scheduleSubtype": "EMEA"}, "scheduleStatus": "Resume", "allowedTimeIncrements": 10, "settings": { diff --git a/tests/objects/test_device.py b/tests/objects/test_device.py index 5b81664..eeaaf80 100644 --- a/tests/objects/test_device.py +++ b/tests/objects/test_device.py @@ -41,7 +41,7 @@ def test_device( ) assert ( obj.schedule_type.schedule_sub_type - == device_fixture_response["scheduleType"]["scheduleSubType"] + == device_fixture_response["scheduleType"]["scheduleSubtype"] ) assert obj.schedule_status == device_fixture_response["scheduleStatus"] assert ( diff --git a/tests/objects/test_location.py b/tests/objects/test_location.py index 095cfcb..e025bc0 100644 --- a/tests/objects/test_location.py +++ b/tests/objects/test_location.py @@ -52,7 +52,7 @@ def test_location( ) assert ( obj.devices[0].schedule_type.schedule_sub_type - == location_fixture_response["devices"][0]["scheduleType"]["scheduleSubType"] + == location_fixture_response["devices"][0]["scheduleType"]["scheduleSubtype"] ) assert ( obj.devices[0].schedule_status From dc955a96b0fc685d0bd7114de8f1737af6857528 Mon Sep 17 00:00:00 2001 From: clutch2sft Date: Mon, 10 Aug 2026 09:00:53 -0400 Subject: [PATCH 2/2] Support both scheduleSubType and scheduleSubtype keys Resideo's docs specify scheduleSubType, but the live API sends scheduleSubtype (lowercase t). Check the documented key first and fall back to the observed one so neither response shape reads back None. Addresses review feedback on #166. Co-Authored-By: Claude Sonnet 5 --- aiolyric/objects/device.py | 4 +++- tests/objects/test_device.py | 14 +++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/aiolyric/objects/device.py b/aiolyric/objects/device.py index 363a590..19899e1 100644 --- a/aiolyric/objects/device.py +++ b/aiolyric/objects/device.py @@ -51,7 +51,9 @@ def schedule_type(self): @property def schedule_sub_type(self): """Return the schedule sub type.""" - return self.attributes.get("scheduleSubtype", None) + return self.attributes.get( + "scheduleSubType", self.attributes.get("scheduleSubtype", None) + ) class SettingsHardwareSettings(LyricBaseObject): diff --git a/tests/objects/test_device.py b/tests/objects/test_device.py index eeaaf80..720ed31 100644 --- a/tests/objects/test_device.py +++ b/tests/objects/test_device.py @@ -1,7 +1,12 @@ """Test device object.""" from aiolyric.client import LyricClient -from aiolyric.objects.device import DeviceSettings, LyricDevice, SettingsSpecialMode +from aiolyric.objects.device import ( + DeviceSettings, + LyricDevice, + ScheduleType, + SettingsSpecialMode, +) def test_device( @@ -144,3 +149,10 @@ def test_device( ) assert obj.device_model == device_fixture_response["deviceModel"] assert obj.fan_mode == device_fixture_response["fanMode"] + + +def test_schedule_type_sub_type_key_variants(): + """Test schedule_sub_type accepts both the documented and live API keys.""" + assert ScheduleType({"scheduleSubType": "EMEA"}).schedule_sub_type == "EMEA" + assert ScheduleType({"scheduleSubtype": "EMEA"}).schedule_sub_type == "EMEA" + assert ScheduleType({}).schedule_sub_type is None