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
https://home-assistant.io/components/light/
"""
import asyncio
import logging
import os
import csv
@ -163,7 +164,7 @@ def async_turn_on(hass, entity_id=None, transition=None, brightness=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):
@ -182,8 +183,8 @@ def async_turn_off(hass, entity_id=None, transition=None):
] if value is not None
}
hass.async_add_job(hass.services.async_call, DOMAIN, SERVICE_TURN_OFF,
data)
hass.async_add_job(hass.services.async_call(
DOMAIN, SERVICE_TURN_OFF, data))
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)
def setup(hass, config):
@asyncio.coroutine
def async_setup(hass, config):
"""Expose light control via statemachine and services."""
component = EntityComponent(
_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__),
LIGHT_PROFILES_FILE),
hass.config.path(LIGHT_PROFILES_FILE)]
@ -226,67 +297,8 @@ def setup(hass, config):
except vol.MultipleInvalid as ex:
_LOGGER.error("Error parsing light profile from %s: %s",
profile_path, ex)
return False
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
return None
return profiles
class Light(ToggleEntity):

View File

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

View File

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

View File

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

View File

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

View File

@ -263,7 +263,7 @@ class MqttTemplate(Light):
)
if self._optimistic:
self.update_ha_state()
self.schedule_update_ha_state()
def turn_off(self, **kwargs):
"""Turn the entity off."""
@ -283,4 +283,4 @@ class MqttTemplate(Light):
)
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
self._state = True
self._values[set_req.V_LIGHT] = STATE_ON
self.update_ha_state()
self.schedule_update_ha_state()
def _turn_on_dimmer(self, **kwargs):
"""Turn on dimmer child device."""
@ -135,7 +135,7 @@ class MySensorsLight(mysensors.MySensorsDeviceEntity, Light):
# optimistically assume that light has changed state
self._brightness = brightness
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):
"""Turn on RGB or RGBW child device."""
@ -165,7 +165,7 @@ class MySensorsLight(mysensors.MySensorsDeviceEntity, Light):
self._white = white
if 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):
"""Turn off light child device."""
@ -211,7 +211,7 @@ class MySensorsLight(mysensors.MySensorsDeviceEntity, Light):
self._state = False
self._values[value_type] = (
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):
"""Update the controller with values from light child."""

View File

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

View File

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

View File

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

View File

@ -271,8 +271,7 @@ class TestLight(unittest.TestCase):
user_file.write('I,WILL,NOT,WORK\n')
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):
"""Test light profiles."""