Fix LIFX effects (#16309)
parent
8be7a0a9b9
commit
16a58bd1cf
|
@ -52,6 +52,8 @@ homeassistant/components/cover/template.py @PhracturedBlue
|
|||
homeassistant/components/device_tracker/automatic.py @armills
|
||||
homeassistant/components/device_tracker/tile.py @bachya
|
||||
homeassistant/components/history_graph.py @andrey-git
|
||||
homeassistant/components/light/lifx.py @amelchio
|
||||
homeassistant/components/light/lifx_legacy.py @amelchio
|
||||
homeassistant/components/light/tplink.py @rytilahti
|
||||
homeassistant/components/light/yeelight.py @rytilahti
|
||||
homeassistant/components/lock/nello.py @pschmitt
|
||||
|
@ -65,6 +67,7 @@ homeassistant/components/media_player/sonos.py @amelchio
|
|||
homeassistant/components/media_player/xiaomi_tv.py @fattdev
|
||||
homeassistant/components/media_player/yamaha_musiccast.py @jalmeroth
|
||||
homeassistant/components/plant.py @ChristianKuehnel
|
||||
homeassistant/components/scene/lifx_cloud.py @amelchio
|
||||
homeassistant/components/sensor/airvisual.py @bachya
|
||||
homeassistant/components/sensor/filter.py @dgomes
|
||||
homeassistant/components/sensor/gearbest.py @HerrHofrat
|
||||
|
|
|
@ -167,9 +167,9 @@ async def async_setup_platform(hass,
|
|||
return True
|
||||
|
||||
|
||||
def lifx_features(device):
|
||||
"""Return a feature map for this device, or a default map if unknown."""
|
||||
return aiolifx().products.features_map.get(device.product) or \
|
||||
def lifx_features(bulb):
|
||||
"""Return a feature map for this bulb, or a default map if unknown."""
|
||||
return aiolifx().products.features_map.get(bulb.product) or \
|
||||
aiolifx().products.features_map.get(1)
|
||||
|
||||
|
||||
|
@ -256,7 +256,7 @@ class LIFXManager:
|
|||
|
||||
async def start_effect(self, entities, service, **kwargs):
|
||||
"""Start a light effect on entities."""
|
||||
devices = [light.device for light in entities]
|
||||
bulbs = [light.bulb for light in entities]
|
||||
|
||||
if service == SERVICE_EFFECT_PULSE:
|
||||
effect = aiolifx_effects().EffectPulse(
|
||||
|
@ -266,7 +266,7 @@ class LIFXManager:
|
|||
mode=kwargs.get(ATTR_MODE),
|
||||
hsbk=find_hsbk(**kwargs),
|
||||
)
|
||||
await self.effects_conductor.start(effect, devices)
|
||||
await self.effects_conductor.start(effect, bulbs)
|
||||
elif service == SERVICE_EFFECT_COLORLOOP:
|
||||
preprocess_turn_on_alternatives(kwargs)
|
||||
|
||||
|
@ -282,12 +282,12 @@ class LIFXManager:
|
|||
transition=kwargs.get(ATTR_TRANSITION),
|
||||
brightness=brightness,
|
||||
)
|
||||
await self.effects_conductor.start(effect, devices)
|
||||
await self.effects_conductor.start(effect, bulbs)
|
||||
elif service == SERVICE_EFFECT_STOP:
|
||||
await self.effects_conductor.stop(devices)
|
||||
await self.effects_conductor.stop(bulbs)
|
||||
|
||||
def service_to_entities(self, service):
|
||||
"""Return the known devices that a service call mentions."""
|
||||
"""Return the known entities that a service call mentions."""
|
||||
entity_ids = extract_entity_ids(self.hass, service)
|
||||
if entity_ids:
|
||||
entities = [entity for entity in self.entities.values()
|
||||
|
@ -298,50 +298,50 @@ class LIFXManager:
|
|||
return entities
|
||||
|
||||
@callback
|
||||
def register(self, device):
|
||||
def register(self, bulb):
|
||||
"""Handle aiolifx detected bulb."""
|
||||
self.hass.async_add_job(self.register_new_device(device))
|
||||
self.hass.async_add_job(self.register_new_bulb(bulb))
|
||||
|
||||
async def register_new_device(self, device):
|
||||
async def register_new_bulb(self, bulb):
|
||||
"""Handle newly detected bulb."""
|
||||
if device.mac_addr in self.entities:
|
||||
entity = self.entities[device.mac_addr]
|
||||
if bulb.mac_addr in self.entities:
|
||||
entity = self.entities[bulb.mac_addr]
|
||||
entity.registered = True
|
||||
_LOGGER.debug("%s register AGAIN", entity.who)
|
||||
await entity.update_hass()
|
||||
else:
|
||||
_LOGGER.debug("%s register NEW", device.ip_addr)
|
||||
_LOGGER.debug("%s register NEW", bulb.ip_addr)
|
||||
|
||||
# Read initial state
|
||||
ack = AwaitAioLIFX().wait
|
||||
color_resp = await ack(device.get_color)
|
||||
color_resp = await ack(bulb.get_color)
|
||||
if color_resp:
|
||||
version_resp = await ack(device.get_version)
|
||||
version_resp = await ack(bulb.get_version)
|
||||
|
||||
if color_resp is None or version_resp is None:
|
||||
_LOGGER.error("Failed to initialize %s", device.ip_addr)
|
||||
device.registered = False
|
||||
_LOGGER.error("Failed to initialize %s", bulb.ip_addr)
|
||||
bulb.registered = False
|
||||
else:
|
||||
device.timeout = MESSAGE_TIMEOUT
|
||||
device.retry_count = MESSAGE_RETRIES
|
||||
device.unregister_timeout = UNAVAILABLE_GRACE
|
||||
bulb.timeout = MESSAGE_TIMEOUT
|
||||
bulb.retry_count = MESSAGE_RETRIES
|
||||
bulb.unregister_timeout = UNAVAILABLE_GRACE
|
||||
|
||||
if lifx_features(device)["multizone"]:
|
||||
entity = LIFXStrip(device, self.effects_conductor)
|
||||
elif lifx_features(device)["color"]:
|
||||
entity = LIFXColor(device, self.effects_conductor)
|
||||
if lifx_features(bulb)["multizone"]:
|
||||
entity = LIFXStrip(bulb, self.effects_conductor)
|
||||
elif lifx_features(bulb)["color"]:
|
||||
entity = LIFXColor(bulb, self.effects_conductor)
|
||||
else:
|
||||
entity = LIFXWhite(device, self.effects_conductor)
|
||||
entity = LIFXWhite(bulb, self.effects_conductor)
|
||||
|
||||
_LOGGER.debug("%s register READY", entity.who)
|
||||
self.entities[device.mac_addr] = entity
|
||||
self.entities[bulb.mac_addr] = entity
|
||||
self.async_add_entities([entity], True)
|
||||
|
||||
@callback
|
||||
def unregister(self, device):
|
||||
def unregister(self, bulb):
|
||||
"""Handle aiolifx disappearing bulbs."""
|
||||
if device.mac_addr in self.entities:
|
||||
entity = self.entities[device.mac_addr]
|
||||
if bulb.mac_addr in self.entities:
|
||||
entity = self.entities[bulb.mac_addr]
|
||||
_LOGGER.debug("%s unregister", entity.who)
|
||||
entity.registered = False
|
||||
self.hass.async_add_job(entity.async_update_ha_state())
|
||||
|
@ -352,20 +352,17 @@ class AwaitAioLIFX:
|
|||
|
||||
def __init__(self):
|
||||
"""Initialize the wrapper."""
|
||||
self.device = None
|
||||
self.message = None
|
||||
self.event = asyncio.Event()
|
||||
|
||||
@callback
|
||||
def callback(self, device, message):
|
||||
def callback(self, bulb, message):
|
||||
"""Handle responses."""
|
||||
self.device = device
|
||||
self.message = message
|
||||
self.event.set()
|
||||
|
||||
async def wait(self, method):
|
||||
"""Call an aiolifx method and wait for its response."""
|
||||
self.device = None
|
||||
self.message = None
|
||||
self.event.clear()
|
||||
method(callb=self.callback)
|
||||
|
@ -387,9 +384,9 @@ def convert_16_to_8(value):
|
|||
class LIFXLight(Light):
|
||||
"""Representation of a LIFX light."""
|
||||
|
||||
def __init__(self, device, effects_conductor):
|
||||
def __init__(self, bulb, effects_conductor):
|
||||
"""Initialize the light."""
|
||||
self.light = device
|
||||
self.bulb = bulb
|
||||
self.effects_conductor = effects_conductor
|
||||
self.registered = True
|
||||
self.postponed_update = None
|
||||
|
@ -397,34 +394,34 @@ class LIFXLight(Light):
|
|||
|
||||
@property
|
||||
def available(self):
|
||||
"""Return the availability of the device."""
|
||||
"""Return the availability of the bulb."""
|
||||
return self.registered
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return a unique ID."""
|
||||
return self.light.mac_addr
|
||||
return self.bulb.mac_addr
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the device."""
|
||||
return self.light.label
|
||||
"""Return the name of the bulb."""
|
||||
return self.bulb.label
|
||||
|
||||
@property
|
||||
def who(self):
|
||||
"""Return a string identifying the device."""
|
||||
return "%s (%s)" % (self.light.ip_addr, self.name)
|
||||
"""Return a string identifying the bulb."""
|
||||
return "%s (%s)" % (self.bulb.ip_addr, self.name)
|
||||
|
||||
@property
|
||||
def min_mireds(self):
|
||||
"""Return the coldest color_temp that this light supports."""
|
||||
kelvin = lifx_features(self.light)['max_kelvin']
|
||||
kelvin = lifx_features(self.bulb)['max_kelvin']
|
||||
return math.floor(color_util.color_temperature_kelvin_to_mired(kelvin))
|
||||
|
||||
@property
|
||||
def max_mireds(self):
|
||||
"""Return the warmest color_temp that this light supports."""
|
||||
kelvin = lifx_features(self.light)['min_kelvin']
|
||||
kelvin = lifx_features(self.bulb)['min_kelvin']
|
||||
return math.ceil(color_util.color_temperature_kelvin_to_mired(kelvin))
|
||||
|
||||
@property
|
||||
|
@ -432,8 +429,8 @@ class LIFXLight(Light):
|
|||
"""Flag supported features."""
|
||||
support = SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION | SUPPORT_EFFECT
|
||||
|
||||
device_features = lifx_features(self.light)
|
||||
if device_features['min_kelvin'] != device_features['max_kelvin']:
|
||||
bulb_features = lifx_features(self.bulb)
|
||||
if bulb_features['min_kelvin'] != bulb_features['max_kelvin']:
|
||||
support |= SUPPORT_COLOR_TEMP
|
||||
|
||||
return support
|
||||
|
@ -441,25 +438,25 @@ class LIFXLight(Light):
|
|||
@property
|
||||
def brightness(self):
|
||||
"""Return the brightness of this light between 0..255."""
|
||||
return convert_16_to_8(self.light.color[2])
|
||||
return convert_16_to_8(self.bulb.color[2])
|
||||
|
||||
@property
|
||||
def color_temp(self):
|
||||
"""Return the color temperature."""
|
||||
_, sat, _, kelvin = self.light.color
|
||||
_, sat, _, kelvin = self.bulb.color
|
||||
if sat:
|
||||
return None
|
||||
return color_util.color_temperature_kelvin_to_mired(kelvin)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if device is on."""
|
||||
return self.light.power_level != 0
|
||||
"""Return true if light is on."""
|
||||
return self.bulb.power_level != 0
|
||||
|
||||
@property
|
||||
def effect(self):
|
||||
"""Return the name of the currently running effect."""
|
||||
effect = self.effects_conductor.effect(self.light)
|
||||
effect = self.effects_conductor.effect(self.bulb)
|
||||
if effect:
|
||||
return 'lifx_effect_' + effect.name
|
||||
return None
|
||||
|
@ -485,19 +482,19 @@ class LIFXLight(Light):
|
|||
util.dt.utcnow() + timedelta(milliseconds=when))
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn the device on."""
|
||||
"""Turn the light on."""
|
||||
kwargs[ATTR_POWER] = True
|
||||
self.hass.async_add_job(self.set_state(**kwargs))
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn the device off."""
|
||||
"""Turn the light off."""
|
||||
kwargs[ATTR_POWER] = False
|
||||
self.hass.async_add_job(self.set_state(**kwargs))
|
||||
|
||||
async def set_state(self, **kwargs):
|
||||
"""Set a color on the light and turn it on/off."""
|
||||
async with self.lock:
|
||||
bulb = self.light
|
||||
bulb = self.bulb
|
||||
|
||||
await self.effects_conductor.stop([bulb])
|
||||
|
||||
|
@ -544,13 +541,13 @@ class LIFXLight(Light):
|
|||
await self.update_during_transition(fade)
|
||||
|
||||
async def set_power(self, ack, pwr, duration=0):
|
||||
"""Send a power change to the device."""
|
||||
await ack(partial(self.light.set_power, pwr, duration=duration))
|
||||
"""Send a power change to the bulb."""
|
||||
await ack(partial(self.bulb.set_power, pwr, duration=duration))
|
||||
|
||||
async def set_color(self, ack, hsbk, kwargs, duration=0):
|
||||
"""Send a color change to the device."""
|
||||
hsbk = merge_hsbk(self.light.color, hsbk)
|
||||
await ack(partial(self.light.set_color, hsbk, duration=duration))
|
||||
"""Send a color change to the bulb."""
|
||||
hsbk = merge_hsbk(self.bulb.color, hsbk)
|
||||
await ack(partial(self.bulb.set_color, hsbk, duration=duration))
|
||||
|
||||
async def default_effect(self, **kwargs):
|
||||
"""Start an effect with default parameters."""
|
||||
|
@ -563,7 +560,7 @@ class LIFXLight(Light):
|
|||
async def async_update(self):
|
||||
"""Update bulb status."""
|
||||
if self.available and not self.lock.locked():
|
||||
await AwaitAioLIFX().wait(self.light.get_color)
|
||||
await AwaitAioLIFX().wait(self.bulb.get_color)
|
||||
|
||||
|
||||
class LIFXWhite(LIFXLight):
|
||||
|
@ -600,7 +597,7 @@ class LIFXColor(LIFXLight):
|
|||
@property
|
||||
def hs_color(self):
|
||||
"""Return the hs value."""
|
||||
hue, sat, _, _ = self.light.color
|
||||
hue, sat, _, _ = self.bulb.color
|
||||
hue = hue / 65535 * 360
|
||||
sat = sat / 65535 * 100
|
||||
return (hue, sat) if sat else None
|
||||
|
@ -610,8 +607,8 @@ class LIFXStrip(LIFXColor):
|
|||
"""Representation of a LIFX light strip with multiple zones."""
|
||||
|
||||
async def set_color(self, ack, hsbk, kwargs, duration=0):
|
||||
"""Send a color change to the device."""
|
||||
bulb = self.light
|
||||
"""Send a color change to the bulb."""
|
||||
bulb = self.bulb
|
||||
num_zones = len(bulb.color_zones)
|
||||
|
||||
zones = kwargs.get(ATTR_ZONES)
|
||||
|
@ -659,7 +656,7 @@ class LIFXStrip(LIFXColor):
|
|||
while self.available and zone < top:
|
||||
# Each get_color_zones can update 8 zones at once
|
||||
resp = await AwaitAioLIFX().wait(partial(
|
||||
self.light.get_color_zones,
|
||||
self.bulb.get_color_zones,
|
||||
start_index=zone))
|
||||
if resp:
|
||||
zone += 8
|
||||
|
|
Loading…
Reference in New Issue