From 22a70e3139da695c98bec86f0b87cc3641011c6b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 29 Apr 2026 06:40:09 -0500 Subject: [PATCH] [cover] Use FIELDS table to match light/climate codegen pattern --- esphome/components/cover/__init__.py | 21 +++++++++-------- esphome/components/template/cover/__init__.py | 23 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/esphome/components/cover/__init__.py b/esphome/components/cover/__init__.py index 30d3e23bf6f..9d5b6ad49ce 100644 --- a/esphome/components/cover/__init__.py +++ b/esphome/components/cover/__init__.py @@ -303,19 +303,20 @@ async def cover_control_to_code(config, action_id, template_arg, args): # All configured fields are folded into a single stateless lambda whose # constants live in flash; the action stores only a function pointer. - # CONF_STATE and CONF_POSITION are mutually exclusive in the schema and - # both map to set_position. - fields: list[tuple[object, str, object]] = [] - if (stop := config.get(CONF_STOP)) is not None: - fields.append((stop, "set_stop", cg.bool_)) - if (position := config.get(CONF_STATE, config.get(CONF_POSITION))) is not None: - fields.append((position, "set_position", cg.float_)) - if (tilt := config.get(CONF_TILT)) is not None: - fields.append((tilt, "set_tilt", cg.float_)) + # CONF_STATE and CONF_POSITION are cv.Exclusive in the schema, so at most + # one is present and both dispatch to set_position. + FIELDS = ( + (CONF_STOP, "set_stop", cg.bool_), + (CONF_STATE, "set_position", cg.float_), + (CONF_POSITION, "set_position", cg.float_), + (CONF_TILT, "set_tilt", cg.float_), + ) fwd_args = ", ".join(name for _, name in args) body_lines: list[str] = [] - for value, setter, type_ in fields: + for conf_key, setter, type_ in FIELDS: + if (value := config.get(conf_key)) is None: + continue if isinstance(value, Lambda): inner = await cg.process_lambda(value, args, return_type=type_) body_lines.append(f"call.{setter}(({inner})({fwd_args}));") diff --git a/esphome/components/template/cover/__init__.py b/esphome/components/template/cover/__init__.py index 8b39dc5b631..1af003d75d6 100644 --- a/esphome/components/template/cover/__init__.py +++ b/esphome/components/template/cover/__init__.py @@ -135,21 +135,20 @@ async def cover_template_publish_to_code(config, action_id, template_arg, args): # constants live in flash; the action stores only a function pointer. # The lambda mutates Cover fields directly (no CoverCall) since publish # is a state push, not a control request. - # CONF_STATE and CONF_POSITION both map to position. - fields: list[tuple[object, str, object]] = [] - position_value = config.get(CONF_STATE, config.get(CONF_POSITION)) - if position_value is not None: - fields.append((position_value, "position", cg.float_)) - if CONF_TILT in config: - fields.append((config[CONF_TILT], "tilt", cg.float_)) - if CONF_CURRENT_OPERATION in config: - fields.append( - (config[CONF_CURRENT_OPERATION], "current_operation", cover.CoverOperation) - ) + # CONF_STATE and CONF_POSITION are cv.Exclusive in the schema, so at most + # one is present and both map to the position field. + FIELDS = ( + (CONF_STATE, "position", cg.float_), + (CONF_POSITION, "position", cg.float_), + (CONF_TILT, "tilt", cg.float_), + (CONF_CURRENT_OPERATION, "current_operation", cover.CoverOperation), + ) fwd_args = ", ".join(name for _, name in args) body_lines: list[str] = [] - for value, field, type_ in fields: + for conf_key, field, type_ in FIELDS: + if (value := config.get(conf_key)) is None: + continue if isinstance(value, Lambda): inner = await cg.process_lambda(value, args, return_type=type_) body_lines.append(f"cover->{field} = ({inner})({fwd_args});")