Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The Honeywell Lyric integration."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from datetime import timedelta
7 from http import HTTPStatus
8 import logging
9 
10 from aiohttp.client_exceptions import ClientResponseError
11 from aiolyric import Lyric
12 from aiolyric.exceptions import LyricAuthenticationException, LyricException
13 
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.const import Platform
16 from homeassistant.core import HomeAssistant
17 from homeassistant.exceptions import ConfigEntryAuthFailed
18 from homeassistant.helpers import (
19  aiohttp_client,
20  config_entry_oauth2_flow,
21  config_validation as cv,
22 )
23 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
24 
25 from .api import (
26  ConfigEntryLyricClient,
27  LyricLocalOAuth2Implementation,
28  OAuth2SessionLyric,
29 )
30 from .const import DOMAIN
31 
32 CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
33 
34 _LOGGER = logging.getLogger(__name__)
35 
36 PLATFORMS = [Platform.CLIMATE, Platform.SENSOR]
37 
38 
39 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
40  """Set up Honeywell Lyric from a config entry."""
41  implementation = (
42  await config_entry_oauth2_flow.async_get_config_entry_implementation(
43  hass, entry
44  )
45  )
46  if not isinstance(implementation, LyricLocalOAuth2Implementation):
47  raise TypeError("Unexpected auth implementation; can't find oauth client id")
48 
49  session = aiohttp_client.async_get_clientsession(hass)
50  oauth_session = OAuth2SessionLyric(hass, entry, implementation)
51 
52  client = ConfigEntryLyricClient(session, oauth_session)
53 
54  client_id = implementation.client_id
55  lyric = Lyric(client, client_id)
56 
57  async def async_update_data(force_refresh_token: bool = False) -> Lyric:
58  """Fetch data from Lyric."""
59  try:
60  if not force_refresh_token:
61  await oauth_session.async_ensure_token_valid()
62  else:
63  await oauth_session.force_refresh_token()
64  except ClientResponseError as exception:
65  if exception.status in (HTTPStatus.UNAUTHORIZED, HTTPStatus.FORBIDDEN):
66  raise ConfigEntryAuthFailed from exception
67  raise UpdateFailed(exception) from exception
68 
69  try:
70  async with asyncio.timeout(60):
71  await lyric.get_locations()
72  await asyncio.gather(
73  *(
74  lyric.get_thermostat_rooms(
75  location.location_id, device.device_id
76  )
77  for location in lyric.locations
78  for device in location.devices
79  if device.device_class == "Thermostat"
80  and device.device_id.startswith("LCC")
81  )
82  )
83 
84  except LyricAuthenticationException as exception:
85  # Attempt to refresh the token before failing.
86  # Honeywell appear to have issues keeping tokens saved.
87  _LOGGER.debug("Authentication failed. Attempting to refresh token")
88  if not force_refresh_token:
89  return await async_update_data(force_refresh_token=True)
90  raise ConfigEntryAuthFailed from exception
91  except (LyricException, ClientResponseError) as exception:
92  raise UpdateFailed(exception) from exception
93  return lyric
94 
95  coordinator = DataUpdateCoordinator[Lyric](
96  hass,
97  _LOGGER,
98  config_entry=entry,
99  # Name of the data. For logging purposes.
100  name="lyric_coordinator",
101  update_method=async_update_data,
102  # Polling interval. Will only be polled if there are subscribers.
103  update_interval=timedelta(seconds=300),
104  )
105 
106  # Fetch initial data so we have data when entities subscribe
107  await coordinator.async_config_entry_first_refresh()
108  hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
109 
110  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
111 
112  return True
113 
114 
115 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
116  """Unload a config entry."""
117  unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
118  if unload_ok:
119  hass.data[DOMAIN].pop(entry.entry_id)
120 
121  return unload_ok
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:115
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:39