Migrate light component to async (#4635)
parent
4c03d670c1
commit
bde7176b3c
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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."""
|
||||
|
|
Loading…
Reference in New Issue