"""The Ninlight integration.""" from __future__ import annotations import logging from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from .const import CONF_TOKEN, DEFAULT_PORT, PLATFORMS from .coordinator import NinlightConfigEntry, NinlightCoordinator _LOGGER = logging.getLogger(__name__) async def async_setup_entry(hass: HomeAssistant, entry: NinlightConfigEntry) -> bool: """Set up a Ninlight bulb from a config entry.""" coordinator = NinlightCoordinator(hass, entry) # Register the teardown before the first refresh: HA runs the on_unload callbacks both # when setup fails and when the entry unloads, and awaits the coroutine they return. # That covers every exit path, so no bulb client can be left with an open connection # slot. The bulb serves one request per connection, so this matters. entry.async_on_unload(coordinator.async_shutdown) try: await coordinator.async_config_entry_first_refresh() except Exception: # ConfigEntryNotReady / ConfigEntryAuthFailed propagate to HA, which retries or # raises reauth. Close now rather than waiting for the retry. await coordinator.async_shutdown() raise entry.runtime_data = coordinator await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True async def async_unload_entry(hass: HomeAssistant, entry: NinlightConfigEntry) -> bool: """Unload a config entry.""" return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: """Migrate an entry written by an earlier version of this integration.""" if config_entry.version > 1: return False if "port" not in config_entry.data or CONF_TOKEN not in config_entry.data: new = dict(config_entry.data) new.setdefault("port", DEFAULT_PORT) new.setdefault(CONF_TOKEN, new.pop("api_key", "")) hass.config_entries.async_update_entry(config_entry, data=new, version=1) _LOGGER.debug("Migrated ninlight entry %s to v1", config_entry.entry_id) return True