LIFX: support for multizone (#8399)
* Make aiolifx modules easily available * Use aiolifx features_map for deciding bulb features Also move the feature detection out of Light so it is available even during the initial detection. * Move each LIFX light type to a separate class * Simplify AwaitAioLIFX This has become possible with recent aiolifx that calls the callback even when a message is lost. Now the wrapper can be used also before a Light is added though the register callback then has to become a coroutine. * Refactor send_color * Add support for multizone This lets lifx_set_state work on individual zones. Also update to aiolifx_effects 0.1.1 that restores the state for individual zones.
This commit is contained in:
parent
abc5c3e128
commit
af9a0e8fea
3 changed files with 181 additions and 94 deletions
|
@ -33,7 +33,7 @@ import homeassistant.util.color as color_util
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
REQUIREMENTS = ['aiolifx==0.5.2', 'aiolifx_effects==0.1.0']
|
REQUIREMENTS = ['aiolifx==0.5.2', 'aiolifx_effects==0.1.1']
|
||||||
|
|
||||||
UDP_BROADCAST_PORT = 56700
|
UDP_BROADCAST_PORT = 56700
|
||||||
|
|
||||||
|
@ -53,10 +53,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
SERVICE_LIFX_SET_STATE = 'lifx_set_state'
|
SERVICE_LIFX_SET_STATE = 'lifx_set_state'
|
||||||
|
|
||||||
ATTR_INFRARED = 'infrared'
|
ATTR_INFRARED = 'infrared'
|
||||||
|
ATTR_ZONES = 'zones'
|
||||||
ATTR_POWER = 'power'
|
ATTR_POWER = 'power'
|
||||||
|
|
||||||
LIFX_SET_STATE_SCHEMA = LIGHT_TURN_ON_SCHEMA.extend({
|
LIFX_SET_STATE_SCHEMA = LIGHT_TURN_ON_SCHEMA.extend({
|
||||||
ATTR_INFRARED: vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255)),
|
ATTR_INFRARED: vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255)),
|
||||||
|
ATTR_ZONES: vol.All(cv.ensure_list, [cv.positive_int]),
|
||||||
ATTR_POWER: cv.boolean,
|
ATTR_POWER: cv.boolean,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -112,11 +114,21 @@ LIFX_EFFECT_STOP_SCHEMA = vol.Schema({
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def aiolifx():
|
||||||
|
"""Return the aiolifx module."""
|
||||||
|
import aiolifx as aiolifx_module
|
||||||
|
return aiolifx_module
|
||||||
|
|
||||||
|
|
||||||
|
def aiolifx_effects():
|
||||||
|
"""Return the aiolifx_effects module."""
|
||||||
|
import aiolifx_effects as aiolifx_effects_module
|
||||||
|
return aiolifx_effects_module
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
"""Set up the LIFX platform."""
|
"""Set up the LIFX platform."""
|
||||||
import aiolifx
|
|
||||||
|
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
_LOGGER.warning("The lifx platform is known to not work on Windows. "
|
_LOGGER.warning("The lifx platform is known to not work on Windows. "
|
||||||
"Consider using the lifx_legacy platform instead")
|
"Consider using the lifx_legacy platform instead")
|
||||||
|
@ -124,7 +136,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
server_addr = config.get(CONF_SERVER)
|
server_addr = config.get(CONF_SERVER)
|
||||||
|
|
||||||
lifx_manager = LIFXManager(hass, async_add_devices)
|
lifx_manager = LIFXManager(hass, async_add_devices)
|
||||||
lifx_discovery = aiolifx.LifxDiscovery(
|
lifx_discovery = aiolifx().LifxDiscovery(
|
||||||
hass.loop,
|
hass.loop,
|
||||||
lifx_manager,
|
lifx_manager,
|
||||||
discovery_interval=DISCOVERY_INTERVAL,
|
discovery_interval=DISCOVERY_INTERVAL,
|
||||||
|
@ -145,6 +157,16 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def lifxwhite(device):
|
||||||
|
"""Return whether this is a white-only bulb."""
|
||||||
|
return not aiolifx().products.features_map[device.product]["color"]
|
||||||
|
|
||||||
|
|
||||||
|
def lifxmultizone(device):
|
||||||
|
"""Return whether this is a multizone bulb/strip."""
|
||||||
|
return aiolifx().products.features_map[device.product]["multizone"]
|
||||||
|
|
||||||
|
|
||||||
def find_hsbk(**kwargs):
|
def find_hsbk(**kwargs):
|
||||||
"""Find the desired color from a number of possible inputs."""
|
"""Find the desired color from a number of possible inputs."""
|
||||||
hue, saturation, brightness, kelvin = [None]*4
|
hue, saturation, brightness, kelvin = [None]*4
|
||||||
|
@ -187,11 +209,10 @@ class LIFXManager(object):
|
||||||
|
|
||||||
def __init__(self, hass, async_add_devices):
|
def __init__(self, hass, async_add_devices):
|
||||||
"""Initialize the light."""
|
"""Initialize the light."""
|
||||||
import aiolifx_effects
|
|
||||||
self.entities = {}
|
self.entities = {}
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.async_add_devices = async_add_devices
|
self.async_add_devices = async_add_devices
|
||||||
self.effects_conductor = aiolifx_effects.Conductor(loop=hass.loop)
|
self.effects_conductor = aiolifx_effects().Conductor(loop=hass.loop)
|
||||||
|
|
||||||
descriptions = load_yaml_config_file(
|
descriptions = load_yaml_config_file(
|
||||||
path.join(path.dirname(__file__), 'services.yaml'))
|
path.join(path.dirname(__file__), 'services.yaml'))
|
||||||
|
@ -245,11 +266,10 @@ class LIFXManager(object):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def start_effect(self, entities, service, **kwargs):
|
def start_effect(self, entities, service, **kwargs):
|
||||||
"""Start a light effect on entities."""
|
"""Start a light effect on entities."""
|
||||||
import aiolifx_effects
|
|
||||||
devices = list(map(lambda l: l.device, entities))
|
devices = list(map(lambda l: l.device, entities))
|
||||||
|
|
||||||
if service == SERVICE_EFFECT_PULSE:
|
if service == SERVICE_EFFECT_PULSE:
|
||||||
effect = aiolifx_effects.EffectPulse(
|
effect = aiolifx_effects().EffectPulse(
|
||||||
power_on=kwargs.get(ATTR_POWER_ON),
|
power_on=kwargs.get(ATTR_POWER_ON),
|
||||||
period=kwargs.get(ATTR_PERIOD),
|
period=kwargs.get(ATTR_PERIOD),
|
||||||
cycles=kwargs.get(ATTR_CYCLES),
|
cycles=kwargs.get(ATTR_CYCLES),
|
||||||
|
@ -264,7 +284,7 @@ class LIFXManager(object):
|
||||||
if ATTR_BRIGHTNESS in kwargs:
|
if ATTR_BRIGHTNESS in kwargs:
|
||||||
brightness = convert_8_to_16(kwargs[ATTR_BRIGHTNESS])
|
brightness = convert_8_to_16(kwargs[ATTR_BRIGHTNESS])
|
||||||
|
|
||||||
effect = aiolifx_effects.EffectColorloop(
|
effect = aiolifx_effects().EffectColorloop(
|
||||||
power_on=kwargs.get(ATTR_POWER_ON),
|
power_on=kwargs.get(ATTR_POWER_ON),
|
||||||
period=kwargs.get(ATTR_PERIOD),
|
period=kwargs.get(ATTR_PERIOD),
|
||||||
change=kwargs.get(ATTR_CHANGE),
|
change=kwargs.get(ATTR_CHANGE),
|
||||||
|
@ -289,32 +309,39 @@ class LIFXManager(object):
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def register(self, device):
|
def register(self, device):
|
||||||
"""Handle for newly detected bulb."""
|
"""Handler for newly detected bulb."""
|
||||||
|
self.hass.async_add_job(self.async_register(device))
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_register(self, device):
|
||||||
|
"""Handler for newly detected bulb."""
|
||||||
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.registered = True
|
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())
|
yield from entity.async_update()
|
||||||
|
yield from entity.async_update_ha_state()
|
||||||
else:
|
else:
|
||||||
_LOGGER.debug("%s register NEW", device.ip_addr)
|
_LOGGER.debug("%s register NEW", device.ip_addr)
|
||||||
device.timeout = MESSAGE_TIMEOUT
|
device.timeout = MESSAGE_TIMEOUT
|
||||||
device.retry_count = MESSAGE_RETRIES
|
device.retry_count = MESSAGE_RETRIES
|
||||||
device.unregister_timeout = UNAVAILABLE_GRACE
|
device.unregister_timeout = UNAVAILABLE_GRACE
|
||||||
device.get_version(self.got_version)
|
|
||||||
|
|
||||||
@callback
|
ack = AwaitAioLIFX().wait
|
||||||
def got_version(self, device, msg):
|
yield from ack(device.get_version)
|
||||||
"""Request current color setting once we have the product version."""
|
yield from ack(device.get_color)
|
||||||
device.get_color(self.ready)
|
|
||||||
|
|
||||||
@callback
|
if lifxwhite(device):
|
||||||
def ready(self, device, msg):
|
entity = LIFXWhite(device, self.effects_conductor)
|
||||||
"""Handle the device once all data is retrieved."""
|
elif lifxmultizone(device):
|
||||||
entity = LIFXLight(device, self.effects_conductor)
|
yield from ack(partial(device.get_color_zones, start_index=0))
|
||||||
_LOGGER.debug("%s register READY", entity.who)
|
entity = LIFXStrip(device, self.effects_conductor)
|
||||||
self.entities[device.mac_addr] = entity
|
else:
|
||||||
self.async_add_devices([entity])
|
entity = LIFXColor(device, self.effects_conductor)
|
||||||
|
|
||||||
|
_LOGGER.debug("%s register READY", entity.who)
|
||||||
|
self.entities[device.mac_addr] = entity
|
||||||
|
self.async_add_devices([entity])
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def unregister(self, device):
|
def unregister(self, device):
|
||||||
|
@ -329,9 +356,8 @@ class LIFXManager(object):
|
||||||
class AwaitAioLIFX:
|
class AwaitAioLIFX:
|
||||||
"""Wait for an aiolifx callback and return the message."""
|
"""Wait for an aiolifx callback and return the message."""
|
||||||
|
|
||||||
def __init__(self, light):
|
def __init__(self):
|
||||||
"""Initialize the wrapper."""
|
"""Initialize the wrapper."""
|
||||||
self.light = light
|
|
||||||
self.device = None
|
self.device = None
|
||||||
self.message = None
|
self.message = None
|
||||||
self.event = asyncio.Event()
|
self.event = asyncio.Event()
|
||||||
|
@ -373,15 +399,8 @@ class LIFXLight(Light):
|
||||||
self.device = device
|
self.device = device
|
||||||
self.effects_conductor = effects_conductor
|
self.effects_conductor = effects_conductor
|
||||||
self.registered = True
|
self.registered = True
|
||||||
self.product = device.product
|
|
||||||
self.postponed_update = None
|
self.postponed_update = None
|
||||||
|
|
||||||
@property
|
|
||||||
def lifxwhite(self):
|
|
||||||
"""Return whether this is a white-only bulb."""
|
|
||||||
# https://lan.developer.lifx.com/docs/lifx-products
|
|
||||||
return self.product in [10, 11, 18]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
"""Return the availability of the device."""
|
"""Return the availability of the device."""
|
||||||
|
@ -397,14 +416,6 @@ class LIFXLight(Light):
|
||||||
"""Return a string identifying the device."""
|
"""Return a string identifying the device."""
|
||||||
return "%s (%s)" % (self.device.ip_addr, self.name)
|
return "%s (%s)" % (self.device.ip_addr, self.name)
|
||||||
|
|
||||||
@property
|
|
||||||
def rgb_color(self):
|
|
||||||
"""Return the RGB value."""
|
|
||||||
hue, sat, bri, _ = self.device.color
|
|
||||||
|
|
||||||
return color_util.color_hsv_to_RGB(
|
|
||||||
hue, convert_16_to_8(sat), convert_16_to_8(bri))
|
|
||||||
|
|
||||||
@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."""
|
||||||
|
@ -421,26 +432,6 @@ class LIFXLight(Light):
|
||||||
_LOGGER.debug("color_temp: %d", temperature)
|
_LOGGER.debug("color_temp: %d", temperature)
|
||||||
return temperature
|
return temperature
|
||||||
|
|
||||||
@property
|
|
||||||
def min_mireds(self):
|
|
||||||
"""Return the coldest color_temp that this light supports."""
|
|
||||||
# The 3 LIFX "White" products supported a limited temperature range
|
|
||||||
if self.lifxwhite:
|
|
||||||
kelvin = 6500
|
|
||||||
else:
|
|
||||||
kelvin = 9000
|
|
||||||
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."""
|
|
||||||
# The 3 LIFX "White" products supported a limited temperature range
|
|
||||||
if self.lifxwhite:
|
|
||||||
kelvin = 2700
|
|
||||||
else:
|
|
||||||
kelvin = 2500
|
|
||||||
return math.ceil(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 device is on."""
|
||||||
|
@ -454,32 +445,6 @@ class LIFXLight(Light):
|
||||||
return 'lifx_effect_' + effect.name
|
return 'lifx_effect_' + effect.name
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
|
||||||
def supported_features(self):
|
|
||||||
"""Flag supported features."""
|
|
||||||
features = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP |
|
|
||||||
SUPPORT_TRANSITION | SUPPORT_EFFECT)
|
|
||||||
|
|
||||||
if not self.lifxwhite:
|
|
||||||
features |= SUPPORT_RGB_COLOR | SUPPORT_XY_COLOR
|
|
||||||
|
|
||||||
return features
|
|
||||||
|
|
||||||
@property
|
|
||||||
def effect_list(self):
|
|
||||||
"""Return the list of supported effects for this light."""
|
|
||||||
if self.lifxwhite:
|
|
||||||
return [
|
|
||||||
SERVICE_EFFECT_PULSE,
|
|
||||||
SERVICE_EFFECT_STOP,
|
|
||||||
]
|
|
||||||
|
|
||||||
return [
|
|
||||||
SERVICE_EFFECT_COLORLOOP,
|
|
||||||
SERVICE_EFFECT_PULSE,
|
|
||||||
SERVICE_EFFECT_STOP,
|
|
||||||
]
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def update_after_transition(self, now):
|
def update_after_transition(self, now):
|
||||||
"""Request new status after completion of the last transition."""
|
"""Request new status after completion of the last transition."""
|
||||||
|
@ -530,30 +495,36 @@ class LIFXLight(Light):
|
||||||
power_on = kwargs.get(ATTR_POWER, False)
|
power_on = kwargs.get(ATTR_POWER, False)
|
||||||
power_off = not kwargs.get(ATTR_POWER, True)
|
power_off = not kwargs.get(ATTR_POWER, True)
|
||||||
|
|
||||||
hsbk = merge_hsbk(self.device.color, find_hsbk(**kwargs))
|
hsbk = find_hsbk(**kwargs)
|
||||||
|
|
||||||
# Send messages, waiting for ACK each time
|
# Send messages, waiting for ACK each time
|
||||||
ack = AwaitAioLIFX(self).wait
|
ack = AwaitAioLIFX().wait
|
||||||
bulb = self.device
|
bulb = self.device
|
||||||
|
|
||||||
if not self.is_on:
|
if not self.is_on:
|
||||||
if power_off:
|
if power_off:
|
||||||
yield from ack(partial(bulb.set_power, False))
|
yield from ack(partial(bulb.set_power, False))
|
||||||
if hsbk:
|
if hsbk:
|
||||||
yield from ack(partial(bulb.set_color, hsbk))
|
yield from self.send_color(ack, hsbk, kwargs, duration=0)
|
||||||
if power_on:
|
if power_on:
|
||||||
yield from ack(partial(bulb.set_power, True, duration=fade))
|
yield from ack(partial(bulb.set_power, True, duration=fade))
|
||||||
else:
|
else:
|
||||||
if power_on:
|
if power_on:
|
||||||
yield from ack(partial(bulb.set_power, True))
|
yield from ack(partial(bulb.set_power, True))
|
||||||
if hsbk:
|
if hsbk:
|
||||||
yield from ack(partial(bulb.set_color, hsbk, duration=fade))
|
yield from self.send_color(ack, hsbk, kwargs, duration=fade)
|
||||||
if power_off:
|
if power_off:
|
||||||
yield from ack(partial(bulb.set_power, False, duration=fade))
|
yield from ack(partial(bulb.set_power, False, duration=fade))
|
||||||
|
|
||||||
# Schedule an update when the transition is complete
|
# Schedule an update when the transition is complete
|
||||||
self.update_later(fade)
|
self.update_later(fade)
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def send_color(self, ack, hsbk, kwargs, duration):
|
||||||
|
"""Send a color change to the device."""
|
||||||
|
hsbk = merge_hsbk(self.device.color, hsbk)
|
||||||
|
yield from ack(partial(self.device.set_color, hsbk, duration=duration))
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def default_effect(self, **kwargs):
|
def default_effect(self, **kwargs):
|
||||||
"""Start an effect with default parameters."""
|
"""Start an effect with default parameters."""
|
||||||
|
@ -569,5 +540,117 @@ class LIFXLight(Light):
|
||||||
_LOGGER.debug("%s async_update", self.who)
|
_LOGGER.debug("%s async_update", self.who)
|
||||||
if self.available:
|
if self.available:
|
||||||
# Avoid state ping-pong by holding off updates as the state settles
|
# Avoid state ping-pong by holding off updates as the state settles
|
||||||
yield from asyncio.sleep(0.25)
|
yield from asyncio.sleep(0.3)
|
||||||
yield from AwaitAioLIFX(self).wait(self.device.get_color)
|
yield from AwaitAioLIFX().wait(self.device.get_color)
|
||||||
|
|
||||||
|
|
||||||
|
class LIFXWhite(LIFXLight):
|
||||||
|
"""Representation of a white-only LIFX light."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def min_mireds(self):
|
||||||
|
"""Return the coldest color_temp that this light supports."""
|
||||||
|
return math.floor(color_util.color_temperature_kelvin_to_mired(6500))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def max_mireds(self):
|
||||||
|
"""Return the warmest color_temp that this light supports."""
|
||||||
|
return math.ceil(color_util.color_temperature_kelvin_to_mired(2700))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supported_features(self):
|
||||||
|
"""Flag supported features."""
|
||||||
|
return (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_TRANSITION |
|
||||||
|
SUPPORT_EFFECT)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def effect_list(self):
|
||||||
|
"""Return the list of supported effects for this light."""
|
||||||
|
return [
|
||||||
|
SERVICE_EFFECT_PULSE,
|
||||||
|
SERVICE_EFFECT_STOP,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class LIFXColor(LIFXLight):
|
||||||
|
"""Representation of a color LIFX light."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def min_mireds(self):
|
||||||
|
"""Return the coldest color_temp that this light supports."""
|
||||||
|
return math.floor(color_util.color_temperature_kelvin_to_mired(9000))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def max_mireds(self):
|
||||||
|
"""Return the warmest color_temp that this light supports."""
|
||||||
|
return math.ceil(color_util.color_temperature_kelvin_to_mired(2500))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supported_features(self):
|
||||||
|
"""Flag supported features."""
|
||||||
|
return (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_TRANSITION |
|
||||||
|
SUPPORT_EFFECT | SUPPORT_RGB_COLOR | SUPPORT_XY_COLOR)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def effect_list(self):
|
||||||
|
"""Return the list of supported effects for this light."""
|
||||||
|
return [
|
||||||
|
SERVICE_EFFECT_COLORLOOP,
|
||||||
|
SERVICE_EFFECT_PULSE,
|
||||||
|
SERVICE_EFFECT_STOP,
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rgb_color(self):
|
||||||
|
"""Return the RGB value."""
|
||||||
|
hue, sat, bri, _ = self.device.color
|
||||||
|
|
||||||
|
return color_util.color_hsv_to_RGB(
|
||||||
|
hue, convert_16_to_8(sat), convert_16_to_8(bri))
|
||||||
|
|
||||||
|
|
||||||
|
class LIFXStrip(LIFXColor):
|
||||||
|
"""Representation of a LIFX light strip with multiple zones."""
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def send_color(self, ack, hsbk, kwargs, duration):
|
||||||
|
"""Send a color change to the device."""
|
||||||
|
bulb = self.device
|
||||||
|
num_zones = len(bulb.color_zones)
|
||||||
|
|
||||||
|
# Zone brightness is not reported when powered off
|
||||||
|
if not self.is_on and hsbk[2] is None:
|
||||||
|
yield from ack(partial(bulb.set_power, True))
|
||||||
|
yield from self.async_update()
|
||||||
|
yield from ack(partial(bulb.set_power, False))
|
||||||
|
|
||||||
|
zones = kwargs.get(ATTR_ZONES, None)
|
||||||
|
if zones is None:
|
||||||
|
zones = list(range(0, num_zones))
|
||||||
|
else:
|
||||||
|
zones = list(filter(lambda x: x < num_zones, set(zones)))
|
||||||
|
|
||||||
|
# Send new color to each zone
|
||||||
|
for index, zone in enumerate(zones):
|
||||||
|
zone_hsbk = merge_hsbk(bulb.color_zones[zone], hsbk)
|
||||||
|
apply = 1 if (index == len(zones)-1) else 0
|
||||||
|
set_zone = partial(bulb.set_color_zones,
|
||||||
|
start_index=zone,
|
||||||
|
end_index=zone,
|
||||||
|
color=zone_hsbk,
|
||||||
|
duration=duration,
|
||||||
|
apply=apply)
|
||||||
|
yield from ack(set_zone)
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_update(self):
|
||||||
|
"""Update strip status."""
|
||||||
|
if self.available:
|
||||||
|
yield from super().async_update()
|
||||||
|
|
||||||
|
ack = AwaitAioLIFX().wait
|
||||||
|
bulb = self.device
|
||||||
|
|
||||||
|
# Each get_color_zones returns the next 8 zones
|
||||||
|
for zone in range(0, len(bulb.color_zones), 8):
|
||||||
|
yield from ack(partial(bulb.get_color_zones, start_index=zone))
|
||||||
|
|
|
@ -117,6 +117,10 @@ lifx_set_state:
|
||||||
description: Automatic infrared level (0..255) when light brightness is low
|
description: Automatic infrared level (0..255) when light brightness is low
|
||||||
example: 255
|
example: 255
|
||||||
|
|
||||||
|
zones:
|
||||||
|
description: List of zone numbers to affect (8 per LIFX Z, starts at 0)
|
||||||
|
example: '[0,5]'
|
||||||
|
|
||||||
transition:
|
transition:
|
||||||
description: Duration in seconds it takes to get to the final state
|
description: Duration in seconds it takes to get to the final state
|
||||||
example: 10
|
example: 10
|
||||||
|
|
|
@ -52,7 +52,7 @@ aiohttp_cors==0.5.3
|
||||||
aiolifx==0.5.2
|
aiolifx==0.5.2
|
||||||
|
|
||||||
# homeassistant.components.light.lifx
|
# homeassistant.components.light.lifx
|
||||||
aiolifx_effects==0.1.0
|
aiolifx_effects==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.scene.hunterdouglas_powerview
|
# homeassistant.components.scene.hunterdouglas_powerview
|
||||||
aiopvapi==1.4
|
aiopvapi==1.4
|
||||||
|
|
Loading…
Add table
Reference in a new issue