mirror of
https://github.com/esphome/esphome.git
synced 2026-09-28 15:30:21 +00:00
[light][lvgl] Add color names for light states (#19712)
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
"""Standard CSS named colors, as 0xRRGGBB values."""
|
||||
|
||||
CSS_COLORS: dict[str, int] = {
|
||||
"aliceblue": 0xF0F8FF,
|
||||
"antiquewhite": 0xFAEBD7,
|
||||
"aqua": 0x00FFFF,
|
||||
"aquamarine": 0x7FFFD4,
|
||||
"azure": 0xF0FFFF,
|
||||
"beige": 0xF5F5DC,
|
||||
"bisque": 0xFFE4C4,
|
||||
"black": 0x000000,
|
||||
"blanchedalmond": 0xFFEBCD,
|
||||
"blue": 0x0000FF,
|
||||
"blueviolet": 0x8A2BE2,
|
||||
"brown": 0xA52A2A,
|
||||
"burlywood": 0xDEB887,
|
||||
"cadetblue": 0x5F9EA0,
|
||||
"chartreuse": 0x7FFF00,
|
||||
"chocolate": 0xD2691E,
|
||||
"coral": 0xFF7F50,
|
||||
"cornflowerblue": 0x6495ED,
|
||||
"cornsilk": 0xFFF8DC,
|
||||
"crimson": 0xDC143C,
|
||||
"cyan": 0x00FFFF,
|
||||
"darkblue": 0x00008B,
|
||||
"darkcyan": 0x008B8B,
|
||||
"darkgoldenrod": 0xB8860B,
|
||||
"darkgray": 0xA9A9A9,
|
||||
"darkgreen": 0x006400,
|
||||
"darkgrey": 0xA9A9A9,
|
||||
"darkkhaki": 0xBDB76B,
|
||||
"darkmagenta": 0x8B008B,
|
||||
"darkolivegreen": 0x556B2F,
|
||||
"darkorange": 0xFF8C00,
|
||||
"darkorchid": 0x9932CC,
|
||||
"darkred": 0x8B0000,
|
||||
"darksalmon": 0xE9967A,
|
||||
"darkseagreen": 0x8FBC8F,
|
||||
"darkslateblue": 0x483D8B,
|
||||
"darkslategray": 0x2F4F4F,
|
||||
"darkslategrey": 0x2F4F4F,
|
||||
"darkturquoise": 0x00CED1,
|
||||
"darkviolet": 0x9400D3,
|
||||
"deeppink": 0xFF1493,
|
||||
"deepskyblue": 0x00BFFF,
|
||||
"dimgray": 0x696969,
|
||||
"dimgrey": 0x696969,
|
||||
"dodgerblue": 0x1E90FF,
|
||||
"firebrick": 0xB22222,
|
||||
"floralwhite": 0xFFFAF0,
|
||||
"forestgreen": 0x228B22,
|
||||
"fuchsia": 0xFF00FF,
|
||||
"gainsboro": 0xDCDCDC,
|
||||
"ghostwhite": 0xF8F8FF,
|
||||
"goldenrod": 0xDAA520,
|
||||
"gold": 0xFFD700,
|
||||
"gray": 0x808080,
|
||||
"green": 0x008000,
|
||||
"greenyellow": 0xADFF2F,
|
||||
"grey": 0x808080,
|
||||
"honeydew": 0xF0FFF0,
|
||||
"hotpink": 0xFF69B4,
|
||||
"indianred": 0xCD5C5C,
|
||||
"indigo": 0x4B0082,
|
||||
"ivory": 0xFFFFF0,
|
||||
"khaki": 0xF0E68C,
|
||||
"lavenderblush": 0xFFF0F5,
|
||||
"lavender": 0xE6E6FA,
|
||||
"lawngreen": 0x7CFC00,
|
||||
"lemonchiffon": 0xFFFACD,
|
||||
"lightblue": 0xADD8E6,
|
||||
"lightcoral": 0xF08080,
|
||||
"lightcyan": 0xE0FFFF,
|
||||
"lightgoldenrodyellow": 0xFAFAD2,
|
||||
"lightgray": 0xD3D3D3,
|
||||
"lightgreen": 0x90EE90,
|
||||
"lightgrey": 0xD3D3D3,
|
||||
"lightpink": 0xFFB6C1,
|
||||
"lightsalmon": 0xFFA07A,
|
||||
"lightseagreen": 0x20B2AA,
|
||||
"lightskyblue": 0x87CEFA,
|
||||
"lightslategray": 0x778899,
|
||||
"lightslategrey": 0x778899,
|
||||
"lightsteelblue": 0xB0C4DE,
|
||||
"lightyellow": 0xFFFFE0,
|
||||
"lime": 0x00FF00,
|
||||
"limegreen": 0x32CD32,
|
||||
"linen": 0xFAF0E6,
|
||||
"magenta": 0xFF00FF,
|
||||
"maroon": 0x800000,
|
||||
"mediumaquamarine": 0x66CDAA,
|
||||
"mediumblue": 0x0000CD,
|
||||
"mediumorchid": 0xBA55D3,
|
||||
"mediumpurple": 0x9370DB,
|
||||
"mediumseagreen": 0x3CB371,
|
||||
"mediumslateblue": 0x7B68EE,
|
||||
"mediumspringgreen": 0x00FA9A,
|
||||
"mediumturquoise": 0x48D1CC,
|
||||
"mediumvioletred": 0xC71585,
|
||||
"midnightblue": 0x191970,
|
||||
"mintcream": 0xF5FFFA,
|
||||
"mistyrose": 0xFFE4E1,
|
||||
"moccasin": 0xFFE4B5,
|
||||
"navajowhite": 0xFFDEAD,
|
||||
"navy": 0x000080,
|
||||
"oldlace": 0xFDF5E6,
|
||||
"olive": 0x808000,
|
||||
"olivedrab": 0x6B8E23,
|
||||
"orange": 0xFFA500,
|
||||
"orangered": 0xFF4500,
|
||||
"orchid": 0xDA70D6,
|
||||
"palegoldenrod": 0xEEE8AA,
|
||||
"palegreen": 0x98FB98,
|
||||
"paleturquoise": 0xAFEEEE,
|
||||
"palevioletred": 0xDB7093,
|
||||
"papayawhip": 0xFFEFD5,
|
||||
"peachpuff": 0xFFDAB9,
|
||||
"peru": 0xCD853F,
|
||||
"pink": 0xFFC0CB,
|
||||
"plum": 0xDDA0DD,
|
||||
"powderblue": 0xB0E0E6,
|
||||
"purple": 0x800080,
|
||||
"rebeccapurple": 0x663399,
|
||||
"red": 0xFF0000,
|
||||
"rosybrown": 0xBC8F8F,
|
||||
"royalblue": 0x4169E1,
|
||||
"saddlebrown": 0x8B4513,
|
||||
"salmon": 0xFA8072,
|
||||
"sandybrown": 0xF4A460,
|
||||
"seagreen": 0x2E8B57,
|
||||
"seashell": 0xFFF5EE,
|
||||
"sienna": 0xA0522D,
|
||||
"silver": 0xC0C0C0,
|
||||
"skyblue": 0x87CEEB,
|
||||
"slateblue": 0x6A5ACD,
|
||||
"slategray": 0x708090,
|
||||
"slategrey": 0x708090,
|
||||
"snow": 0xFFFAFA,
|
||||
"springgreen": 0x00FF7F,
|
||||
"steelblue": 0x4682B4,
|
||||
"tan": 0xD2B48C,
|
||||
"teal": 0x008080,
|
||||
"thistle": 0xD8BFD8,
|
||||
"tomato": 0xFF6347,
|
||||
"turquoise": 0x40E0D0,
|
||||
"violet": 0xEE82EE,
|
||||
"wheat": 0xF5DEB3,
|
||||
"white": 0xFFFFFF,
|
||||
"whitesmoke": 0xF5F5F5,
|
||||
"yellow": 0xFFFF00,
|
||||
"yellowgreen": 0x9ACD32,
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
from collections.abc import Callable
|
||||
import logging
|
||||
from typing import Any, NamedTuple
|
||||
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.const.css_colors import CSS_COLORS
|
||||
from esphome.config import path_context
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
@@ -10,6 +12,7 @@ from esphome.const import (
|
||||
CONF_BRIGHTNESS,
|
||||
CONF_BRIGHTNESS_LIMITS,
|
||||
CONF_COLD_WHITE,
|
||||
CONF_COLOR,
|
||||
CONF_COLOR_BRIGHTNESS,
|
||||
CONF_COLOR_MODE,
|
||||
CONF_COLOR_TEMPERATURE,
|
||||
@@ -46,6 +49,8 @@ from .types import (
|
||||
ToggleAction,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_INCLUDE_NONE = "include_none"
|
||||
|
||||
_STATE_ON_OFF = cv.one_of("ON", "OFF", upper=True)
|
||||
@@ -141,6 +146,50 @@ LIGHT_STATE_FIELDS: tuple[LightStateField, ...] = (
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@schema_extractor("one_of")
|
||||
def validate_color(value: Any) -> str | int:
|
||||
"""Validate a CSS color name or a 0xRRGGBB value."""
|
||||
if value == SCHEMA_EXTRACT:
|
||||
return ["CSS color name", "hex color value"]
|
||||
if isinstance(value, int) or (
|
||||
isinstance(value, str) and value.lower().startswith("0x")
|
||||
):
|
||||
return cv.hex_int_range(0, 0xFFFFFF)(value)
|
||||
return cv.one_of(*CSS_COLORS, lower=True)(value)
|
||||
|
||||
|
||||
COLOR_SCHEMA: dict[cv.Optional, Any] = {cv.Optional(CONF_COLOR): validate_color}
|
||||
|
||||
|
||||
def color_to_rgb(config: ConfigType) -> ConfigType:
|
||||
"""Replace a `color` CSS name or 0xRRGGBB value with red, green and blue values.
|
||||
|
||||
The light scales its color so the brightest channel is at full level, so a dark
|
||||
color is given as a full-level color plus a color brightness.
|
||||
"""
|
||||
if (color := config.pop(CONF_COLOR, None)) is None:
|
||||
return config
|
||||
if any(key in config for key in (CONF_RED, CONF_GREEN, CONF_BLUE)):
|
||||
raise cv.Invalid(
|
||||
f"'{CONF_COLOR}' cannot be used with '{CONF_RED}', '{CONF_GREEN}' or '{CONF_BLUE}'"
|
||||
)
|
||||
rgb = color if isinstance(color, int) else CSS_COLORS[color]
|
||||
channels = (rgb >> 16 & 0xFF, rgb >> 8 & 0xFF, rgb & 0xFF)
|
||||
peak = max(channels)
|
||||
if CONF_COLOR_BRIGHTNESS not in config:
|
||||
config[CONF_COLOR_BRIGHTNESS] = peak / 255
|
||||
elif peak < 0xFF:
|
||||
_LOGGER.warning(
|
||||
"'%s' overrides the brightness of color '%s'",
|
||||
CONF_COLOR_BRIGHTNESS,
|
||||
f"0x{color:06X}" if isinstance(color, int) else color,
|
||||
)
|
||||
for key, value in zip((CONF_RED, CONF_GREEN, CONF_BLUE), channels, strict=True):
|
||||
config[key] = value / peak if peak else 0.0
|
||||
return config
|
||||
|
||||
|
||||
LIGHT_STATE_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(field.conf_key): (
|
||||
@@ -148,7 +197,8 @@ LIGHT_STATE_SCHEMA = cv.Schema(
|
||||
)
|
||||
for field in LIGHT_STATE_FIELDS
|
||||
}
|
||||
)
|
||||
).extend(COLOR_SCHEMA)
|
||||
LIGHT_STATE_SCHEMA.add_extra(color_to_rgb)
|
||||
|
||||
LIGHT_CONTROL_ACTION_SCHEMA = LIGHT_STATE_SCHEMA.extend(
|
||||
{
|
||||
@@ -405,7 +455,8 @@ LIGHT_ADDRESSABLE_SET_ACTION_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_BLUE): cv.templatable(cv.percentage),
|
||||
cv.Optional(CONF_WHITE): cv.templatable(cv.percentage),
|
||||
}
|
||||
)
|
||||
).extend(COLOR_SCHEMA)
|
||||
LIGHT_ADDRESSABLE_SET_ACTION_SCHEMA.add_extra(color_to_rgb)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
|
||||
@@ -4,6 +4,7 @@ from typing import Any
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import image
|
||||
from esphome.components.color import CONF_HEX, ColorStruct, from_rgbw
|
||||
from esphome.components.const.css_colors import CSS_COLORS
|
||||
from esphome.components.font import Font
|
||||
from esphome.components.image import Image_
|
||||
import esphome.config_validation as cv
|
||||
@@ -64,170 +65,19 @@ opacity = LValidator(
|
||||
animatable=True,
|
||||
)
|
||||
|
||||
COLOR_NAMES = {
|
||||
"aliceblue": 0xF0F8FF,
|
||||
"antiquewhite": 0xFAEBD7,
|
||||
"aqua": 0x00FFFF,
|
||||
"aquamarine": 0x7FFFD4,
|
||||
"azure": 0xF0FFFF,
|
||||
"beige": 0xF5F5DC,
|
||||
"bisque": 0xFFE4C4,
|
||||
"black": 0x000000,
|
||||
"blanchedalmond": 0xFFEBCD,
|
||||
"blue": 0x0000FF,
|
||||
"blueviolet": 0x8A2BE2,
|
||||
"brown": 0xA52A2A,
|
||||
"burlywood": 0xDEB887,
|
||||
"cadetblue": 0x5F9EA0,
|
||||
"chartreuse": 0x7FFF00,
|
||||
"chocolate": 0xD2691E,
|
||||
"coral": 0xFF7F50,
|
||||
"cornflowerblue": 0x6495ED,
|
||||
"cornsilk": 0xFFF8DC,
|
||||
"crimson": 0xDC143C,
|
||||
"cyan": 0x00FFFF,
|
||||
"darkblue": 0x00008B,
|
||||
"darkcyan": 0x008B8B,
|
||||
"darkgoldenrod": 0xB8860B,
|
||||
"darkgray": 0xA9A9A9,
|
||||
"darkgreen": 0x006400,
|
||||
"darkgrey": 0xA9A9A9,
|
||||
"darkkhaki": 0xBDB76B,
|
||||
"darkmagenta": 0x8B008B,
|
||||
"darkolivegreen": 0x556B2F,
|
||||
"darkorange": 0xFF8C00,
|
||||
"darkorchid": 0x9932CC,
|
||||
"darkred": 0x8B0000,
|
||||
"darksalmon": 0xE9967A,
|
||||
"darkseagreen": 0x8FBC8F,
|
||||
"darkslateblue": 0x483D8B,
|
||||
"darkslategray": 0x2F4F4F,
|
||||
"darkslategrey": 0x2F4F4F,
|
||||
"darkturquoise": 0x00CED1,
|
||||
"darkviolet": 0x9400D3,
|
||||
"deeppink": 0xFF1493,
|
||||
"deepskyblue": 0x00BFFF,
|
||||
"dimgray": 0x696969,
|
||||
"dimgrey": 0x696969,
|
||||
"dodgerblue": 0x1E90FF,
|
||||
"firebrick": 0xB22222,
|
||||
"floralwhite": 0xFFFAF0,
|
||||
"forestgreen": 0x228B22,
|
||||
"fuchsia": 0xFF00FF,
|
||||
"gainsboro": 0xDCDCDC,
|
||||
"ghostwhite": 0xF8F8FF,
|
||||
"goldenrod": 0xDAA520,
|
||||
"gold": 0xFFD700,
|
||||
"gray": 0x808080,
|
||||
"green": 0x008000,
|
||||
"greenyellow": 0xADFF2F,
|
||||
"grey": 0x808080,
|
||||
"honeydew": 0xF0FFF0,
|
||||
"hotpink": 0xFF69B4,
|
||||
"indianred": 0xCD5C5C,
|
||||
"indigo": 0x4B0082,
|
||||
"ivory": 0xFFFFF0,
|
||||
"khaki": 0xF0E68C,
|
||||
"lavenderblush": 0xFFF0F5,
|
||||
"lavender": 0xE6E6FA,
|
||||
"lawngreen": 0x7CFC00,
|
||||
"lemonchiffon": 0xFFFACD,
|
||||
"lightblue": 0xADD8E6,
|
||||
"lightcoral": 0xF08080,
|
||||
"lightcyan": 0xE0FFFF,
|
||||
"lightgoldenrodyellow": 0xFAFAD2,
|
||||
"lightgray": 0xD3D3D3,
|
||||
"lightgreen": 0x90EE90,
|
||||
"lightgrey": 0xD3D3D3,
|
||||
"lightpink": 0xFFB6C1,
|
||||
"lightsalmon": 0xFFA07A,
|
||||
"lightseagreen": 0x20B2AA,
|
||||
"lightskyblue": 0x87CEFA,
|
||||
"lightslategray": 0x778899,
|
||||
"lightslategrey": 0x778899,
|
||||
"lightsteelblue": 0xB0C4DE,
|
||||
"lightyellow": 0xFFFFE0,
|
||||
"lime": 0x00FF00,
|
||||
"limegreen": 0x32CD32,
|
||||
"linen": 0xFAF0E6,
|
||||
"magenta": 0xFF00FF,
|
||||
"maroon": 0x800000,
|
||||
"mediumaquamarine": 0x66CDAA,
|
||||
"mediumblue": 0x0000CD,
|
||||
"mediumorchid": 0xBA55D3,
|
||||
"mediumpurple": 0x9370DB,
|
||||
"mediumseagreen": 0x3CB371,
|
||||
"mediumslateblue": 0x7B68EE,
|
||||
"mediumspringgreen": 0x00FA9A,
|
||||
"mediumturquoise": 0x48D1CC,
|
||||
"mediumvioletred": 0xC71585,
|
||||
"midnightblue": 0x191970,
|
||||
"mintcream": 0xF5FFFA,
|
||||
"mistyrose": 0xFFE4E1,
|
||||
"moccasin": 0xFFE4B5,
|
||||
"navajowhite": 0xFFDEAD,
|
||||
"navy": 0x000080,
|
||||
"oldlace": 0xFDF5E6,
|
||||
"olive": 0x808000,
|
||||
"olivedrab": 0x6B8E23,
|
||||
"orange": 0xFFA500,
|
||||
"orangered": 0xFF4500,
|
||||
"orchid": 0xDA70D6,
|
||||
"palegoldenrod": 0xEEE8AA,
|
||||
"palegreen": 0x98FB98,
|
||||
"paleturquoise": 0xAFEEEE,
|
||||
"palevioletred": 0xDB7093,
|
||||
"papayawhip": 0xFFEFD5,
|
||||
"peachpuff": 0xFFDAB9,
|
||||
"peru": 0xCD853F,
|
||||
"pink": 0xFFC0CB,
|
||||
"plum": 0xDDA0DD,
|
||||
"powderblue": 0xB0E0E6,
|
||||
"purple": 0x800080,
|
||||
"rebeccapurple": 0x663399,
|
||||
"red": 0xFF0000,
|
||||
"rosybrown": 0xBC8F8F,
|
||||
"royalblue": 0x4169E1,
|
||||
"saddlebrown": 0x8B4513,
|
||||
"salmon": 0xFA8072,
|
||||
"sandybrown": 0xF4A460,
|
||||
"seagreen": 0x2E8B57,
|
||||
"seashell": 0xFFF5EE,
|
||||
"sienna": 0xA0522D,
|
||||
"silver": 0xC0C0C0,
|
||||
"skyblue": 0x87CEEB,
|
||||
"slateblue": 0x6A5ACD,
|
||||
"slategray": 0x708090,
|
||||
"slategrey": 0x708090,
|
||||
"snow": 0xFFFAFA,
|
||||
"springgreen": 0x00FF7F,
|
||||
"steelblue": 0x4682B4,
|
||||
"tan": 0xD2B48C,
|
||||
"teal": 0x008080,
|
||||
"thistle": 0xD8BFD8,
|
||||
"tomato": 0xFF6347,
|
||||
"turquoise": 0x40E0D0,
|
||||
"violet": 0xEE82EE,
|
||||
"wheat": 0xF5DEB3,
|
||||
"white": 0xFFFFFF,
|
||||
"whitesmoke": 0xF5F5F5,
|
||||
"yellow": 0xFFFF00,
|
||||
"yellowgreen": 0x9ACD32,
|
||||
}
|
||||
|
||||
|
||||
@schema_extractor("one_of")
|
||||
def color(value):
|
||||
if value == SCHEMA_EXTRACT:
|
||||
return ["hex color value", "color ID"]
|
||||
return cv.Any(cv.int_, cv.one_of(*COLOR_NAMES, lower=True), cv.use_id(ColorStruct))(
|
||||
return cv.Any(cv.int_, cv.one_of(*CSS_COLORS, lower=True), cv.use_id(ColorStruct))(
|
||||
value
|
||||
)
|
||||
|
||||
|
||||
def get_component_colors(value):
|
||||
if isinstance(value, str) and value in COLOR_NAMES:
|
||||
value = COLOR_NAMES[value]
|
||||
if isinstance(value, str) and value in CSS_COLORS:
|
||||
value = CSS_COLORS[value]
|
||||
if isinstance(value, int):
|
||||
return value >> 16, value >> 8 & 0xFF, value & 0xFF
|
||||
if isinstance(value, ID):
|
||||
@@ -254,8 +104,8 @@ class LvColor(LValidator):
|
||||
)
|
||||
|
||||
def __getattr__(self, item):
|
||||
if item in COLOR_NAMES:
|
||||
return color_retmapper(COLOR_NAMES[item])
|
||||
if item in CSS_COLORS:
|
||||
return color_retmapper(CSS_COLORS[item])
|
||||
raise AttributeError(item)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
"""Tests for the light `color` option."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome import config_validation as cv
|
||||
from esphome.components.light.automation import (
|
||||
LIGHT_CONTROL_ACTION_SCHEMA,
|
||||
LIGHT_STATE_SCHEMA,
|
||||
)
|
||||
from esphome.const import (
|
||||
CONF_BLUE,
|
||||
CONF_COLOR_BRIGHTNESS,
|
||||
CONF_GREEN,
|
||||
CONF_ID,
|
||||
CONF_RED,
|
||||
)
|
||||
|
||||
LOGGER_NAME: str = "esphome.components.light.automation"
|
||||
|
||||
|
||||
def test_color_name_sets_rgb() -> None:
|
||||
result = LIGHT_STATE_SCHEMA({"color": "Tomato"})
|
||||
assert "color" not in result
|
||||
assert result[CONF_RED] == 1.0
|
||||
assert result[CONF_GREEN] == pytest.approx(0x63 / 0xFF)
|
||||
assert result[CONF_BLUE] == pytest.approx(0x47 / 0xFF)
|
||||
assert result[CONF_COLOR_BRIGHTNESS] == 1.0
|
||||
|
||||
|
||||
def test_color_name_in_control_action() -> None:
|
||||
result = LIGHT_CONTROL_ACTION_SCHEMA({CONF_ID: "test_light", "color": "blue"})
|
||||
assert (result[CONF_RED], result[CONF_GREEN], result[CONF_BLUE]) == (0, 0, 1.0)
|
||||
|
||||
|
||||
def test_unknown_color_name() -> None:
|
||||
with pytest.raises(cv.Invalid, match="notacolor"):
|
||||
LIGHT_STATE_SCHEMA({"color": "notacolor"})
|
||||
|
||||
|
||||
def test_color_name_conflicts_with_rgb() -> None:
|
||||
with pytest.raises(cv.Invalid, match="cannot be used with"):
|
||||
LIGHT_STATE_SCHEMA({"color": "red", CONF_GREEN: 0.5})
|
||||
|
||||
|
||||
def test_dark_color_sets_color_brightness() -> None:
|
||||
result = LIGHT_STATE_SCHEMA({"color": "darkred"})
|
||||
assert result[CONF_RED] == 1.0
|
||||
assert result[CONF_GREEN] == 0.0
|
||||
assert result[CONF_BLUE] == 0.0
|
||||
assert result[CONF_COLOR_BRIGHTNESS] == pytest.approx(0x8B / 0xFF)
|
||||
|
||||
|
||||
def test_black_sets_zero_color_brightness() -> None:
|
||||
result = LIGHT_STATE_SCHEMA({"color": "black"})
|
||||
assert result[CONF_COLOR_BRIGHTNESS] == 0.0
|
||||
assert (result[CONF_RED], result[CONF_GREEN], result[CONF_BLUE]) == (0, 0, 0)
|
||||
|
||||
|
||||
def test_explicit_color_brightness_wins(caplog: pytest.LogCaptureFixture) -> None:
|
||||
with caplog.at_level(logging.WARNING, logger=LOGGER_NAME):
|
||||
result = LIGHT_STATE_SCHEMA({"color": "darkred", CONF_COLOR_BRIGHTNESS: 0.25})
|
||||
assert result[CONF_COLOR_BRIGHTNESS] == 0.25
|
||||
assert "overrides the brightness of color 'darkred'" in caplog.text
|
||||
|
||||
|
||||
def test_explicit_color_brightness_full_color(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
with caplog.at_level(logging.WARNING, logger=LOGGER_NAME):
|
||||
result = LIGHT_STATE_SCHEMA({"color": "red", CONF_COLOR_BRIGHTNESS: 0.25})
|
||||
assert result[CONF_COLOR_BRIGHTNESS] == 0.25
|
||||
assert not [r for r in caplog.records if r.name == LOGGER_NAME]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [0x223344, "0x223344", "0X223344"])
|
||||
def test_hex_color(value: int | str) -> None:
|
||||
result = LIGHT_STATE_SCHEMA({"color": value})
|
||||
assert "color" not in result
|
||||
assert result[CONF_COLOR_BRIGHTNESS] == pytest.approx(0x44 / 0xFF)
|
||||
assert result[CONF_BLUE] == 1.0
|
||||
assert result[CONF_RED] == pytest.approx(0x22 / 0x44)
|
||||
assert result[CONF_GREEN] == pytest.approx(0x33 / 0x44)
|
||||
|
||||
|
||||
def test_hex_color_full_level() -> None:
|
||||
result = LIGHT_STATE_SCHEMA({"color": 0xFF8000})
|
||||
assert result[CONF_COLOR_BRIGHTNESS] == 1.0
|
||||
assert result[CONF_RED] == 1.0
|
||||
assert result[CONF_GREEN] == pytest.approx(0x80 / 0xFF)
|
||||
assert result[CONF_BLUE] == 0.0
|
||||
|
||||
|
||||
def test_hex_color_black() -> None:
|
||||
result = LIGHT_STATE_SCHEMA({"color": 0})
|
||||
assert result[CONF_COLOR_BRIGHTNESS] == 0.0
|
||||
assert (result[CONF_RED], result[CONF_GREEN], result[CONF_BLUE]) == (0, 0, 0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [0x1000000, -1, "0xGG", "0x1000000"])
|
||||
def test_hex_color_invalid(value: int | str) -> None:
|
||||
with pytest.raises(cv.Invalid):
|
||||
LIGHT_STATE_SCHEMA({"color": value})
|
||||
|
||||
|
||||
def test_hex_color_conflicts_with_rgb() -> None:
|
||||
with pytest.raises(cv.Invalid, match="cannot be used with"):
|
||||
LIGHT_STATE_SCHEMA({"color": 0x223344, CONF_RED: 0.5})
|
||||
|
||||
|
||||
def test_explicit_color_brightness_warning_names_hex_color(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
with caplog.at_level(logging.WARNING, logger=LOGGER_NAME):
|
||||
LIGHT_STATE_SCHEMA({"color": 0x223344, CONF_COLOR_BRIGHTNESS: 0.25})
|
||||
assert "overrides the brightness of color '0x223344'" in caplog.text
|
||||
@@ -85,6 +85,12 @@ esphome:
|
||||
red: 100%
|
||||
green: 100%
|
||||
blue: 1.0
|
||||
- light.turn_on:
|
||||
id: test_rgb_light
|
||||
color: Tomato
|
||||
- light.turn_on:
|
||||
id: test_rgb_light
|
||||
color: 0x223344
|
||||
- light.control:
|
||||
id: test_monochromatic_light
|
||||
state: on
|
||||
@@ -157,6 +163,17 @@ esphome:
|
||||
green: 100%
|
||||
blue: 0%
|
||||
transition_length: 1s
|
||||
- light.addressable_set:
|
||||
id: test_addressable_transition
|
||||
range_from: 0
|
||||
range_to: 4
|
||||
color: darkred
|
||||
- light.addressable_set:
|
||||
id: test_addressable_transition
|
||||
color: tomato
|
||||
- light.addressable_set:
|
||||
id: test_addressable_transition
|
||||
color: 0x223344
|
||||
|
||||
# Exercise light actions inside a trigger with non-empty Ts (number on_value
|
||||
# passes float).
|
||||
@@ -336,6 +353,15 @@ light:
|
||||
red: 100%
|
||||
green: 50%
|
||||
blue: 50%
|
||||
# Test initial_state: with a color name (a dark color also sets color_brightness)
|
||||
- platform: rgb
|
||||
id: test_rgb_light_initial_state_color
|
||||
name: RGB Light Initial State Color
|
||||
red: test_ledc_1
|
||||
green: test_ledc_2
|
||||
blue: test_ledc_3
|
||||
initial_state:
|
||||
color: darkred
|
||||
# Test initial_state: with every templatable field set via !lambda (color_mode is
|
||||
# the only field that isn't templatable, so it's the only one left as a literal)
|
||||
- platform: rgbww
|
||||
|
||||
Reference in New Issue
Block a user