LIFX async/await conversion (#12973)

* LIFX async/await conversion

* async with
This commit is contained in:
Anders Melchiorsen 2018-03-08 07:24:35 +01:00 committed by GitHub
parent b159e8acee
commit 5dd0193ba6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -123,8 +123,10 @@ def aiolifx_effects():
return aiolifx_effects_module return aiolifx_effects_module
@asyncio.coroutine async def async_setup_platform(hass,
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): config,
async_add_devices,
discovery_info=None):
"""Set up the LIFX platform.""" """Set up the LIFX platform."""
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. "
@ -214,8 +216,7 @@ class LIFXManager(object):
def register_set_state(self): def register_set_state(self):
"""Register the LIFX set_state service call.""" """Register the LIFX set_state service call."""
@asyncio.coroutine async def service_handler(service):
def async_service_handle(service):
"""Apply a service.""" """Apply a service."""
tasks = [] tasks = []
for light in self.service_to_entities(service): for light in self.service_to_entities(service):
@ -223,36 +224,34 @@ class LIFXManager(object):
task = light.async_set_state(**service.data) task = light.async_set_state(**service.data)
tasks.append(self.hass.async_add_job(task)) tasks.append(self.hass.async_add_job(task))
if tasks: if tasks:
yield from asyncio.wait(tasks, loop=self.hass.loop) await asyncio.wait(tasks, loop=self.hass.loop)
self.hass.services.async_register( self.hass.services.async_register(
DOMAIN, SERVICE_LIFX_SET_STATE, async_service_handle, DOMAIN, SERVICE_LIFX_SET_STATE, service_handler,
schema=LIFX_SET_STATE_SCHEMA) schema=LIFX_SET_STATE_SCHEMA)
def register_effects(self): def register_effects(self):
"""Register the LIFX effects as hass service calls.""" """Register the LIFX effects as hass service calls."""
@asyncio.coroutine async def service_handler(service):
def async_service_handle(service):
"""Apply a service, i.e. start an effect.""" """Apply a service, i.e. start an effect."""
entities = self.service_to_entities(service) entities = self.service_to_entities(service)
if entities: if entities:
yield from self.start_effect( await self.start_effect(
entities, service.service, **service.data) entities, service.service, **service.data)
self.hass.services.async_register( self.hass.services.async_register(
DOMAIN, SERVICE_EFFECT_PULSE, async_service_handle, DOMAIN, SERVICE_EFFECT_PULSE, service_handler,
schema=LIFX_EFFECT_PULSE_SCHEMA) schema=LIFX_EFFECT_PULSE_SCHEMA)
self.hass.services.async_register( self.hass.services.async_register(
DOMAIN, SERVICE_EFFECT_COLORLOOP, async_service_handle, DOMAIN, SERVICE_EFFECT_COLORLOOP, service_handler,
schema=LIFX_EFFECT_COLORLOOP_SCHEMA) schema=LIFX_EFFECT_COLORLOOP_SCHEMA)
self.hass.services.async_register( self.hass.services.async_register(
DOMAIN, SERVICE_EFFECT_STOP, async_service_handle, DOMAIN, SERVICE_EFFECT_STOP, service_handler,
schema=LIFX_EFFECT_STOP_SCHEMA) schema=LIFX_EFFECT_STOP_SCHEMA)
@asyncio.coroutine async 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."""
devices = list(map(lambda l: l.device, entities)) devices = list(map(lambda l: l.device, entities))
@ -264,7 +263,7 @@ class LIFXManager(object):
mode=kwargs.get(ATTR_MODE), mode=kwargs.get(ATTR_MODE),
hsbk=find_hsbk(**kwargs), hsbk=find_hsbk(**kwargs),
) )
yield from self.effects_conductor.start(effect, devices) await self.effects_conductor.start(effect, devices)
elif service == SERVICE_EFFECT_COLORLOOP: elif service == SERVICE_EFFECT_COLORLOOP:
preprocess_turn_on_alternatives(kwargs) preprocess_turn_on_alternatives(kwargs)
@ -280,9 +279,9 @@ class LIFXManager(object):
transition=kwargs.get(ATTR_TRANSITION), transition=kwargs.get(ATTR_TRANSITION),
brightness=brightness, brightness=brightness,
) )
yield from self.effects_conductor.start(effect, devices) await self.effects_conductor.start(effect, devices)
elif service == SERVICE_EFFECT_STOP: elif service == SERVICE_EFFECT_STOP:
yield from self.effects_conductor.stop(devices) await self.effects_conductor.stop(devices)
def service_to_entities(self, service): def service_to_entities(self, service):
"""Return the known devices that a service call mentions.""" """Return the known devices that a service call mentions."""
@ -297,25 +296,24 @@ class LIFXManager(object):
@callback @callback
def register(self, device): def register(self, device):
"""Handle newly detected bulb.""" """Handle aiolifx detected bulb."""
self.hass.async_add_job(self.async_register(device)) self.hass.async_add_job(self.register_new_device(device))
@asyncio.coroutine async def register_new_device(self, device):
def async_register(self, device):
"""Handle newly detected bulb.""" """Handle 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.registered = True entity.registered = True
_LOGGER.debug("%s register AGAIN", entity.who) _LOGGER.debug("%s register AGAIN", entity.who)
yield from entity.update_hass() await entity.update_hass()
else: else:
_LOGGER.debug("%s register NEW", device.ip_addr) _LOGGER.debug("%s register NEW", device.ip_addr)
# Read initial state # Read initial state
ack = AwaitAioLIFX().wait ack = AwaitAioLIFX().wait
version_resp = yield from ack(device.get_version) version_resp = await ack(device.get_version)
if version_resp: if version_resp:
color_resp = yield from ack(device.get_color) color_resp = await ack(device.get_color)
if version_resp is None or color_resp is None: if version_resp is None or color_resp is None:
_LOGGER.error("Failed to initialize %s", device.ip_addr) _LOGGER.error("Failed to initialize %s", device.ip_addr)
@ -337,7 +335,7 @@ class LIFXManager(object):
@callback @callback
def unregister(self, device): def unregister(self, device):
"""Handle disappearing bulbs.""" """Handle aiolifx disappearing bulbs."""
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)
@ -361,15 +359,14 @@ class AwaitAioLIFX:
self.message = message self.message = message
self.event.set() self.event.set()
@asyncio.coroutine async def wait(self, method):
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.device = None
self.message = None self.message = None
self.event.clear() self.event.clear()
method(callb=self.callback) method(callb=self.callback)
yield from self.event.wait() await self.event.wait()
return self.message return self.message
@ -466,21 +463,19 @@ class LIFXLight(Light):
return 'lifx_effect_' + effect.name return 'lifx_effect_' + effect.name
return None return None
@asyncio.coroutine async def update_hass(self, now=None):
def update_hass(self, now=None):
"""Request new status and push it to hass.""" """Request new status and push it to hass."""
self.postponed_update = None self.postponed_update = None
yield from self.async_update() await self.async_update()
yield from self.async_update_ha_state() await self.async_update_ha_state()
@asyncio.coroutine async def update_during_transition(self, when):
def update_during_transition(self, when):
"""Update state at the start and end of a transition.""" """Update state at the start and end of a transition."""
if self.postponed_update: if self.postponed_update:
self.postponed_update() self.postponed_update()
# Transition has started # Transition has started
yield from self.update_hass() await self.update_hass()
# Transition has ended # Transition has ended
if when > 0: if when > 0:
@ -488,28 +483,25 @@ class LIFXLight(Light):
self.hass, self.update_hass, self.hass, self.update_hass,
util.dt.utcnow() + timedelta(milliseconds=when)) util.dt.utcnow() + timedelta(milliseconds=when))
@asyncio.coroutine async def async_turn_on(self, **kwargs):
def async_turn_on(self, **kwargs):
"""Turn the device on.""" """Turn the device on."""
kwargs[ATTR_POWER] = True kwargs[ATTR_POWER] = True
self.hass.async_add_job(self.async_set_state(**kwargs)) self.hass.async_add_job(self.set_state(**kwargs))
@asyncio.coroutine async def async_turn_off(self, **kwargs):
def async_turn_off(self, **kwargs):
"""Turn the device off.""" """Turn the device off."""
kwargs[ATTR_POWER] = False kwargs[ATTR_POWER] = False
self.hass.async_add_job(self.async_set_state(**kwargs)) self.hass.async_add_job(self.set_state(**kwargs))
@asyncio.coroutine async def set_state(self, **kwargs):
def async_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."""
with (yield from self.lock): async with self.lock:
bulb = self.device bulb = self.device
yield from self.effects_conductor.stop([bulb]) await self.effects_conductor.stop([bulb])
if ATTR_EFFECT in kwargs: if ATTR_EFFECT in kwargs:
yield from self.default_effect(**kwargs) await self.default_effect(**kwargs)
return return
if ATTR_INFRARED in kwargs: if ATTR_INFRARED in kwargs:
@ -531,51 +523,47 @@ class LIFXLight(Light):
if not self.is_on: if not self.is_on:
if power_off: if power_off:
yield from self.set_power(ack, False) await self.set_power(ack, False)
if hsbk: if hsbk:
yield from self.set_color(ack, hsbk, kwargs) await self.set_color(ack, hsbk, kwargs)
if power_on: if power_on:
yield from self.set_power(ack, True, duration=fade) await self.set_power(ack, True, duration=fade)
else: else:
if power_on: if power_on:
yield from self.set_power(ack, True) await self.set_power(ack, True)
if hsbk: if hsbk:
yield from self.set_color(ack, hsbk, kwargs, duration=fade) await self.set_color(ack, hsbk, kwargs, duration=fade)
if power_off: if power_off:
yield from self.set_power(ack, False, duration=fade) await self.set_power(ack, False, duration=fade)
# 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.3) await asyncio.sleep(0.3)
# Update when the transition starts and ends # Update when the transition starts and ends
yield from self.update_during_transition(fade) await self.update_during_transition(fade)
@asyncio.coroutine async def set_power(self, ack, pwr, duration=0):
def set_power(self, ack, pwr, duration=0):
"""Send a power change to the device.""" """Send a power change to the device."""
yield from ack(partial(self.device.set_power, pwr, duration=duration)) await ack(partial(self.device.set_power, pwr, duration=duration))
@asyncio.coroutine async def set_color(self, ack, hsbk, kwargs, duration=0):
def set_color(self, ack, hsbk, kwargs, duration=0):
"""Send a color change to the device.""" """Send a color change to the device."""
hsbk = merge_hsbk(self.device.color, hsbk) hsbk = merge_hsbk(self.device.color, hsbk)
yield from ack(partial(self.device.set_color, hsbk, duration=duration)) await ack(partial(self.device.set_color, hsbk, duration=duration))
@asyncio.coroutine async def default_effect(self, **kwargs):
def default_effect(self, **kwargs):
"""Start an effect with default parameters.""" """Start an effect with default parameters."""
service = kwargs[ATTR_EFFECT] service = kwargs[ATTR_EFFECT]
data = { data = {
ATTR_ENTITY_ID: self.entity_id, ATTR_ENTITY_ID: self.entity_id,
} }
yield from self.hass.services.async_call(DOMAIN, service, data) await self.hass.services.async_call(DOMAIN, service, data)
@asyncio.coroutine async def async_update(self):
def async_update(self):
"""Update bulb status.""" """Update bulb status."""
_LOGGER.debug("%s async_update", self.who) _LOGGER.debug("%s async_update", self.who)
if self.available and not self.lock.locked(): if self.available and not self.lock.locked():
yield from AwaitAioLIFX().wait(self.device.get_color) await AwaitAioLIFX().wait(self.device.get_color)
class LIFXWhite(LIFXLight): class LIFXWhite(LIFXLight):
@ -624,8 +612,7 @@ class LIFXColor(LIFXLight):
class LIFXStrip(LIFXColor): class LIFXStrip(LIFXColor):
"""Representation of a LIFX light strip with multiple zones.""" """Representation of a LIFX light strip with multiple zones."""
@asyncio.coroutine async def set_color(self, ack, hsbk, kwargs, duration=0):
def set_color(self, ack, hsbk, kwargs, duration=0):
"""Send a color change to the device.""" """Send a color change to the device."""
bulb = self.device bulb = self.device
num_zones = len(bulb.color_zones) num_zones = len(bulb.color_zones)
@ -635,7 +622,7 @@ class LIFXStrip(LIFXColor):
# Fast track: setting all zones to the same brightness and color # Fast track: setting all zones to the same brightness and color
# can be treated as a single-zone bulb. # can be treated as a single-zone bulb.
if hsbk[2] is not None and hsbk[3] is not None: if hsbk[2] is not None and hsbk[3] is not None:
yield from super().set_color(ack, hsbk, kwargs, duration) await super().set_color(ack, hsbk, kwargs, duration)
return return
zones = list(range(0, num_zones)) zones = list(range(0, num_zones))
@ -644,11 +631,11 @@ class LIFXStrip(LIFXColor):
# Zone brightness is not reported when powered off # Zone brightness is not reported when powered off
if not self.is_on and hsbk[2] is None: if not self.is_on and hsbk[2] is None:
yield from self.set_power(ack, True) await self.set_power(ack, True)
yield from asyncio.sleep(0.3) await asyncio.sleep(0.3)
yield from self.update_color_zones() await self.update_color_zones()
yield from self.set_power(ack, False) await self.set_power(ack, False)
yield from asyncio.sleep(0.3) await asyncio.sleep(0.3)
# Send new color to each zone # Send new color to each zone
for index, zone in enumerate(zones): for index, zone in enumerate(zones):
@ -660,23 +647,21 @@ class LIFXStrip(LIFXColor):
color=zone_hsbk, color=zone_hsbk,
duration=duration, duration=duration,
apply=apply) apply=apply)
yield from ack(set_zone) await ack(set_zone)
@asyncio.coroutine async def async_update(self):
def async_update(self):
"""Update strip status.""" """Update strip status."""
if self.available and not self.lock.locked(): if self.available and not self.lock.locked():
yield from super().async_update() await super().async_update()
yield from self.update_color_zones() await self.update_color_zones()
@asyncio.coroutine async def update_color_zones(self):
def update_color_zones(self):
"""Get updated color information for each zone.""" """Get updated color information for each zone."""
zone = 0 zone = 0
top = 1 top = 1
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 = yield from AwaitAioLIFX().wait(partial( resp = await AwaitAioLIFX().wait(partial(
self.device.get_color_zones, self.device.get_color_zones,
start_index=zone)) start_index=zone))
if resp: if resp: