text: """The Honeywell Lyric integration."""
  from __future__ import annotations
  
  from datetime import timedelta
  from http import HTTPStatus
  import logging
  
  from aiohttp.client_exceptions import ClientResponseError
  from aiolyric import Lyric
  from aiolyric.exceptions import LyricAuthenticationException, LyricException
  from aiolyric.objects.device import LyricDevice
  from aiolyric.objects.location import LyricLocation
  import async_timeout
  import voluptuous as vol
  
  from homeassistant.components.application_credentials import (
      ClientCredential,
      async_import_client_credential,
  )
  from homeassistant.config_entries import ConfigEntry
  from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, Platform
  from homeassistant.core import HomeAssistant
  from homeassistant.exceptions import ConfigEntryAuthFailed
  from homeassistant.helpers import (
      aiohttp_client,
      config_entry_oauth2_flow,
      config_validation as cv,
      device_registry as dr,
  )
  from homeassistant.helpers.entity import DeviceInfo
  from homeassistant.helpers.typing import ConfigType
  from homeassistant.helpers.update_coordinator import (
      CoordinatorEntity,
      DataUpdateCoordinator,
      UpdateFailed,
  )
  
  from .api import (
      ConfigEntryLyricClient,
      LyricLocalOAuth2Implementation,
      OAuth2SessionLyric,
  )
  from .const import DOMAIN
  
  CONFIG_SCHEMA = vol.Schema(
      vol.All(
          cv.deprecated(DOMAIN),
          {
              DOMAIN: vol.Schema(
                  {
                      vol.Required(CONF_CLIENT_ID): cv.string,
                      vol.Required(CONF_CLIENT_SECRET): cv.string,
                  }
              )
          },
      ),
      extra=vol.ALLOW_EXTRA,
  )
  
  _LOGGER = logging.getLogger(__name__)
  
  PLATFORMS = [Platform.CLIMATE, Platform.SENSOR]
  
  
  async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
      """Set up the Honeywell Lyric component."""
      hass.data[DOMAIN] = {}
  
      if DOMAIN not in config:
          return True
  
      await async_import_client_credential(
          hass,
          DOMAIN,
          ClientCredential(
              config[DOMAIN][CONF_CLIENT_ID],
              config[DOMAIN][CONF_CLIENT_SECRET],
          ),
      )
  
      _LOGGER.warning(
          "Configuration of Honeywell Lyric integration in YAML is deprecated "
          "and will be removed in a future release; Your existing OAuth "
          "Application Credentials have been imported into the UI "
          "automatically and can be safely removed from your "
          "configuration.yaml file"
      )
  
      return True
  
  
  async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
      """Set up Honeywell Lyric from a config entry."""
      implementation = (
          await config_entry_oauth2_flow.async_get_config_entry_implementation(
              hass, entry
          )
      )
      if not isinstance(implementation, LyricLocalOAuth2Implementation):
          raise ValueError("Unexpected auth implementation; can't find oauth client id")
  
      session = aiohttp_client.async_get_clientsession(hass)
      oauth_session = OAuth2SessionLyric(hass, entry, implementation)
  
      client = ConfigEntryLyricClient(session, oauth_session)
  
      client_id = implementation.client_id
      lyric = Lyric(client, client_id)
  
      async def async_update_data(force_refresh_token: bool = False) -> Lyric:
          """Fetch data from Lyric."""
          try:
              if not force_refresh_token:
                  await oauth_session.async_ensure_token_valid()
              else:
                  await oauth_session.force_refresh_token()
          except ClientResponseError as exception:
              if exception.status in (HTTPStatus.UNAUTHORIZED, HTTPStatus.FORBIDDEN):
                  raise ConfigEntryAuthFailed from exception
              raise UpdateFailed(exception) from exception
  
          try:
              async with async_timeout.timeout(60):
                  await lyric.get_locations()
              return lyric
          except LyricAuthenticationException as exception:
              # Attempt to refresh the token before failing.
              # Honeywell appear to have issues keeping tokens saved.
              _LOGGER.debug("Authentication failed. Attempting to refresh token")
              if not force_refresh_token:
                  return await async_update_data(force_refresh_token=True)
              raise ConfigEntryAuthFailed from exception
          except (LyricException, ClientResponseError) as exception:
              raise UpdateFailed(exception) from exception
  
      coordinator = DataUpdateCoordinator(
          hass,
          _LOGGER,
          # Name of the data. For logging purposes.
          name="lyric_coordinator",
          update_method=async_update_data,
          # Polling interval. Will only be polled if there are subscribers.
          update_interval=timedelta(seconds=300),
      )
  
      hass.data[DOMAIN][entry.entry_id] = coordinator
  
      # Fetch initial data so we have data when entities subscribe
      await coordinator.async_config_entry_first_refresh()
  
      hass.config_entries.async_setup_platforms(entry, PLATFORMS)
  
      return True
  
  
  async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
      """Unload a config entry."""
      unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
      if unload_ok:
          hass.data[DOMAIN].pop(entry.entry_id)
  
      return unload_ok
  
  
  class LyricEntity(CoordinatorEntity):
      """Defines a base Honeywell Lyric entity."""
  
      def __init__(
          self,
          coordinator: DataUpdateCoordinator,
          location: LyricLocation,
          device: LyricDevice,
          key: str,
      ) -> None:
          """Initialize the Honeywell Lyric entity."""
          super().__init__(coordinator)
          self._key = key
          self._location = location
          self._mac_id = device.macID
          self._update_thermostat = coordinator.data.update_thermostat
  
      @property
      def unique_id(self) -> str:
          """Return the unique ID for this entity."""
          return self._key
  
      @property
      def location(self) -> LyricLocation:
          """Get the Lyric Location."""
          return self.coordinator.data.locations_dict[self._location.locationID]
  
      @property
      def device(self) -> LyricDevice:
          """Get the Lyric Device."""
          return self.location.devices_dict[self._mac_id]
  
  
  class LyricDeviceEntity(LyricEntity):
      """Defines a Honeywell Lyric device entity."""
  
      @property
      def device_info(self) -> DeviceInfo:
          """Return device information about this Honeywell Lyric instance."""
          return DeviceInfo(
              connections={(dr.CONNECTION_NETWORK_MAC, self._mac_id)},
              manufacturer="Honeywell",
              model=self.device.deviceModel,
              name=self.device.name,
          )
  