From 1e4463957d9da7c335020010907c88f9aa11500a Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Wed, 17 Oct 2018 10:50:13 +0200 Subject: [PATCH] Scan all network interfaces for LIFX bulbs (#17530) --- homeassistant/components/lifx/__init__.py | 59 ++++------------------- homeassistant/components/light/lifx.py | 35 ++++++++------ requirements_all.txt | 2 +- 3 files changed, 32 insertions(+), 64 deletions(-) diff --git a/homeassistant/components/lifx/__init__.py b/homeassistant/components/lifx/__init__.py index 85e249eb934..1ca6c00b23a 100644 --- a/homeassistant/components/lifx/__init__.py +++ b/homeassistant/components/lifx/__init__.py @@ -1,8 +1,4 @@ """Component to embed LIFX.""" -import asyncio -import socket - -import async_timeout import voluptuous as vol import homeassistant.helpers.config_validation as cv @@ -12,17 +8,20 @@ from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN DOMAIN = 'lifx' -REQUIREMENTS = ['aiolifx==0.6.3'] +REQUIREMENTS = ['aiolifx==0.6.5'] CONF_SERVER = 'server' CONF_BROADCAST = 'broadcast' +INTERFACE_SCHEMA = vol.Schema({ + vol.Optional(CONF_SERVER): cv.string, + vol.Optional(CONF_BROADCAST): cv.string, +}) + CONFIG_SCHEMA = vol.Schema({ DOMAIN: { - LIGHT_DOMAIN: { - vol.Optional(CONF_SERVER): cv.string, - vol.Optional(CONF_BROADCAST): cv.string, - } + LIGHT_DOMAIN: + vol.Schema(vol.All(cv.ensure_list, [INTERFACE_SCHEMA])), } }, extra=vol.ALLOW_EXTRA) @@ -51,47 +50,9 @@ async def _async_has_devices(hass): """Return if there are devices that can be discovered.""" import aiolifx - manager = DiscoveryManager() - lifx_discovery = aiolifx.LifxDiscovery(hass.loop, manager) - coro = hass.loop.create_datagram_endpoint( - lambda: lifx_discovery, - family=socket.AF_INET) - hass.async_create_task(coro) - - has_devices = await manager.found_devices() - lifx_discovery.cleanup() - - return has_devices + lifx_ip_addresses = await aiolifx.LifxScan(hass.loop).scan() + return len(lifx_ip_addresses) > 0 config_entry_flow.register_discovery_flow( DOMAIN, 'LIFX', _async_has_devices, config_entries.CONN_CLASS_LOCAL_POLL) - - -class DiscoveryManager: - """Temporary LIFX manager for discovering any bulb.""" - - def __init__(self): - """Initialize the manager.""" - self._event = asyncio.Event() - - async def found_devices(self): - """Return whether any device could be discovered.""" - try: - async with async_timeout.timeout(2): - await self._event.wait() - - # Let bulbs recover from the discovery - await asyncio.sleep(1) - - return True - except asyncio.TimeoutError: - return False - - def register(self, bulb): - """Handle aiolifx detected bulb.""" - self._event.set() - - def unregister(self, bulb): - """Handle aiolifx disappearing bulbs.""" - pass diff --git a/homeassistant/components/light/lifx.py b/homeassistant/components/light/lifx.py index 49f2c56826f..f346f88c42b 100644 --- a/homeassistant/components/light/lifx.py +++ b/homeassistant/components/light/lifx.py @@ -5,7 +5,6 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.lifx/ """ import asyncio -import socket from datetime import timedelta from functools import partial import logging @@ -145,23 +144,31 @@ async def async_setup_entry(hass, config_entry, async_add_entities): _LOGGER.warning("The lifx platform is known to not work on Windows. " "Consider using the lifx_legacy platform instead") - config = hass.data[LIFX_DOMAIN].get(DOMAIN, {}) + # Priority 1: manual config + interfaces = hass.data[LIFX_DOMAIN].get(DOMAIN) + if not interfaces: + # Priority 2: scanned interfaces + lifx_ip_addresses = await aiolifx().LifxScan(hass.loop).scan() + interfaces = [{CONF_SERVER: ip} for ip in lifx_ip_addresses] + if not interfaces: + # Priority 3: default interface + interfaces = [{}] lifx_manager = LIFXManager(hass, async_add_entities) - broadcast_ip = config.get(CONF_BROADCAST) - kwargs = {'discovery_interval': DISCOVERY_INTERVAL} - if broadcast_ip: - kwargs['broadcast_ip'] = broadcast_ip - lifx_discovery = aiolifx().LifxDiscovery(hass.loop, lifx_manager, **kwargs) + for interface in interfaces: + kwargs = {'discovery_interval': DISCOVERY_INTERVAL} + broadcast_ip = interface.get(CONF_BROADCAST) + if broadcast_ip: + kwargs['broadcast_ip'] = broadcast_ip + lifx_discovery = aiolifx().LifxDiscovery( + hass.loop, lifx_manager, **kwargs) - kwargs = {'family': socket.AF_INET} - local_addr = config.get(CONF_SERVER) - if local_addr is not None: - kwargs['local_addr'] = (local_addr, 0) - coro = hass.loop.create_datagram_endpoint(lambda: lifx_discovery, **kwargs) - - hass.async_create_task(coro) + kwargs = {} + listen_ip = interface.get(CONF_SERVER) + if listen_ip: + kwargs['listen_ip'] = listen_ip + lifx_discovery.start(**kwargs) @callback def cleanup(event): diff --git a/requirements_all.txt b/requirements_all.txt index aaab9407864..43eb37a11f9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -110,7 +110,7 @@ aiohue==1.5.0 aioimaplib==0.7.13 # homeassistant.components.lifx -aiolifx==0.6.3 +aiolifx==0.6.5 # homeassistant.components.light.lifx aiolifx_effects==0.2.1