From 5d8e6d5432721bb66f5efef814a1e0431ae02e79 Mon Sep 17 00:00:00 2001 From: Xiaonan Shen Date: Mon, 11 May 2020 03:58:59 -0700 Subject: [PATCH] Fix light toggle service attributes (#35483) --- homeassistant/components/light/__init__.py | 37 +++++++---- tests/components/light/common.py | 74 ++++++++++++++++++++-- tests/components/light/test_init.py | 9 +++ 3 files changed, 102 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index d25d6b961ed..0a3c087950e 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -167,12 +167,19 @@ def preprocess_turn_on_alternatives(params): if rgb_color is not None: params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color) + return params + + +def filter_turn_off_params(params): + """Filter out params not used in turn off.""" + return {k: v for k, v in params.items() if k in (ATTR_TRANSITION, ATTR_FLASH)} + def preprocess_turn_off(params): """Process data for turning light off if brightness is 0.""" if ATTR_BRIGHTNESS in params and params[ATTR_BRIGHTNESS] == 0: # Zero brightness: Light will be turned off - params = {k: v for k, v in params.items() if k in (ATTR_TRANSITION, ATTR_FLASH)} + params = filter_turn_off_params(params) return (True, params) # Light should be turned off return (False, None) # Light should be turned on @@ -198,13 +205,7 @@ async def async_setup(hass, config): if entity_field in data } - preprocess_turn_on_alternatives(data) - turn_lights_off, off_params = preprocess_turn_off(data) - - base["params"] = data - base["turn_lights_off"] = turn_lights_off - base["off_params"] = off_params - + base["params"] = preprocess_turn_on_alternatives(data) return base async def async_handle_light_on_service(light, call): @@ -213,8 +214,6 @@ async def async_setup(hass, config): If brightness is set to 0, this service will turn the light off. """ params = call.data["params"] - turn_light_off = call.data["turn_lights_off"] - off_params = call.data["off_params"] if not params: default_profile = Profiles.get_default(light.entity_id) @@ -222,7 +221,6 @@ async def async_setup(hass, config): if default_profile is not None: params = {ATTR_PROFILE: default_profile} preprocess_turn_on_alternatives(params) - turn_light_off, off_params = preprocess_turn_off(params) elif ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params: brightness = light.brightness if light.is_on else 0 @@ -236,13 +234,24 @@ async def async_setup(hass, config): brightness += round(params.pop(ATTR_BRIGHTNESS_STEP_PCT) / 100 * 255) params[ATTR_BRIGHTNESS] = max(0, min(255, brightness)) - turn_light_off, off_params = preprocess_turn_off(params) + turn_light_off, off_params = preprocess_turn_off(params) if turn_light_off: await light.async_turn_off(**off_params) else: await light.async_turn_on(**params) + async def async_handle_toggle_service(light, call): + """Handle toggling a light. + + If brightness is set to 0, this service will turn the light off. + """ + if light.is_on: + off_params = filter_turn_off_params(call.data["params"]) + await light.async_turn_off(**off_params) + else: + await async_handle_light_on_service(light, call) + # Listen for light on and light off service calls. component.async_register_entity_service( @@ -258,7 +267,9 @@ async def async_setup(hass, config): ) component.async_register_entity_service( - SERVICE_TOGGLE, LIGHT_TURN_ON_SCHEMA, "async_toggle" + SERVICE_TOGGLE, + vol.All(cv.make_entity_service_schema(LIGHT_TURN_ON_SCHEMA), preprocess_data), + async_handle_toggle_service, ) return True diff --git a/tests/components/light/common.py b/tests/components/light/common.py index aa1e62db5bf..a9991bf3594 100644 --- a/tests/components/light/common.py +++ b/tests/components/light/common.py @@ -128,16 +128,80 @@ async def async_turn_off(hass, entity_id=ENTITY_MATCH_ALL, transition=None): @bind_hass -def toggle(hass, entity_id=ENTITY_MATCH_ALL, transition=None): +def toggle( + hass, + entity_id=ENTITY_MATCH_ALL, + transition=None, + brightness=None, + brightness_pct=None, + rgb_color=None, + xy_color=None, + hs_color=None, + color_temp=None, + kelvin=None, + white_value=None, + profile=None, + flash=None, + effect=None, + color_name=None, +): """Toggle all or specified light.""" - hass.add_job(async_toggle, hass, entity_id, transition) + hass.add_job( + async_toggle, + hass, + entity_id, + transition, + brightness, + brightness_pct, + rgb_color, + xy_color, + hs_color, + color_temp, + kelvin, + white_value, + profile, + flash, + effect, + color_name, + ) -async def async_toggle(hass, entity_id=ENTITY_MATCH_ALL, transition=None): - """Toggle all or specified light.""" +async def async_toggle( + hass, + entity_id=ENTITY_MATCH_ALL, + transition=None, + brightness=None, + brightness_pct=None, + rgb_color=None, + xy_color=None, + hs_color=None, + color_temp=None, + kelvin=None, + white_value=None, + profile=None, + flash=None, + effect=None, + color_name=None, +): + """Turn all or specified light on.""" data = { key: value - for key, value in [(ATTR_ENTITY_ID, entity_id), (ATTR_TRANSITION, transition)] + for key, value in [ + (ATTR_ENTITY_ID, entity_id), + (ATTR_PROFILE, profile), + (ATTR_TRANSITION, transition), + (ATTR_BRIGHTNESS, brightness), + (ATTR_BRIGHTNESS_PCT, brightness_pct), + (ATTR_RGB_COLOR, rgb_color), + (ATTR_XY_COLOR, xy_color), + (ATTR_HS_COLOR, hs_color), + (ATTR_COLOR_TEMP, color_temp), + (ATTR_KELVIN, kelvin), + (ATTR_WHITE_VALUE, white_value), + (ATTR_FLASH, flash), + (ATTR_EFFECT, effect), + (ATTR_COLOR_NAME, color_name), + ] if value is not None } diff --git a/tests/components/light/test_init.py b/tests/components/light/test_init.py index 87452d62893..b1f9327ff50 100644 --- a/tests/components/light/test_init.py +++ b/tests/components/light/test_init.py @@ -263,6 +263,15 @@ class TestLight(unittest.TestCase): light.ATTR_HS_COLOR: (prof_h, prof_s), } == data + # Test toggle with parameters + common.toggle(self.hass, ent3.entity_id, profile=prof_name, brightness_pct=100) + self.hass.block_till_done() + _, data = ent3.last_call("turn_on") + assert { + light.ATTR_BRIGHTNESS: 255, + light.ATTR_HS_COLOR: (prof_h, prof_s), + } == data + # Test bad data common.turn_on(self.hass) common.turn_on(self.hass, ent1.entity_id, profile="nonexisting")