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