Fix update_priority functionality to support T9 and T10 with sensors#134
Open
alibosworth wants to merge 2 commits intotimmo001:masterfrom
Open
Fix update_priority functionality to support T9 and T10 with sensors#134alibosworth wants to merge 2 commits intotimmo001:masterfrom
alibosworth wants to merge 2 commits intotimmo001:masterfrom
Conversation
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.
c10d5f2 to
19383b4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
selectedRoomswhen rooms is not passed into update_priority. During debugging the broken functionality I noticedselectedRoomswas being passed even when the priorityType was something other thanPickARoom.Note: setting priorityType to
WholeHouseappears 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())