1 """Support for LIFX."""
3 from __future__
import annotations
6 from collections.abc
import Iterable
7 from datetime
import datetime, timedelta
11 from aiolifx.aiolifx
import Light
12 from aiolifx.connection
import LIFXConnection
13 import voluptuous
as vol
20 EVENT_HOMEASSISTANT_STARTED,
29 from .const
import _LOGGER, DATA_LIFX_MANAGER, DOMAIN, TARGET_ANY
30 from .coordinator
import LIFXUpdateCoordinator
31 from .discovery
import async_discover_devices, async_trigger_discovery
32 from .manager
import LIFXManager
33 from .migration
import async_migrate_entities_devices, async_migrate_legacy_entries
34 from .util
import async_entry_is_legacy, async_get_legacy_entry, formatted_serial
36 CONF_SERVER =
"server"
37 CONF_BROADCAST =
"broadcast"
40 INTERFACE_SCHEMA = vol.Schema(
42 vol.Optional(CONF_SERVER): cv.string,
43 vol.Optional(CONF_PORT): cv.port,
44 vol.Optional(CONF_BROADCAST): cv.string,
48 CONFIG_SCHEMA = vol.All(
49 cv.deprecated(DOMAIN),
53 LIGHT_DOMAIN: vol.Schema(vol.All(cv.ensure_list, [INTERFACE_SCHEMA]))
56 extra=vol.ALLOW_EXTRA,
62 Platform.BINARY_SENSOR,
71 DISCOVERY_COOLDOWN = 5
76 legacy_entry: ConfigEntry,
77 discovered_devices: Iterable[Light],
79 """Migrate config entries."""
82 for entry
in hass.config_entries.async_entries(DOMAIN)
86 hosts_by_serial = {device.mac_addr: device.ip_addr
for device
in discovered_devices}
88 hass, hosts_by_serial, existing_serials, legacy_entry
90 if missing_discovery_count:
92 "Migration in progress, waiting to discover %s device(s)",
93 missing_discovery_count,
98 "Migration successful, removing legacy entry %s", legacy_entry.entry_id
100 await hass.config_entries.async_remove(legacy_entry.entry_id)
105 """Manage discovery and migration."""
107 def __init__(self, hass: HomeAssistant, migrating: bool) ->
None:
108 """Init the manager."""
116 """Set up discovery at an interval."""
120 discovery_interval = (
121 MIGRATION_INTERVAL
if self.
migratingmigrating
else DISCOVERY_INTERVAL
124 "LIFX starting discovery with interval: %s and migrating: %s",
129 self.
hasshass, self.
async_discoveryasync_discovery, discovery_interval, cancel_on_shutdown=
True
133 """Discovery and migrate LIFX devics."""
134 migrating_was_in_progress = self.
migratingmigrating
136 async
with self.
locklock:
141 self.
hasshass, legacy_entry, discovered
143 if migration_complete
and migrating_was_in_progress:
147 "LIFX migration complete, switching to normal discovery"
158 async
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
159 """Set up the LIFX component."""
160 hass.data[DOMAIN] = {}
165 def _async_delayed_discovery(now: datetime) ->
None:
166 """Start an untracked task to discover devices.
168 We do not want the discovery task to block startup.
170 hass.async_create_background_task(
171 discovery_manager.async_discovery(),
"lifx-discovery"
177 discovery_manager.async_setup_discovery_interval()
181 HassJob(_async_delayed_discovery, cancel_on_shutdown=
True),
183 hass.bus.async_listen_once(
184 EVENT_HOMEASSISTANT_STARTED, discovery_manager.async_discovery
191 """Set up LIFX from a config entry."""
200 assert entry.unique_id
is not None
201 domain_data = hass.data[DOMAIN]
202 if DATA_LIFX_MANAGER
not in domain_data:
204 domain_data[DATA_LIFX_MANAGER] = manager
205 manager.async_setup()
207 host = entry.data[CONF_HOST]
208 connection = LIFXConnection(host, TARGET_ANY)
210 await connection.async_setup()
211 except socket.gaierror
as ex:
212 connection.async_stop()
215 coordinator.async_setup()
217 await coordinator.async_config_entry_first_refresh()
218 except ConfigEntryNotReady:
219 connection.async_stop()
223 if serial != entry.unique_id:
230 f
"Unexpected device found at {host}; expected {entry.unique_id}, found {serial}"
232 domain_data[entry.entry_id] = coordinator
233 await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
238 """Unload a config entry."""
241 domain_data = hass.data[DOMAIN]
242 if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
243 coordinator: LIFXUpdateCoordinator = domain_data.pop(entry.entry_id)
244 coordinator.connection.async_stop()
246 if len(domain_data) == 1:
247 manager: LIFXManager = domain_data.pop(DATA_LIFX_MANAGER)
248 manager.async_unload()
None __init__(self, HomeAssistant hass, bool migrating)
None async_discovery(self, *Any _)
None async_setup_discovery_interval(self)
None async_migrate_entities_devices(HomeAssistant hass, str legacy_entry_id, ConfigEntry new_entry)
int async_migrate_legacy_entries(HomeAssistant hass, dict[str, str] discovered_hosts_by_serial, set[str] existing_serials, ConfigEntry legacy_entry)
ConfigEntry|None async_get_legacy_entry(HomeAssistant hass)
bool async_entry_is_legacy(ConfigEntry entry)
str formatted_serial(str serial_number)
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
bool async_setup(HomeAssistant hass, ConfigType config)
bool async_legacy_migration(HomeAssistant hass, ConfigEntry legacy_entry, Iterable[Light] discovered_devices)
dict[str, Device] async_discover_devices(HomeAssistant hass)
None async_trigger_discovery(HomeAssistant hass, dict[str, Device] discovered_devices)
CALLBACK_TYPE async_call_later(HomeAssistant hass, float|timedelta delay, HassJob[[datetime], Coroutine[Any, Any, None]|None]|Callable[[datetime], Coroutine[Any, Any, None]|None] action)
CALLBACK_TYPE async_track_time_interval(HomeAssistant hass, Callable[[datetime], Coroutine[Any, Any, None]|None] action, timedelta interval, *str|None name=None, bool|None cancel_on_shutdown=None)