text: """The Honeywell Lyric integration."""
  import asyncio
  from datetime import timedelta
  import logging
  from typing import Any, Dict, Optional
  
  from aiolyric import Lyric
  from aiolyric.objects.device import LyricDevice
  from aiolyric.objects.location import LyricLocation
  import async_timeout
  import voluptuous as vol
  
  from homeassistant.config_entries import ConfigEntry
  from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
  from homeassistant.core import HomeAssistant
  from homeassistant.exceptions import ConfigEntryNotReady
  from homeassistant.helpers import (
      aiohttp_client,
      config_entry_oauth2_flow,
      config_validation as cv,
      device_registry as dr,
  )
  from homeassistant.helpers.update_coordinator import (
      CoordinatorEntity,
      DataUpdateCoordinator,
      UpdateFailed,
  )
  
  from .api import ConfigEntryLyricClient, LyricLocalOAuth2Implementation
  from .config_flow import OAuth2FlowHandler
  from .const import DOMAIN, LYRIC_EXCEPTIONS, OAUTH2_AUTHORIZE, OAUTH2_TOKEN
  
  CONFIG_SCHEMA = vol.Schema(
      {
          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 = ["climate"]
  
  
  async def async_setup(hass: HomeAssistant, config: dict):
      """Set up the Honeywell Lyric component."""
      hass.data[DOMAIN] = {}
  
      if DOMAIN not in config:
          return True
  
      hass.data[DOMAIN][CONF_CLIENT_ID] = config[DOMAIN][CONF_CLIENT_ID]
  
      OAuth2FlowHandler.async_register_implementation(
          hass,
          LyricLocalOAuth2Implementation(
              hass,
              DOMAIN,
              config[DOMAIN][CONF_CLIENT_ID],
              config[DOMAIN][CONF_CLIENT_SECRET],
              OAUTH2_AUTHORIZE,
              OAUTH2_TOKEN,
          ),
      )
  
      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
          )
      )
  
      session = aiohttp_client.async_get_clientsession(hass)
      oauth_session = config_entry_oauth2_flow.OAuth2Session(hass, entry, implementation)
  
      client = ConfigEntryLyricClient(session, oauth_session)
  
      client_id = hass.data[DOMAIN][CONF_CLIENT_ID]
      lyric: Lyric = Lyric(client, client_id)
  
      async def async_update_data() -> Lyric:
          """Fetch data from Lyric."""
          try:
              async with async_timeout.timeout(60):
                  await lyric.get_locations()
              return lyric
          except (*LYRIC_EXCEPTIONS, TimeoutError) 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=120),
      )
  
      hass.data[DOMAIN][entry.entry_id] = coordinator
  
      # Fetch initial data so we have data when entities subscribe
      await coordinator.async_refresh()
      if not coordinator.last_update_success:
          raise ConfigEntryNotReady
  
      for component in PLATFORMS:
          hass.async_create_task(
              hass.config_entries.async_forward_entry_setup(entry, component)
          )
  
      return True
  
  
  async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
      """Unload a config entry."""
      unload_ok = all(
          await asyncio.gather(
              *[
                  hass.config_entries.async_forward_entry_unload(entry, component)
                  for component in 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,
          name: str,
          icon: Optional[str],
      ) -> None:
          """Initialize the Honeywell Lyric entity."""
          super().__init__(coordinator)
          self._key = key
          self._name = name
          self._icon = icon
          self._location = location
          self._mac_id = device.macID
          self._device_name = device.name
          self._device_model = device.deviceModel
          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 name(self) -> str:
          """Return the name of the entity."""
          return self._name
  
      @property
      def icon(self) -> str:
          """Return the mdi icon of the entity."""
          return self._icon
  
      @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) -> Dict[str, Any]:
          """Return device information about this Honeywell Lyric instance."""
          return {
              "connections": {(dr.CONNECTION_NETWORK_MAC, self._mac_id)},
              "manufacturer": "Honeywell",
              "model": self._device_model,
              "name": self._device_name,
          }
  