1 """Support for Template lights."""
3 from __future__
import annotations
8 import voluptuous
as vol
20 PLATFORM_SCHEMA
as LIGHT_PLATFORM_SCHEMA,
24 filter_supported_color_modes,
43 from .const
import DOMAIN
44 from .template_entity
import (
45 TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY,
47 rewrite_common_legacy_to_modern_conf,
50 _LOGGER = logging.getLogger(__name__)
51 _VALID_STATES = [STATE_ON, STATE_OFF,
"true",
"false"]
54 CONF_COLOR_ACTION =
"set_color"
55 CONF_COLOR_TEMPLATE =
"color_template"
57 CONF_HS_ACTION =
"set_hs"
58 CONF_HS_TEMPLATE =
"hs_template"
59 CONF_RGB_ACTION =
"set_rgb"
60 CONF_RGB_TEMPLATE =
"rgb_template"
61 CONF_RGBW_ACTION =
"set_rgbw"
62 CONF_RGBW_TEMPLATE =
"rgbw_template"
63 CONF_RGBWW_ACTION =
"set_rgbww"
64 CONF_RGBWW_TEMPLATE =
"rgbww_template"
65 CONF_EFFECT_ACTION =
"set_effect"
66 CONF_EFFECT_LIST_TEMPLATE =
"effect_list_template"
67 CONF_EFFECT_TEMPLATE =
"effect_template"
68 CONF_LEVEL_ACTION =
"set_level"
69 CONF_LEVEL_TEMPLATE =
"level_template"
70 CONF_MAX_MIREDS_TEMPLATE =
"max_mireds_template"
71 CONF_MIN_MIREDS_TEMPLATE =
"min_mireds_template"
72 CONF_OFF_ACTION =
"turn_off"
73 CONF_ON_ACTION =
"turn_on"
74 CONF_SUPPORTS_TRANSITION =
"supports_transition_template"
75 CONF_TEMPERATURE_ACTION =
"set_temperature"
76 CONF_TEMPERATURE_TEMPLATE =
"temperature_template"
77 CONF_WHITE_VALUE_ACTION =
"set_white_value"
78 CONF_WHITE_VALUE_TEMPLATE =
"white_value_template"
80 LIGHT_SCHEMA = vol.All(
81 cv.deprecated(CONF_ENTITY_ID),
84 vol.Exclusive(CONF_COLOR_ACTION,
"hs_legacy_action"): cv.SCRIPT_SCHEMA,
85 vol.Exclusive(CONF_COLOR_TEMPLATE,
"hs_legacy_template"): cv.template,
86 vol.Exclusive(CONF_HS_ACTION,
"hs_legacy_action"): cv.SCRIPT_SCHEMA,
87 vol.Exclusive(CONF_HS_TEMPLATE,
"hs_legacy_template"): cv.template,
88 vol.Optional(CONF_RGB_ACTION): cv.SCRIPT_SCHEMA,
89 vol.Optional(CONF_RGB_TEMPLATE): cv.template,
90 vol.Optional(CONF_RGBW_ACTION): cv.SCRIPT_SCHEMA,
91 vol.Optional(CONF_RGBW_TEMPLATE): cv.template,
92 vol.Optional(CONF_RGBWW_ACTION): cv.SCRIPT_SCHEMA,
93 vol.Optional(CONF_RGBWW_TEMPLATE): cv.template,
94 vol.Inclusive(CONF_EFFECT_ACTION,
"effect"): cv.SCRIPT_SCHEMA,
95 vol.Inclusive(CONF_EFFECT_LIST_TEMPLATE,
"effect"): cv.template,
96 vol.Inclusive(CONF_EFFECT_TEMPLATE,
"effect"): cv.template,
97 vol.Optional(CONF_ENTITY_ID): cv.entity_ids,
98 vol.Optional(CONF_FRIENDLY_NAME): cv.string,
99 vol.Optional(CONF_LEVEL_ACTION): cv.SCRIPT_SCHEMA,
100 vol.Optional(CONF_LEVEL_TEMPLATE): cv.template,
101 vol.Optional(CONF_MAX_MIREDS_TEMPLATE): cv.template,
102 vol.Optional(CONF_MIN_MIREDS_TEMPLATE): cv.template,
103 vol.Required(CONF_OFF_ACTION): cv.SCRIPT_SCHEMA,
104 vol.Required(CONF_ON_ACTION): cv.SCRIPT_SCHEMA,
105 vol.Optional(CONF_SUPPORTS_TRANSITION): cv.template,
106 vol.Optional(CONF_TEMPERATURE_ACTION): cv.SCRIPT_SCHEMA,
107 vol.Optional(CONF_TEMPERATURE_TEMPLATE): cv.template,
108 vol.Optional(CONF_UNIQUE_ID): cv.string,
109 vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
111 ).extend(TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY.schema),
114 PLATFORM_SCHEMA = vol.All(
116 cv.removed(CONF_WHITE_VALUE_ACTION),
117 cv.removed(CONF_WHITE_VALUE_TEMPLATE),
118 LIGHT_PLATFORM_SCHEMA.extend(
119 {vol.Required(CONF_LIGHTS): cv.schema_with_slug_keys(LIGHT_SCHEMA)}
125 """Create the Template Lights."""
128 for object_id, entity_config
in config[CONF_LIGHTS].items():
130 unique_id = entity_config.get(CONF_UNIQUE_ID)
147 async_add_entities: AddEntitiesCallback,
148 discovery_info: DiscoveryInfoType |
None =
None,
150 """Set up the template lights."""
155 """Representation of a templated Light, including dimmable."""
157 _attr_should_poll =
False
166 """Initialize the light."""
168 hass, config=config, fallback_name=object_id, unique_id=unique_id
171 ENTITY_ID_FORMAT, object_id, hass=hass
174 self.
_template_template = config.get(CONF_VALUE_TEMPLATE)
178 if (level_action := config.get(CONF_LEVEL_ACTION))
is not None:
182 if (temperature_action := config.get(CONF_TEMPERATURE_ACTION))
is not None:
184 hass, temperature_action, friendly_name, DOMAIN
188 if (color_action := config.get(CONF_COLOR_ACTION))
is not None:
192 if (hs_action := config.get(CONF_HS_ACTION))
is not None:
196 if (rgb_action := config.get(CONF_RGB_ACTION))
is not None:
200 if (rgbw_action := config.get(CONF_RGBW_ACTION))
is not None:
204 if (rgbww_action := config.get(CONF_RGBWW_ACTION))
is not None:
208 if (effect_action := config.get(CONF_EFFECT_ACTION))
is not None:
231 color_modes = {ColorMode.ONOFF}
233 color_modes.add(ColorMode.BRIGHTNESS)
235 color_modes.add(ColorMode.COLOR_TEMP)
237 color_modes.add(ColorMode.HS)
239 color_modes.add(ColorMode.HS)
241 color_modes.add(ColorMode.RGB)
243 color_modes.add(ColorMode.RGBW)
245 color_modes.add(ColorMode.RGBWW)
261 """Return the brightness of the light."""
266 """Return the CT color value in mireds."""
271 """Return the max mireds value in mireds."""
275 return super().max_mireds
279 """Return the min mireds value in mireds."""
283 return super().min_mireds
287 """Return the hue and saturation color value [float, float]."""
292 """Return the rgb color value."""
297 """Return the rgbw color value."""
302 """Return the rgbww color value."""
307 """Return the effect."""
312 """Return the effect list."""
317 """Return current color mode."""
322 """Flag supported color modes."""
327 """Return true if device is on."""
332 """Set up templates."""
343 none_on_template_error=
True,
347 "_max_mireds_template",
351 none_on_template_error=
True,
355 "_min_mireds_template",
359 none_on_template_error=
True,
367 none_on_template_error=
True,
375 none_on_template_error=
True,
383 none_on_template_error=
True,
391 none_on_template_error=
True,
399 none_on_template_error=
True,
407 none_on_template_error=
True,
415 none_on_template_error=
True,
423 none_on_template_error=
True,
427 "_supports_transition_template",
431 none_on_template_error=
True,
436 """Turn the light on."""
437 optimistic_set =
False
441 optimistic_set =
True
443 if self.
_level_template_level_template
is None and ATTR_BRIGHTNESS
in kwargs:
445 "Optimistically setting brightness to %s", kwargs[ATTR_BRIGHTNESS]
447 self.
_brightness_brightness = kwargs[ATTR_BRIGHTNESS]
448 optimistic_set =
True
452 "Optimistically setting color temperature to %s",
453 kwargs[ATTR_COLOR_TEMP],
465 optimistic_set =
True
470 and ATTR_HS_COLOR
in kwargs
473 "Optimistically setting hs color to %s",
474 kwargs[ATTR_HS_COLOR],
477 self.
_hs_color_hs_color = kwargs[ATTR_HS_COLOR]
486 optimistic_set =
True
488 if self.
_rgb_template_rgb_template
is None and ATTR_RGB_COLOR
in kwargs:
490 "Optimistically setting rgb color to %s",
491 kwargs[ATTR_RGB_COLOR],
494 self.
_rgb_color_rgb_color = kwargs[ATTR_RGB_COLOR]
503 optimistic_set =
True
505 if self.
_rgbw_template_rgbw_template
is None and ATTR_RGBW_COLOR
in kwargs:
507 "Optimistically setting rgbw color to %s",
508 kwargs[ATTR_RGBW_COLOR],
511 self.
_rgbw_color_rgbw_color = kwargs[ATTR_RGBW_COLOR]
520 optimistic_set =
True
522 if self.
_rgbww_template_rgbww_template
is None and ATTR_RGBWW_COLOR
in kwargs:
524 "Optimistically setting rgbww color to %s",
525 kwargs[ATTR_RGBWW_COLOR],
528 self.
_rgbww_color_rgbww_color = kwargs[ATTR_RGBWW_COLOR]
537 optimistic_set =
True
541 if ATTR_BRIGHTNESS
in kwargs:
542 common_params[
"brightness"] = kwargs[ATTR_BRIGHTNESS]
545 common_params[
"transition"] = kwargs[ATTR_TRANSITION]
548 common_params[
"color_temp"] = kwargs[ATTR_COLOR_TEMP]
552 run_variables=common_params,
556 effect = kwargs[ATTR_EFFECT]
559 "Received invalid effect: %s for entity %s. Expected one of: %s",
566 common_params[
"effect"] = effect
571 elif ATTR_HS_COLOR
in kwargs
and self.
_color_script_color_script:
572 hs_value = kwargs[ATTR_HS_COLOR]
573 common_params[
"hs"] = hs_value
574 common_params[
"h"] =
int(hs_value[0])
575 common_params[
"s"] =
int(hs_value[1])
580 elif ATTR_HS_COLOR
in kwargs
and self.
_hs_script_hs_script:
581 hs_value = kwargs[ATTR_HS_COLOR]
582 common_params[
"hs"] = hs_value
583 common_params[
"h"] =
int(hs_value[0])
584 common_params[
"s"] =
int(hs_value[1])
589 elif ATTR_RGBWW_COLOR
in kwargs
and self.
_rgbww_script_rgbww_script:
590 rgbww_value = kwargs[ATTR_RGBWW_COLOR]
591 common_params[
"rgbww"] = rgbww_value
592 common_params[
"rgb"] = (
597 common_params[
"r"] =
int(rgbww_value[0])
598 common_params[
"g"] =
int(rgbww_value[1])
599 common_params[
"b"] =
int(rgbww_value[2])
600 common_params[
"cw"] =
int(rgbww_value[3])
601 common_params[
"ww"] =
int(rgbww_value[4])
606 elif ATTR_RGBW_COLOR
in kwargs
and self.
_rgbw_script_rgbw_script:
607 rgbw_value = kwargs[ATTR_RGBW_COLOR]
608 common_params[
"rgbw"] = rgbw_value
609 common_params[
"rgb"] = (
614 common_params[
"r"] =
int(rgbw_value[0])
615 common_params[
"g"] =
int(rgbw_value[1])
616 common_params[
"b"] =
int(rgbw_value[2])
617 common_params[
"w"] =
int(rgbw_value[3])
622 elif ATTR_RGB_COLOR
in kwargs
and self.
_rgb_script_rgb_script:
623 rgb_value = kwargs[ATTR_RGB_COLOR]
624 common_params[
"rgb"] = rgb_value
625 common_params[
"r"] =
int(rgb_value[0])
626 common_params[
"g"] =
int(rgb_value[1])
627 common_params[
"b"] =
int(rgb_value[2])
632 elif ATTR_BRIGHTNESS
in kwargs
and self.
_level_script_level_script:
645 """Turn the light off."""
649 run_variables={
"transition": kwargs[ATTR_TRANSITION]},
660 """Update the brightness from the template."""
662 if brightness
in (
None,
"None",
""):
665 if 0 <=
int(brightness) <= 255:
669 "Received invalid brightness : %s for entity %s. Expected: 0-255",
676 "Template must supply an integer brightness from 0-255, or 'None'"
682 """Update the effect list from the template."""
683 if effect_list
in (
None,
"None",
""):
687 if not isinstance(effect_list, list):
690 "Received invalid effect list: %s for entity %s. Expected list of"
699 if len(effect_list) == 0:
707 """Update the effect from the template."""
708 if effect
in (
None,
"None",
""):
714 "Received invalid effect: %s for entity %s. Expected one of: %s",
726 """Update the state from the template."""
727 if isinstance(result, TemplateError):
734 if isinstance(result, bool):
735 self.
_state_state = result
738 state =
str(result).lower()
739 if state
in _VALID_STATES:
740 self.
_state_state = state
in (
"true", STATE_ON)
744 "Received invalid light is_on state: %s for entity %s. Expected: %s",
747 ", ".join(_VALID_STATES),
753 """Update the temperature from the template."""
755 if render
in (
None,
"None",
""):
758 temperature =
int(render)
764 "Received invalid color temperature : %s for entity %s."
775 "Template must supply an integer temperature within the range for"
776 " this light, or 'None'"
783 """Update the color from the template."""
789 if isinstance(render, str):
790 if render
in (
"None",
""):
794 float, render.replace(
"(",
"").replace(
")",
"").split(
",", 1)
796 elif isinstance(render, (list, tuple))
and len(render) == 2:
797 h_str, s_str = render
801 and s_str
is not None
802 and isinstance(h_str, (int, float))
803 and isinstance(s_str, (int, float))
804 and 0 <= h_str <= 360
805 and 0 <= s_str <= 100
808 elif h_str
is not None and s_str
is not None:
811 "Received invalid hs_color : (%s, %s) for entity %s. Expected:"
828 """Update the color from the template."""
833 r_int = g_int = b_int =
None
834 if isinstance(render, str):
835 if render
in (
"None",
""):
838 cleanup_char = [
"(",
")",
"[",
"]",
" "]
839 for char
in cleanup_char:
840 render = render.replace(char,
"")
841 r_int, g_int, b_int = map(int, render.split(
",", 3))
842 elif isinstance(render, (list, tuple))
and len(render) == 3:
843 r_int, g_int, b_int = render
846 value
is not None and isinstance(value, (int, float))
and 0 <= value <= 255
847 for value
in (r_int, g_int, b_int)
849 self.
_rgb_color_rgb_color = (r_int, g_int, b_int)
851 isinstance(value, (int, float))
and not 0 <= value <= 255
852 for value
in (r_int, g_int, b_int)
855 "Received invalid rgb_color : (%s, %s, %s) for entity %s. Expected: (0-255, 0-255, 0-255)",
864 "Received invalid rgb_color : (%s) for entity %s",
873 """Update the color from the template."""
878 r_int = g_int = b_int = w_int =
None
879 if isinstance(render, str):
880 if render
in (
"None",
""):
883 cleanup_char = [
"(",
")",
"[",
"]",
" "]
884 for char
in cleanup_char:
885 render = render.replace(char,
"")
886 r_int, g_int, b_int, w_int = map(int, render.split(
",", 4))
887 elif isinstance(render, (list, tuple))
and len(render) == 4:
888 r_int, g_int, b_int, w_int = render
891 value
is not None and isinstance(value, (int, float))
and 0 <= value <= 255
892 for value
in (r_int, g_int, b_int, w_int)
894 self.
_rgbw_color_rgbw_color = (r_int, g_int, b_int, w_int)
896 isinstance(value, (int, float))
and not 0 <= value <= 255
897 for value
in (r_int, g_int, b_int, w_int)
900 "Received invalid rgb_color : (%s, %s, %s, %s) for entity %s. Expected: (0-255, 0-255, 0-255, 0-255)",
910 "Received invalid rgb_color : (%s) for entity %s",
919 """Update the color from the template."""
924 r_int = g_int = b_int = cw_int = ww_int =
None
925 if isinstance(render, str):
926 if render
in (
"None",
""):
929 cleanup_char = [
"(",
")",
"[",
"]",
" "]
930 for char
in cleanup_char:
931 render = render.replace(char,
"")
932 r_int, g_int, b_int, cw_int, ww_int = map(int, render.split(
",", 5))
933 elif isinstance(render, (list, tuple))
and len(render) == 5:
934 r_int, g_int, b_int, cw_int, ww_int = render
937 value
is not None and isinstance(value, (int, float))
and 0 <= value <= 255
938 for value
in (r_int, g_int, b_int, cw_int, ww_int)
940 self.
_rgbww_color_rgbww_color = (r_int, g_int, b_int, cw_int, ww_int)
942 isinstance(value, (int, float))
and not 0 <= value <= 255
943 for value
in (r_int, g_int, b_int, cw_int, ww_int)
946 "Received invalid rgb_color : (%s, %s, %s, %s, %s) for entity %s. Expected: (0-255, 0-255, 0-255, 0-255)",
957 "Received invalid rgb_color : (%s) for entity %s",
966 """Update the max mireds from the template."""
969 if render
in (
None,
"None",
""):
975 "Template must supply an integer temperature within the range for"
976 " this light, or 'None'"
982 """Update the min mireds from the template."""
984 if render
in (
None,
"None",
""):
990 "Template must supply an integer temperature within the range for"
991 " this light, or 'None'"
997 """Update the supports transition from the template."""
998 if render
in (
None,
"None",
""):
_supports_transition_template
None async_turn_off(self, **Any kwargs)
int|None color_temp(self)
def _update_min_mireds(self, render)
def _update_state(self, result)
tuple[float, float]|None hs_color(self)
None _async_setup_templates(self)
def _update_effect_list(self, effect_list)
def __init__(self, hass, object_id, config, unique_id)
tuple[int, int, int]|None rgb_color(self)
def supported_color_modes(self)
def _update_effect(self, effect)
list[str]|None effect_list(self)
def _update_temperature(self, render)
def _update_max_mireds(self, render)
def _update_supports_transition(self, render)
tuple[int, int, int, int]|None rgbw_color(self)
None async_turn_on(self, **Any kwargs)
int|None brightness(self)
tuple[int, int, int, int, int]|None rgbww_color(self)
def _update_rgbww(self, render)
def _update_rgbw(self, render)
def _update_hs(self, render)
def _update_brightness(self, brightness)
def _update_rgb(self, render)
None _update_state(self, str|TemplateError result)
None async_run_script(self, Script script, *_VarsType|None run_variables=None, Context|None context=None)
None add_template_attribute(self, str attribute, Template template, Callable[[Any], Any]|None validator=None, Callable[[Any], None]|None on_update=None, bool none_on_template_error=False)
None async_write_ha_state(self)
set[ColorMode] filter_supported_color_modes(Iterable[ColorMode] color_modes)
def _async_create_entities(hass, config)
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
dict[str, Any] rewrite_common_legacy_to_modern_conf(HomeAssistant hass, dict[str, Any] entity_cfg, dict[str, str]|None extra_legacy_fields=None)
str async_generate_entity_id(str entity_id_format, str|None name, Iterable[str]|None current_ids=None, HomeAssistant|None hass=None)