diff --git a/esphome/components/select/__init__.py b/esphome/components/select/__init__.py index ae78e729e6..fec88d2bfd 100644 --- a/esphome/components/select/__init__.py +++ b/esphome/components/select/__init__.py @@ -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 diff --git a/tests/component_tests/select/__init__.py b/tests/component_tests/select/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/component_tests/select/config/select_is.yaml b/tests/component_tests/select/config/select_is.yaml new file mode 100644 index 0000000000..3bc3bdcc02 --- /dev/null +++ b/tests/component_tests/select/config/select_is.yaml @@ -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: diff --git a/tests/component_tests/select/test_select_is.py b/tests/component_tests/select/test_select_is.py new file mode 100644 index 0000000000..6c179c3c85 --- /dev/null +++ b/tests/component_tests/select/test_select_is.py @@ -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