mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Refactor LIFX discovery to make it faster and more reliable (#70458)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
c15c22655b
commit
f593b387a4
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from ipaddress import IPv4Address
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ from awesomeversion import AwesomeVersion
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import util
|
from homeassistant import util
|
||||||
|
from homeassistant.components import network
|
||||||
from homeassistant.components.light import (
|
from homeassistant.components.light import (
|
||||||
ATTR_BRIGHTNESS,
|
ATTR_BRIGHTNESS,
|
||||||
ATTR_BRIGHTNESS_PCT,
|
ATTR_BRIGHTNESS_PCT,
|
||||||
@ -69,8 +71,8 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
SCAN_INTERVAL = timedelta(seconds=10)
|
SCAN_INTERVAL = timedelta(seconds=10)
|
||||||
|
|
||||||
DISCOVERY_INTERVAL = 60
|
DISCOVERY_INTERVAL = 60
|
||||||
MESSAGE_TIMEOUT = 1.0
|
MESSAGE_TIMEOUT = 1
|
||||||
MESSAGE_RETRIES = 8
|
MESSAGE_RETRIES = 3
|
||||||
UNAVAILABLE_GRACE = 90
|
UNAVAILABLE_GRACE = 90
|
||||||
|
|
||||||
FIX_MAC_FW = AwesomeVersion("3.70")
|
FIX_MAC_FW = AwesomeVersion("3.70")
|
||||||
@ -193,12 +195,13 @@ async def async_setup_entry(
|
|||||||
"""Set up LIFX from a config entry."""
|
"""Set up LIFX from a config entry."""
|
||||||
# Priority 1: manual config
|
# Priority 1: manual config
|
||||||
if not (interfaces := hass.data[LIFX_DOMAIN].get(DOMAIN)):
|
if not (interfaces := hass.data[LIFX_DOMAIN].get(DOMAIN)):
|
||||||
# Priority 2: scanned interfaces
|
# Priority 2: Home Assistant enabled interfaces
|
||||||
lifx_ip_addresses = await aiolifx().LifxScan(hass.loop).scan()
|
ip_addresses = (
|
||||||
interfaces = [{CONF_SERVER: ip} for ip in lifx_ip_addresses]
|
source_ip
|
||||||
if not interfaces:
|
for source_ip in await network.async_get_enabled_source_ips(hass)
|
||||||
# Priority 3: default interface
|
if isinstance(source_ip, IPv4Address) and not source_ip.is_loopback
|
||||||
interfaces = [{}]
|
)
|
||||||
|
interfaces = [{CONF_SERVER: str(ip)} for ip in ip_addresses]
|
||||||
|
|
||||||
platform = entity_platform.async_get_current_platform()
|
platform = entity_platform.async_get_current_platform()
|
||||||
lifx_manager = LIFXManager(hass, platform, config_entry, async_add_entities)
|
lifx_manager = LIFXManager(hass, platform, config_entry, async_add_entities)
|
||||||
@ -259,6 +262,7 @@ class LIFXManager:
|
|||||||
def __init__(self, hass, platform, config_entry, async_add_entities):
|
def __init__(self, hass, platform, config_entry, async_add_entities):
|
||||||
"""Initialize the light."""
|
"""Initialize the light."""
|
||||||
self.entities = {}
|
self.entities = {}
|
||||||
|
self.discoveries_inflight = {}
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.platform = platform
|
self.platform = platform
|
||||||
self.config_entry = config_entry
|
self.config_entry = config_entry
|
||||||
@ -378,18 +382,23 @@ class LIFXManager:
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def register(self, bulb):
|
def register(self, bulb):
|
||||||
"""Handle aiolifx detected bulb."""
|
"""Allow a single in-flight discovery per bulb."""
|
||||||
self.hass.async_create_task(self.register_new_bulb(bulb))
|
if bulb.mac_addr not in self.discoveries_inflight:
|
||||||
|
self.discoveries_inflight[bulb.mac_addr] = bulb.ip_addr
|
||||||
|
_LOGGER.debug("Discovered %s (%s)", bulb.ip_addr, bulb.mac_addr)
|
||||||
|
self.hass.async_create_task(self.register_bulb(bulb))
|
||||||
|
else:
|
||||||
|
_LOGGER.warning("Duplicate LIFX discovery response ignored")
|
||||||
|
|
||||||
async def register_new_bulb(self, bulb):
|
async def register_bulb(self, bulb):
|
||||||
"""Handle newly detected bulb."""
|
"""Handle LIFX bulb registration lifecycle."""
|
||||||
if bulb.mac_addr in self.entities:
|
if bulb.mac_addr in self.entities:
|
||||||
entity = self.entities[bulb.mac_addr]
|
entity = self.entities[bulb.mac_addr]
|
||||||
entity.registered = True
|
entity.registered = True
|
||||||
_LOGGER.debug("%s register AGAIN", entity.who)
|
_LOGGER.debug("Reconnected to %s", entity.who)
|
||||||
await entity.update_hass()
|
await entity.update_hass()
|
||||||
else:
|
else:
|
||||||
_LOGGER.debug("%s register NEW", bulb.ip_addr)
|
_LOGGER.debug("Connecting to %s (%s)", bulb.ip_addr, bulb.mac_addr)
|
||||||
|
|
||||||
# Read initial state
|
# Read initial state
|
||||||
ack = AwaitAioLIFX().wait
|
ack = AwaitAioLIFX().wait
|
||||||
@ -398,8 +407,8 @@ class LIFXManager:
|
|||||||
# can be ignored.
|
# can be ignored.
|
||||||
version_resp = await ack(bulb.get_version)
|
version_resp = await ack(bulb.get_version)
|
||||||
if version_resp and bulb.product in SWITCH_PRODUCT_IDS:
|
if version_resp and bulb.product in SWITCH_PRODUCT_IDS:
|
||||||
_LOGGER.warning(
|
_LOGGER.debug(
|
||||||
"(Switch) action=skip_discovery, reason=unsupported, serial=%s, ip_addr=%s, type='LIFX Switch'",
|
"Not connecting to LIFX Switch %s (%s)",
|
||||||
str(bulb.mac_addr).replace(":", ""),
|
str(bulb.mac_addr).replace(":", ""),
|
||||||
bulb.ip_addr,
|
bulb.ip_addr,
|
||||||
)
|
)
|
||||||
@ -408,7 +417,7 @@ class LIFXManager:
|
|||||||
color_resp = await ack(bulb.get_color)
|
color_resp = await ack(bulb.get_color)
|
||||||
|
|
||||||
if color_resp is None or version_resp is None:
|
if color_resp is None or version_resp is None:
|
||||||
_LOGGER.error("Failed to initialize %s", bulb.ip_addr)
|
_LOGGER.error("Failed to connect to %s", bulb.ip_addr)
|
||||||
bulb.registered = False
|
bulb.registered = False
|
||||||
else:
|
else:
|
||||||
bulb.timeout = MESSAGE_TIMEOUT
|
bulb.timeout = MESSAGE_TIMEOUT
|
||||||
@ -422,16 +431,17 @@ class LIFXManager:
|
|||||||
else:
|
else:
|
||||||
entity = LIFXWhite(bulb, self.effects_conductor)
|
entity = LIFXWhite(bulb, self.effects_conductor)
|
||||||
|
|
||||||
_LOGGER.debug("%s register READY", entity.who)
|
_LOGGER.debug("Connected to %s", entity.who)
|
||||||
self.entities[bulb.mac_addr] = entity
|
self.entities[bulb.mac_addr] = entity
|
||||||
|
self.discoveries_inflight.pop(bulb.mac_addr, None)
|
||||||
self.async_add_entities([entity], True)
|
self.async_add_entities([entity], True)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def unregister(self, bulb):
|
def unregister(self, bulb):
|
||||||
"""Handle aiolifx disappearing bulbs."""
|
"""Disconnect and unregister non-responsive bulbs."""
|
||||||
if bulb.mac_addr in self.entities:
|
if bulb.mac_addr in self.entities:
|
||||||
entity = self.entities[bulb.mac_addr]
|
entity = self.entities[bulb.mac_addr]
|
||||||
_LOGGER.debug("%s unregister", entity.who)
|
_LOGGER.debug("Disconnected from %s", entity.who)
|
||||||
entity.registered = False
|
entity.registered = False
|
||||||
entity.async_write_ha_state()
|
entity.async_write_ha_state()
|
||||||
|
|
||||||
@ -551,8 +561,8 @@ class LIFXLight(LightEntity):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def who(self):
|
def who(self):
|
||||||
"""Return a string identifying the bulb."""
|
"""Return a string identifying the bulb by name and mac."""
|
||||||
return f"{self.bulb.ip_addr} ({self.name})"
|
return f"{self.name} ({self.bulb.mac_addr})"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_mireds(self):
|
def min_mireds(self):
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/lifx",
|
"documentation": "https://www.home-assistant.io/integrations/lifx",
|
||||||
"requirements": ["aiolifx==0.7.1", "aiolifx_effects==0.2.2"],
|
"requirements": ["aiolifx==0.7.1", "aiolifx_effects==0.2.2"],
|
||||||
|
"dependencies": ["network"],
|
||||||
"homekit": {
|
"homekit": {
|
||||||
"models": [
|
"models": [
|
||||||
"LIFX A19",
|
"LIFX A19",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user