mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Add trigger based template lights (#140631)
* Add abstract template light class in preparation for trigger based template lights * add base for trigger entity * Update more tests * revert trigger template entity changes and light trigger tests. * fix merge conflicts * address comments * change function name * nitpick * fix merge conflict issue --------- Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
parent
5da57271b2
commit
95552e9a5b
@ -134,9 +134,7 @@ CONFIG_SECTION_SCHEMA = vol.All(
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ensure_domains_do_not_have_trigger_or_action(
|
ensure_domains_do_not_have_trigger_or_action(BUTTON_DOMAIN, COVER_DOMAIN),
|
||||||
BUTTON_DOMAIN, COVER_DOMAIN, LIGHT_DOMAIN
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATE_BLUEPRINT_SCHEMA = vol.All(
|
TEMPLATE_BLUEPRINT_SCHEMA = vol.All(
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Generator, Sequence
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ from homeassistant.components.light import (
|
|||||||
ATTR_TRANSITION,
|
ATTR_TRANSITION,
|
||||||
DEFAULT_MAX_KELVIN,
|
DEFAULT_MAX_KELVIN,
|
||||||
DEFAULT_MIN_KELVIN,
|
DEFAULT_MIN_KELVIN,
|
||||||
|
DOMAIN as LIGHT_DOMAIN,
|
||||||
ENTITY_ID_FORMAT,
|
ENTITY_ID_FORMAT,
|
||||||
PLATFORM_SCHEMA as LIGHT_PLATFORM_SCHEMA,
|
PLATFORM_SCHEMA as LIGHT_PLATFORM_SCHEMA,
|
||||||
ColorMode,
|
ColorMode,
|
||||||
@ -46,6 +48,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
from homeassistant.util import color as color_util
|
from homeassistant.util import color as color_util
|
||||||
|
|
||||||
|
from . import TriggerUpdateCoordinator
|
||||||
from .const import CONF_OBJECT_ID, CONF_PICTURE, DOMAIN
|
from .const import CONF_OBJECT_ID, CONF_PICTURE, DOMAIN
|
||||||
from .template_entity import (
|
from .template_entity import (
|
||||||
LEGACY_FIELDS as TEMPLATE_ENTITY_LEGACY_FIELDS,
|
LEGACY_FIELDS as TEMPLATE_ENTITY_LEGACY_FIELDS,
|
||||||
@ -55,6 +58,7 @@ from .template_entity import (
|
|||||||
TemplateEntity,
|
TemplateEntity,
|
||||||
rewrite_common_legacy_to_modern_conf,
|
rewrite_common_legacy_to_modern_conf,
|
||||||
)
|
)
|
||||||
|
from .trigger_entity import TriggerEntity
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
_VALID_STATES = [STATE_ON, STATE_OFF, "true", "false"]
|
_VALID_STATES = [STATE_ON, STATE_OFF, "true", "false"]
|
||||||
@ -253,6 +257,13 @@ async def async_setup_platform(
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if "coordinator" in discovery_info:
|
||||||
|
async_add_entities(
|
||||||
|
TriggerLightEntity(hass, discovery_info["coordinator"], config)
|
||||||
|
for config in discovery_info["entities"]
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
_async_create_template_tracking_entities(
|
_async_create_template_tracking_entities(
|
||||||
async_add_entities,
|
async_add_entities,
|
||||||
hass,
|
hass,
|
||||||
@ -261,27 +272,17 @@ async def async_setup_platform(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LightTemplate(TemplateEntity, LightEntity):
|
class AbstractTemplateLight(LightEntity):
|
||||||
"""Representation of a templated Light, including dimmable."""
|
"""Representation of a template lights features."""
|
||||||
|
|
||||||
_attr_should_poll = False
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self, config: dict[str, Any], initial_state: bool | None = False
|
||||||
hass: HomeAssistant,
|
|
||||||
config: dict[str, Any],
|
|
||||||
unique_id: str | None,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the light."""
|
"""Initialize the features."""
|
||||||
super().__init__(hass, config=config, fallback_name=None, unique_id=unique_id)
|
|
||||||
if (object_id := config.get(CONF_OBJECT_ID)) is not None:
|
|
||||||
self.entity_id = async_generate_entity_id(
|
|
||||||
ENTITY_ID_FORMAT, object_id, hass=hass
|
|
||||||
)
|
|
||||||
name = self._attr_name
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
assert name is not None
|
|
||||||
|
|
||||||
|
self._registered_scripts: list[str] = []
|
||||||
|
|
||||||
|
# Template attributes
|
||||||
self._template = config.get(CONF_STATE)
|
self._template = config.get(CONF_STATE)
|
||||||
self._level_template = config.get(CONF_LEVEL)
|
self._level_template = config.get(CONF_LEVEL)
|
||||||
self._temperature_template = config.get(CONF_TEMPERATURE)
|
self._temperature_template = config.get(CONF_TEMPERATURE)
|
||||||
@ -295,12 +296,8 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
self._min_mireds_template = config.get(CONF_MIN_MIREDS)
|
self._min_mireds_template = config.get(CONF_MIN_MIREDS)
|
||||||
self._supports_transition_template = config.get(CONF_SUPPORTS_TRANSITION)
|
self._supports_transition_template = config.get(CONF_SUPPORTS_TRANSITION)
|
||||||
|
|
||||||
for action_id in (CONF_ON_ACTION, CONF_OFF_ACTION, CONF_EFFECT_ACTION):
|
# Stored values for template attributes
|
||||||
# Scripts can be an empty list, therefore we need to check for None
|
self._state = initial_state
|
||||||
if (action_config := config.get(action_id)) is not None:
|
|
||||||
self.add_script(action_id, action_config, name, DOMAIN)
|
|
||||||
|
|
||||||
self._state = False
|
|
||||||
self._brightness = None
|
self._brightness = None
|
||||||
self._temperature: int | None = None
|
self._temperature: int | None = None
|
||||||
self._hs_color = None
|
self._hs_color = None
|
||||||
@ -309,14 +306,19 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
self._rgbww_color = None
|
self._rgbww_color = None
|
||||||
self._effect = None
|
self._effect = None
|
||||||
self._effect_list = None
|
self._effect_list = None
|
||||||
self._color_mode = None
|
|
||||||
self._max_mireds = None
|
self._max_mireds = None
|
||||||
self._min_mireds = None
|
self._min_mireds = None
|
||||||
self._supports_transition = False
|
self._supports_transition = False
|
||||||
self._supported_color_modes = None
|
self._color_mode: ColorMode | None = None
|
||||||
|
self._supported_color_modes: set[ColorMode] | None = None
|
||||||
|
|
||||||
color_modes = {ColorMode.ONOFF}
|
def _register_scripts(
|
||||||
|
self, config: dict[str, Any]
|
||||||
|
) -> Generator[tuple[str, Sequence[dict[str, Any]], ColorMode | None]]:
|
||||||
for action_id, color_mode in (
|
for action_id, color_mode in (
|
||||||
|
(CONF_ON_ACTION, None),
|
||||||
|
(CONF_OFF_ACTION, None),
|
||||||
|
(CONF_EFFECT_ACTION, None),
|
||||||
(CONF_TEMPERATURE_ACTION, ColorMode.COLOR_TEMP),
|
(CONF_TEMPERATURE_ACTION, ColorMode.COLOR_TEMP),
|
||||||
(CONF_LEVEL_ACTION, ColorMode.BRIGHTNESS),
|
(CONF_LEVEL_ACTION, ColorMode.BRIGHTNESS),
|
||||||
(CONF_HS_ACTION, ColorMode.HS),
|
(CONF_HS_ACTION, ColorMode.HS),
|
||||||
@ -324,21 +326,9 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
(CONF_RGBW_ACTION, ColorMode.RGBW),
|
(CONF_RGBW_ACTION, ColorMode.RGBW),
|
||||||
(CONF_RGBWW_ACTION, ColorMode.RGBWW),
|
(CONF_RGBWW_ACTION, ColorMode.RGBWW),
|
||||||
):
|
):
|
||||||
# Scripts can be an empty list, therefore we need to check for None
|
|
||||||
if (action_config := config.get(action_id)) is not None:
|
if (action_config := config.get(action_id)) is not None:
|
||||||
self.add_script(action_id, action_config, name, DOMAIN)
|
self._registered_scripts.append(action_id)
|
||||||
color_modes.add(color_mode)
|
yield (action_id, action_config, color_mode)
|
||||||
self._supported_color_modes = filter_supported_color_modes(color_modes)
|
|
||||||
if len(self._supported_color_modes) > 1:
|
|
||||||
self._color_mode = ColorMode.UNKNOWN
|
|
||||||
if len(self._supported_color_modes) == 1:
|
|
||||||
self._color_mode = next(iter(self._supported_color_modes))
|
|
||||||
|
|
||||||
self._attr_supported_features = LightEntityFeature(0)
|
|
||||||
if (self._action_scripts.get(CONF_EFFECT_ACTION)) is not None:
|
|
||||||
self._attr_supported_features |= LightEntityFeature.EFFECT
|
|
||||||
if self._supports_transition is True:
|
|
||||||
self._attr_supported_features |= LightEntityFeature.TRANSITION
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def brightness(self) -> int | None:
|
def brightness(self) -> int | None:
|
||||||
@ -413,107 +403,12 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
"""Return true if device is on."""
|
"""Return true if device is on."""
|
||||||
return self._state
|
return self._state
|
||||||
|
|
||||||
@callback
|
def set_optimistic_attributes(self, **kwargs) -> bool: # noqa: C901
|
||||||
def _async_setup_templates(self) -> None:
|
"""Update attributes which should be set optimistically.
|
||||||
"""Set up templates."""
|
|
||||||
if self._template:
|
|
||||||
self.add_template_attribute(
|
|
||||||
"_state", self._template, None, self._update_state
|
|
||||||
)
|
|
||||||
if self._level_template:
|
|
||||||
self.add_template_attribute(
|
|
||||||
"_brightness",
|
|
||||||
self._level_template,
|
|
||||||
None,
|
|
||||||
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",
|
|
||||||
self._temperature_template,
|
|
||||||
None,
|
|
||||||
self._update_temperature,
|
|
||||||
none_on_template_error=True,
|
|
||||||
)
|
|
||||||
if self._hs_template:
|
|
||||||
self.add_template_attribute(
|
|
||||||
"_hs_color",
|
|
||||||
self._hs_template,
|
|
||||||
None,
|
|
||||||
self._update_hs,
|
|
||||||
none_on_template_error=True,
|
|
||||||
)
|
|
||||||
if self._rgb_template:
|
|
||||||
self.add_template_attribute(
|
|
||||||
"_rgb_color",
|
|
||||||
self._rgb_template,
|
|
||||||
None,
|
|
||||||
self._update_rgb,
|
|
||||||
none_on_template_error=True,
|
|
||||||
)
|
|
||||||
if self._rgbw_template:
|
|
||||||
self.add_template_attribute(
|
|
||||||
"_rgbw_color",
|
|
||||||
self._rgbw_template,
|
|
||||||
None,
|
|
||||||
self._update_rgbw,
|
|
||||||
none_on_template_error=True,
|
|
||||||
)
|
|
||||||
if self._rgbww_template:
|
|
||||||
self.add_template_attribute(
|
|
||||||
"_rgbww_color",
|
|
||||||
self._rgbww_template,
|
|
||||||
None,
|
|
||||||
self._update_rgbww,
|
|
||||||
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,
|
|
||||||
)
|
|
||||||
super()._async_setup_templates()
|
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None: # noqa: C901
|
Returns True if any attribute was updated.
|
||||||
"""Turn the light on."""
|
"""
|
||||||
optimistic_set = False
|
optimistic_set = False
|
||||||
# set optimistic states
|
|
||||||
if self._template is None:
|
if self._template is None:
|
||||||
self._state = True
|
self._state = True
|
||||||
optimistic_set = True
|
optimistic_set = True
|
||||||
@ -613,6 +508,10 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
self._rgbw_color = None
|
self._rgbw_color = None
|
||||||
optimistic_set = True
|
optimistic_set = True
|
||||||
|
|
||||||
|
return optimistic_set
|
||||||
|
|
||||||
|
def get_registered_script(self, **kwargs) -> tuple[str, dict]:
|
||||||
|
"""Get registered script for turn_on."""
|
||||||
common_params = {}
|
common_params = {}
|
||||||
|
|
||||||
if ATTR_BRIGHTNESS in kwargs:
|
if ATTR_BRIGHTNESS in kwargs:
|
||||||
@ -621,24 +520,23 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
if ATTR_TRANSITION in kwargs and self._supports_transition is True:
|
if ATTR_TRANSITION in kwargs and self._supports_transition is True:
|
||||||
common_params["transition"] = kwargs[ATTR_TRANSITION]
|
common_params["transition"] = kwargs[ATTR_TRANSITION]
|
||||||
|
|
||||||
if ATTR_COLOR_TEMP_KELVIN in kwargs and (
|
if (
|
||||||
temperature_script := self._action_scripts.get(CONF_TEMPERATURE_ACTION)
|
ATTR_COLOR_TEMP_KELVIN in kwargs
|
||||||
|
and (script := CONF_TEMPERATURE_ACTION) in self._registered_scripts
|
||||||
):
|
):
|
||||||
common_params["color_temp"] = color_util.color_temperature_kelvin_to_mired(
|
common_params["color_temp"] = color_util.color_temperature_kelvin_to_mired(
|
||||||
kwargs[ATTR_COLOR_TEMP_KELVIN]
|
kwargs[ATTR_COLOR_TEMP_KELVIN]
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.async_run_script(
|
return (script, common_params)
|
||||||
temperature_script,
|
|
||||||
run_variables=common_params,
|
if (
|
||||||
context=self._context,
|
ATTR_EFFECT in kwargs
|
||||||
)
|
and (script := CONF_EFFECT_ACTION) in self._registered_scripts
|
||||||
elif ATTR_EFFECT in kwargs and (
|
|
||||||
effect_script := self._action_scripts.get(CONF_EFFECT_ACTION)
|
|
||||||
):
|
):
|
||||||
assert self._effect_list is not None
|
assert self._effect_list is not None
|
||||||
effect = kwargs[ATTR_EFFECT]
|
effect = kwargs[ATTR_EFFECT]
|
||||||
if effect not in self._effect_list:
|
if self._effect_list is not None and effect not in self._effect_list:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Received invalid effect: %s for entity %s. Expected one of: %s",
|
"Received invalid effect: %s for entity %s. Expected one of: %s",
|
||||||
effect,
|
effect,
|
||||||
@ -649,22 +547,22 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
|
|
||||||
common_params["effect"] = effect
|
common_params["effect"] = effect
|
||||||
|
|
||||||
await self.async_run_script(
|
return (script, common_params)
|
||||||
effect_script, run_variables=common_params, context=self._context
|
|
||||||
)
|
if (
|
||||||
elif ATTR_HS_COLOR in kwargs and (
|
ATTR_HS_COLOR in kwargs
|
||||||
hs_script := self._action_scripts.get(CONF_HS_ACTION)
|
and (script := CONF_HS_ACTION) in self._registered_scripts
|
||||||
):
|
):
|
||||||
hs_value = kwargs[ATTR_HS_COLOR]
|
hs_value = kwargs[ATTR_HS_COLOR]
|
||||||
common_params["hs"] = hs_value
|
common_params["hs"] = hs_value
|
||||||
common_params["h"] = int(hs_value[0])
|
common_params["h"] = int(hs_value[0])
|
||||||
common_params["s"] = int(hs_value[1])
|
common_params["s"] = int(hs_value[1])
|
||||||
|
|
||||||
await self.async_run_script(
|
return (script, common_params)
|
||||||
hs_script, run_variables=common_params, context=self._context
|
|
||||||
)
|
if (
|
||||||
elif ATTR_RGBWW_COLOR in kwargs and (
|
ATTR_RGBWW_COLOR in kwargs
|
||||||
rgbww_script := self._action_scripts.get(CONF_RGBWW_ACTION)
|
and (script := CONF_RGBWW_ACTION) in self._registered_scripts
|
||||||
):
|
):
|
||||||
rgbww_value = kwargs[ATTR_RGBWW_COLOR]
|
rgbww_value = kwargs[ATTR_RGBWW_COLOR]
|
||||||
common_params["rgbww"] = rgbww_value
|
common_params["rgbww"] = rgbww_value
|
||||||
@ -679,11 +577,11 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
common_params["cw"] = int(rgbww_value[3])
|
common_params["cw"] = int(rgbww_value[3])
|
||||||
common_params["ww"] = int(rgbww_value[4])
|
common_params["ww"] = int(rgbww_value[4])
|
||||||
|
|
||||||
await self.async_run_script(
|
return (script, common_params)
|
||||||
rgbww_script, run_variables=common_params, context=self._context
|
|
||||||
)
|
if (
|
||||||
elif ATTR_RGBW_COLOR in kwargs and (
|
ATTR_RGBW_COLOR in kwargs
|
||||||
rgbw_script := self._action_scripts.get(CONF_RGBW_ACTION)
|
and (script := CONF_RGBW_ACTION) in self._registered_scripts
|
||||||
):
|
):
|
||||||
rgbw_value = kwargs[ATTR_RGBW_COLOR]
|
rgbw_value = kwargs[ATTR_RGBW_COLOR]
|
||||||
common_params["rgbw"] = rgbw_value
|
common_params["rgbw"] = rgbw_value
|
||||||
@ -697,11 +595,11 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
common_params["b"] = int(rgbw_value[2])
|
common_params["b"] = int(rgbw_value[2])
|
||||||
common_params["w"] = int(rgbw_value[3])
|
common_params["w"] = int(rgbw_value[3])
|
||||||
|
|
||||||
await self.async_run_script(
|
return (script, common_params)
|
||||||
rgbw_script, run_variables=common_params, context=self._context
|
|
||||||
)
|
if (
|
||||||
elif ATTR_RGB_COLOR in kwargs and (
|
ATTR_RGB_COLOR in kwargs
|
||||||
rgb_script := self._action_scripts.get(CONF_RGB_ACTION)
|
and (script := CONF_RGB_ACTION) in self._registered_scripts
|
||||||
):
|
):
|
||||||
rgb_value = kwargs[ATTR_RGB_COLOR]
|
rgb_value = kwargs[ATTR_RGB_COLOR]
|
||||||
common_params["rgb"] = rgb_value
|
common_params["rgb"] = rgb_value
|
||||||
@ -709,39 +607,15 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
common_params["g"] = int(rgb_value[1])
|
common_params["g"] = int(rgb_value[1])
|
||||||
common_params["b"] = int(rgb_value[2])
|
common_params["b"] = int(rgb_value[2])
|
||||||
|
|
||||||
await self.async_run_script(
|
return (script, common_params)
|
||||||
rgb_script, run_variables=common_params, context=self._context
|
|
||||||
)
|
if (
|
||||||
elif ATTR_BRIGHTNESS in kwargs and (
|
ATTR_BRIGHTNESS in kwargs
|
||||||
level_script := self._action_scripts.get(CONF_LEVEL_ACTION)
|
and (script := CONF_LEVEL_ACTION) in self._registered_scripts
|
||||||
):
|
):
|
||||||
await self.async_run_script(
|
return (script, common_params)
|
||||||
level_script, run_variables=common_params, context=self._context
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await self.async_run_script(
|
|
||||||
self._action_scripts[CONF_ON_ACTION],
|
|
||||||
run_variables=common_params,
|
|
||||||
context=self._context,
|
|
||||||
)
|
|
||||||
|
|
||||||
if optimistic_set:
|
return (CONF_ON_ACTION, common_params)
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
|
||||||
"""Turn the light off."""
|
|
||||||
off_script = self._action_scripts[CONF_OFF_ACTION]
|
|
||||||
if ATTR_TRANSITION in kwargs and self._supports_transition is True:
|
|
||||||
await self.async_run_script(
|
|
||||||
off_script,
|
|
||||||
run_variables={"transition": kwargs[ATTR_TRANSITION]},
|
|
||||||
context=self._context,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await self.async_run_script(off_script, context=self._context)
|
|
||||||
if self._template is None:
|
|
||||||
self._state = False
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _update_brightness(self, brightness):
|
def _update_brightness(self, brightness):
|
||||||
@ -809,33 +683,6 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
|
|
||||||
self._effect = effect
|
self._effect = effect
|
||||||
|
|
||||||
@callback
|
|
||||||
def _update_state(self, result):
|
|
||||||
"""Update the state from the template."""
|
|
||||||
if isinstance(result, TemplateError):
|
|
||||||
# This behavior is legacy
|
|
||||||
self._state = False
|
|
||||||
if not self._availability_template:
|
|
||||||
self._attr_available = True
|
|
||||||
return
|
|
||||||
|
|
||||||
if isinstance(result, bool):
|
|
||||||
self._state = result
|
|
||||||
return
|
|
||||||
|
|
||||||
state = str(result).lower()
|
|
||||||
if state in _VALID_STATES:
|
|
||||||
self._state = state in ("true", STATE_ON)
|
|
||||||
return
|
|
||||||
|
|
||||||
_LOGGER.error(
|
|
||||||
"Received invalid light is_on state: %s for entity %s. Expected: %s",
|
|
||||||
state,
|
|
||||||
self.entity_id,
|
|
||||||
", ".join(_VALID_STATES),
|
|
||||||
)
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _update_temperature(self, render):
|
def _update_temperature(self, render):
|
||||||
"""Update the temperature from the template."""
|
"""Update the temperature from the template."""
|
||||||
@ -1092,3 +939,338 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||||||
self._supports_transition = bool(render)
|
self._supports_transition = bool(render)
|
||||||
if self._supports_transition:
|
if self._supports_transition:
|
||||||
self._attr_supported_features |= LightEntityFeature.TRANSITION
|
self._attr_supported_features |= LightEntityFeature.TRANSITION
|
||||||
|
|
||||||
|
|
||||||
|
class LightTemplate(TemplateEntity, AbstractTemplateLight):
|
||||||
|
"""Representation of a templated Light, including dimmable."""
|
||||||
|
|
||||||
|
_attr_should_poll = False
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config: dict[str, Any],
|
||||||
|
unique_id: str | None,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the light."""
|
||||||
|
TemplateEntity.__init__(
|
||||||
|
self, hass, config=config, fallback_name=None, unique_id=unique_id
|
||||||
|
)
|
||||||
|
AbstractTemplateLight.__init__(self, config)
|
||||||
|
if (object_id := config.get(CONF_OBJECT_ID)) is not None:
|
||||||
|
self.entity_id = async_generate_entity_id(
|
||||||
|
ENTITY_ID_FORMAT, object_id, hass=hass
|
||||||
|
)
|
||||||
|
name = self._attr_name
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
assert name is not None
|
||||||
|
|
||||||
|
color_modes = {ColorMode.ONOFF}
|
||||||
|
for action_id, action_config, color_mode in self._register_scripts(config):
|
||||||
|
self.add_script(action_id, action_config, name, DOMAIN)
|
||||||
|
if color_mode:
|
||||||
|
color_modes.add(color_mode)
|
||||||
|
|
||||||
|
self._supported_color_modes = filter_supported_color_modes(color_modes)
|
||||||
|
if len(self._supported_color_modes) > 1:
|
||||||
|
self._color_mode = ColorMode.UNKNOWN
|
||||||
|
if len(self._supported_color_modes) == 1:
|
||||||
|
self._color_mode = next(iter(self._supported_color_modes))
|
||||||
|
|
||||||
|
self._attr_supported_features = LightEntityFeature(0)
|
||||||
|
if self._action_scripts.get(CONF_EFFECT_ACTION):
|
||||||
|
self._attr_supported_features |= LightEntityFeature.EFFECT
|
||||||
|
if self._supports_transition is True:
|
||||||
|
self._attr_supported_features |= LightEntityFeature.TRANSITION
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_setup_templates(self) -> None:
|
||||||
|
"""Set up templates."""
|
||||||
|
if self._template:
|
||||||
|
self.add_template_attribute(
|
||||||
|
"_state", self._template, None, self._update_state
|
||||||
|
)
|
||||||
|
if self._level_template:
|
||||||
|
self.add_template_attribute(
|
||||||
|
"_brightness",
|
||||||
|
self._level_template,
|
||||||
|
None,
|
||||||
|
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",
|
||||||
|
self._temperature_template,
|
||||||
|
None,
|
||||||
|
self._update_temperature,
|
||||||
|
none_on_template_error=True,
|
||||||
|
)
|
||||||
|
if self._hs_template:
|
||||||
|
self.add_template_attribute(
|
||||||
|
"_hs_color",
|
||||||
|
self._hs_template,
|
||||||
|
None,
|
||||||
|
self._update_hs,
|
||||||
|
none_on_template_error=True,
|
||||||
|
)
|
||||||
|
if self._rgb_template:
|
||||||
|
self.add_template_attribute(
|
||||||
|
"_rgb_color",
|
||||||
|
self._rgb_template,
|
||||||
|
None,
|
||||||
|
self._update_rgb,
|
||||||
|
none_on_template_error=True,
|
||||||
|
)
|
||||||
|
if self._rgbw_template:
|
||||||
|
self.add_template_attribute(
|
||||||
|
"_rgbw_color",
|
||||||
|
self._rgbw_template,
|
||||||
|
None,
|
||||||
|
self._update_rgbw,
|
||||||
|
none_on_template_error=True,
|
||||||
|
)
|
||||||
|
if self._rgbww_template:
|
||||||
|
self.add_template_attribute(
|
||||||
|
"_rgbww_color",
|
||||||
|
self._rgbww_template,
|
||||||
|
None,
|
||||||
|
self._update_rgbww,
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
super()._async_setup_templates()
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _update_state(self, result):
|
||||||
|
"""Update the state from the template."""
|
||||||
|
if isinstance(result, TemplateError):
|
||||||
|
# This behavior is legacy
|
||||||
|
self._state = False
|
||||||
|
if not self._availability_template:
|
||||||
|
self._attr_available = True
|
||||||
|
return
|
||||||
|
|
||||||
|
if isinstance(result, bool):
|
||||||
|
self._state = result
|
||||||
|
return
|
||||||
|
|
||||||
|
state = str(result).lower()
|
||||||
|
if state in _VALID_STATES:
|
||||||
|
self._state = state in ("true", STATE_ON)
|
||||||
|
return
|
||||||
|
|
||||||
|
_LOGGER.error(
|
||||||
|
"Received invalid light is_on state: %s for entity %s. Expected: %s",
|
||||||
|
state,
|
||||||
|
self.entity_id,
|
||||||
|
", ".join(_VALID_STATES),
|
||||||
|
)
|
||||||
|
self._state = None
|
||||||
|
|
||||||
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the light on."""
|
||||||
|
optimistic_set = self.set_optimistic_attributes(**kwargs)
|
||||||
|
script_id, script_params = self.get_registered_script(**kwargs)
|
||||||
|
await self.async_run_script(
|
||||||
|
self._action_scripts[script_id],
|
||||||
|
run_variables=script_params,
|
||||||
|
context=self._context,
|
||||||
|
)
|
||||||
|
|
||||||
|
if optimistic_set:
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the light off."""
|
||||||
|
off_script = self._action_scripts[CONF_OFF_ACTION]
|
||||||
|
if ATTR_TRANSITION in kwargs and self._supports_transition is True:
|
||||||
|
await self.async_run_script(
|
||||||
|
off_script,
|
||||||
|
run_variables={"transition": kwargs[ATTR_TRANSITION]},
|
||||||
|
context=self._context,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await self.async_run_script(off_script, context=self._context)
|
||||||
|
if self._template is None:
|
||||||
|
self._state = False
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
||||||
|
class TriggerLightEntity(TriggerEntity, AbstractTemplateLight):
|
||||||
|
"""Light entity based on trigger data."""
|
||||||
|
|
||||||
|
domain = LIGHT_DOMAIN
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
coordinator: TriggerUpdateCoordinator,
|
||||||
|
config: ConfigType,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the entity."""
|
||||||
|
TriggerEntity.__init__(self, hass, coordinator, config)
|
||||||
|
AbstractTemplateLight.__init__(self, config, None)
|
||||||
|
|
||||||
|
# Render the _attr_name before initializing TemplateLightEntity
|
||||||
|
self._attr_name = name = self._rendered.get(CONF_NAME, DEFAULT_NAME)
|
||||||
|
|
||||||
|
self._optimistic_attrs: dict[str, str] = {}
|
||||||
|
self._optimistic = True
|
||||||
|
for key in (
|
||||||
|
CONF_STATE,
|
||||||
|
CONF_LEVEL,
|
||||||
|
CONF_TEMPERATURE,
|
||||||
|
CONF_RGB,
|
||||||
|
CONF_RGBW,
|
||||||
|
CONF_RGBWW,
|
||||||
|
CONF_EFFECT,
|
||||||
|
CONF_MAX_MIREDS,
|
||||||
|
CONF_MIN_MIREDS,
|
||||||
|
CONF_SUPPORTS_TRANSITION,
|
||||||
|
):
|
||||||
|
if isinstance(config.get(key), template.Template):
|
||||||
|
if key == CONF_STATE:
|
||||||
|
self._optimistic = False
|
||||||
|
self._to_render_simple.append(key)
|
||||||
|
self._parse_result.add(key)
|
||||||
|
|
||||||
|
for key in (CONF_EFFECT_LIST, CONF_HS):
|
||||||
|
if isinstance(config.get(key), template.Template):
|
||||||
|
self._to_render_complex.append(key)
|
||||||
|
self._parse_result.add(key)
|
||||||
|
|
||||||
|
color_modes = {ColorMode.ONOFF}
|
||||||
|
for action_id, action_config, color_mode in self._register_scripts(config):
|
||||||
|
self.add_script(action_id, action_config, name, DOMAIN)
|
||||||
|
if color_mode:
|
||||||
|
color_modes.add(color_mode)
|
||||||
|
|
||||||
|
self._supported_color_modes = filter_supported_color_modes(color_modes)
|
||||||
|
if len(self._supported_color_modes) > 1:
|
||||||
|
self._color_mode = ColorMode.UNKNOWN
|
||||||
|
if len(self._supported_color_modes) == 1:
|
||||||
|
self._color_mode = next(iter(self._supported_color_modes))
|
||||||
|
|
||||||
|
self._attr_supported_features = LightEntityFeature(0)
|
||||||
|
if self._action_scripts.get(CONF_EFFECT_ACTION):
|
||||||
|
self._attr_supported_features |= LightEntityFeature.EFFECT
|
||||||
|
if self._supports_transition is True:
|
||||||
|
self._attr_supported_features |= LightEntityFeature.TRANSITION
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _handle_coordinator_update(self) -> None:
|
||||||
|
"""Handle update of the data."""
|
||||||
|
self._process_data()
|
||||||
|
|
||||||
|
if not self.available:
|
||||||
|
self.async_write_ha_state()
|
||||||
|
return
|
||||||
|
|
||||||
|
write_ha_state = False
|
||||||
|
for key, updater in (
|
||||||
|
(CONF_LEVEL, self._update_brightness),
|
||||||
|
(CONF_EFFECT_LIST, self._update_effect_list),
|
||||||
|
(CONF_EFFECT, self._update_effect),
|
||||||
|
(CONF_TEMPERATURE, self._update_temperature),
|
||||||
|
(CONF_HS, self._update_hs),
|
||||||
|
(CONF_RGB, self._update_rgb),
|
||||||
|
(CONF_RGBW, self._update_rgbw),
|
||||||
|
(CONF_RGBWW, self._update_rgbww),
|
||||||
|
(CONF_MAX_MIREDS, self._update_max_mireds),
|
||||||
|
(CONF_MIN_MIREDS, self._update_min_mireds),
|
||||||
|
):
|
||||||
|
if (rendered := self._rendered.get(key)) is not None:
|
||||||
|
updater(rendered)
|
||||||
|
write_ha_state = True
|
||||||
|
|
||||||
|
if (rendered := self._rendered.get(CONF_SUPPORTS_TRANSITION)) is not None:
|
||||||
|
self._update_supports_transition(rendered)
|
||||||
|
write_ha_state = True
|
||||||
|
|
||||||
|
if not self._optimistic:
|
||||||
|
raw = self._rendered.get(CONF_STATE)
|
||||||
|
self._state = template.result_as_boolean(raw)
|
||||||
|
|
||||||
|
self.async_set_context(self.coordinator.data["context"])
|
||||||
|
write_ha_state = True
|
||||||
|
elif self._optimistic and len(self._rendered) > 0:
|
||||||
|
# In case any non optimistic template
|
||||||
|
write_ha_state = True
|
||||||
|
|
||||||
|
if write_ha_state:
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the light on."""
|
||||||
|
optimistic_set = self.set_optimistic_attributes(**kwargs)
|
||||||
|
script_id, script_params = self.get_registered_script(**kwargs)
|
||||||
|
if self._template and self._state is None:
|
||||||
|
# Ensure an optimistic state is set on the entity when turn_on
|
||||||
|
# is called and the main state hasn't rendered. This will only
|
||||||
|
# occur when the state is unknown, the template hasn't triggered,
|
||||||
|
# and turn_on is called.
|
||||||
|
self._state = True
|
||||||
|
|
||||||
|
await self.async_run_script(
|
||||||
|
self._action_scripts[script_id],
|
||||||
|
run_variables=script_params,
|
||||||
|
context=self._context,
|
||||||
|
)
|
||||||
|
|
||||||
|
if optimistic_set:
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the light off."""
|
||||||
|
off_script = self._action_scripts[CONF_OFF_ACTION]
|
||||||
|
if ATTR_TRANSITION in kwargs and self._supports_transition is True:
|
||||||
|
await self.async_run_script(
|
||||||
|
off_script,
|
||||||
|
run_variables={"transition": kwargs[ATTR_TRANSITION]},
|
||||||
|
context=self._context,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await self.async_run_script(off_script, context=self._context)
|
||||||
|
if self._template is None:
|
||||||
|
self._state = False
|
||||||
|
self.async_write_ha_state()
|
||||||
|
@ -25,6 +25,7 @@ from homeassistant.const import (
|
|||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
STATE_ON,
|
STATE_ON,
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
|
STATE_UNKNOWN,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall
|
from homeassistant.core import HomeAssistant, ServiceCall
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
@ -159,6 +160,20 @@ OPTIMISTIC_RGBWW_COLOR_LIGHT_CONFIG = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_STATE_TRIGGER = {
|
||||||
|
"trigger": {"trigger": "state", "entity_id": "light.test_state"},
|
||||||
|
"variables": {"triggering_entity": "{{ trigger.entity_id }}"},
|
||||||
|
"action": [{"event": "action_event", "event_data": {"what": "triggering_entity"}}],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_EVENT_TRIGGER = {
|
||||||
|
"trigger": {"platform": "event", "event_type": "test_event"},
|
||||||
|
"variables": {"type": "{{ trigger.event.data.type }}"},
|
||||||
|
"action": [{"event": "action_event", "event_data": {"type": "{{ type }}"}}],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_MISSING_KEY_CONFIG = {
|
TEST_MISSING_KEY_CONFIG = {
|
||||||
"turn_on": {
|
"turn_on": {
|
||||||
"service": "light.turn_on",
|
"service": "light.turn_on",
|
||||||
@ -434,7 +449,7 @@ async def async_setup_legacy_format_with_attribute(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_new_format(
|
async def async_setup_modern_format(
|
||||||
hass: HomeAssistant, count: int, light_config: dict[str, Any]
|
hass: HomeAssistant, count: int, light_config: dict[str, Any]
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Do setup of light integration via new format."""
|
"""Do setup of light integration via new format."""
|
||||||
@ -461,7 +476,51 @@ async def async_setup_modern_format_with_attribute(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Do setup of a legacy light that has a single templated attribute."""
|
"""Do setup of a legacy light that has a single templated attribute."""
|
||||||
extra = {attribute: attribute_template} if attribute and attribute_template else {}
|
extra = {attribute: attribute_template} if attribute and attribute_template else {}
|
||||||
await async_setup_new_format(
|
await async_setup_modern_format(
|
||||||
|
hass,
|
||||||
|
count,
|
||||||
|
{
|
||||||
|
"name": "test_template_light",
|
||||||
|
**extra_config,
|
||||||
|
"state": "{{ 1 == 1 }}",
|
||||||
|
**extra,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_trigger_format(
|
||||||
|
hass: HomeAssistant, count: int, light_config: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Do setup of light integration via new format."""
|
||||||
|
config = {
|
||||||
|
"template": {
|
||||||
|
**TEST_STATE_TRIGGER,
|
||||||
|
"light": light_config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with assert_setup_component(count, template.DOMAIN):
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
template.DOMAIN,
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
await hass.async_start()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_trigger_format_with_attribute(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
count: int,
|
||||||
|
attribute: str,
|
||||||
|
attribute_template: str,
|
||||||
|
extra_config: dict,
|
||||||
|
) -> None:
|
||||||
|
"""Do setup of a legacy light that has a single templated attribute."""
|
||||||
|
extra = {attribute: attribute_template} if attribute and attribute_template else {}
|
||||||
|
await async_setup_trigger_format(
|
||||||
hass,
|
hass,
|
||||||
count,
|
count,
|
||||||
{
|
{
|
||||||
@ -484,7 +543,9 @@ async def setup_light(
|
|||||||
if style == ConfigurationStyle.LEGACY:
|
if style == ConfigurationStyle.LEGACY:
|
||||||
await async_setup_legacy_format(hass, count, light_config)
|
await async_setup_legacy_format(hass, count, light_config)
|
||||||
elif style == ConfigurationStyle.MODERN:
|
elif style == ConfigurationStyle.MODERN:
|
||||||
await async_setup_new_format(hass, count, light_config)
|
await async_setup_modern_format(hass, count, light_config)
|
||||||
|
elif style == ConfigurationStyle.TRIGGER:
|
||||||
|
await async_setup_trigger_format(hass, count, light_config)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -507,7 +568,17 @@ async def setup_state_light(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
elif style == ConfigurationStyle.MODERN:
|
elif style == ConfigurationStyle.MODERN:
|
||||||
await async_setup_new_format(
|
await async_setup_modern_format(
|
||||||
|
hass,
|
||||||
|
count,
|
||||||
|
{
|
||||||
|
**OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
|
||||||
|
"name": "test_template_light",
|
||||||
|
"state": state_template,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
elif style == ConfigurationStyle.TRIGGER:
|
||||||
|
await async_setup_trigger_format(
|
||||||
hass,
|
hass,
|
||||||
count,
|
count,
|
||||||
{
|
{
|
||||||
@ -536,6 +607,10 @@ async def setup_single_attribute_light(
|
|||||||
await async_setup_modern_format_with_attribute(
|
await async_setup_modern_format_with_attribute(
|
||||||
hass, count, attribute, attribute_template, extra_config
|
hass, count, attribute, attribute_template, extra_config
|
||||||
)
|
)
|
||||||
|
elif style == ConfigurationStyle.TRIGGER:
|
||||||
|
await async_setup_trigger_format_with_attribute(
|
||||||
|
hass, count, attribute, attribute_template, extra_config
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -554,6 +629,10 @@ async def setup_single_action_light(
|
|||||||
await async_setup_modern_format_with_attribute(
|
await async_setup_modern_format_with_attribute(
|
||||||
hass, count, "", "", extra_config
|
hass, count, "", "", extra_config
|
||||||
)
|
)
|
||||||
|
elif style == ConfigurationStyle.TRIGGER:
|
||||||
|
await async_setup_trigger_format_with_attribute(
|
||||||
|
hass, count, "", "", extra_config
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -579,7 +658,7 @@ async def setup_empty_action_light(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
elif style == ConfigurationStyle.MODERN:
|
elif style == ConfigurationStyle.MODERN:
|
||||||
await async_setup_new_format(
|
await async_setup_modern_format(
|
||||||
hass,
|
hass,
|
||||||
count,
|
count,
|
||||||
{
|
{
|
||||||
@ -627,7 +706,20 @@ async def setup_light_with_effects(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
elif style == ConfigurationStyle.MODERN:
|
elif style == ConfigurationStyle.MODERN:
|
||||||
await async_setup_new_format(
|
await async_setup_modern_format(
|
||||||
|
hass,
|
||||||
|
count,
|
||||||
|
{
|
||||||
|
"name": "test_template_light",
|
||||||
|
**OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
|
||||||
|
"state": "{{true}}",
|
||||||
|
**common,
|
||||||
|
"effect_list": effect_list_template,
|
||||||
|
"effect": effect_template,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
elif style == ConfigurationStyle.TRIGGER:
|
||||||
|
await async_setup_trigger_format(
|
||||||
hass,
|
hass,
|
||||||
count,
|
count,
|
||||||
{
|
{
|
||||||
@ -674,7 +766,19 @@ async def setup_light_with_mireds(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
elif style == ConfigurationStyle.MODERN:
|
elif style == ConfigurationStyle.MODERN:
|
||||||
await async_setup_new_format(
|
await async_setup_modern_format(
|
||||||
|
hass,
|
||||||
|
count,
|
||||||
|
{
|
||||||
|
"name": "test_template_light",
|
||||||
|
**OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
|
||||||
|
"state": "{{ 1 == 1 }}",
|
||||||
|
**common,
|
||||||
|
"temperature": "{{200}}",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
elif style == ConfigurationStyle.TRIGGER:
|
||||||
|
await async_setup_trigger_format(
|
||||||
hass,
|
hass,
|
||||||
count,
|
count,
|
||||||
{
|
{
|
||||||
@ -720,7 +824,21 @@ async def setup_light_with_transition_template(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
elif style == ConfigurationStyle.MODERN:
|
elif style == ConfigurationStyle.MODERN:
|
||||||
await async_setup_new_format(
|
await async_setup_modern_format(
|
||||||
|
hass,
|
||||||
|
count,
|
||||||
|
{
|
||||||
|
"name": "test_template_light",
|
||||||
|
**OPTIMISTIC_COLOR_TEMP_LIGHT_CONFIG,
|
||||||
|
"state": "{{ 1 == 1 }}",
|
||||||
|
**common,
|
||||||
|
"effect_list": "{{ ['Disco', 'Police'] }}",
|
||||||
|
"effect": "{{ None }}",
|
||||||
|
"supports_transition": transition_template,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
elif style == ConfigurationStyle.TRIGGER:
|
||||||
|
await async_setup_trigger_format(
|
||||||
hass,
|
hass,
|
||||||
count,
|
count,
|
||||||
{
|
{
|
||||||
@ -741,19 +859,24 @@ async def setup_light_with_transition_template(
|
|||||||
[(0, [ColorMode.BRIGHTNESS])],
|
[(0, [ColorMode.BRIGHTNESS])],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"style",
|
("style", "expected_state"),
|
||||||
[
|
[
|
||||||
ConfigurationStyle.LEGACY,
|
(ConfigurationStyle.LEGACY, STATE_OFF),
|
||||||
ConfigurationStyle.MODERN,
|
(ConfigurationStyle.MODERN, STATE_OFF),
|
||||||
|
(ConfigurationStyle.TRIGGER, STATE_UNKNOWN),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize("state_template", ["{{states.test['big.fat...']}}"])
|
@pytest.mark.parametrize("state_template", ["{{states.test['big.fat...']}}"])
|
||||||
async def test_template_state_invalid(
|
async def test_template_state_invalid(
|
||||||
hass: HomeAssistant, supported_features, supported_color_modes, setup_state_light
|
hass: HomeAssistant,
|
||||||
|
supported_features,
|
||||||
|
supported_color_modes,
|
||||||
|
expected_state,
|
||||||
|
setup_state_light,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test template state with render error."""
|
"""Test template state with render error."""
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.state == STATE_OFF
|
assert state.state == expected_state
|
||||||
assert state.attributes["color_mode"] is None
|
assert state.attributes["color_mode"] is None
|
||||||
assert state.attributes["supported_color_modes"] == supported_color_modes
|
assert state.attributes["supported_color_modes"] == supported_color_modes
|
||||||
assert state.attributes["supported_features"] == supported_features
|
assert state.attributes["supported_features"] == supported_features
|
||||||
@ -765,6 +888,7 @@ async def test_template_state_invalid(
|
|||||||
[
|
[
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize("state_template", ["{{ states.light.test_state.state }}"])
|
@pytest.mark.parametrize("state_template", ["{{ states.light.test_state.state }}"])
|
||||||
@ -795,6 +919,7 @@ async def test_template_state_text(hass: HomeAssistant, setup_state_light) -> No
|
|||||||
[
|
[
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -812,13 +937,18 @@ async def test_template_state_text(hass: HomeAssistant, setup_state_light) -> No
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_legacy_template_state_boolean(
|
async def test_template_state_boolean(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
expected_color_mode,
|
expected_color_mode,
|
||||||
expected_state,
|
expected_state,
|
||||||
|
style,
|
||||||
setup_state_light,
|
setup_state_light,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the setting of the state with boolean on."""
|
"""Test the setting of the state with boolean on."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
hass.states.async_set("light.test_state", expected_state)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.state == expected_state
|
assert state.state == expected_state
|
||||||
assert state.attributes.get("color_mode") == expected_color_mode
|
assert state.attributes.get("color_mode") == expected_color_mode
|
||||||
@ -860,6 +990,14 @@ async def test_legacy_template_state_boolean(
|
|||||||
},
|
},
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
**OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
|
||||||
|
"name": "test_template_light",
|
||||||
|
"state": "{%- if false -%}",
|
||||||
|
},
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_template_config_errors(hass: HomeAssistant, setup_light) -> None:
|
async def test_template_config_errors(hass: HomeAssistant, setup_light) -> None:
|
||||||
@ -880,6 +1018,11 @@ async def test_template_config_errors(hass: HomeAssistant, setup_light) -> None:
|
|||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
{"name": "light_one", "state": "{{ 1== 1}}", **TEST_MISSING_KEY_CONFIG},
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
|
0,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_missing_key(hass: HomeAssistant, count, setup_light) -> None:
|
async def test_missing_key(hass: HomeAssistant, count, setup_light) -> None:
|
||||||
@ -896,6 +1039,7 @@ async def test_missing_key(hass: HomeAssistant, count, setup_light) -> None:
|
|||||||
[
|
[
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize("state_template", ["{{ states.light.test_state.state }}"])
|
@pytest.mark.parametrize("state_template", ["{{ states.light.test_state.state }}"])
|
||||||
@ -946,11 +1090,21 @@ async def test_on_action(
|
|||||||
(
|
(
|
||||||
{
|
{
|
||||||
"name": "test_template_light",
|
"name": "test_template_light",
|
||||||
|
"state": "{{states.light.test_state.state}}",
|
||||||
**TEST_ON_ACTION_WITH_TRANSITION_CONFIG,
|
**TEST_ON_ACTION_WITH_TRANSITION_CONFIG,
|
||||||
"supports_transition": "{{true}}",
|
"supports_transition": "{{true}}",
|
||||||
},
|
},
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"name": "test_template_light",
|
||||||
|
"state": "{{states.light.test_state.state}}",
|
||||||
|
**TEST_ON_ACTION_WITH_TRANSITION_CONFIG,
|
||||||
|
"supports_transition": "{{true}}",
|
||||||
|
},
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_on_action_with_transition(
|
async def test_on_action_with_transition(
|
||||||
@ -984,7 +1138,7 @@ async def test_on_action_with_transition(
|
|||||||
|
|
||||||
@pytest.mark.parametrize("count", [1])
|
@pytest.mark.parametrize("count", [1])
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("light_config", "style"),
|
("light_config", "style", "initial_state"),
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
@ -993,6 +1147,7 @@ async def test_on_action_with_transition(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
|
STATE_OFF,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
@ -1000,11 +1155,21 @@ async def test_on_action_with_transition(
|
|||||||
**OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
|
**OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
|
||||||
},
|
},
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
STATE_OFF,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"name": "test_template_light",
|
||||||
|
**OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
|
||||||
|
},
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
|
STATE_UNKNOWN,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_on_action_optimistic(
|
async def test_on_action_optimistic(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
initial_state: str,
|
||||||
setup_light,
|
setup_light,
|
||||||
calls: list[ServiceCall],
|
calls: list[ServiceCall],
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -1013,7 +1178,7 @@ async def test_on_action_optimistic(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.state == STATE_OFF
|
assert state.state == initial_state
|
||||||
assert state.attributes["color_mode"] is None
|
assert state.attributes["color_mode"] is None
|
||||||
assert state.attributes["supported_color_modes"] == [ColorMode.BRIGHTNESS]
|
assert state.attributes["supported_color_modes"] == [ColorMode.BRIGHTNESS]
|
||||||
assert state.attributes["supported_features"] == 0
|
assert state.attributes["supported_features"] == 0
|
||||||
@ -1058,6 +1223,7 @@ async def test_on_action_optimistic(
|
|||||||
[
|
[
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize("state_template", ["{{ states.light.test_state.state }}"])
|
@pytest.mark.parametrize("state_template", ["{{ states.light.test_state.state }}"])
|
||||||
@ -1113,6 +1279,15 @@ async def test_off_action(
|
|||||||
},
|
},
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"name": "test_template_light",
|
||||||
|
"state": "{{states.light.test_state.state}}",
|
||||||
|
**TEST_OFF_ACTION_WITH_TRANSITION_CONFIG,
|
||||||
|
"supports_transition": "{{true}}",
|
||||||
|
},
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_off_action_with_transition(
|
async def test_off_action_with_transition(
|
||||||
@ -1145,7 +1320,7 @@ async def test_off_action_with_transition(
|
|||||||
|
|
||||||
@pytest.mark.parametrize("count", [1])
|
@pytest.mark.parametrize("count", [1])
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("light_config", "style"),
|
("light_config", "style", "initial_state"),
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
@ -1154,6 +1329,7 @@ async def test_off_action_with_transition(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
|
STATE_OFF,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
@ -1161,15 +1337,24 @@ async def test_off_action_with_transition(
|
|||||||
**OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
|
**OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
|
||||||
},
|
},
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
STATE_OFF,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"name": "test_template_light",
|
||||||
|
**OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
|
||||||
|
},
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
|
STATE_UNKNOWN,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_off_action_optimistic(
|
async def test_off_action_optimistic(
|
||||||
hass: HomeAssistant, setup_light, calls: list[ServiceCall]
|
hass: HomeAssistant, initial_state, setup_light, calls: list[ServiceCall]
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test off action with optimistic state."""
|
"""Test off action with optimistic state."""
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.state == STATE_OFF
|
assert state.state == initial_state
|
||||||
assert state.attributes["color_mode"] is None
|
assert state.attributes["color_mode"] is None
|
||||||
assert state.attributes["supported_color_modes"] == [ColorMode.BRIGHTNESS]
|
assert state.attributes["supported_color_modes"] == [ColorMode.BRIGHTNESS]
|
||||||
assert state.attributes["supported_features"] == 0
|
assert state.attributes["supported_features"] == 0
|
||||||
@ -1195,6 +1380,7 @@ async def test_off_action_optimistic(
|
|||||||
[
|
[
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize("state_template", ["{{1 == 1}}"])
|
@pytest.mark.parametrize("state_template", ["{{1 == 1}}"])
|
||||||
@ -1235,6 +1421,7 @@ async def test_level_action_no_template(
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "level_template"),
|
(ConfigurationStyle.LEGACY, "level_template"),
|
||||||
(ConfigurationStyle.MODERN, "level"),
|
(ConfigurationStyle.MODERN, "level"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "level"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -1255,14 +1442,20 @@ async def test_level_action_no_template(
|
|||||||
)
|
)
|
||||||
async def test_level_template(
|
async def test_level_template(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
style: ConfigurationStyle,
|
||||||
expected_level: Any,
|
expected_level: Any,
|
||||||
expected_color_mode: ColorMode,
|
expected_color_mode: ColorMode,
|
||||||
setup_single_attribute_light,
|
setup_single_attribute_light,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the level."""
|
"""Test the template for the level."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.attributes.get("brightness") == expected_level
|
assert state.attributes.get("brightness") == expected_level
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_ON
|
||||||
|
|
||||||
assert state.attributes["color_mode"] == expected_color_mode
|
assert state.attributes["color_mode"] == expected_color_mode
|
||||||
assert state.attributes["supported_color_modes"] == [ColorMode.BRIGHTNESS]
|
assert state.attributes["supported_color_modes"] == [ColorMode.BRIGHTNESS]
|
||||||
assert state.attributes["supported_features"] == 0
|
assert state.attributes["supported_features"] == 0
|
||||||
@ -1276,6 +1469,7 @@ async def test_level_template(
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "temperature_template"),
|
(ConfigurationStyle.LEGACY, "temperature_template"),
|
||||||
(ConfigurationStyle.MODERN, "temperature"),
|
(ConfigurationStyle.MODERN, "temperature"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "temperature"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -1292,15 +1486,20 @@ async def test_level_template(
|
|||||||
)
|
)
|
||||||
async def test_temperature_template(
|
async def test_temperature_template(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
style: ConfigurationStyle,
|
||||||
expected_temp: Any,
|
expected_temp: Any,
|
||||||
expected_color_mode: ColorMode,
|
expected_color_mode: ColorMode,
|
||||||
setup_single_attribute_light,
|
setup_single_attribute_light,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the temperature."""
|
"""Test the template for the temperature."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.attributes.get("color_temp") == expected_temp
|
assert state.attributes.get("color_temp") == expected_temp
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_ON
|
||||||
assert state.attributes["color_mode"] == expected_color_mode
|
assert state.attributes.get("color_mode") == expected_color_mode
|
||||||
assert state.attributes["supported_color_modes"] == [ColorMode.COLOR_TEMP]
|
assert state.attributes["supported_color_modes"] == [ColorMode.COLOR_TEMP]
|
||||||
assert state.attributes["supported_features"] == 0
|
assert state.attributes["supported_features"] == 0
|
||||||
|
|
||||||
@ -1313,6 +1512,7 @@ async def test_temperature_template(
|
|||||||
[
|
[
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_temperature_action_no_template(
|
async def test_temperature_action_no_template(
|
||||||
@ -1369,6 +1569,15 @@ async def test_temperature_action_no_template(
|
|||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
"light.template_light",
|
"light.template_light",
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
**OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
|
||||||
|
"name": "Template light",
|
||||||
|
"state": "{{ 1 == 1 }}",
|
||||||
|
},
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
|
"light.template_light",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_friendly_name(hass: HomeAssistant, entity_id: str, setup_light) -> None:
|
async def test_friendly_name(hass: HomeAssistant, entity_id: str, setup_light) -> None:
|
||||||
@ -1388,6 +1597,7 @@ async def test_friendly_name(hass: HomeAssistant, entity_id: str, setup_light) -
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "icon_template"),
|
(ConfigurationStyle.LEGACY, "icon_template"),
|
||||||
(ConfigurationStyle.MODERN, "icon"),
|
(ConfigurationStyle.MODERN, "icon"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "icon"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -1396,7 +1606,7 @@ async def test_friendly_name(hass: HomeAssistant, entity_id: str, setup_light) -
|
|||||||
async def test_icon_template(hass: HomeAssistant, setup_single_attribute_light) -> None:
|
async def test_icon_template(hass: HomeAssistant, setup_single_attribute_light) -> None:
|
||||||
"""Test icon template."""
|
"""Test icon template."""
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.attributes.get("icon") == ""
|
assert state.attributes.get("icon") in ("", None)
|
||||||
|
|
||||||
state = hass.states.async_set("light.test_state", STATE_ON)
|
state = hass.states.async_set("light.test_state", STATE_ON)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -1414,6 +1624,7 @@ async def test_icon_template(hass: HomeAssistant, setup_single_attribute_light)
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "entity_picture_template"),
|
(ConfigurationStyle.LEGACY, "entity_picture_template"),
|
||||||
(ConfigurationStyle.MODERN, "picture"),
|
(ConfigurationStyle.MODERN, "picture"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "picture"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -1425,7 +1636,7 @@ async def test_entity_picture_template(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test entity_picture template."""
|
"""Test entity_picture template."""
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.attributes.get("entity_picture") == ""
|
assert state.attributes.get("entity_picture") in ("", None)
|
||||||
|
|
||||||
state = hass.states.async_set("light.test_state", STATE_ON)
|
state = hass.states.async_set("light.test_state", STATE_ON)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -1488,6 +1699,7 @@ async def test_legacy_color_action_no_template(
|
|||||||
[
|
[
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_hs_color_action_no_template(
|
async def test_hs_color_action_no_template(
|
||||||
@ -1529,6 +1741,7 @@ async def test_hs_color_action_no_template(
|
|||||||
[
|
[
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_rgb_color_action_no_template(
|
async def test_rgb_color_action_no_template(
|
||||||
@ -1571,6 +1784,7 @@ async def test_rgb_color_action_no_template(
|
|||||||
[
|
[
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_rgbw_color_action_no_template(
|
async def test_rgbw_color_action_no_template(
|
||||||
@ -1617,6 +1831,7 @@ async def test_rgbw_color_action_no_template(
|
|||||||
[
|
[
|
||||||
ConfigurationStyle.LEGACY,
|
ConfigurationStyle.LEGACY,
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_rgbww_color_action_no_template(
|
async def test_rgbww_color_action_no_template(
|
||||||
@ -1702,6 +1917,7 @@ async def test_legacy_color_template(
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "hs_template"),
|
(ConfigurationStyle.LEGACY, "hs_template"),
|
||||||
(ConfigurationStyle.MODERN, "hs"),
|
(ConfigurationStyle.MODERN, "hs"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "hs"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -1723,9 +1939,14 @@ async def test_hs_template(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
expected_hs,
|
expected_hs,
|
||||||
expected_color_mode,
|
expected_color_mode,
|
||||||
|
style: ConfigurationStyle,
|
||||||
setup_single_attribute_light,
|
setup_single_attribute_light,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the color."""
|
"""Test the template for the color."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.attributes.get("hs_color") == expected_hs
|
assert state.attributes.get("hs_color") == expected_hs
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_ON
|
||||||
@ -1742,6 +1963,7 @@ async def test_hs_template(
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "rgb_template"),
|
(ConfigurationStyle.LEGACY, "rgb_template"),
|
||||||
(ConfigurationStyle.MODERN, "rgb"),
|
(ConfigurationStyle.MODERN, "rgb"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "rgb"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -1764,9 +1986,14 @@ async def test_rgb_template(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
expected_rgb,
|
expected_rgb,
|
||||||
expected_color_mode,
|
expected_color_mode,
|
||||||
|
style: ConfigurationStyle,
|
||||||
setup_single_attribute_light,
|
setup_single_attribute_light,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the color."""
|
"""Test the template for the color."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.attributes.get("rgb_color") == expected_rgb
|
assert state.attributes.get("rgb_color") == expected_rgb
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_ON
|
||||||
@ -1783,6 +2010,7 @@ async def test_rgb_template(
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "rgbw_template"),
|
(ConfigurationStyle.LEGACY, "rgbw_template"),
|
||||||
(ConfigurationStyle.MODERN, "rgbw"),
|
(ConfigurationStyle.MODERN, "rgbw"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "rgbw"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -1806,9 +2034,14 @@ async def test_rgbw_template(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
expected_rgbw,
|
expected_rgbw,
|
||||||
expected_color_mode,
|
expected_color_mode,
|
||||||
|
style: ConfigurationStyle,
|
||||||
setup_single_attribute_light,
|
setup_single_attribute_light,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the color."""
|
"""Test the template for the color."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.attributes.get("rgbw_color") == expected_rgbw
|
assert state.attributes.get("rgbw_color") == expected_rgbw
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_ON
|
||||||
@ -1825,6 +2058,7 @@ async def test_rgbw_template(
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "rgbww_template"),
|
(ConfigurationStyle.LEGACY, "rgbww_template"),
|
||||||
(ConfigurationStyle.MODERN, "rgbww"),
|
(ConfigurationStyle.MODERN, "rgbww"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "rgbww"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -1853,9 +2087,14 @@ async def test_rgbww_template(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
expected_rgbww,
|
expected_rgbww,
|
||||||
expected_color_mode,
|
expected_color_mode,
|
||||||
|
style: ConfigurationStyle,
|
||||||
setup_single_attribute_light,
|
setup_single_attribute_light,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the color."""
|
"""Test the template for the color."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state.attributes.get("rgbww_color") == expected_rgbww
|
assert state.attributes.get("rgbww_color") == expected_rgbww
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_ON
|
||||||
@ -1887,6 +2126,15 @@ async def test_rgbww_template(
|
|||||||
},
|
},
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"name": "test_template_light",
|
||||||
|
**OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
|
||||||
|
"state": "{{1 == 1}}",
|
||||||
|
**TEST_ALL_COLORS_NO_TEMPLATE_CONFIG,
|
||||||
|
},
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_all_colors_mode_no_template(
|
async def test_all_colors_mode_no_template(
|
||||||
@ -2084,7 +2332,8 @@ async def test_all_colors_mode_no_template(
|
|||||||
|
|
||||||
@pytest.mark.parametrize("count", [1])
|
@pytest.mark.parametrize("count", [1])
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"style", [ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN]
|
"style",
|
||||||
|
[ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("effect_list_template", "effect_template", "effect", "expected"),
|
("effect_list_template", "effect_template", "effect", "expected"),
|
||||||
@ -2097,10 +2346,17 @@ async def test_effect_action(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
effect: str,
|
effect: str,
|
||||||
expected: Any,
|
expected: Any,
|
||||||
|
style: ConfigurationStyle,
|
||||||
setup_light_with_effects,
|
setup_light_with_effects,
|
||||||
calls: list[ServiceCall],
|
calls: list[ServiceCall],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test setting valid effect with template."""
|
"""Test setting valid effect with template."""
|
||||||
|
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
# Ensures the trigger template entity updates
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
|
|
||||||
@ -2123,7 +2379,8 @@ async def test_effect_action(
|
|||||||
|
|
||||||
@pytest.mark.parametrize(("count", "effect_template"), [(1, "{{ None }}")])
|
@pytest.mark.parametrize(("count", "effect_template"), [(1, "{{ None }}")])
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"style", [ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN]
|
"style",
|
||||||
|
[ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("expected_effect_list", "effect_list_template"),
|
("expected_effect_list", "effect_list_template"),
|
||||||
@ -2145,9 +2402,16 @@ async def test_effect_action(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_effect_list_template(
|
async def test_effect_list_template(
|
||||||
hass: HomeAssistant, expected_effect_list, setup_light_with_effects
|
hass: HomeAssistant,
|
||||||
|
expected_effect_list,
|
||||||
|
style: ConfigurationStyle,
|
||||||
|
setup_light_with_effects,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the effect list."""
|
"""Test the template for the effect list."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.attributes.get("effect_list") == expected_effect_list
|
assert state.attributes.get("effect_list") == expected_effect_list
|
||||||
@ -2158,7 +2422,8 @@ async def test_effect_list_template(
|
|||||||
[(1, "{{ ['Strobe color', 'Police', 'Christmas', 'RGB', 'Random Loop'] }}")],
|
[(1, "{{ ['Strobe color', 'Police', 'Christmas', 'RGB', 'Random Loop'] }}")],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"style", [ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN]
|
"style",
|
||||||
|
[ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("expected_effect", "effect_template"),
|
("expected_effect", "effect_template"),
|
||||||
@ -2171,9 +2436,16 @@ async def test_effect_list_template(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_effect_template(
|
async def test_effect_template(
|
||||||
hass: HomeAssistant, expected_effect, setup_light_with_effects
|
hass: HomeAssistant,
|
||||||
|
expected_effect,
|
||||||
|
style: ConfigurationStyle,
|
||||||
|
setup_light_with_effects,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the effect."""
|
"""Test the template for the effect."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.attributes.get("effect") == expected_effect
|
assert state.attributes.get("effect") == expected_effect
|
||||||
@ -2185,6 +2457,7 @@ async def test_effect_template(
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "min_mireds_template"),
|
(ConfigurationStyle.LEGACY, "min_mireds_template"),
|
||||||
(ConfigurationStyle.MODERN, "min_mireds"),
|
(ConfigurationStyle.MODERN, "min_mireds"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "min_mireds"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -2199,9 +2472,16 @@ async def test_effect_template(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_min_mireds_template(
|
async def test_min_mireds_template(
|
||||||
hass: HomeAssistant, expected_min_mireds, setup_light_with_mireds
|
hass: HomeAssistant,
|
||||||
|
expected_min_mireds,
|
||||||
|
style: ConfigurationStyle,
|
||||||
|
setup_light_with_mireds,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the min mireds."""
|
"""Test the template for the min mireds."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.attributes.get("min_mireds") == expected_min_mireds
|
assert state.attributes.get("min_mireds") == expected_min_mireds
|
||||||
@ -2213,6 +2493,7 @@ async def test_min_mireds_template(
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "max_mireds_template"),
|
(ConfigurationStyle.LEGACY, "max_mireds_template"),
|
||||||
(ConfigurationStyle.MODERN, "max_mireds"),
|
(ConfigurationStyle.MODERN, "max_mireds"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "max_mireds"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -2227,9 +2508,16 @@ async def test_min_mireds_template(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_max_mireds_template(
|
async def test_max_mireds_template(
|
||||||
hass: HomeAssistant, expected_max_mireds, setup_light_with_mireds
|
hass: HomeAssistant,
|
||||||
|
expected_max_mireds,
|
||||||
|
style: ConfigurationStyle,
|
||||||
|
setup_light_with_mireds,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the max mireds."""
|
"""Test the template for the max mireds."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.attributes.get("max_mireds") == expected_max_mireds
|
assert state.attributes.get("max_mireds") == expected_max_mireds
|
||||||
@ -2243,6 +2531,7 @@ async def test_max_mireds_template(
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "supports_transition_template"),
|
(ConfigurationStyle.LEGACY, "supports_transition_template"),
|
||||||
(ConfigurationStyle.MODERN, "supports_transition"),
|
(ConfigurationStyle.MODERN, "supports_transition"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "supports_transition"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -2257,9 +2546,17 @@ async def test_max_mireds_template(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_supports_transition_template(
|
async def test_supports_transition_template(
|
||||||
hass: HomeAssistant, expected_supports_transition, setup_single_attribute_light
|
hass: HomeAssistant,
|
||||||
|
style: ConfigurationStyle,
|
||||||
|
expected_supports_transition,
|
||||||
|
setup_single_attribute_light,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the supports transition."""
|
"""Test the template for the supports transition."""
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
# Ensures the trigger template entity updates
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
|
|
||||||
expected_value = 1
|
expected_value = 1
|
||||||
@ -2277,10 +2574,11 @@ async def test_supports_transition_template(
|
|||||||
("count", "transition_template"), [(1, "{{ states('sensor.test') }}")]
|
("count", "transition_template"), [(1, "{{ states('sensor.test') }}")]
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"style", [ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN]
|
"style",
|
||||||
|
[ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER],
|
||||||
)
|
)
|
||||||
async def test_supports_transition_template_updates(
|
async def test_supports_transition_template_updates(
|
||||||
hass: HomeAssistant, setup_light_with_transition_template
|
hass: HomeAssistant, style: ConfigurationStyle, setup_light_with_transition_template
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the template for the supports transition dynamically."""
|
"""Test the template for the supports transition dynamically."""
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
@ -2288,12 +2586,24 @@ async def test_supports_transition_template_updates(
|
|||||||
|
|
||||||
hass.states.async_set("sensor.test", 0)
|
hass.states.async_set("sensor.test", 0)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
# Ensures the trigger template entity updates
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
supported_features = state.attributes.get("supported_features")
|
supported_features = state.attributes.get("supported_features")
|
||||||
assert supported_features == LightEntityFeature.EFFECT
|
assert supported_features == LightEntityFeature.EFFECT
|
||||||
|
|
||||||
hass.states.async_set("sensor.test", 1)
|
hass.states.async_set("sensor.test", 1)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
# Ensures the trigger template entity updates
|
||||||
|
hass.states.async_set("light.test_state", STATE_OFF)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
supported_features = state.attributes.get("supported_features")
|
supported_features = state.attributes.get("supported_features")
|
||||||
assert (
|
assert (
|
||||||
@ -2302,6 +2612,12 @@ async def test_supports_transition_template_updates(
|
|||||||
|
|
||||||
hass.states.async_set("sensor.test", 0)
|
hass.states.async_set("sensor.test", 0)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
# Ensures the trigger template entity updates
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("light.test_template_light")
|
state = hass.states.get("light.test_template_light")
|
||||||
supported_features = state.attributes.get("supported_features")
|
supported_features = state.attributes.get("supported_features")
|
||||||
assert supported_features == LightEntityFeature.EFFECT
|
assert supported_features == LightEntityFeature.EFFECT
|
||||||
@ -2322,16 +2638,22 @@ async def test_supports_transition_template_updates(
|
|||||||
[
|
[
|
||||||
(ConfigurationStyle.LEGACY, "availability_template"),
|
(ConfigurationStyle.LEGACY, "availability_template"),
|
||||||
(ConfigurationStyle.MODERN, "availability"),
|
(ConfigurationStyle.MODERN, "availability"),
|
||||||
|
(ConfigurationStyle.TRIGGER, "availability"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_available_template_with_entities(
|
async def test_available_template_with_entities(
|
||||||
hass: HomeAssistant, setup_single_attribute_light
|
hass: HomeAssistant, style: ConfigurationStyle, setup_single_attribute_light
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test availability templates with values from other entities."""
|
"""Test availability templates with values from other entities."""
|
||||||
# When template returns true..
|
# When template returns true..
|
||||||
hass.states.async_set(_STATE_AVAILABILITY_BOOLEAN, STATE_ON)
|
hass.states.async_set(_STATE_AVAILABILITY_BOOLEAN, STATE_ON)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
# Ensures the trigger template entity updates
|
||||||
|
hass.states.async_set("light.test_state", STATE_ON)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# Device State should not be unavailable
|
# Device State should not be unavailable
|
||||||
assert hass.states.get("light.test_template_light").state != STATE_UNAVAILABLE
|
assert hass.states.get("light.test_template_light").state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
@ -2339,6 +2661,11 @@ async def test_available_template_with_entities(
|
|||||||
hass.states.async_set(_STATE_AVAILABILITY_BOOLEAN, STATE_OFF)
|
hass.states.async_set(_STATE_AVAILABILITY_BOOLEAN, STATE_OFF)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
if style == ConfigurationStyle.TRIGGER:
|
||||||
|
# Ensures the trigger template entity updates
|
||||||
|
hass.states.async_set("light.test_state", STATE_OFF)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# device state should be unavailable
|
# device state should be unavailable
|
||||||
assert hass.states.get("light.test_template_light").state == STATE_UNAVAILABLE
|
assert hass.states.get("light.test_template_light").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
@ -2361,7 +2688,9 @@ async def test_available_template_with_entities(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_invalid_availability_template_keeps_component_available(
|
async def test_invalid_availability_template_keeps_component_available(
|
||||||
hass: HomeAssistant, setup_single_attribute_light, caplog_setup_text
|
hass: HomeAssistant,
|
||||||
|
setup_single_attribute_light,
|
||||||
|
caplog_setup_text,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test that an invalid availability keeps the device available."""
|
"""Test that an invalid availability keeps the device available."""
|
||||||
assert hass.states.get("light.test_template_light").state != STATE_UNAVAILABLE
|
assert hass.states.get("light.test_template_light").state != STATE_UNAVAILABLE
|
||||||
@ -2392,6 +2721,19 @@ async def test_invalid_availability_template_keeps_component_available(
|
|||||||
],
|
],
|
||||||
ConfigurationStyle.MODERN,
|
ConfigurationStyle.MODERN,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "test_template_light_01",
|
||||||
|
**TEST_UNIQUE_ID_CONFIG,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_template_light_02",
|
||||||
|
**TEST_UNIQUE_ID_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ConfigurationStyle.TRIGGER,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_unique_id(hass: HomeAssistant, setup_light) -> None:
|
async def test_unique_id(hass: HomeAssistant, setup_light) -> None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user