[select] Keep select.is option lists in flash (#20108)

This commit is contained in:
J. Nick Koston
2026-10-04 18:30:45 -05:00
committed by GitHub
parent 99bf080092
commit e4be4c7fcb
4 changed files with 76 additions and 8 deletions
+2 -8
View File
@@ -187,14 +187,8 @@ automation.register_apply_action(
async def select_is_to_code(config, condition_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
if options := config.get(CONF_OPTIONS):
# List of constant options
# Create a constexpr and pass that with a template length
arr_id = ID(
f"{condition_id}_data",
is_declaration=True,
type=global_ns.namespace("constexpr char * const"),
)
arg = cg.static_const_array(arr_id, cg.ArrayInitializer(*options))
# Shared flash table of option pointers, length passed as a template argument
arg = cg.shared_progmem_array("select_is_options", cg.const_char_ptr, options)
template_arg = TemplateArguments(len(options), *template_arg)
else:
# Lambda
@@ -0,0 +1,52 @@
esphome:
name: test
esp8266:
board: esp01_1m
select:
- platform: template
id: mode
optimistic: true
options: [one, two, three]
button:
- platform: template
name: A
on_press:
- if:
condition:
select.is:
id: mode
options: [one, two]
then:
- logger.log: a
- platform: template
name: B
on_press:
- if:
condition:
select.is:
id: mode
options: [one, two]
then:
- logger.log: b
- platform: template
name: C
on_press:
- if:
condition:
select.is:
id: mode
options: three
then:
- logger.log: c
- if:
condition:
select.is:
id: mode
lambda: return current == "two";
then:
- logger.log: d
logger:
@@ -0,0 +1,22 @@
"""select.is option lists live in shared PROGMEM tables."""
from collections.abc import Callable
from pathlib import Path
import re
def test_select_is_options_use_shared_progmem_tables(
generate_main: Callable[[str | Path], str],
component_config_path: Callable[[str], Path],
) -> None:
main_cpp = generate_main(component_config_path("select_is.yaml"))
tables = re.findall(
r"static constexpr const char \* (select_is_options\w*)\[\] PROGMEM = \{([^;]*)\};",
main_cpp,
)
# Two conditions with [one, two] share one table; [three] gets its own
assert sorted(body for _, body in tables) == ['"one", "two"', '"three"']
one_two = next(name for name, body in tables if body == '"one", "two"')
assert main_cpp.count(f", {one_two});") == 2
assert "SelectIsCondition<0" in main_cpp