Migrate light component to async (#4635)

pull/4419/merge
Pascal Vizeli 2016-11-30 22:33:38 +01:00 committed by Paulus Schoutsen
parent 4c03d670c1
commit bde7176b3c
11 changed files with 99 additions and 88 deletions

View File

@ -4,6 +4,7 @@ Provides functionality to interact with lights.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/light/ https://home-assistant.io/components/light/
""" """
import asyncio
import logging import logging
import os import os
import csv import csv
@ -163,7 +164,7 @@ def async_turn_on(hass, entity_id=None, transition=None, brightness=None,
] if value is not None ] if value is not None
} }
hass.async_add_job(hass.services.async_call, DOMAIN, SERVICE_TURN_ON, data) hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data))
def turn_off(hass, entity_id=None, transition=None): def turn_off(hass, entity_id=None, transition=None):
@ -182,8 +183,8 @@ def async_turn_off(hass, entity_id=None, transition=None):
] if value is not None ] if value is not None
} }
hass.async_add_job(hass.services.async_call, DOMAIN, SERVICE_TURN_OFF, hass.async_add_job(hass.services.async_call(
data) DOMAIN, SERVICE_TURN_OFF, data))
def toggle(hass, entity_id=None, transition=None): def toggle(hass, entity_id=None, transition=None):
@ -198,13 +199,83 @@ def toggle(hass, entity_id=None, transition=None):
hass.services.call(DOMAIN, SERVICE_TOGGLE, data) hass.services.call(DOMAIN, SERVICE_TOGGLE, data)
def setup(hass, config): @asyncio.coroutine
def async_setup(hass, config):
"""Expose light control via statemachine and services.""" """Expose light control via statemachine and services."""
component = EntityComponent( component = EntityComponent(
_LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_LIGHTS) _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_LIGHTS)
component.setup(config) yield from component.async_setup(config)
# Load built-in profiles and custom profiles # load profiles from files
profiles = yield from hass.loop.run_in_executor(
None, _load_profile_data, hass)
if profiles is None:
return False
@asyncio.coroutine
def async_handle_light_service(service):
"""Hande a turn light on or off service call."""
# Get the validated data
params = service.data.copy()
# Convert the entity ids to valid light ids
target_lights = component.async_extract_from_service(service)
params.pop(ATTR_ENTITY_ID, None)
# Processing extra data for turn light on request.
profile = profiles.get(params.pop(ATTR_PROFILE, None))
if profile:
params.setdefault(ATTR_XY_COLOR, profile[:2])
params.setdefault(ATTR_BRIGHTNESS, profile[2])
color_name = params.pop(ATTR_COLOR_NAME, None)
if color_name is not None:
params[ATTR_RGB_COLOR] = color_util.color_name_to_rgb(color_name)
update_tasks = []
for light in target_lights:
if service.service == SERVICE_TURN_ON:
yield from light.async_turn_on(**params)
elif service.service == SERVICE_TURN_OFF:
yield from light.async_turn_off(**params)
else:
yield from light.async_toggle(**params)
if light.should_poll:
update_coro = light.async_update_ha_state(True)
if hasattr(light, 'async_update'):
update_tasks.append(hass.loop.create_task(update_coro))
else:
yield from update_coro
if update_tasks:
yield from asyncio.wait(update_tasks, loop=hass.loop)
# Listen for light on and light off service calls.
descriptions = yield from hass.loop.run_in_executor(
None, load_yaml_config_file, os.path.join(
os.path.dirname(__file__), 'services.yaml'))
hass.services.async_register(
DOMAIN, SERVICE_TURN_ON, async_handle_light_service,
descriptions.get(SERVICE_TURN_ON), schema=LIGHT_TURN_ON_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_TURN_OFF, async_handle_light_service,
descriptions.get(SERVICE_TURN_OFF), schema=LIGHT_TURN_OFF_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_TOGGLE, async_handle_light_service,
descriptions.get(SERVICE_TOGGLE), schema=LIGHT_TOGGLE_SCHEMA)
return True
def _load_profile_data(hass):
"""Load built-in profiles and custom profiles."""
profile_paths = [os.path.join(os.path.dirname(__file__), profile_paths = [os.path.join(os.path.dirname(__file__),
LIGHT_PROFILES_FILE), LIGHT_PROFILES_FILE),
hass.config.path(LIGHT_PROFILES_FILE)] hass.config.path(LIGHT_PROFILES_FILE)]
@ -226,67 +297,8 @@ def setup(hass, config):
except vol.MultipleInvalid as ex: except vol.MultipleInvalid as ex:
_LOGGER.error("Error parsing light profile from %s: %s", _LOGGER.error("Error parsing light profile from %s: %s",
profile_path, ex) profile_path, ex)
return False return None
return profiles
def handle_light_service(service):
"""Hande a turn light on or off service call."""
# Get the validated data
params = service.data.copy()
# Convert the entity ids to valid light ids
target_lights = component.extract_from_service(service)
params.pop(ATTR_ENTITY_ID, None)
service_fun = None
if service.service == SERVICE_TURN_OFF:
service_fun = 'turn_off'
elif service.service == SERVICE_TOGGLE:
service_fun = 'toggle'
if service_fun:
for light in target_lights:
getattr(light, service_fun)(**params)
for light in target_lights:
if light.should_poll:
light.update_ha_state(True)
return
# Processing extra data for turn light on request.
profile = profiles.get(params.pop(ATTR_PROFILE, None))
if profile:
params.setdefault(ATTR_XY_COLOR, profile[:2])
params.setdefault(ATTR_BRIGHTNESS, profile[2])
color_name = params.pop(ATTR_COLOR_NAME, None)
if color_name is not None:
params[ATTR_RGB_COLOR] = color_util.color_name_to_rgb(color_name)
for light in target_lights:
light.turn_on(**params)
for light in target_lights:
if light.should_poll:
light.update_ha_state(True)
# Listen for light on and light off service calls.
descriptions = load_yaml_config_file(
os.path.join(os.path.dirname(__file__), 'services.yaml'))
hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_light_service,
descriptions.get(SERVICE_TURN_ON),
schema=LIGHT_TURN_ON_SCHEMA)
hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_light_service,
descriptions.get(SERVICE_TURN_OFF),
schema=LIGHT_TURN_OFF_SCHEMA)
hass.services.register(DOMAIN, SERVICE_TOGGLE, handle_light_service,
descriptions.get(SERVICE_TOGGLE),
schema=LIGHT_TOGGLE_SCHEMA)
return True
class Light(ToggleEntity): class Light(ToggleEntity):

View File

@ -129,9 +129,9 @@ class DemoLight(Light):
if ATTR_EFFECT in kwargs: if ATTR_EFFECT in kwargs:
self._effect = kwargs[ATTR_EFFECT] self._effect = kwargs[ATTR_EFFECT]
self.update_ha_state() self.schedule_update_ha_state()
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
"""Turn the light off.""" """Turn the light off."""
self._state = False self._state = False
self.update_ha_state() self.schedule_update_ha_state()

View File

@ -140,7 +140,7 @@ def state(new_state):
# Update state. # Update state.
self._is_on = new_state self._is_on = new_state
self.group.enqueue(pipeline) self.group.enqueue(pipeline)
self.update_ha_state() self.schedule_update_ha_state()
return wrapper return wrapper
return decorator return decorator

View File

@ -283,7 +283,7 @@ class MqttLight(Light):
should_update = True should_update = True
if should_update: if should_update:
self.update_ha_state() self.schedule_update_ha_state()
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
"""Turn the device off.""" """Turn the device off."""
@ -293,4 +293,4 @@ class MqttLight(Light):
if self._optimistic: if self._optimistic:
# Optimistically assume that switch has changed state. # Optimistically assume that switch has changed state.
self._state = False self._state = False
self.update_ha_state() self.schedule_update_ha_state()

View File

@ -216,7 +216,7 @@ class MqttJson(Light):
should_update = True should_update = True
if should_update: if should_update:
self.update_ha_state() self.schedule_update_ha_state()
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
"""Turn the device off.""" """Turn the device off."""
@ -231,4 +231,4 @@ class MqttJson(Light):
if self._optimistic: if self._optimistic:
# Optimistically assume that the light has changed state. # Optimistically assume that the light has changed state.
self._state = False self._state = False
self.update_ha_state() self.schedule_update_ha_state()

View File

@ -263,7 +263,7 @@ class MqttTemplate(Light):
) )
if self._optimistic: if self._optimistic:
self.update_ha_state() self.schedule_update_ha_state()
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
"""Turn the entity off.""" """Turn the entity off."""
@ -283,4 +283,4 @@ class MqttTemplate(Light):
) )
if self._optimistic: if self._optimistic:
self.update_ha_state() self.schedule_update_ha_state()

View File

@ -115,7 +115,7 @@ class MySensorsLight(mysensors.MySensorsDeviceEntity, Light):
# optimistically assume that light has changed state # optimistically assume that light has changed state
self._state = True self._state = True
self._values[set_req.V_LIGHT] = STATE_ON self._values[set_req.V_LIGHT] = STATE_ON
self.update_ha_state() self.schedule_update_ha_state()
def _turn_on_dimmer(self, **kwargs): def _turn_on_dimmer(self, **kwargs):
"""Turn on dimmer child device.""" """Turn on dimmer child device."""
@ -135,7 +135,7 @@ class MySensorsLight(mysensors.MySensorsDeviceEntity, Light):
# optimistically assume that light has changed state # optimistically assume that light has changed state
self._brightness = brightness self._brightness = brightness
self._values[set_req.V_DIMMER] = percent self._values[set_req.V_DIMMER] = percent
self.update_ha_state() self.schedule_update_ha_state()
def _turn_on_rgb_and_w(self, hex_template, **kwargs): def _turn_on_rgb_and_w(self, hex_template, **kwargs):
"""Turn on RGB or RGBW child device.""" """Turn on RGB or RGBW child device."""
@ -165,7 +165,7 @@ class MySensorsLight(mysensors.MySensorsDeviceEntity, Light):
self._white = white self._white = white
if hex_color: if hex_color:
self._values[self.value_type] = hex_color self._values[self.value_type] = hex_color
self.update_ha_state() self.schedule_update_ha_state()
def _turn_off_light(self, value_type=None, value=None): def _turn_off_light(self, value_type=None, value=None):
"""Turn off light child device.""" """Turn off light child device."""
@ -211,7 +211,7 @@ class MySensorsLight(mysensors.MySensorsDeviceEntity, Light):
self._state = False self._state = False
self._values[value_type] = ( self._values[value_type] = (
STATE_OFF if set_req.V_LIGHT in self._values else value) STATE_OFF if set_req.V_LIGHT in self._values else value)
self.update_ha_state() self.schedule_update_ha_state()
def _update_light(self): def _update_light(self):
"""Update the controller with values from light child.""" """Update the controller with values from light child."""

View File

@ -189,7 +189,7 @@ class OsramLightifyLight(Light):
" %s with transition %s ", " %s with transition %s ",
self._name, transition) self._name, transition)
self.update_ha_state() self.schedule_update_ha_state()
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
"""Turn the device off.""" """Turn the device off."""
@ -209,7 +209,7 @@ class OsramLightifyLight(Light):
self._light.set_onoff(0) self._light.set_onoff(0)
self._state = self._light.on() self._state = self._light.on()
self.update_ha_state() self.schedule_update_ha_state()
def update(self): def update(self):
"""Synchronize state with bridge.""" """Synchronize state with bridge."""

View File

@ -84,7 +84,7 @@ class SCSGateLight(Light):
ToggleStatusTask(target=self._scs_id, toggled=True)) ToggleStatusTask(target=self._scs_id, toggled=True))
self._toggled = True self._toggled = True
self.update_ha_state() self.schedule_update_ha_state()
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
"""Turn the device off.""" """Turn the device off."""
@ -94,7 +94,7 @@ class SCSGateLight(Light):
ToggleStatusTask(target=self._scs_id, toggled=False)) ToggleStatusTask(target=self._scs_id, toggled=False))
self._toggled = False self._toggled = False
self.update_ha_state() self.schedule_update_ha_state()
def process_event(self, message): def process_event(self, message):
"""Handle a SCSGate message related with this light.""" """Handle a SCSGate message related with this light."""

View File

@ -53,13 +53,13 @@ class VeraLight(VeraDevice, Light):
self.vera_device.switch_on() self.vera_device.switch_on()
self._state = STATE_ON self._state = STATE_ON
self.update_ha_state(True) self.schedule_update_ha_state(True)
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
"""Turn the light off.""" """Turn the light off."""
self.vera_device.switch_off() self.vera_device.switch_off()
self._state = STATE_OFF self._state = STATE_OFF
self.update_ha_state() self.schedule_update_ha_state()
@property @property
def is_on(self): def is_on(self):

View File

@ -271,8 +271,7 @@ class TestLight(unittest.TestCase):
user_file.write('I,WILL,NOT,WORK\n') user_file.write('I,WILL,NOT,WORK\n')
self.assertFalse(setup_component( self.assertFalse(setup_component(
self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}} self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}))
))
def test_light_profiles(self): def test_light_profiles(self):
"""Test light profiles.""" """Test light profiles."""