mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 10:12:52 +00:00
Share the unique global name logic, emit the no-random marker symbol, test the color limits
This commit is contained in:
@@ -45,6 +45,7 @@ from esphome.cpp_generator import ( # noqa: F401
|
||||
static_const_array,
|
||||
static_function,
|
||||
templatable,
|
||||
unique_global_id,
|
||||
variable,
|
||||
with_local_variable,
|
||||
)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.config import iter_ids
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ALPHA,
|
||||
@@ -30,9 +29,8 @@ from esphome.const import (
|
||||
CONF_WHITE,
|
||||
CONF_WIDTH,
|
||||
)
|
||||
from esphome.core import CORE, ID
|
||||
from esphome.core import CORE
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.helpers import ensure_unique_string
|
||||
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
|
||||
from esphome.types import ConfigType
|
||||
from esphome.util import Registry
|
||||
@@ -494,7 +492,7 @@ async def addressable_color_wipe_effect_to_code(config, effect_id):
|
||||
int(round(color[CONF_BLUE] * color_brightness * 255)),
|
||||
int(round(color[CONF_WHITE] * 255)),
|
||||
)
|
||||
random_slot = NO_RANDOM_SLOT
|
||||
random_slot = cg.RawExpression("light::NO_RANDOM_SLOT")
|
||||
if color[CONF_RANDOM]:
|
||||
random_slot = len(random_colors)
|
||||
random_colors.append(rgbw)
|
||||
@@ -518,14 +516,7 @@ async def addressable_color_wipe_effect_to_code(config, effect_id):
|
||||
random_storage = cg.nullptr
|
||||
if random_colors:
|
||||
# One RAM slot per random entry; it starts at the configured color, as before
|
||||
used = {str(i) for i, _ in iter_ids(CORE.config)} | {
|
||||
str(i) for i in CORE.variables
|
||||
}
|
||||
id_ = ID(
|
||||
ensure_unique_string(f"{effect_id.id}_random_colors", used),
|
||||
is_declaration=True,
|
||||
type=Color,
|
||||
)
|
||||
id_ = cg.unique_global_id(f"{effect_id.id}_random_colors", Color)
|
||||
values = cg.ArrayInitializer(
|
||||
*(Color(r, g, b, w) for r, g, b, w in random_colors)
|
||||
)
|
||||
|
||||
@@ -468,6 +468,17 @@ def progmem_array(id_, rhs) -> "MockObj":
|
||||
return obj
|
||||
|
||||
|
||||
def unique_global_id(name: str, type_: "MockObjClass") -> ID:
|
||||
"""A declaration ID for a generated global, unique against config ids, variables and reserved names."""
|
||||
from esphome.config import iter_ids
|
||||
from esphome.config_validation import RESERVED_IDS
|
||||
|
||||
used = {str(i) for i, _ in iter_ids(CORE.config)}
|
||||
used |= {str(i) for i in CORE.variables}
|
||||
used |= set(RESERVED_IDS) | CORE.loaded_integrations
|
||||
return ID(ensure_unique_string(name, used), is_declaration=True, type=type_)
|
||||
|
||||
|
||||
def shared_progmem_array(
|
||||
name: str, type_: "MockObjClass", rhs: SafeExpType, *, share: bool = True
|
||||
) -> "MockObj":
|
||||
@@ -477,18 +488,12 @@ def shared_progmem_array(
|
||||
must be captureless. Its name is made unique against every config id and variable.
|
||||
``share=False`` always emits a new array, e.g. for lambdas that may keep static state.
|
||||
"""
|
||||
from esphome.config import iter_ids
|
||||
from esphome.config_validation import RESERVED_IDS
|
||||
|
||||
arrays: dict[str, MockObj] = CORE.data.setdefault("shared_progmem_array", {})
|
||||
rhs = safe_exp(rhs)
|
||||
key = f"{type_} {rhs}"
|
||||
if share and (array := arrays.get(key)) is not None:
|
||||
return array
|
||||
used = {str(i) for i, _ in iter_ids(CORE.config)}
|
||||
used |= {str(i) for i in CORE.variables}
|
||||
used |= set(RESERVED_IDS) | CORE.loaded_integrations
|
||||
id_ = ID(ensure_unique_string(name, used), is_declaration=True, type=type_)
|
||||
id_ = unique_global_id(name, type_)
|
||||
# Global, so any scope can use it; anything a lambda references is already declared.
|
||||
CORE.add_global(ProgmemAssignmentExpression(type_, id_, rhs))
|
||||
array = MockObj(id_, ".")
|
||||
|
||||
@@ -6,6 +6,10 @@ from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
import esphome.config_validation as cv
|
||||
|
||||
|
||||
def test_effect_colors_use_flash_tables(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
@@ -26,4 +30,23 @@ def test_effect_colors_use_flash_tables(
|
||||
# Only the random entry gets a RAM slot, starting at its configured color
|
||||
assert re.search(r"static Color \w+_random_colors\[\] = \{Color\(", main_cpp)
|
||||
assert ".random_slot = 0," in main_cpp
|
||||
assert ".random_slot = 255," in main_cpp
|
||||
assert ".random_slot = light::NO_RANDOM_SLOT," in main_cpp
|
||||
|
||||
|
||||
def _color_wipe_colors(colors: list[dict]) -> list[dict]:
|
||||
from esphome.components.light.effects import EFFECTS_REGISTRY
|
||||
|
||||
entry = EFFECTS_REGISTRY["addressable_color_wipe"]
|
||||
return entry.schema({"name": "Wipe", "colors": colors})["colors"]
|
||||
|
||||
|
||||
def test_color_wipe_requires_a_color() -> None:
|
||||
with pytest.raises(cv.Invalid):
|
||||
_color_wipe_colors([])
|
||||
|
||||
|
||||
def test_color_wipe_random_entry_limit() -> None:
|
||||
random_color = {"random": True, "num_leds": 1}
|
||||
assert len(_color_wipe_colors([random_color] * 254)) == 254
|
||||
with pytest.raises(cv.Invalid, match="At most 254 colors can be random"):
|
||||
_color_wipe_colors([random_color] * 255)
|
||||
|
||||
Reference in New Issue
Block a user