"""The IntelliFire integration.""" from __future__ import annotations import asyncio from intellifire4py import UnifiedFireplace from intellifire4py.cloud_interface import IntelliFireCloudInterface from intellifire4py.model import IntelliFireCommonFireplaceData from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( CONF_API_KEY, CONF_HOST, CONF_IP_ADDRESS, CONF_PASSWORD, CONF_USERNAME, Platform, ) from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from .const import ( CONF_AUTH_COOKIE, CONF_CONTROL_MODE, CONF_READ_MODE, CONF_SERIAL, CONF_USER_ID, CONF_WEB_CLIENT_ID, DOMAIN, INIT_WAIT_TIME_SECONDS, LOGGER, STARTUP_TIMEOUT, ) from .coordinator import IntellifireDataUpdateCoordinator PLATFORMS = [ Platform.BINARY_SENSOR, Platform.CLIMATE, Platform.FAN, Platform.LIGHT, Platform.NUMBER, Platform.SENSOR, Platform.SWITCH, ] def _construct_common_data(entry: ConfigEntry) -> IntelliFireCommonFireplaceData: """Convert config entry data into IntelliFireCommonFireplaceData.""" return IntelliFireCommonFireplaceData( auth_cookie=entry.data[CONF_AUTH_COOKIE], user_id=entry.data[CONF_USER_ID], web_client_id=entry.data[CONF_WEB_CLIENT_ID], serial=entry.data[CONF_SERIAL], api_key=entry.data[CONF_API_KEY], ip_address=entry.data[CONF_IP_ADDRESS], read_mode=entry.options[CONF_READ_MODE], control_mode=entry.options[CONF_CONTROL_MODE], ) async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: """Migrate entries.""" LOGGER.debug( "Migrating configuration from version %s.%s", config_entry.version, config_entry.minor_version, ) if config_entry.version == 1: new = {**config_entry.data} if config_entry.minor_version < 2: username = config_entry.data[CONF_USERNAME] password = config_entry.data[CONF_PASSWORD] # Create a Cloud Interface async with IntelliFireCloudInterface() as cloud_interface: await cloud_interface.login_with_credentials( username=username, password=password ) new_data = cloud_interface.user_data.get_data_for_ip(new[CONF_HOST]) if not new_data: raise ConfigEntryAuthFailed new[CONF_API_KEY] = new_data.api_key new[CONF_WEB_CLIENT_ID] = new_data.web_client_id new[CONF_AUTH_COOKIE] = new_data.auth_cookie new[CONF_IP_ADDRESS] = new_data.ip_address new[CONF_SERIAL] = new_data.serial hass.config_entries.async_update_entry( config_entry, data=new, options={CONF_READ_MODE: "local", CONF_CONTROL_MODE: "local"}, unique_id=new[CONF_SERIAL], version=1, minor_version=2, ) LOGGER.debug("Pseudo Migration %s successful", config_entry.version) return True async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up IntelliFire from a config entry.""" if CONF_USERNAME not in entry.data: LOGGER.debug("Config entry without username detected: %s", entry.unique_id) raise ConfigEntryAuthFailed try: fireplace: UnifiedFireplace = ( await UnifiedFireplace.build_fireplace_from_common( _construct_common_data(entry) ) ) LOGGER.debug("Waiting for Fireplace to Initialize") await asyncio.wait_for( _async_wait_for_initialization(fireplace), timeout=STARTUP_TIMEOUT ) except TimeoutError as err: raise ConfigEntryNotReady( "Initialization of fireplace timed out after 10 minutes" ) from err # Construct coordinator data_update_coordinator = IntellifireDataUpdateCoordinator( hass=hass, fireplace=fireplace ) LOGGER.debug("Fireplace to Initialized - Awaiting first refresh") await data_update_coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {})[entry.entry_id] = data_update_coordinator await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True async def _async_wait_for_initialization( fireplace: UnifiedFireplace, timeout=STARTUP_TIMEOUT ): """Wait for a fireplace to be initialized.""" while ( fireplace.data.ipv4_address == "127.0.0.1" and fireplace.data.serial == "unset" ): LOGGER.debug("Waiting for fireplace to initialize [%s]", fireplace.read_mode) await asyncio.sleep(INIT_WAIT_TIME_SECONDS) async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): hass.data[DOMAIN].pop(entry.entry_id) return unload_ok