mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 23:37:34 +00:00
[cover] Extract build_apply_lambda_action helper, add typing, use kwargs
This commit is contained in:
@@ -295,37 +295,38 @@ COVER_CONTROL_ACTION_SCHEMA = cv.Schema(
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"cover.control", ControlAction, COVER_CONTROL_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def cover_control_to_code(config, action_id, template_arg, args):
|
||||
async def build_apply_lambda_action(
|
||||
config: ConfigType,
|
||||
action_id: ID,
|
||||
template_arg: cg.TemplateArguments,
|
||||
args: TemplateArgsType,
|
||||
fields: tuple[tuple[str, str, object], ...],
|
||||
prefix_args: list[tuple[object, str]],
|
||||
statement_fn,
|
||||
) -> MockObj:
|
||||
"""Fold configured fields into a single stateless apply lambda action.
|
||||
|
||||
Used by both `cover.control` and `cover.template.publish` (and shared
|
||||
with the template/cover platform). Constants are emitted as flash
|
||||
immediates; user lambdas are invoked inline so trigger args still flow.
|
||||
The trigger arg types are wrapped as `const T &` to match the
|
||||
`void (*)(..., const Ts &...)` ApplyFn signature.
|
||||
"""
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
# 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 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 conf_key, setter, type_ in FIELDS:
|
||||
for conf_key, target, 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}));")
|
||||
value_expr = f"({inner})({fwd_args})"
|
||||
else:
|
||||
body_lines.append(f"call.{setter}({cg.safe_exp(value)});")
|
||||
value_expr = str(cg.safe_exp(value))
|
||||
body_lines.append(statement_fn(target, value_expr))
|
||||
|
||||
# Match ControlAction::ApplyFn signature: const Ts &... for trigger args.
|
||||
apply_args = [
|
||||
(CoverCall.operator("ref"), "call"),
|
||||
*prefix_args,
|
||||
*((t.operator("const").operator("ref"), n) for t, n in args),
|
||||
]
|
||||
apply_lambda = LambdaExpression(
|
||||
@@ -337,6 +338,36 @@ async def cover_control_to_code(config, action_id, template_arg, args):
|
||||
return cg.new_Pvariable(action_id, template_arg, paren, apply_lambda)
|
||||
|
||||
|
||||
# CONF_STATE and CONF_POSITION are cv.Exclusive in the schema, so at most
|
||||
# one is present and both dispatch to set_position.
|
||||
_COVER_CONTROL_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_),
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"cover.control", ControlAction, COVER_CONTROL_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def cover_control_to_code(
|
||||
config: ConfigType,
|
||||
action_id: ID,
|
||||
template_arg: cg.TemplateArguments,
|
||||
args: TemplateArgsType,
|
||||
) -> MockObj:
|
||||
return await build_apply_lambda_action(
|
||||
config=config,
|
||||
action_id=action_id,
|
||||
template_arg=template_arg,
|
||||
args=args,
|
||||
fields=_COVER_CONTROL_FIELDS,
|
||||
prefix_args=[(CoverCall.operator("ref"), "call")],
|
||||
statement_fn=lambda setter, expr: f"call.{setter}({expr});",
|
||||
)
|
||||
|
||||
|
||||
COVER_CONDITION_SCHEMA = cv.maybe_simple_value(
|
||||
{cv.Required(CONF_ID): cv.use_id(Cover)}, key=CONF_ID
|
||||
)
|
||||
|
||||
@@ -19,8 +19,9 @@ from esphome.const import (
|
||||
CONF_TILT_ACTION,
|
||||
CONF_TILT_LAMBDA,
|
||||
)
|
||||
from esphome.core import Lambda
|
||||
from esphome.cpp_generator import LambdaExpression
|
||||
from esphome.core import ID
|
||||
from esphome.cpp_generator import MockObj
|
||||
from esphome.types import ConfigType, TemplateArgsType
|
||||
|
||||
from .. import template_ns
|
||||
|
||||
@@ -112,6 +113,16 @@ async def to_code(config):
|
||||
cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE]))
|
||||
|
||||
|
||||
# CONF_STATE and CONF_POSITION are cv.Exclusive in the schema, so at most
|
||||
# one is present and both map to the position field.
|
||||
_COVER_PUBLISH_FIELDS = (
|
||||
(CONF_STATE, "position", cg.float_),
|
||||
(CONF_POSITION, "position", cg.float_),
|
||||
(CONF_TILT, "tilt", cg.float_),
|
||||
(CONF_CURRENT_OPERATION, "current_operation", cover.CoverOperation),
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"cover.template.publish",
|
||||
cover.CoverPublishAction,
|
||||
@@ -128,42 +139,20 @@ async def to_code(config):
|
||||
),
|
||||
synchronous=True,
|
||||
)
|
||||
async def cover_template_publish_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
# All configured fields are folded into a single stateless lambda whose
|
||||
# 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 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),
|
||||
async def cover_template_publish_to_code(
|
||||
config: ConfigType,
|
||||
action_id: ID,
|
||||
template_arg: cg.TemplateArguments,
|
||||
args: TemplateArgsType,
|
||||
) -> MockObj:
|
||||
# Mutates Cover fields directly (no CoverCall) since publish is a state
|
||||
# push, not a control request.
|
||||
return await cover.build_apply_lambda_action(
|
||||
config=config,
|
||||
action_id=action_id,
|
||||
template_arg=template_arg,
|
||||
args=args,
|
||||
fields=_COVER_PUBLISH_FIELDS,
|
||||
prefix_args=[(cover.Cover.operator("ptr"), "cover")],
|
||||
statement_fn=lambda field, expr: f"cover->{field} = {expr};",
|
||||
)
|
||||
|
||||
fwd_args = ", ".join(name for _, name in args)
|
||||
body_lines: list[str] = []
|
||||
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});")
|
||||
else:
|
||||
body_lines.append(f"cover->{field} = {cg.safe_exp(value)};")
|
||||
|
||||
# Match CoverPublishAction::ApplyFn: const Ts &... for trigger args.
|
||||
apply_args = [
|
||||
(cover.Cover.operator("ptr"), "cover"),
|
||||
*((t.operator("const").operator("ref"), n) for t, n in args),
|
||||
]
|
||||
apply_lambda = LambdaExpression(
|
||||
["\n".join(body_lines)],
|
||||
apply_args,
|
||||
capture="",
|
||||
return_type=cg.void,
|
||||
)
|
||||
return cg.new_Pvariable(action_id, template_arg, paren, apply_lambda)
|
||||
|
||||
Reference in New Issue
Block a user