mirror of
https://github.com/esphome/esphome.git
synced 2026-05-10 05:37:55 +08:00
[cover] Fix ControlAction / CoverPublishAction trigger args with reference types (#16227)
This commit is contained in:
@@ -328,17 +328,28 @@ async def build_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.
|
||||
Trigger arg types are normalized to `const std::remove_cvref_t<T> &`
|
||||
to match the ApplyFn signature for any T (value, ref, or const-ref).
|
||||
"""
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
# Normalize trigger args to `const std::remove_cvref_t<T> &` so the
|
||||
# apply lambda and any inner field lambdas (generated below via
|
||||
# `process_lambda`) share one parameter spelling that's well-formed for
|
||||
# any T.
|
||||
normalized_args = [
|
||||
(cg.RawExpression(f"const std::remove_cvref_t<{cg.safe_exp(t)}> &"), n)
|
||||
for t, n in args
|
||||
]
|
||||
|
||||
fwd_args = ", ".join(name for _, name in args)
|
||||
body_lines: list[str] = []
|
||||
for field in fields:
|
||||
if (value := config.get(field.conf_key)) is None:
|
||||
continue
|
||||
if isinstance(value, Lambda):
|
||||
inner = await cg.process_lambda(value, args, return_type=field.type_)
|
||||
inner = await cg.process_lambda(
|
||||
value, normalized_args, return_type=field.type_
|
||||
)
|
||||
value_expr = f"({inner})({fwd_args})"
|
||||
else:
|
||||
value_expr = str(cg.safe_exp(value))
|
||||
@@ -346,7 +357,7 @@ async def build_apply_lambda_action(
|
||||
|
||||
apply_args = [
|
||||
*prefix_args,
|
||||
*((t.operator("const").operator("ref"), n) for t, n in args),
|
||||
*normalized_args,
|
||||
]
|
||||
apply_lambda = LambdaExpression(
|
||||
["\n".join(body_lines)],
|
||||
|
||||
@@ -51,10 +51,17 @@ template<typename... Ts> class ToggleAction : public Action<Ts...> {
|
||||
// plus one parent pointer, regardless of how many fields the user set.
|
||||
// Trigger args are forwarded to the apply function so user lambdas
|
||||
// (e.g. `position: !lambda "return x;"`) keep working.
|
||||
//
|
||||
// Trigger args are normalized to `const std::remove_cvref_t<Ts> &...` so
|
||||
// the codegen can emit a matching parameter list for both the apply lambda
|
||||
// and any inner field lambdas without producing invalid C++ source text
|
||||
// (e.g. `const T & &` if Ts already carries a reference, or `const const
|
||||
// T &` if Ts already carries a const). This keeps trigger args no-copy
|
||||
// regardless of whether the trigger supplies `T`, `T &`, or `const T &`.
|
||||
|
||||
template<typename... Ts> class ControlAction : public Action<Ts...> {
|
||||
public:
|
||||
using ApplyFn = void (*)(CoverCall &, const Ts &...);
|
||||
using ApplyFn = void (*)(CoverCall &, const std::remove_cvref_t<Ts> &...);
|
||||
ControlAction(Cover *cover, ApplyFn apply) : cover_(cover), apply_(apply) {}
|
||||
|
||||
void play(const Ts &...x) override {
|
||||
@@ -70,7 +77,7 @@ template<typename... Ts> class ControlAction : public Action<Ts...> {
|
||||
|
||||
template<typename... Ts> class CoverPublishAction : public Action<Ts...> {
|
||||
public:
|
||||
using ApplyFn = void (*)(Cover *, const Ts &...);
|
||||
using ApplyFn = void (*)(Cover *, const std::remove_cvref_t<Ts> &...);
|
||||
CoverPublishAction(Cover *cover, ApplyFn apply) : cover_(cover), apply_(apply) {}
|
||||
|
||||
void play(const Ts &...x) override {
|
||||
|
||||
@@ -369,6 +369,19 @@ number:
|
||||
- valve.control:
|
||||
id: template_valve
|
||||
position: !lambda "return x / 100.0f;"
|
||||
# Same regression test for cover.control: forces the apply-lambda
|
||||
# codegen to handle a non-empty trigger Ts (float).
|
||||
- platform: template
|
||||
id: template_cover_position_number
|
||||
optimistic: true
|
||||
min_value: 0
|
||||
max_value: 100
|
||||
step: 1
|
||||
on_value:
|
||||
then:
|
||||
- cover.control:
|
||||
id: template_cover_with_triggers
|
||||
position: !lambda "return x / 100.0f;"
|
||||
|
||||
select:
|
||||
- platform: template
|
||||
|
||||
Reference in New Issue
Block a user