Add support for effects, transition/brightness parameters to template light, min_mireds and max_mireds templates (#43850)
* Add support for effects, transition/brightness parameters to template light, min_mireds and max_mireds templates * code fixes * min_mireds, max_mireds fixes * test fixes * more fixes * format fix * style fix * _update_effect_list change * style fix * Fixes after review * additional fixes * duplicated lines removed * fixes after CI run * test fixes * code and test fixes * supports transition change, added test casespull/51031/head
parent
c497c0eadd
commit
85495c08b0
|
@ -6,12 +6,16 @@ import voluptuous as vol
|
|||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_TEMP,
|
||||
ATTR_EFFECT,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_TRANSITION,
|
||||
ATTR_WHITE_VALUE,
|
||||
ENTITY_ID_FORMAT,
|
||||
SUPPORT_BRIGHTNESS,
|
||||
SUPPORT_COLOR,
|
||||
SUPPORT_COLOR_TEMP,
|
||||
SUPPORT_EFFECT,
|
||||
SUPPORT_TRANSITION,
|
||||
SUPPORT_WHITE_VALUE,
|
||||
LightEntity,
|
||||
)
|
||||
|
@ -49,6 +53,12 @@ CONF_COLOR_TEMPLATE = "color_template"
|
|||
CONF_COLOR_ACTION = "set_color"
|
||||
CONF_WHITE_VALUE_TEMPLATE = "white_value_template"
|
||||
CONF_WHITE_VALUE_ACTION = "set_white_value"
|
||||
CONF_EFFECT_ACTION = "set_effect"
|
||||
CONF_EFFECT_LIST_TEMPLATE = "effect_list_template"
|
||||
CONF_EFFECT_TEMPLATE = "effect_template"
|
||||
CONF_MAX_MIREDS_TEMPLATE = "max_mireds_template"
|
||||
CONF_MIN_MIREDS_TEMPLATE = "min_mireds_template"
|
||||
CONF_SUPPORTS_TRANSITION = "supports_transition_template"
|
||||
|
||||
LIGHT_SCHEMA = vol.All(
|
||||
cv.deprecated(CONF_ENTITY_ID),
|
||||
|
@ -70,6 +80,12 @@ LIGHT_SCHEMA = vol.All(
|
|||
vol.Optional(CONF_COLOR_ACTION): cv.SCRIPT_SCHEMA,
|
||||
vol.Optional(CONF_WHITE_VALUE_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_WHITE_VALUE_ACTION): cv.SCRIPT_SCHEMA,
|
||||
vol.Inclusive(CONF_EFFECT_LIST_TEMPLATE, "effect"): cv.template,
|
||||
vol.Inclusive(CONF_EFFECT_TEMPLATE, "effect"): cv.template,
|
||||
vol.Inclusive(CONF_EFFECT_ACTION, "effect"): cv.SCRIPT_SCHEMA,
|
||||
vol.Optional(CONF_MAX_MIREDS_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_MIN_MIREDS_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_SUPPORTS_TRANSITION): cv.template,
|
||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||
}
|
||||
),
|
||||
|
@ -108,6 +124,15 @@ async def _async_create_entities(hass, config):
|
|||
white_value_action = device_config.get(CONF_WHITE_VALUE_ACTION)
|
||||
white_value_template = device_config.get(CONF_WHITE_VALUE_TEMPLATE)
|
||||
|
||||
effect_action = device_config.get(CONF_EFFECT_ACTION)
|
||||
effect_list_template = device_config.get(CONF_EFFECT_LIST_TEMPLATE)
|
||||
effect_template = device_config.get(CONF_EFFECT_TEMPLATE)
|
||||
|
||||
max_mireds_template = device_config.get(CONF_MAX_MIREDS_TEMPLATE)
|
||||
min_mireds_template = device_config.get(CONF_MIN_MIREDS_TEMPLATE)
|
||||
|
||||
supports_transition_template = device_config.get(CONF_SUPPORTS_TRANSITION)
|
||||
|
||||
lights.append(
|
||||
LightTemplate(
|
||||
hass,
|
||||
|
@ -127,6 +152,12 @@ async def _async_create_entities(hass, config):
|
|||
color_template,
|
||||
white_value_action,
|
||||
white_value_template,
|
||||
effect_action,
|
||||
effect_list_template,
|
||||
effect_template,
|
||||
max_mireds_template,
|
||||
min_mireds_template,
|
||||
supports_transition_template,
|
||||
unique_id,
|
||||
)
|
||||
)
|
||||
|
@ -161,6 +192,12 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
color_template,
|
||||
white_value_action,
|
||||
white_value_template,
|
||||
effect_action,
|
||||
effect_list_template,
|
||||
effect_template,
|
||||
max_mireds_template,
|
||||
min_mireds_template,
|
||||
supports_transition_template,
|
||||
unique_id,
|
||||
):
|
||||
"""Initialize the light."""
|
||||
|
@ -197,12 +234,25 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
hass, white_value_action, friendly_name, domain
|
||||
)
|
||||
self._white_value_template = white_value_template
|
||||
self._effect_script = None
|
||||
if effect_action is not None:
|
||||
self._effect_script = Script(hass, effect_action, friendly_name, domain)
|
||||
self._effect_list_template = effect_list_template
|
||||
self._effect_template = effect_template
|
||||
self._max_mireds_template = max_mireds_template
|
||||
self._min_mireds_template = min_mireds_template
|
||||
self._supports_transition_template = supports_transition_template
|
||||
|
||||
self._state = False
|
||||
self._brightness = None
|
||||
self._temperature = None
|
||||
self._color = None
|
||||
self._white_value = None
|
||||
self._effect = None
|
||||
self._effect_list = None
|
||||
self._max_mireds = None
|
||||
self._min_mireds = None
|
||||
self._supports_transition = False
|
||||
self._unique_id = unique_id
|
||||
|
||||
@property
|
||||
|
@ -215,6 +265,22 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
"""Return the CT color value in mireds."""
|
||||
return self._temperature
|
||||
|
||||
@property
|
||||
def max_mireds(self):
|
||||
"""Return the max mireds value in mireds."""
|
||||
if self._max_mireds is not None:
|
||||
return self._max_mireds
|
||||
|
||||
return super().max_mireds
|
||||
|
||||
@property
|
||||
def min_mireds(self):
|
||||
"""Return the min mireds value in mireds."""
|
||||
if self._min_mireds is not None:
|
||||
return self._min_mireds
|
||||
|
||||
return super().min_mireds
|
||||
|
||||
@property
|
||||
def white_value(self):
|
||||
"""Return the white value."""
|
||||
|
@ -225,6 +291,16 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
"""Return the hue and saturation color value [float, float]."""
|
||||
return self._color
|
||||
|
||||
@property
|
||||
def effect(self):
|
||||
"""Return the effect."""
|
||||
return self._effect
|
||||
|
||||
@property
|
||||
def effect_list(self):
|
||||
"""Return the effect list."""
|
||||
return self._effect_list
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the display name of this light."""
|
||||
|
@ -247,6 +323,10 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
supported_features |= SUPPORT_COLOR
|
||||
if self._white_value_script is not None:
|
||||
supported_features |= SUPPORT_WHITE_VALUE
|
||||
if self._effect_script is not None:
|
||||
supported_features |= SUPPORT_EFFECT
|
||||
if self._supports_transition is True:
|
||||
supported_features |= SUPPORT_TRANSITION
|
||||
return supported_features
|
||||
|
||||
@property
|
||||
|
@ -268,6 +348,22 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
self._update_brightness,
|
||||
none_on_template_error=True,
|
||||
)
|
||||
if self._max_mireds_template:
|
||||
self.add_template_attribute(
|
||||
"_max_mireds_template",
|
||||
self._max_mireds_template,
|
||||
None,
|
||||
self._update_max_mireds,
|
||||
none_on_template_error=True,
|
||||
)
|
||||
if self._min_mireds_template:
|
||||
self.add_template_attribute(
|
||||
"_min_mireds_template",
|
||||
self._min_mireds_template,
|
||||
None,
|
||||
self._update_min_mireds,
|
||||
none_on_template_error=True,
|
||||
)
|
||||
if self._temperature_template:
|
||||
self.add_template_attribute(
|
||||
"_temperature",
|
||||
|
@ -292,6 +388,30 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
self._update_white_value,
|
||||
none_on_template_error=True,
|
||||
)
|
||||
if self._effect_list_template:
|
||||
self.add_template_attribute(
|
||||
"_effect_list",
|
||||
self._effect_list_template,
|
||||
None,
|
||||
self._update_effect_list,
|
||||
none_on_template_error=True,
|
||||
)
|
||||
if self._effect_template:
|
||||
self.add_template_attribute(
|
||||
"_effect",
|
||||
self._effect_template,
|
||||
None,
|
||||
self._update_effect,
|
||||
none_on_template_error=True,
|
||||
)
|
||||
if self._supports_transition_template:
|
||||
self.add_template_attribute(
|
||||
"_supports_transition_template",
|
||||
self._supports_transition_template,
|
||||
None,
|
||||
self._update_supports_transition,
|
||||
none_on_template_error=True,
|
||||
)
|
||||
await super().async_added_to_hass()
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
|
@ -324,33 +444,65 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
self._temperature = kwargs[ATTR_COLOR_TEMP]
|
||||
optimistic_set = True
|
||||
|
||||
if ATTR_BRIGHTNESS in kwargs and self._level_script:
|
||||
await self._level_script.async_run(
|
||||
{"brightness": kwargs[ATTR_BRIGHTNESS]}, context=self._context
|
||||
)
|
||||
elif ATTR_COLOR_TEMP in kwargs and self._temperature_script:
|
||||
common_params = {}
|
||||
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
common_params["brightness"] = kwargs[ATTR_BRIGHTNESS]
|
||||
|
||||
if ATTR_TRANSITION in kwargs and self._supports_transition is True:
|
||||
common_params["transition"] = kwargs[ATTR_TRANSITION]
|
||||
|
||||
if ATTR_COLOR_TEMP in kwargs and self._temperature_script:
|
||||
common_params["color_temp"] = kwargs[ATTR_COLOR_TEMP]
|
||||
|
||||
await self._temperature_script.async_run(
|
||||
{"color_temp": kwargs[ATTR_COLOR_TEMP]}, context=self._context
|
||||
common_params, context=self._context
|
||||
)
|
||||
elif ATTR_WHITE_VALUE in kwargs and self._white_value_script:
|
||||
common_params["white_value"] = kwargs[ATTR_WHITE_VALUE]
|
||||
|
||||
await self._white_value_script.async_run(
|
||||
{"white_value": kwargs[ATTR_WHITE_VALUE]}, context=self._context
|
||||
common_params, context=self._context
|
||||
)
|
||||
elif ATTR_EFFECT in kwargs and self._effect_script:
|
||||
effect = kwargs[ATTR_EFFECT]
|
||||
if effect not in self._effect_list:
|
||||
_LOGGER.error(
|
||||
"Received invalid effect: %s. Expected one of: %s",
|
||||
effect,
|
||||
self._effect_list,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
common_params["effect"] = effect
|
||||
|
||||
await self._effect_script.async_run(common_params, context=self._context)
|
||||
elif ATTR_HS_COLOR in kwargs and self._color_script:
|
||||
hs_value = kwargs[ATTR_HS_COLOR]
|
||||
common_params["hs"] = hs_value
|
||||
common_params["h"] = int(hs_value[0])
|
||||
common_params["s"] = int(hs_value[1])
|
||||
|
||||
await self._color_script.async_run(
|
||||
{"hs": hs_value, "h": int(hs_value[0]), "s": int(hs_value[1])},
|
||||
common_params,
|
||||
context=self._context,
|
||||
)
|
||||
elif ATTR_BRIGHTNESS in kwargs and self._level_script:
|
||||
await self._level_script.async_run(common_params, context=self._context)
|
||||
else:
|
||||
await self._on_script.async_run(context=self._context)
|
||||
await self._on_script.async_run(common_params, context=self._context)
|
||||
|
||||
if optimistic_set:
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn the light off."""
|
||||
await self._off_script.async_run(context=self._context)
|
||||
if ATTR_TRANSITION in kwargs and self._supports_transition is True:
|
||||
await self._off_script.async_run(
|
||||
{"transition": kwargs[ATTR_TRANSITION]}, context=self._context
|
||||
)
|
||||
else:
|
||||
await self._off_script.async_run(context=self._context)
|
||||
if self._template is None:
|
||||
self._state = False
|
||||
self.async_write_ha_state()
|
||||
|
@ -397,6 +549,45 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
)
|
||||
self._white_value = None
|
||||
|
||||
@callback
|
||||
def _update_effect_list(self, effect_list):
|
||||
"""Update the effect list from the template."""
|
||||
if effect_list in ("None", ""):
|
||||
self._effect_list = None
|
||||
return
|
||||
|
||||
if not isinstance(effect_list, list):
|
||||
_LOGGER.error(
|
||||
"Received invalid effect list: %s. Expected list of strings",
|
||||
effect_list,
|
||||
)
|
||||
self._effect_list = None
|
||||
return
|
||||
|
||||
if len(effect_list) == 0:
|
||||
self._effect_list = None
|
||||
return
|
||||
|
||||
self._effect_list = effect_list
|
||||
|
||||
@callback
|
||||
def _update_effect(self, effect):
|
||||
"""Update the effect from the template."""
|
||||
if effect in ("None", ""):
|
||||
self._effect = None
|
||||
return
|
||||
|
||||
if effect not in self._effect_list:
|
||||
_LOGGER.error(
|
||||
"Received invalid effect: %s. Expected one of: %s",
|
||||
effect,
|
||||
self._effect_list,
|
||||
)
|
||||
self._effect = None
|
||||
return
|
||||
|
||||
self._effect = effect
|
||||
|
||||
@callback
|
||||
def _update_state(self, result):
|
||||
"""Update the state from the template."""
|
||||
|
@ -479,3 +670,42 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
else:
|
||||
_LOGGER.error("Received invalid hs_color : (%s)", render)
|
||||
self._color = None
|
||||
|
||||
@callback
|
||||
def _update_max_mireds(self, render):
|
||||
"""Update the max mireds from the template."""
|
||||
|
||||
try:
|
||||
if render in ("None", ""):
|
||||
self._max_mireds = None
|
||||
return
|
||||
self._max_mireds = int(render)
|
||||
except ValueError:
|
||||
_LOGGER.error(
|
||||
"Template must supply an integer temperature within the range for this light, or 'None'",
|
||||
exc_info=True,
|
||||
)
|
||||
self._max_mireds = None
|
||||
|
||||
@callback
|
||||
def _update_min_mireds(self, render):
|
||||
"""Update the min mireds from the template."""
|
||||
try:
|
||||
if render in ("None", ""):
|
||||
self._min_mireds = None
|
||||
return
|
||||
self._min_mireds = int(render)
|
||||
except ValueError:
|
||||
_LOGGER.error(
|
||||
"Template must supply an integer temperature within the range for this light, or 'None'",
|
||||
exc_info=True,
|
||||
)
|
||||
self._min_mireds = None
|
||||
|
||||
@callback
|
||||
def _update_supports_transition(self, render):
|
||||
"""Update the supports transition from the template."""
|
||||
if render in ("None", ""):
|
||||
self._supports_transition = False
|
||||
return
|
||||
self._supports_transition = bool(render)
|
||||
|
|
|
@ -8,8 +8,11 @@ import homeassistant.components.light as light
|
|||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_TEMP,
|
||||
ATTR_EFFECT,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_TRANSITION,
|
||||
ATTR_WHITE_VALUE,
|
||||
SUPPORT_TRANSITION,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
|
@ -378,6 +381,64 @@ async def test_on_action(hass, calls):
|
|||
assert len(calls) == 1
|
||||
|
||||
|
||||
async def test_on_action_with_transition(hass, calls):
|
||||
"""Test on action with transition."""
|
||||
assert await setup.async_setup_component(
|
||||
hass,
|
||||
light.DOMAIN,
|
||||
{
|
||||
"light": {
|
||||
"platform": "template",
|
||||
"lights": {
|
||||
"test_template_light": {
|
||||
"value_template": "{{states.light.test_state.state}}",
|
||||
"turn_on": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"transition": "{{transition}}",
|
||||
},
|
||||
},
|
||||
"turn_off": {
|
||||
"service": "light.turn_off",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"supports_transition_template": "{{true}}",
|
||||
"set_level": {
|
||||
"service": "light.turn_on",
|
||||
"data_template": {
|
||||
"entity_id": "light.test_state",
|
||||
"brightness": "{{brightness}}",
|
||||
"transition": "{{transition}}",
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
hass.states.async_set("light.test_state", STATE_OFF)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "light.test_template_light", ATTR_TRANSITION: 5},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
print(calls[0].data)
|
||||
assert calls[0].data["transition"] == 5
|
||||
|
||||
|
||||
async def test_on_action_optimistic(hass, calls):
|
||||
"""Test on action with optimistic state."""
|
||||
assert await setup.async_setup_component(
|
||||
|
@ -443,7 +504,9 @@ async def test_off_action(hass, calls):
|
|||
"service": "light.turn_on",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"turn_off": {"service": "test.automation"},
|
||||
"turn_off": {
|
||||
"service": "test.automation",
|
||||
},
|
||||
"set_level": {
|
||||
"service": "light.turn_on",
|
||||
"data_template": {
|
||||
|
@ -477,6 +540,63 @@ async def test_off_action(hass, calls):
|
|||
assert len(calls) == 1
|
||||
|
||||
|
||||
async def test_off_action_with_transition(hass, calls):
|
||||
"""Test off action with transition."""
|
||||
assert await setup.async_setup_component(
|
||||
hass,
|
||||
light.DOMAIN,
|
||||
{
|
||||
"light": {
|
||||
"platform": "template",
|
||||
"lights": {
|
||||
"test_template_light": {
|
||||
"value_template": "{{states.light.test_state.state}}",
|
||||
"turn_on": {
|
||||
"service": "light.turn_on",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"turn_off": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"transition": "{{transition}}",
|
||||
},
|
||||
},
|
||||
"supports_transition_template": "{{true}}",
|
||||
"set_level": {
|
||||
"service": "light.turn_on",
|
||||
"data_template": {
|
||||
"entity_id": "light.test_state",
|
||||
"brightness": "{{brightness}}",
|
||||
"transition": "{{transition}}",
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
hass.states.async_set("light.test_state", STATE_ON)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.state == STATE_ON
|
||||
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: "light.test_template_light", ATTR_TRANSITION: 2},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data["transition"] == 2
|
||||
|
||||
|
||||
async def test_off_action_optimistic(hass, calls):
|
||||
"""Test off action with optimistic state."""
|
||||
assert await setup.async_setup_component(
|
||||
|
@ -1119,6 +1239,417 @@ async def test_color_template(hass, expected_hs, template):
|
|||
assert state.attributes.get("hs_color") == expected_hs
|
||||
|
||||
|
||||
async def test_effect_action_valid_effect(hass, calls):
|
||||
"""Test setting valid effect with template."""
|
||||
assert await setup.async_setup_component(
|
||||
hass,
|
||||
light.DOMAIN,
|
||||
{
|
||||
"light": {
|
||||
"platform": "template",
|
||||
"lights": {
|
||||
"test_template_light": {
|
||||
"value_template": "{{true}}",
|
||||
"turn_on": {"service": "test.automation"},
|
||||
"turn_off": {
|
||||
"service": "light.turn_off",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"set_level": {
|
||||
"service": "light.turn_on",
|
||||
"data_template": {
|
||||
"entity_id": "light.test_state",
|
||||
"brightness": "{{brightness}}",
|
||||
},
|
||||
},
|
||||
"set_effect": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"entity_id": "test.test_state",
|
||||
"effect": "{{effect}}",
|
||||
},
|
||||
},
|
||||
"effect_list_template": "{{ ['Disco', 'Police'] }}",
|
||||
"effect_template": "{{ 'Disco' }}",
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state is not None
|
||||
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "light.test_template_light", ATTR_EFFECT: "Disco"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data["effect"] == "Disco"
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state is not None
|
||||
assert state.attributes.get("effect") == "Disco"
|
||||
|
||||
|
||||
async def test_effect_action_invalid_effect(hass, calls):
|
||||
"""Test setting invalid effect with template."""
|
||||
assert await setup.async_setup_component(
|
||||
hass,
|
||||
light.DOMAIN,
|
||||
{
|
||||
"light": {
|
||||
"platform": "template",
|
||||
"lights": {
|
||||
"test_template_light": {
|
||||
"value_template": "{{true}}",
|
||||
"turn_on": {"service": "test.automation"},
|
||||
"turn_off": {
|
||||
"service": "light.turn_off",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"set_level": {
|
||||
"service": "light.turn_on",
|
||||
"data_template": {
|
||||
"entity_id": "light.test_state",
|
||||
"brightness": "{{brightness}}",
|
||||
},
|
||||
},
|
||||
"set_effect": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"entity_id": "test.test_state",
|
||||
"effect": "{{effect}}",
|
||||
},
|
||||
},
|
||||
"effect_list_template": "{{ ['Disco', 'Police'] }}",
|
||||
"effect_template": "{{ None }}",
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state is not None
|
||||
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "light.test_template_light", ATTR_EFFECT: "RGB"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data["effect"] == "RGB"
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state is not None
|
||||
assert state.attributes.get("effect") is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expected_effect_list,template",
|
||||
[
|
||||
(
|
||||
["Strobe color", "Police", "Christmas", "RGB", "Random Loop"],
|
||||
"{{ ['Strobe color', 'Police', 'Christmas', 'RGB', 'Random Loop'] }}",
|
||||
),
|
||||
(
|
||||
["Police", "RGB", "Random Loop"],
|
||||
"{{ ['Police', 'RGB', 'Random Loop'] }}",
|
||||
),
|
||||
(None, "{{ [] }}"),
|
||||
(None, "{{ '[]' }}"),
|
||||
(None, "{{ 124 }}"),
|
||||
(None, "{{ '124' }}"),
|
||||
(None, "{{ none }}"),
|
||||
(None, ""),
|
||||
],
|
||||
)
|
||||
async def test_effect_list_template(hass, expected_effect_list, template):
|
||||
"""Test the template for the effect list."""
|
||||
with assert_setup_component(1, light.DOMAIN):
|
||||
assert await setup.async_setup_component(
|
||||
hass,
|
||||
light.DOMAIN,
|
||||
{
|
||||
"light": {
|
||||
"platform": "template",
|
||||
"lights": {
|
||||
"test_template_light": {
|
||||
"value_template": "{{ 1 == 1 }}",
|
||||
"turn_on": {
|
||||
"service": "light.turn_on",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"turn_off": {
|
||||
"service": "light.turn_off",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"set_effect": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"entity_id": "test.test_state",
|
||||
"effect": "{{effect}}",
|
||||
},
|
||||
},
|
||||
"effect_list_template": template,
|
||||
"effect_template": "{{ None }}",
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state is not None
|
||||
assert state.attributes.get("effect_list") == expected_effect_list
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expected_effect,template",
|
||||
[
|
||||
(None, "Disco"),
|
||||
(None, "None"),
|
||||
(None, "{{ None }}"),
|
||||
("Police", "Police"),
|
||||
("Strobe color", "{{ 'Strobe color' }}"),
|
||||
],
|
||||
)
|
||||
async def test_effect_template(hass, expected_effect, template):
|
||||
"""Test the template for the effect."""
|
||||
with assert_setup_component(1, light.DOMAIN):
|
||||
assert await setup.async_setup_component(
|
||||
hass,
|
||||
light.DOMAIN,
|
||||
{
|
||||
"light": {
|
||||
"platform": "template",
|
||||
"lights": {
|
||||
"test_template_light": {
|
||||
"value_template": "{{ 1 == 1 }}",
|
||||
"turn_on": {
|
||||
"service": "light.turn_on",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"turn_off": {
|
||||
"service": "light.turn_off",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"set_effect": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"entity_id": "test.test_state",
|
||||
"effect": "{{effect}}",
|
||||
},
|
||||
},
|
||||
"effect_list_template": "{{ ['Strobe color', 'Police', 'Christmas', 'RGB', 'Random Loop'] }}",
|
||||
"effect_template": template,
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state is not None
|
||||
assert state.attributes.get("effect") == expected_effect
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expected_min_mireds,template",
|
||||
[
|
||||
(118, "{{118}}"),
|
||||
(153, "{{x - 12}}"),
|
||||
(153, "None"),
|
||||
(153, "{{ none }}"),
|
||||
(153, ""),
|
||||
(153, "{{ 'a' }}"),
|
||||
],
|
||||
)
|
||||
async def test_min_mireds_template(hass, expected_min_mireds, template):
|
||||
"""Test the template for the min mireds."""
|
||||
with assert_setup_component(1, light.DOMAIN):
|
||||
assert await setup.async_setup_component(
|
||||
hass,
|
||||
"light",
|
||||
{
|
||||
"light": {
|
||||
"platform": "template",
|
||||
"lights": {
|
||||
"test_template_light": {
|
||||
"value_template": "{{ 1 == 1 }}",
|
||||
"turn_on": {
|
||||
"service": "light.turn_on",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"turn_off": {
|
||||
"service": "light.turn_off",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"set_temperature": {
|
||||
"service": "light.turn_on",
|
||||
"data_template": {
|
||||
"entity_id": "light.test_state",
|
||||
"color_temp": "{{color_temp}}",
|
||||
},
|
||||
},
|
||||
"temperature_template": "{{200}}",
|
||||
"min_mireds_template": template,
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state is not None
|
||||
assert state.attributes.get("min_mireds") == expected_min_mireds
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expected_max_mireds,template",
|
||||
[
|
||||
(488, "{{488}}"),
|
||||
(500, "{{x - 12}}"),
|
||||
(500, "None"),
|
||||
(500, "{{ none }}"),
|
||||
(500, ""),
|
||||
(500, "{{ 'a' }}"),
|
||||
],
|
||||
)
|
||||
async def test_max_mireds_template(hass, expected_max_mireds, template):
|
||||
"""Test the template for the max mireds."""
|
||||
with assert_setup_component(1, light.DOMAIN):
|
||||
assert await setup.async_setup_component(
|
||||
hass,
|
||||
"light",
|
||||
{
|
||||
"light": {
|
||||
"platform": "template",
|
||||
"lights": {
|
||||
"test_template_light": {
|
||||
"value_template": "{{ 1 == 1 }}",
|
||||
"turn_on": {
|
||||
"service": "light.turn_on",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"turn_off": {
|
||||
"service": "light.turn_off",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"set_temperature": {
|
||||
"service": "light.turn_on",
|
||||
"data_template": {
|
||||
"entity_id": "light.test_state",
|
||||
"color_temp": "{{color_temp}}",
|
||||
},
|
||||
},
|
||||
"temperature_template": "{{200}}",
|
||||
"max_mireds_template": template,
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state is not None
|
||||
assert state.attributes.get("max_mireds") == expected_max_mireds
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expected_supports_transition,template",
|
||||
[
|
||||
(True, "{{true}}"),
|
||||
(True, "{{1 == 1}}"),
|
||||
(False, "{{false}}"),
|
||||
(False, "{{ none }}"),
|
||||
(False, ""),
|
||||
(False, "None"),
|
||||
],
|
||||
)
|
||||
async def test_supports_transition_template(
|
||||
hass, expected_supports_transition, template
|
||||
):
|
||||
"""Test the template for the supports transition."""
|
||||
with assert_setup_component(1, light.DOMAIN):
|
||||
assert await setup.async_setup_component(
|
||||
hass,
|
||||
"light",
|
||||
{
|
||||
"light": {
|
||||
"platform": "template",
|
||||
"lights": {
|
||||
"test_template_light": {
|
||||
"value_template": "{{ 1 == 1 }}",
|
||||
"turn_on": {
|
||||
"service": "light.turn_on",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"turn_off": {
|
||||
"service": "light.turn_off",
|
||||
"entity_id": "light.test_state",
|
||||
},
|
||||
"set_temperature": {
|
||||
"service": "light.turn_on",
|
||||
"data_template": {
|
||||
"entity_id": "light.test_state",
|
||||
"color_temp": "{{color_temp}}",
|
||||
},
|
||||
},
|
||||
"supports_transition_template": template,
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
|
||||
expected_value = 1
|
||||
|
||||
if expected_supports_transition is True:
|
||||
expected_value = 0
|
||||
|
||||
assert state is not None
|
||||
assert (
|
||||
int(state.attributes.get("supported_features")) & SUPPORT_TRANSITION
|
||||
) != expected_value
|
||||
|
||||
|
||||
async def test_available_template_with_entities(hass):
|
||||
"""Test availability templates with values from other entities."""
|
||||
await setup.async_setup_component(
|
||||
|
|
Loading…
Reference in New Issue