From 7aa9f0d796397171cb130b033ea9e63b455791b8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 3 May 2026 16:06:54 -0500 Subject: [PATCH] [light] Fix LightControlAction trigger args with reference types `const Ts &...` is ill-formed when Ts is already a reference (e.g. a trigger that passes `std::string &`). Forward Ts by-value so the generated lambda matches ApplyFn for any valid trigger arg type. --- esphome/components/light/automation.h | 5 ++++- esphome/components/light/automation.py | 5 +++-- tests/components/light/common.yaml | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/esphome/components/light/automation.h b/esphome/components/light/automation.h index a5c73997b0..620ea3aca9 100644 --- a/esphome/components/light/automation.h +++ b/esphome/components/light/automation.h @@ -36,9 +36,12 @@ template class ToggleAction : public A // 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. `brightness: !lambda "return x;"`) keep working. +// +// Ts... must be forwarded by-value: `const T &` is ill-formed when T is +// already a reference type (some triggers pass `std::string &`). template class LightControlAction : public Action { public: - using ApplyFn = void (*)(LightState *, LightCall &, const Ts &...); + using ApplyFn = void (*)(LightState *, LightCall &, Ts...); LightControlAction(LightState *parent, ApplyFn apply) : parent_(parent), apply_(apply) {} void play(const Ts &...x) override { diff --git a/esphome/components/light/automation.py b/esphome/components/light/automation.py index ca4018a975..370489770d 100644 --- a/esphome/components/light/automation.py +++ b/esphome/components/light/automation.py @@ -230,11 +230,12 @@ async def light_control_to_code(config, action_id, template_arg, args): f"call.set_effect(static_cast({_resolve_effect_index(config)}));" ) - # Match LightControlAction::ApplyFn signature: const Ts &... for trigger args. + # Match LightControlAction::ApplyFn signature: trigger args forwarded + # by-value as Ts... apply_args = [ (LightState.operator("ptr"), "parent"), (LightCall.operator("ref"), "call"), - *((t.operator("const").operator("ref"), n) for t, n in args), + *args, ] apply_lambda = LambdaExpression( ["\n".join(body_lines)], diff --git a/tests/components/light/common.yaml b/tests/components/light/common.yaml index e58f7baee4..044a8144fa 100644 --- a/tests/components/light/common.yaml +++ b/tests/components/light/common.yaml @@ -127,6 +127,21 @@ esphome: blue: 0% transition_length: 1s +# Exercise light actions inside a trigger with non-empty Ts (number on_value +# passes float). +number: + - platform: template + id: test_number_brightness + optimistic: true + min_value: 0 + max_value: 100 + step: 1 + on_value: + then: + - light.turn_on: + id: test_monochromatic_light + brightness: !lambda "return x / 100.0;" + light: - platform: binary id: test_binary_light