Add RGB, RGBW and RGBWW capability to template.light (#86047)
* Add RGB, RGBW and RGBWW capability to template.light Add the required unit test Mute 'LightTemplate.async_turn_on' is too complex Rename all HS color mode from a generic "Color" name to a specific "HS" name * Bring back legacy "color" keyword * Cleanup unrequested commented test * Increase code coverage to 100% * Remove confusing if that should never be false * Apply suggestions from code review --------- Co-authored-by: Erik Montnemery <erik@montnemery.com>pull/104349/head
parent
edf18df0e6
commit
3929b0163c
|
@ -11,6 +11,9 @@ from homeassistant.components.light import (
|
|||
ATTR_COLOR_TEMP,
|
||||
ATTR_EFFECT,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_RGB_COLOR,
|
||||
ATTR_RGBW_COLOR,
|
||||
ATTR_RGBWW_COLOR,
|
||||
ATTR_TRANSITION,
|
||||
ENTITY_ID_FORMAT,
|
||||
ColorMode,
|
||||
|
@ -46,8 +49,18 @@ from .template_entity import (
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
_VALID_STATES = [STATE_ON, STATE_OFF, "true", "false"]
|
||||
|
||||
# Legacy
|
||||
CONF_COLOR_ACTION = "set_color"
|
||||
CONF_COLOR_TEMPLATE = "color_template"
|
||||
|
||||
CONF_HS_ACTION = "set_hs"
|
||||
CONF_HS_TEMPLATE = "hs_template"
|
||||
CONF_RGB_ACTION = "set_rgb"
|
||||
CONF_RGB_TEMPLATE = "rgb_template"
|
||||
CONF_RGBW_ACTION = "set_rgbw"
|
||||
CONF_RGBW_TEMPLATE = "rgbw_template"
|
||||
CONF_RGBWW_ACTION = "set_rgbww"
|
||||
CONF_RGBWW_TEMPLATE = "rgbww_template"
|
||||
CONF_EFFECT_ACTION = "set_effect"
|
||||
CONF_EFFECT_LIST_TEMPLATE = "effect_list_template"
|
||||
CONF_EFFECT_TEMPLATE = "effect_template"
|
||||
|
@ -67,8 +80,16 @@ LIGHT_SCHEMA = vol.All(
|
|||
cv.deprecated(CONF_ENTITY_ID),
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_COLOR_ACTION): cv.SCRIPT_SCHEMA,
|
||||
vol.Optional(CONF_COLOR_TEMPLATE): cv.template,
|
||||
vol.Exclusive(CONF_COLOR_ACTION, "hs_legacy_action"): cv.SCRIPT_SCHEMA,
|
||||
vol.Exclusive(CONF_COLOR_TEMPLATE, "hs_legacy_template"): cv.template,
|
||||
vol.Exclusive(CONF_HS_ACTION, "hs_legacy_action"): cv.SCRIPT_SCHEMA,
|
||||
vol.Exclusive(CONF_HS_TEMPLATE, "hs_legacy_template"): cv.template,
|
||||
vol.Optional(CONF_RGB_ACTION): cv.SCRIPT_SCHEMA,
|
||||
vol.Optional(CONF_RGB_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_RGBW_ACTION): cv.SCRIPT_SCHEMA,
|
||||
vol.Optional(CONF_RGBW_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_RGBWW_ACTION): cv.SCRIPT_SCHEMA,
|
||||
vol.Optional(CONF_RGBWW_TEMPLATE): cv.template,
|
||||
vol.Inclusive(CONF_EFFECT_ACTION, "effect"): cv.SCRIPT_SCHEMA,
|
||||
vol.Inclusive(CONF_EFFECT_LIST_TEMPLATE, "effect"): cv.template,
|
||||
vol.Inclusive(CONF_EFFECT_TEMPLATE, "effect"): cv.template,
|
||||
|
@ -166,6 +187,22 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
if (color_action := config.get(CONF_COLOR_ACTION)) is not None:
|
||||
self._color_script = Script(hass, color_action, friendly_name, DOMAIN)
|
||||
self._color_template = config.get(CONF_COLOR_TEMPLATE)
|
||||
self._hs_script = None
|
||||
if (hs_action := config.get(CONF_HS_ACTION)) is not None:
|
||||
self._hs_script = Script(hass, hs_action, friendly_name, DOMAIN)
|
||||
self._hs_template = config.get(CONF_HS_TEMPLATE)
|
||||
self._rgb_script = None
|
||||
if (rgb_action := config.get(CONF_RGB_ACTION)) is not None:
|
||||
self._rgb_script = Script(hass, rgb_action, friendly_name, DOMAIN)
|
||||
self._rgb_template = config.get(CONF_RGB_TEMPLATE)
|
||||
self._rgbw_script = None
|
||||
if (rgbw_action := config.get(CONF_RGBW_ACTION)) is not None:
|
||||
self._rgbw_script = Script(hass, rgbw_action, friendly_name, DOMAIN)
|
||||
self._rgbw_template = config.get(CONF_RGBW_TEMPLATE)
|
||||
self._rgbww_script = None
|
||||
if (rgbww_action := config.get(CONF_RGBWW_ACTION)) is not None:
|
||||
self._rgbww_script = Script(hass, rgbww_action, friendly_name, DOMAIN)
|
||||
self._rgbww_template = config.get(CONF_RGBWW_TEMPLATE)
|
||||
self._effect_script = None
|
||||
if (effect_action := config.get(CONF_EFFECT_ACTION)) is not None:
|
||||
self._effect_script = Script(hass, effect_action, friendly_name, DOMAIN)
|
||||
|
@ -178,24 +215,39 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
self._state = False
|
||||
self._brightness = None
|
||||
self._temperature = None
|
||||
self._color = None
|
||||
self._hs_color = None
|
||||
self._rgb_color = None
|
||||
self._rgbw_color = None
|
||||
self._rgbww_color = None
|
||||
self._effect = None
|
||||
self._effect_list = None
|
||||
self._fixed_color_mode = None
|
||||
self._color_mode = None
|
||||
self._max_mireds = None
|
||||
self._min_mireds = None
|
||||
self._supports_transition = False
|
||||
self._supported_color_modes = None
|
||||
|
||||
color_modes = {ColorMode.ONOFF}
|
||||
if self._level_script is not None:
|
||||
color_modes.add(ColorMode.BRIGHTNESS)
|
||||
if self._temperature_script is not None:
|
||||
color_modes.add(ColorMode.COLOR_TEMP)
|
||||
if self._hs_script is not None:
|
||||
color_modes.add(ColorMode.HS)
|
||||
if self._color_script is not None:
|
||||
color_modes.add(ColorMode.HS)
|
||||
if self._rgb_script is not None:
|
||||
color_modes.add(ColorMode.RGB)
|
||||
if self._rgbw_script is not None:
|
||||
color_modes.add(ColorMode.RGBW)
|
||||
if self._rgbww_script is not None:
|
||||
color_modes.add(ColorMode.RGBWW)
|
||||
|
||||
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._fixed_color_mode = next(iter(self._supported_color_modes))
|
||||
self._color_mode = next(iter(self._supported_color_modes))
|
||||
|
||||
self._attr_supported_features = LightEntityFeature(0)
|
||||
if self._effect_script is not None:
|
||||
|
@ -232,7 +284,22 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
@property
|
||||
def hs_color(self) -> tuple[float, float] | None:
|
||||
"""Return the hue and saturation color value [float, float]."""
|
||||
return self._color
|
||||
return self._hs_color
|
||||
|
||||
@property
|
||||
def rgb_color(self) -> tuple[int, int, int] | None:
|
||||
"""Return the rgb color value."""
|
||||
return self._rgb_color
|
||||
|
||||
@property
|
||||
def rgbw_color(self) -> tuple[int, int, int, int] | None:
|
||||
"""Return the rgbw color value."""
|
||||
return self._rgbw_color
|
||||
|
||||
@property
|
||||
def rgbww_color(self) -> tuple[int, int, int, int, int] | None:
|
||||
"""Return the rgbww color value."""
|
||||
return self._rgbww_color
|
||||
|
||||
@property
|
||||
def effect(self) -> str | None:
|
||||
|
@ -247,12 +314,7 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
@property
|
||||
def color_mode(self):
|
||||
"""Return current color mode."""
|
||||
if self._fixed_color_mode:
|
||||
return self._fixed_color_mode
|
||||
# Support for ct + hs, prioritize hs
|
||||
if self._color is not None:
|
||||
return ColorMode.HS
|
||||
return ColorMode.COLOR_TEMP
|
||||
return self._color_mode
|
||||
|
||||
@property
|
||||
def supported_color_modes(self):
|
||||
|
@ -305,10 +367,42 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
)
|
||||
if self._color_template:
|
||||
self.add_template_attribute(
|
||||
"_color",
|
||||
"_hs_color",
|
||||
self._color_template,
|
||||
None,
|
||||
self._update_color,
|
||||
self._update_hs,
|
||||
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:
|
||||
|
@ -337,7 +431,7 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
)
|
||||
super()._async_setup_templates()
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
async def async_turn_on(self, **kwargs: Any) -> None: # noqa: C901
|
||||
"""Turn the light on."""
|
||||
optimistic_set = False
|
||||
# set optimistic states
|
||||
|
@ -357,19 +451,88 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
"Optimistically setting color temperature to %s",
|
||||
kwargs[ATTR_COLOR_TEMP],
|
||||
)
|
||||
self._color_mode = ColorMode.COLOR_TEMP
|
||||
self._temperature = kwargs[ATTR_COLOR_TEMP]
|
||||
if self._color_template is None:
|
||||
self._color = None
|
||||
if self._hs_template is None and self._color_template is None:
|
||||
self._hs_color = None
|
||||
if self._rgb_template is None:
|
||||
self._rgb_color = None
|
||||
if self._rgbw_template is None:
|
||||
self._rgbw_color = None
|
||||
if self._rgbww_template is None:
|
||||
self._rgbww_color = None
|
||||
optimistic_set = True
|
||||
|
||||
if self._color_template is None and ATTR_HS_COLOR in kwargs:
|
||||
if (
|
||||
self._hs_template is None
|
||||
and self._color_template is None
|
||||
and ATTR_HS_COLOR in kwargs
|
||||
):
|
||||
_LOGGER.debug(
|
||||
"Optimistically setting color to %s",
|
||||
"Optimistically setting hs color to %s",
|
||||
kwargs[ATTR_HS_COLOR],
|
||||
)
|
||||
self._color = kwargs[ATTR_HS_COLOR]
|
||||
self._color_mode = ColorMode.HS
|
||||
self._hs_color = kwargs[ATTR_HS_COLOR]
|
||||
if self._temperature_template is None:
|
||||
self._temperature = None
|
||||
if self._rgb_template is None:
|
||||
self._rgb_color = None
|
||||
if self._rgbw_template is None:
|
||||
self._rgbw_color = None
|
||||
if self._rgbww_template is None:
|
||||
self._rgbww_color = None
|
||||
optimistic_set = True
|
||||
|
||||
if self._rgb_template is None and ATTR_RGB_COLOR in kwargs:
|
||||
_LOGGER.debug(
|
||||
"Optimistically setting rgb color to %s",
|
||||
kwargs[ATTR_RGB_COLOR],
|
||||
)
|
||||
self._color_mode = ColorMode.RGB
|
||||
self._rgb_color = kwargs[ATTR_RGB_COLOR]
|
||||
if self._temperature_template is None:
|
||||
self._temperature = None
|
||||
if self._hs_template is None and self._color_template is None:
|
||||
self._hs_color = None
|
||||
if self._rgbw_template is None:
|
||||
self._rgbw_color = None
|
||||
if self._rgbww_template is None:
|
||||
self._rgbww_color = None
|
||||
optimistic_set = True
|
||||
|
||||
if self._rgbw_template is None and ATTR_RGBW_COLOR in kwargs:
|
||||
_LOGGER.debug(
|
||||
"Optimistically setting rgbw color to %s",
|
||||
kwargs[ATTR_RGBW_COLOR],
|
||||
)
|
||||
self._color_mode = ColorMode.RGBW
|
||||
self._rgbw_color = kwargs[ATTR_RGBW_COLOR]
|
||||
if self._temperature_template is None:
|
||||
self._temperature = None
|
||||
if self._hs_template is None and self._color_template is None:
|
||||
self._hs_color = None
|
||||
if self._rgb_template is None:
|
||||
self._rgb_color = None
|
||||
if self._rgbww_template is None:
|
||||
self._rgbww_color = None
|
||||
optimistic_set = True
|
||||
|
||||
if self._rgbww_template is None and ATTR_RGBWW_COLOR in kwargs:
|
||||
_LOGGER.debug(
|
||||
"Optimistically setting rgbww color to %s",
|
||||
kwargs[ATTR_RGBWW_COLOR],
|
||||
)
|
||||
self._color_mode = ColorMode.RGBWW
|
||||
self._rgbww_color = kwargs[ATTR_RGBWW_COLOR]
|
||||
if self._temperature_template is None:
|
||||
self._temperature = None
|
||||
if self._hs_template is None and self._color_template is None:
|
||||
self._hs_color = None
|
||||
if self._rgb_template is None:
|
||||
self._rgb_color = None
|
||||
if self._rgbw_template is None:
|
||||
self._rgbw_color = None
|
||||
optimistic_set = True
|
||||
|
||||
common_params = {}
|
||||
|
@ -413,6 +576,58 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
await self.async_run_script(
|
||||
self._color_script, run_variables=common_params, context=self._context
|
||||
)
|
||||
elif ATTR_HS_COLOR in kwargs and self._hs_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.async_run_script(
|
||||
self._hs_script, run_variables=common_params, context=self._context
|
||||
)
|
||||
elif ATTR_RGBWW_COLOR in kwargs and self._rgbww_script:
|
||||
rgbww_value = kwargs[ATTR_RGBWW_COLOR]
|
||||
common_params["rgbww"] = rgbww_value
|
||||
common_params["rgb"] = (
|
||||
int(rgbww_value[0]),
|
||||
int(rgbww_value[1]),
|
||||
int(rgbww_value[2]),
|
||||
)
|
||||
common_params["r"] = int(rgbww_value[0])
|
||||
common_params["g"] = int(rgbww_value[1])
|
||||
common_params["b"] = int(rgbww_value[2])
|
||||
common_params["cw"] = int(rgbww_value[3])
|
||||
common_params["ww"] = int(rgbww_value[4])
|
||||
|
||||
await self.async_run_script(
|
||||
self._rgbww_script, run_variables=common_params, context=self._context
|
||||
)
|
||||
elif ATTR_RGBW_COLOR in kwargs and self._rgbw_script:
|
||||
rgbw_value = kwargs[ATTR_RGBW_COLOR]
|
||||
common_params["rgbw"] = rgbw_value
|
||||
common_params["rgb"] = (
|
||||
int(rgbw_value[0]),
|
||||
int(rgbw_value[1]),
|
||||
int(rgbw_value[2]),
|
||||
)
|
||||
common_params["r"] = int(rgbw_value[0])
|
||||
common_params["g"] = int(rgbw_value[1])
|
||||
common_params["b"] = int(rgbw_value[2])
|
||||
common_params["w"] = int(rgbw_value[3])
|
||||
|
||||
await self.async_run_script(
|
||||
self._rgbw_script, run_variables=common_params, context=self._context
|
||||
)
|
||||
elif ATTR_RGB_COLOR in kwargs and self._rgb_script:
|
||||
rgb_value = kwargs[ATTR_RGB_COLOR]
|
||||
common_params["rgb"] = rgb_value
|
||||
common_params["r"] = int(rgb_value[0])
|
||||
common_params["g"] = int(rgb_value[1])
|
||||
common_params["b"] = int(rgb_value[2])
|
||||
|
||||
await self.async_run_script(
|
||||
self._rgb_script, run_variables=common_params, context=self._context
|
||||
)
|
||||
elif ATTR_BRIGHTNESS in kwargs and self._level_script:
|
||||
await self.async_run_script(
|
||||
self._level_script, run_variables=common_params, context=self._context
|
||||
|
@ -560,18 +775,19 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
" this light, or 'None'"
|
||||
)
|
||||
self._temperature = None
|
||||
self._color_mode = ColorMode.COLOR_TEMP
|
||||
|
||||
@callback
|
||||
def _update_color(self, render):
|
||||
"""Update the hs_color from the template."""
|
||||
def _update_hs(self, render):
|
||||
"""Update the color from the template."""
|
||||
if render is None:
|
||||
self._color = None
|
||||
self._hs_color = None
|
||||
return
|
||||
|
||||
h_str = s_str = None
|
||||
if isinstance(render, str):
|
||||
if render in ("None", ""):
|
||||
self._color = None
|
||||
self._hs_color = None
|
||||
return
|
||||
h_str, s_str = map(
|
||||
float, render.replace("(", "").replace(")", "").split(",", 1)
|
||||
|
@ -582,10 +798,12 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
if (
|
||||
h_str is not None
|
||||
and s_str is not None
|
||||
and isinstance(h_str, (int, float))
|
||||
and isinstance(s_str, (int, float))
|
||||
and 0 <= h_str <= 360
|
||||
and 0 <= s_str <= 100
|
||||
):
|
||||
self._color = (h_str, s_str)
|
||||
self._hs_color = (h_str, s_str)
|
||||
elif h_str is not None and s_str is not None:
|
||||
_LOGGER.error(
|
||||
(
|
||||
|
@ -596,12 +814,151 @@ class LightTemplate(TemplateEntity, LightEntity):
|
|||
s_str,
|
||||
self.entity_id,
|
||||
)
|
||||
self._color = None
|
||||
self._hs_color = None
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Received invalid hs_color : (%s) for entity %s", render, self.entity_id
|
||||
)
|
||||
self._color = None
|
||||
self._hs_color = None
|
||||
self._color_mode = ColorMode.HS
|
||||
|
||||
@callback
|
||||
def _update_rgb(self, render):
|
||||
"""Update the color from the template."""
|
||||
if render is None:
|
||||
self._rgb_color = None
|
||||
return
|
||||
|
||||
r_int = g_int = b_int = None
|
||||
if isinstance(render, str):
|
||||
if render in ("None", ""):
|
||||
self._rgb_color = None
|
||||
return
|
||||
cleanup_char = ["(", ")", "[", "]", " "]
|
||||
for char in cleanup_char:
|
||||
render = render.replace(char, "")
|
||||
r_int, g_int, b_int = map(int, render.split(",", 3))
|
||||
elif isinstance(render, (list, tuple)) and len(render) == 3:
|
||||
r_int, g_int, b_int = render
|
||||
|
||||
if all(
|
||||
value is not None and isinstance(value, (int, float)) and 0 <= value <= 255
|
||||
for value in (r_int, g_int, b_int)
|
||||
):
|
||||
self._rgb_color = (r_int, g_int, b_int)
|
||||
elif any(
|
||||
isinstance(value, (int, float)) and not 0 <= value <= 255
|
||||
for value in (r_int, g_int, b_int)
|
||||
):
|
||||
_LOGGER.error(
|
||||
"Received invalid rgb_color : (%s, %s, %s) for entity %s. Expected: (0-255, 0-255, 0-255)",
|
||||
r_int,
|
||||
g_int,
|
||||
b_int,
|
||||
self.entity_id,
|
||||
)
|
||||
self._rgb_color = None
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Received invalid rgb_color : (%s) for entity %s",
|
||||
render,
|
||||
self.entity_id,
|
||||
)
|
||||
self._rgb_color = None
|
||||
self._color_mode = ColorMode.RGB
|
||||
|
||||
@callback
|
||||
def _update_rgbw(self, render):
|
||||
"""Update the color from the template."""
|
||||
if render is None:
|
||||
self._rgbw_color = None
|
||||
return
|
||||
|
||||
r_int = g_int = b_int = w_int = None
|
||||
if isinstance(render, str):
|
||||
if render in ("None", ""):
|
||||
self._rgb_color = None
|
||||
return
|
||||
cleanup_char = ["(", ")", "[", "]", " "]
|
||||
for char in cleanup_char:
|
||||
render = render.replace(char, "")
|
||||
r_int, g_int, b_int, w_int = map(int, render.split(",", 4))
|
||||
elif isinstance(render, (list, tuple)) and len(render) == 4:
|
||||
r_int, g_int, b_int, w_int = render
|
||||
|
||||
if all(
|
||||
value is not None and isinstance(value, (int, float)) and 0 <= value <= 255
|
||||
for value in (r_int, g_int, b_int, w_int)
|
||||
):
|
||||
self._rgbw_color = (r_int, g_int, b_int, w_int)
|
||||
elif any(
|
||||
isinstance(value, (int, float)) and not 0 <= value <= 255
|
||||
for value in (r_int, g_int, b_int, w_int)
|
||||
):
|
||||
_LOGGER.error(
|
||||
"Received invalid rgb_color : (%s, %s, %s, %s) for entity %s. Expected: (0-255, 0-255, 0-255, 0-255)",
|
||||
r_int,
|
||||
g_int,
|
||||
b_int,
|
||||
w_int,
|
||||
self.entity_id,
|
||||
)
|
||||
self._rgbw_color = None
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Received invalid rgb_color : (%s) for entity %s",
|
||||
render,
|
||||
self.entity_id,
|
||||
)
|
||||
self._rgbw_color = None
|
||||
self._color_mode = ColorMode.RGBW
|
||||
|
||||
@callback
|
||||
def _update_rgbww(self, render):
|
||||
"""Update the color from the template."""
|
||||
if render is None:
|
||||
self._rgbww_color = None
|
||||
return
|
||||
|
||||
r_int = g_int = b_int = cw_int = ww_int = None
|
||||
if isinstance(render, str):
|
||||
if render in ("None", ""):
|
||||
self._rgb_color = None
|
||||
return
|
||||
cleanup_char = ["(", ")", "[", "]", " "]
|
||||
for char in cleanup_char:
|
||||
render = render.replace(char, "")
|
||||
r_int, g_int, b_int, cw_int, ww_int = map(int, render.split(",", 5))
|
||||
elif isinstance(render, (list, tuple)) and len(render) == 5:
|
||||
r_int, g_int, b_int, cw_int, ww_int = render
|
||||
|
||||
if all(
|
||||
value is not None and isinstance(value, (int, float)) and 0 <= value <= 255
|
||||
for value in (r_int, g_int, b_int, cw_int, ww_int)
|
||||
):
|
||||
self._rgbww_color = (r_int, g_int, b_int, cw_int, ww_int)
|
||||
elif any(
|
||||
isinstance(value, (int, float)) and not 0 <= value <= 255
|
||||
for value in (r_int, g_int, b_int, cw_int, ww_int)
|
||||
):
|
||||
_LOGGER.error(
|
||||
"Received invalid rgb_color : (%s, %s, %s, %s, %s) for entity %s. Expected: (0-255, 0-255, 0-255, 0-255)",
|
||||
r_int,
|
||||
g_int,
|
||||
b_int,
|
||||
cw_int,
|
||||
ww_int,
|
||||
self.entity_id,
|
||||
)
|
||||
self._rgbww_color = None
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Received invalid rgb_color : (%s) for entity %s",
|
||||
render,
|
||||
self.entity_id,
|
||||
)
|
||||
self._rgbww_color = None
|
||||
self._color_mode = ColorMode.RGBWW
|
||||
|
||||
@callback
|
||||
def _update_max_mireds(self, render):
|
||||
|
|
|
@ -7,6 +7,9 @@ from homeassistant.components.light import (
|
|||
ATTR_COLOR_TEMP,
|
||||
ATTR_EFFECT,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_RGB_COLOR,
|
||||
ATTR_RGBW_COLOR,
|
||||
ATTR_RGBWW_COLOR,
|
||||
ATTR_TRANSITION,
|
||||
ColorMode,
|
||||
LightEntityFeature,
|
||||
|
@ -72,7 +75,7 @@ OPTIMISTIC_COLOR_TEMP_LIGHT_CONFIG = {
|
|||
}
|
||||
|
||||
|
||||
OPTIMISTIC_HS_COLOR_LIGHT_CONFIG = {
|
||||
OPTIMISTIC_LEGACY_COLOR_LIGHT_CONFIG = {
|
||||
**OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
|
||||
"set_color": {
|
||||
"service": "test.automation",
|
||||
|
@ -86,6 +89,68 @@ OPTIMISTIC_HS_COLOR_LIGHT_CONFIG = {
|
|||
}
|
||||
|
||||
|
||||
OPTIMISTIC_HS_COLOR_LIGHT_CONFIG = {
|
||||
**OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
|
||||
"set_hs": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"action": "set_hs",
|
||||
"caller": "{{ this.entity_id }}",
|
||||
"s": "{{s}}",
|
||||
"h": "{{h}}",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
OPTIMISTIC_RGB_COLOR_LIGHT_CONFIG = {
|
||||
**OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
|
||||
"set_rgb": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"action": "set_rgb",
|
||||
"caller": "{{ this.entity_id }}",
|
||||
"r": "{{r}}",
|
||||
"g": "{{g}}",
|
||||
"b": "{{b}}",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
OPTIMISTIC_RGBW_COLOR_LIGHT_CONFIG = {
|
||||
**OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
|
||||
"set_rgbw": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"action": "set_rgbw",
|
||||
"caller": "{{ this.entity_id }}",
|
||||
"r": "{{r}}",
|
||||
"g": "{{g}}",
|
||||
"b": "{{b}}",
|
||||
"w": "{{w}}",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
OPTIMISTIC_RGBWW_COLOR_LIGHT_CONFIG = {
|
||||
**OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
|
||||
"set_rgbww": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"action": "set_rgbww",
|
||||
"caller": "{{ this.entity_id }}",
|
||||
"r": "{{r}}",
|
||||
"g": "{{g}}",
|
||||
"b": "{{b}}",
|
||||
"cw": "{{cw}}",
|
||||
"ww": "{{ww}}",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_light(hass, count, light_config):
|
||||
"""Do setup of light integration."""
|
||||
config = {"light": {"platform": "template", "lights": light_config}}
|
||||
|
@ -607,6 +672,7 @@ async def test_level_action_no_template(
|
|||
"{{ state_attr('light.nolight', 'brightness') }}",
|
||||
ColorMode.BRIGHTNESS,
|
||||
),
|
||||
(None, "{{'one'}}", ColorMode.BRIGHTNESS),
|
||||
],
|
||||
)
|
||||
async def test_level_template(
|
||||
|
@ -643,6 +709,7 @@ async def test_level_template(
|
|||
(None, "None", ColorMode.COLOR_TEMP),
|
||||
(None, "{{ none }}", ColorMode.COLOR_TEMP),
|
||||
(None, "", ColorMode.COLOR_TEMP),
|
||||
(None, "{{ 'one' }}", ColorMode.COLOR_TEMP),
|
||||
],
|
||||
)
|
||||
async def test_temperature_template(
|
||||
|
@ -797,17 +864,17 @@ async def test_entity_picture_template(hass: HomeAssistant, setup_light) -> None
|
|||
[
|
||||
{
|
||||
"test_template_light": {
|
||||
**OPTIMISTIC_HS_COLOR_LIGHT_CONFIG,
|
||||
**OPTIMISTIC_LEGACY_COLOR_LIGHT_CONFIG,
|
||||
"value_template": "{{1 == 1}}",
|
||||
}
|
||||
},
|
||||
],
|
||||
)
|
||||
async def test_color_action_no_template(
|
||||
hass: HomeAssistant,
|
||||
async def test_legacy_color_action_no_template(
|
||||
hass,
|
||||
setup_light,
|
||||
calls,
|
||||
) -> None:
|
||||
):
|
||||
"""Test setting color with optimistic template."""
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes.get("hs_color") is None
|
||||
|
@ -833,6 +900,186 @@ async def test_color_action_no_template(
|
|||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", [1])
|
||||
@pytest.mark.parametrize(
|
||||
"light_config",
|
||||
[
|
||||
{
|
||||
"test_template_light": {
|
||||
**OPTIMISTIC_HS_COLOR_LIGHT_CONFIG,
|
||||
"value_template": "{{1 == 1}}",
|
||||
}
|
||||
},
|
||||
],
|
||||
)
|
||||
async def test_hs_color_action_no_template(
|
||||
hass: HomeAssistant,
|
||||
setup_light,
|
||||
calls,
|
||||
) -> None:
|
||||
"""Test setting hs color with optimistic template."""
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes.get("hs_color") is None
|
||||
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "light.test_template_light", ATTR_HS_COLOR: (40, 50)},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[-1].data["action"] == "set_hs"
|
||||
assert calls[-1].data["caller"] == "light.test_template_light"
|
||||
assert calls[-1].data["h"] == 40
|
||||
assert calls[-1].data["s"] == 50
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["color_mode"] == ColorMode.HS
|
||||
assert state.attributes.get("hs_color") == (40, 50)
|
||||
assert state.attributes["supported_color_modes"] == [ColorMode.HS]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", [1])
|
||||
@pytest.mark.parametrize(
|
||||
"light_config",
|
||||
[
|
||||
{
|
||||
"test_template_light": {
|
||||
**OPTIMISTIC_RGB_COLOR_LIGHT_CONFIG,
|
||||
"value_template": "{{1 == 1}}",
|
||||
}
|
||||
},
|
||||
],
|
||||
)
|
||||
async def test_rgb_color_action_no_template(
|
||||
hass: HomeAssistant,
|
||||
setup_light,
|
||||
calls,
|
||||
) -> None:
|
||||
"""Test setting rgb color with optimistic template."""
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes.get("rgb_color") is None
|
||||
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "light.test_template_light", ATTR_RGB_COLOR: (160, 78, 192)},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[-1].data["action"] == "set_rgb"
|
||||
assert calls[-1].data["caller"] == "light.test_template_light"
|
||||
assert calls[-1].data["r"] == 160
|
||||
assert calls[-1].data["g"] == 78
|
||||
assert calls[-1].data["b"] == 192
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["color_mode"] == ColorMode.RGB
|
||||
assert state.attributes.get("rgb_color") == (160, 78, 192)
|
||||
assert state.attributes["supported_color_modes"] == [ColorMode.RGB]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", [1])
|
||||
@pytest.mark.parametrize(
|
||||
"light_config",
|
||||
[
|
||||
{
|
||||
"test_template_light": {
|
||||
**OPTIMISTIC_RGBW_COLOR_LIGHT_CONFIG,
|
||||
"value_template": "{{1 == 1}}",
|
||||
}
|
||||
},
|
||||
],
|
||||
)
|
||||
async def test_rgbw_color_action_no_template(
|
||||
hass: HomeAssistant,
|
||||
setup_light,
|
||||
calls,
|
||||
) -> None:
|
||||
"""Test setting rgbw color with optimistic template."""
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes.get("rgbw_color") is None
|
||||
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.test_template_light",
|
||||
ATTR_RGBW_COLOR: (160, 78, 192, 25),
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[-1].data["action"] == "set_rgbw"
|
||||
assert calls[-1].data["caller"] == "light.test_template_light"
|
||||
assert calls[-1].data["r"] == 160
|
||||
assert calls[-1].data["g"] == 78
|
||||
assert calls[-1].data["b"] == 192
|
||||
assert calls[-1].data["w"] == 25
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["color_mode"] == ColorMode.RGBW
|
||||
assert state.attributes.get("rgbw_color") == (160, 78, 192, 25)
|
||||
assert state.attributes["supported_color_modes"] == [ColorMode.RGBW]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", [1])
|
||||
@pytest.mark.parametrize(
|
||||
"light_config",
|
||||
[
|
||||
{
|
||||
"test_template_light": {
|
||||
**OPTIMISTIC_RGBWW_COLOR_LIGHT_CONFIG,
|
||||
"value_template": "{{1 == 1}}",
|
||||
}
|
||||
},
|
||||
],
|
||||
)
|
||||
async def test_rgbww_color_action_no_template(
|
||||
hass: HomeAssistant,
|
||||
setup_light,
|
||||
calls,
|
||||
) -> None:
|
||||
"""Test setting rgbww color with optimistic template."""
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes.get("rgbww_color") is None
|
||||
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.test_template_light",
|
||||
ATTR_RGBWW_COLOR: (160, 78, 192, 25, 55),
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[-1].data["action"] == "set_rgbww"
|
||||
assert calls[-1].data["caller"] == "light.test_template_light"
|
||||
assert calls[-1].data["r"] == 160
|
||||
assert calls[-1].data["g"] == 78
|
||||
assert calls[-1].data["b"] == 192
|
||||
assert calls[-1].data["cw"] == 25
|
||||
assert calls[-1].data["ww"] == 55
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["color_mode"] == ColorMode.RGBWW
|
||||
assert state.attributes.get("rgbww_color") == (160, 78, 192, 25, 55)
|
||||
assert state.attributes["supported_color_modes"] == [ColorMode.RGBWW]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", [1])
|
||||
@pytest.mark.parametrize(
|
||||
("expected_hs", "color_template", "expected_color_mode"),
|
||||
|
@ -845,19 +1092,20 @@ async def test_color_action_no_template(
|
|||
(None, "{{x - 12}}", ColorMode.HS),
|
||||
(None, "", ColorMode.HS),
|
||||
(None, "{{ none }}", ColorMode.HS),
|
||||
(None, "{{('one','two')}}", ColorMode.HS),
|
||||
],
|
||||
)
|
||||
async def test_color_template(
|
||||
hass: HomeAssistant,
|
||||
async def test_legacy_color_template(
|
||||
hass,
|
||||
expected_hs,
|
||||
expected_color_mode,
|
||||
count,
|
||||
color_template,
|
||||
) -> None:
|
||||
):
|
||||
"""Test the template for the color."""
|
||||
light_config = {
|
||||
"test_template_light": {
|
||||
**OPTIMISTIC_HS_COLOR_LIGHT_CONFIG,
|
||||
**OPTIMISTIC_LEGACY_COLOR_LIGHT_CONFIG,
|
||||
"value_template": "{{ 1 == 1 }}",
|
||||
"color_template": color_template,
|
||||
}
|
||||
|
@ -871,6 +1119,176 @@ async def test_color_template(
|
|||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", [1])
|
||||
@pytest.mark.parametrize(
|
||||
("expected_hs", "hs_template", "expected_color_mode"),
|
||||
[
|
||||
((360, 100), "{{(360, 100)}}", ColorMode.HS),
|
||||
((360, 100), "(360, 100)", ColorMode.HS),
|
||||
((359.9, 99.9), "{{(359.9, 99.9)}}", ColorMode.HS),
|
||||
(None, "{{(361, 100)}}", ColorMode.HS),
|
||||
(None, "{{(360, 101)}}", ColorMode.HS),
|
||||
(None, "[{{(360)}},{{null}}]", ColorMode.HS),
|
||||
(None, "{{x - 12}}", ColorMode.HS),
|
||||
(None, "", ColorMode.HS),
|
||||
(None, "{{ none }}", ColorMode.HS),
|
||||
(None, "{{('one','two')}}", ColorMode.HS),
|
||||
],
|
||||
)
|
||||
async def test_hs_template(
|
||||
hass: HomeAssistant,
|
||||
expected_hs,
|
||||
expected_color_mode,
|
||||
count,
|
||||
hs_template,
|
||||
) -> None:
|
||||
"""Test the template for the color."""
|
||||
light_config = {
|
||||
"test_template_light": {
|
||||
**OPTIMISTIC_HS_COLOR_LIGHT_CONFIG,
|
||||
"value_template": "{{ 1 == 1 }}",
|
||||
"hs_template": hs_template,
|
||||
}
|
||||
}
|
||||
await async_setup_light(hass, count, light_config)
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes.get("hs_color") == expected_hs
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["color_mode"] == expected_color_mode
|
||||
assert state.attributes["supported_color_modes"] == [ColorMode.HS]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", [1])
|
||||
@pytest.mark.parametrize(
|
||||
("expected_rgb", "rgb_template", "expected_color_mode"),
|
||||
[
|
||||
((160, 78, 192), "{{(160, 78, 192)}}", ColorMode.RGB),
|
||||
((160, 78, 192), "{{[160, 78, 192]}}", ColorMode.RGB),
|
||||
((160, 78, 192), "(160, 78, 192)", ColorMode.RGB),
|
||||
((159, 77, 191), "{{(159.9, 77.9, 191.9)}}", ColorMode.RGB),
|
||||
(None, "{{(256, 100, 100)}}", ColorMode.RGB),
|
||||
(None, "{{(100, 256, 100)}}", ColorMode.RGB),
|
||||
(None, "{{(100, 100, 256)}}", ColorMode.RGB),
|
||||
(None, "{{x - 12}}", ColorMode.RGB),
|
||||
(None, "", ColorMode.RGB),
|
||||
(None, "{{ none }}", ColorMode.RGB),
|
||||
(None, "{{('one','two','tree')}}", ColorMode.RGB),
|
||||
],
|
||||
)
|
||||
async def test_rgb_template(
|
||||
hass: HomeAssistant,
|
||||
expected_rgb,
|
||||
expected_color_mode,
|
||||
count,
|
||||
rgb_template,
|
||||
) -> None:
|
||||
"""Test the template for the color."""
|
||||
light_config = {
|
||||
"test_template_light": {
|
||||
**OPTIMISTIC_RGB_COLOR_LIGHT_CONFIG,
|
||||
"value_template": "{{ 1 == 1 }}",
|
||||
"rgb_template": rgb_template,
|
||||
}
|
||||
}
|
||||
await async_setup_light(hass, count, light_config)
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes.get("rgb_color") == expected_rgb
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["color_mode"] == expected_color_mode
|
||||
assert state.attributes["supported_color_modes"] == [ColorMode.RGB]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", [1])
|
||||
@pytest.mark.parametrize(
|
||||
("expected_rgbw", "rgbw_template", "expected_color_mode"),
|
||||
[
|
||||
((160, 78, 192, 25), "{{(160, 78, 192, 25)}}", ColorMode.RGBW),
|
||||
((160, 78, 192, 25), "{{[160, 78, 192, 25]}}", ColorMode.RGBW),
|
||||
((160, 78, 192, 25), "(160, 78, 192, 25)", ColorMode.RGBW),
|
||||
((159, 77, 191, 24), "{{(159.9, 77.9, 191.9, 24.9)}}", ColorMode.RGBW),
|
||||
(None, "{{(256, 100, 100, 100)}}", ColorMode.RGBW),
|
||||
(None, "{{(100, 256, 100, 100)}}", ColorMode.RGBW),
|
||||
(None, "{{(100, 100, 256, 100)}}", ColorMode.RGBW),
|
||||
(None, "{{(100, 100, 100, 256)}}", ColorMode.RGBW),
|
||||
(None, "{{x - 12}}", ColorMode.RGBW),
|
||||
(None, "", ColorMode.RGBW),
|
||||
(None, "{{ none }}", ColorMode.RGBW),
|
||||
(None, "{{('one','two','tree','four')}}", ColorMode.RGBW),
|
||||
],
|
||||
)
|
||||
async def test_rgbw_template(
|
||||
hass: HomeAssistant,
|
||||
expected_rgbw,
|
||||
expected_color_mode,
|
||||
count,
|
||||
rgbw_template,
|
||||
) -> None:
|
||||
"""Test the template for the color."""
|
||||
light_config = {
|
||||
"test_template_light": {
|
||||
**OPTIMISTIC_RGBW_COLOR_LIGHT_CONFIG,
|
||||
"value_template": "{{ 1 == 1 }}",
|
||||
"rgbw_template": rgbw_template,
|
||||
}
|
||||
}
|
||||
await async_setup_light(hass, count, light_config)
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes.get("rgbw_color") == expected_rgbw
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["color_mode"] == expected_color_mode
|
||||
assert state.attributes["supported_color_modes"] == [ColorMode.RGBW]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", [1])
|
||||
@pytest.mark.parametrize(
|
||||
("expected_rgbww", "rgbww_template", "expected_color_mode"),
|
||||
[
|
||||
((160, 78, 192, 25, 55), "{{(160, 78, 192, 25, 55)}}", ColorMode.RGBWW),
|
||||
((160, 78, 192, 25, 55), "(160, 78, 192, 25, 55)", ColorMode.RGBWW),
|
||||
((160, 78, 192, 25, 55), "{{[160, 78, 192, 25, 55]}}", ColorMode.RGBWW),
|
||||
(
|
||||
(159, 77, 191, 24, 54),
|
||||
"{{(159.9, 77.9, 191.9, 24.9, 54.9)}}",
|
||||
ColorMode.RGBWW,
|
||||
),
|
||||
(None, "{{(256, 100, 100, 100, 100)}}", ColorMode.RGBWW),
|
||||
(None, "{{(100, 256, 100, 100, 100)}}", ColorMode.RGBWW),
|
||||
(None, "{{(100, 100, 256, 100, 100)}}", ColorMode.RGBWW),
|
||||
(None, "{{(100, 100, 100, 256, 100)}}", ColorMode.RGBWW),
|
||||
(None, "{{(100, 100, 100, 100, 256)}}", ColorMode.RGBWW),
|
||||
(None, "{{x - 12}}", ColorMode.RGBWW),
|
||||
(None, "", ColorMode.RGBWW),
|
||||
(None, "{{ none }}", ColorMode.RGBWW),
|
||||
(None, "{{('one','two','tree','four','five')}}", ColorMode.RGBWW),
|
||||
],
|
||||
)
|
||||
async def test_rgbww_template(
|
||||
hass: HomeAssistant,
|
||||
expected_rgbww,
|
||||
expected_color_mode,
|
||||
count,
|
||||
rgbww_template,
|
||||
) -> None:
|
||||
"""Test the template for the color."""
|
||||
light_config = {
|
||||
"test_template_light": {
|
||||
**OPTIMISTIC_RGBWW_COLOR_LIGHT_CONFIG,
|
||||
"value_template": "{{ 1 == 1 }}",
|
||||
"rgbww_template": rgbww_template,
|
||||
}
|
||||
}
|
||||
await async_setup_light(hass, count, light_config)
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes.get("rgbww_color") == expected_rgbww
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["color_mode"] == expected_color_mode
|
||||
assert state.attributes["supported_color_modes"] == [ColorMode.RGBWW]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", [1])
|
||||
@pytest.mark.parametrize(
|
||||
"light_config",
|
||||
|
@ -879,16 +1297,14 @@ async def test_color_template(
|
|||
"test_template_light": {
|
||||
**OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
|
||||
"value_template": "{{1 == 1}}",
|
||||
"set_color": [
|
||||
{
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"entity_id": "test.test_state",
|
||||
"h": "{{h}}",
|
||||
"s": "{{s}}",
|
||||
},
|
||||
"set_hs": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"entity_id": "test.test_state",
|
||||
"h": "{{h}}",
|
||||
"s": "{{s}}",
|
||||
},
|
||||
],
|
||||
},
|
||||
"set_temperature": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
|
@ -896,18 +1312,48 @@ async def test_color_template(
|
|||
"color_temp": "{{color_temp}}",
|
||||
},
|
||||
},
|
||||
"set_rgb": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"entity_id": "test.test_state",
|
||||
"r": "{{r}}",
|
||||
"g": "{{g}}",
|
||||
"b": "{{b}}",
|
||||
},
|
||||
},
|
||||
"set_rgbw": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"entity_id": "test.test_state",
|
||||
"r": "{{r}}",
|
||||
"g": "{{g}}",
|
||||
"b": "{{b}}",
|
||||
"w": "{{w}}",
|
||||
},
|
||||
},
|
||||
"set_rgbww": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"entity_id": "test.test_state",
|
||||
"r": "{{r}}",
|
||||
"g": "{{g}}",
|
||||
"b": "{{b}}",
|
||||
"cw": "{{cw}}",
|
||||
"ww": "{{ww}}",
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
],
|
||||
)
|
||||
async def test_color_and_temperature_actions_no_template(
|
||||
async def test_all_colors_mode_no_template(
|
||||
hass: HomeAssistant, setup_light, calls
|
||||
) -> None:
|
||||
"""Test setting color and color temperature with optimistic template."""
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes.get("hs_color") is None
|
||||
|
||||
# Optimistically set color, light should be in hs_color mode
|
||||
# Optimistically set hs color, light should be in hs_color mode
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
|
@ -926,6 +1372,9 @@ async def test_color_and_temperature_actions_no_template(
|
|||
assert state.attributes["supported_color_modes"] == [
|
||||
ColorMode.COLOR_TEMP,
|
||||
ColorMode.HS,
|
||||
ColorMode.RGB,
|
||||
ColorMode.RGBW,
|
||||
ColorMode.RGBWW,
|
||||
]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
@ -947,10 +1396,100 @@ async def test_color_and_temperature_actions_no_template(
|
|||
assert state.attributes["supported_color_modes"] == [
|
||||
ColorMode.COLOR_TEMP,
|
||||
ColorMode.HS,
|
||||
ColorMode.RGB,
|
||||
ColorMode.RGBW,
|
||||
ColorMode.RGBWW,
|
||||
]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
# Optimistically set color, light should again be in hs_color mode
|
||||
# Optimistically set rgb color, light should be in rgb_color mode
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "light.test_template_light", ATTR_RGB_COLOR: (160, 78, 192)},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 3
|
||||
assert calls[-1].data["r"] == 160
|
||||
assert calls[-1].data["g"] == 78
|
||||
assert calls[-1].data["b"] == 192
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes["color_mode"] == ColorMode.RGB
|
||||
assert state.attributes["color_temp"] is None
|
||||
assert state.attributes["rgb_color"] == (160, 78, 192)
|
||||
assert state.attributes["supported_color_modes"] == [
|
||||
ColorMode.COLOR_TEMP,
|
||||
ColorMode.HS,
|
||||
ColorMode.RGB,
|
||||
ColorMode.RGBW,
|
||||
ColorMode.RGBWW,
|
||||
]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
# Optimistically set rgbw color, light should be in rgb_color mode
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.test_template_light",
|
||||
ATTR_RGBW_COLOR: (160, 78, 192, 25),
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 4
|
||||
assert calls[-1].data["r"] == 160
|
||||
assert calls[-1].data["g"] == 78
|
||||
assert calls[-1].data["b"] == 192
|
||||
assert calls[-1].data["w"] == 25
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes["color_mode"] == ColorMode.RGBW
|
||||
assert state.attributes["color_temp"] is None
|
||||
assert state.attributes["rgbw_color"] == (160, 78, 192, 25)
|
||||
assert state.attributes["supported_color_modes"] == [
|
||||
ColorMode.COLOR_TEMP,
|
||||
ColorMode.HS,
|
||||
ColorMode.RGB,
|
||||
ColorMode.RGBW,
|
||||
ColorMode.RGBWW,
|
||||
]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
# Optimistically set rgbww color, light should be in rgb_color mode
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.test_template_light",
|
||||
ATTR_RGBWW_COLOR: (160, 78, 192, 25, 55),
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 5
|
||||
assert calls[-1].data["r"] == 160
|
||||
assert calls[-1].data["g"] == 78
|
||||
assert calls[-1].data["b"] == 192
|
||||
assert calls[-1].data["cw"] == 25
|
||||
assert calls[-1].data["ww"] == 55
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
assert state.attributes["color_mode"] == ColorMode.RGBWW
|
||||
assert state.attributes["color_temp"] is None
|
||||
assert state.attributes["rgbww_color"] == (160, 78, 192, 25, 55)
|
||||
assert state.attributes["supported_color_modes"] == [
|
||||
ColorMode.COLOR_TEMP,
|
||||
ColorMode.HS,
|
||||
ColorMode.RGB,
|
||||
ColorMode.RGBW,
|
||||
ColorMode.RGBWW,
|
||||
]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
# Optimistically set hs color, light should again be in hs_color mode
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
|
@ -958,7 +1497,7 @@ async def test_color_and_temperature_actions_no_template(
|
|||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 3
|
||||
assert len(calls) == 6
|
||||
assert calls[-1].data["h"] == 10
|
||||
assert calls[-1].data["s"] == 20
|
||||
|
||||
|
@ -969,6 +1508,9 @@ async def test_color_and_temperature_actions_no_template(
|
|||
assert state.attributes["supported_color_modes"] == [
|
||||
ColorMode.COLOR_TEMP,
|
||||
ColorMode.HS,
|
||||
ColorMode.RGB,
|
||||
ColorMode.RGBW,
|
||||
ColorMode.RGBWW,
|
||||
]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
@ -980,7 +1522,7 @@ async def test_color_and_temperature_actions_no_template(
|
|||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 4
|
||||
assert len(calls) == 7
|
||||
assert calls[-1].data["color_temp"] == 234
|
||||
|
||||
state = hass.states.get("light.test_template_light")
|
||||
|
@ -990,6 +1532,9 @@ async def test_color_and_temperature_actions_no_template(
|
|||
assert state.attributes["supported_color_modes"] == [
|
||||
ColorMode.COLOR_TEMP,
|
||||
ColorMode.HS,
|
||||
ColorMode.RGB,
|
||||
ColorMode.RGBW,
|
||||
ColorMode.RGBWW,
|
||||
]
|
||||
assert state.attributes["supported_features"] == 0
|
||||
|
||||
|
|
Loading…
Reference in New Issue