Skip to content

Comments

Fix update_priority functionality to support T9 and T10 with sensors#134

Open
alibosworth wants to merge 2 commits intotimmo001:masterfrom
alibosworth:fix_set_priority
Open

Fix update_priority functionality to support T9 and T10 with sensors#134
alibosworth wants to merge 2 commits intotimmo001:masterfrom
alibosworth:fix_set_priority

Conversation

@alibosworth
Copy link

@alibosworth alibosworth commented Feb 22, 2026

As per the lyric API docs the "Set Room Priority" endpoint is used via a PUT not a POST. It was not working as a POST (maybe it did previously). This commit switches to a PUT and also stops sending selectedRooms when rooms is not passed into update_priority. During debugging the broken functionality I noticed selectedRooms was being passed even when the priorityType was something other than PickARoom.

Note: setting priorityType to WholeHouse appears to work however on re-fetch it never persists. The Resideo app does not expose the WholeHouse option (even when multiple rooms with sensors are configured) so I suspect this is a feature that is not fully built out on the API side.

Here is a video demonstrating using this post-fix, showing the priority changes are reflected in the Resideo iOS app

Screen.Recording.2026-02-21.at.6.16.12.PM.mp4
Here is the test code that I was using in the video """Interactive test for setting room priority via aiolyric.""" import asyncio import base64 import aiohttp from aiolyric import Lyric from aiolyric.client import LyricClient from aiolyric.const import TOKEN_URL # Your Honeywell Developer API credentials CLIENT_ID = "[[YOUR CLIENT ID]]" CLIENT_SECRET = "[[YOUR CLIENT SECRET]]" REFRESH_TOKEN = "[[YOUR REFRESH TOKEN]]" class LiveLyricClient(LyricClient): """Client that refreshes the access token automatically.""" def __init__(self, session: aiohttp.ClientSession) -> None: """Initialize the client.""" super().__init__(session) self._access_token: str | None = None async def async_get_access_token(self) -> str: """Refresh and return a valid access token.""" if self._access_token is not None: return self._access_token print("Refreshing access token...") credentials = base64.b64encode( f"{CLIENT_ID}:{CLIENT_SECRET}".encode() ).decode() async with self._session.post( TOKEN_URL, headers={ "Authorization": f"Basic {credentials}", "Content-Type": "application/x-www-form-urlencoded", }, data={ "grant_type": "refresh_token", "refresh_token": REFRESH_TOKEN, }, ) as resp: data = await resp.json() if resp.status != 200: raise Exception(f"Token refresh failed: {data}") self._access_token = data["access_token"] # print(f"New access token: {self._access_token}") # print(f"New refresh token: {data.get('refresh_token', 'N/A')}") return self._access_token async def main(): async with aiohttp.ClientSession() as session: client = LiveLyricClient(session) lyric = Lyric(client, CLIENT_ID) await lyric.get_locations() for location in lyric.locations: await lyric.get_devices(location.location_id) thermostats = [d for d in lyric.devices if d.device_class == "Thermostat"] if not thermostats: print(f"No thermostats found at {location.name}") continue # Pick thermostat if multiple if len(thermostats) == 1: thermostat = thermostats[0] else: print("\nThermostats:") for i, t in enumerate(thermostats): print(f" {i + 1}) {t.name}") try: choice = int(input("Select thermostat: ")) - 1 thermostat = thermostats[choice] except (ValueError, IndexError): print("Invalid choice") continue print(f"\nThermostat: {thermostat.name}") while True: # Fetch current priority (includes room details) await lyric.get_thermostat_rooms(location.location_id, thermostat.device_id) rooms_for_device = lyric.rooms_dict.get(thermostat.mac_id, {}) priority_rooms = list(rooms_for_device.values()) # We need the raw priority data for selected rooms and priority type. # get_thermostat_rooms only exposes rooms via rooms_dict, so we need # to re-fetch the priority endpoint for the full response. from aiolyric.const import BASE_URL response = await client.get( f"{BASE_URL}/devices/thermostats/{thermostat.device_id}/priority" f"?apikey={CLIENT_ID}&locationId={location.location_id}" ) priority_json = await response.json() current_priority = priority_json.get("currentPriority", {}) current_type = current_priority.get("priorityType") # Build room name lookup room_names = {} for room in priority_rooms: room_names[room.id] = room.room_name or f"Room {room.id}" # Display current priority print(f"\nCurrent priority type: {current_type}") if current_type == "PickARoom": selected_room_ids = current_priority.get("selectedRooms", []) print("Selected rooms:") for rid in selected_room_ids: room_type = "Unknown" for room in priority_rooms: if room.id == rid: types = [a.type or "Unknown" for a in room.accessories] room_type = ", ".join(types) if types else "No accessories" break print(f" - {room_names.get(rid, f'Room {rid}')} (id: {rid}, {room_type})") # Count rooms with motion-enabled sensors motion_rooms = 0 for room in priority_rooms: for accessory in room.accessories: if accessory.exclude_motion is False and accessory.type != "Thermostat": motion_rooms += 1 break # Prompt for priority type print("\nPriority types:") print(" 1) PickARoom - Set priority to selected room(s)") followme_note = "" if motion_rooms == 0: followme_note = " (warning: no rooms have motion detection enabled)" else: followme_note = f" ({motion_rooms} room(s) with motion detection)" print(f" 2) FollowMe - Set priority based on motion/occupancy{followme_note}") print(" 3) WholeHouse - Use all rooms for priority (may not persist API side, option not present in iOS app)") print(" q) Quit") type_choice = input("\nSelect priority type (1-3, q): ").strip() if type_choice.lower() == "q": break priority_map = {"1": "PickARoom", "2": "FollowMe", "3": "WholeHouse"} if type_choice not in priority_map: print("Invalid choice") continue priority_type = priority_map[type_choice] selected_rooms = None if priority_type == "PickARoom": # Show available rooms valid_room_ids = set() print("\nAvailable rooms:") for room in priority_rooms: valid_room_ids.add(room.id) types = [a.type or "Unknown" for a in room.accessories] type_label = ", ".join(types) if types else "No accessories" print(f" id {room.id}: {room.room_name or f'Room {room.id}'} ({type_label})") picks = input("\nSelect room ids (comma-separated, e.g. 0,2): ").strip() selected_rooms = [] for p in picks.split(","): try: room_id = int(p.strip()) except ValueError: print(f"Invalid input: '{p.strip()}'") selected_rooms = None break if room_id not in valid_room_ids: print(f"Invalid room id: {room_id} (valid: {sorted(valid_room_ids)})") selected_rooms = None break selected_rooms.append(room_id) if selected_rooms is None: continue print(f"\nSetting priority to '{priority_type}'", end="") if selected_rooms: room_labels = [room_names.get(r, f"Room {r}") for r in selected_rooms] print(f" with rooms: {', '.join(room_labels)}", end="") print("...", flush=True) await lyric.update_priority(location, thermostat, priority_type, selected_rooms) print("Fetching updated priority...", flush=True) asyncio.run(main())

As per the [lyric API docs](https://developer.honeywellhome.com/lyric/apis) the "Set Room Priority" endpoint is used via a PUT not a POST.  It was not working as a POST (maybe it did previously. This commit switches to a PUT and also stops sending `selectedRooms` when rooms is not passed into update_priority. During debugging the broken functionality I noticed `selectedRooms` was being passed even when the priorityType was something other than `PickARoom`.

Note: setting priorityType to `WholeHouse` appears to work however on re-fetch it never persists.  The Resideo app does not expose the WholeHouse option (even when multiple rooms with sensors are configured) so I suspect this is a feature that is not fully built out on the API side.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant