LIFX: handle unavailable lights gracefully

Recent aiolifx allow sending messages to unregistered devices (as a
no-op). This is handy because bulbs can disappear anytime we yield and
constantly testing for availability is both error-prone and annoying.

So keep the aiolifx device around until a new one registers on the same
mac_addr.
This commit is contained in:
Anders Melchiorsen 2017-05-03 21:26:04 +02:00
parent 494a776959
commit 78a3f259d6
2 changed files with 24 additions and 22 deletions

View file

@ -93,6 +93,7 @@ class LIFXManager(object):
if device.mac_addr in self.entities: if device.mac_addr in self.entities:
entity = self.entities[device.mac_addr] entity = self.entities[device.mac_addr]
entity.device = device entity.device = device
entity.registered = True
_LOGGER.debug("%s register AGAIN", entity.who) _LOGGER.debug("%s register AGAIN", entity.who)
self.hass.async_add_job(entity.async_update_ha_state()) self.hass.async_add_job(entity.async_update_ha_state())
else: else:
@ -118,7 +119,7 @@ class LIFXManager(object):
if device.mac_addr in self.entities: if device.mac_addr in self.entities:
entity = self.entities[device.mac_addr] entity = self.entities[device.mac_addr]
_LOGGER.debug("%s unregister", entity.who) _LOGGER.debug("%s unregister", entity.who)
entity.device = None entity.registered = False
self.hass.async_add_job(entity.async_update_ha_state()) self.hass.async_add_job(entity.async_update_ha_state())
@ -172,6 +173,7 @@ class LIFXLight(Light):
def __init__(self, device): def __init__(self, device):
"""Initialize the light.""" """Initialize the light."""
self.device = device self.device = device
self.registered = True
self.product = device.product self.product = device.product
self.blocker = None self.blocker = None
self.effect_data = None self.effect_data = None
@ -183,7 +185,7 @@ class LIFXLight(Light):
@property @property
def available(self): def available(self):
"""Return the availability of the device.""" """Return the availability of the device."""
return self.device is not None return self.registered
@property @property
def name(self): def name(self):
@ -345,7 +347,7 @@ class LIFXLight(Light):
def async_update(self): def async_update(self):
"""Update bulb status (if it is available).""" """Update bulb status (if it is available)."""
_LOGGER.debug("%s async_update", self.who) _LOGGER.debug("%s async_update", self.who)
if self.available and self.blocker is None: if self.blocker is None:
yield from self.refresh_state() yield from self.refresh_state()
@asyncio.coroutine @asyncio.coroutine
@ -357,6 +359,7 @@ class LIFXLight(Light):
@asyncio.coroutine @asyncio.coroutine
def refresh_state(self): def refresh_state(self):
"""Ask the device about its current state and update our copy.""" """Ask the device about its current state and update our copy."""
if self.available:
msg = yield from AwaitAioLIFX(self).wait(self.device.get_color) msg = yield from AwaitAioLIFX(self).wait(self.device.get_color)
if msg is not None: if msg is not None:
self.set_power(self.device.power_level) self.set_power(self.device.power_level)

View file

@ -176,10 +176,8 @@ class LIFXEffect(object):
def async_setup(self, **kwargs): def async_setup(self, **kwargs):
"""Prepare all lights for the effect.""" """Prepare all lights for the effect."""
for light in self.lights: for light in self.lights:
# Remember the current state (as far as we know it)
yield from light.refresh_state() yield from light.refresh_state()
if not light.device:
self.lights.remove(light)
else:
light.effect_data = LIFXEffectData( light.effect_data = LIFXEffectData(
self, light.is_on, light.device.color) self, light.is_on, light.device.color)
@ -202,12 +200,13 @@ class LIFXEffect(object):
self.lights.remove(light) self.lights.remove(light)
if light.effect_data and light.effect_data.effect == self: if light.effect_data and light.effect_data.effect == self:
if light.device and not light.effect_data.power: if not light.effect_data.power:
light.device.set_power(False) light.device.set_power(False)
yield from asyncio.sleep(0.5) yield from asyncio.sleep(0.5)
if light.device:
light.device.set_color(light.effect_data.color) light.device.set_color(light.effect_data.color)
yield from asyncio.sleep(0.5) yield from asyncio.sleep(0.5)
light.effect_data = None light.effect_data = None
yield from light.refresh_state() yield from light.refresh_state()