ESPHome 2026.5.1
Loading...
Searching...
No Matches
automation.h
Go to the documentation of this file.
1#pragma once
2
4#include "light_state.h"
5#include "addressable_light.h"
6
7namespace esphome::light {
8
9enum class LimitMode { CLAMP, DO_NOTHING };
10
11template<bool HasTransitionLength, typename... Ts> class ToggleAction : public Action<Ts...> {
12 public:
14
15 template<typename V> void set_transition_length(V value) requires(HasTransitionLength) {
16 this->transition_length_ = value;
17 }
18
19 void play(const Ts &...x) override {
20 auto call = this->state_->toggle();
21 if constexpr (HasTransitionLength) {
22 call.set_transition_length(this->transition_length_.optional_value(x...));
23 }
24 call.perform();
25 }
26
27 protected:
29 struct NoTransition {};
30 [[no_unique_address]] std::conditional_t<HasTransitionLength, TemplatableFn<uint32_t, Ts...>, NoTransition>
32};
33
34// All configured fields are baked into a single stateless lambda whose
35// constants live in flash. The action only stores one function pointer
36// plus one parent pointer, regardless of how many fields the user set.
37// Trigger args are forwarded to the apply function so user lambdas
38// (e.g. `brightness: !lambda "return x;"`) keep working.
39//
40// Trigger args are normalized to `const std::remove_cvref_t<Ts> &...` so
41// the codegen can emit a matching parameter list for both the apply lambda
42// and any inner field lambdas without producing invalid C++ source text
43// (e.g. `const T & &` if Ts already carries a reference, or `const const
44// T &` if Ts already carries a const). This keeps trigger args no-copy
45// regardless of whether the trigger supplies `T`, `T &`, or `const T &`.
46template<typename... Ts> class LightControlAction : public Action<Ts...> {
47 public:
48 using ApplyFn = void (*)(LightState *, LightCall &, const std::remove_cvref_t<Ts> &...);
50
51 void play(const Ts &...x) override {
52 auto call = this->parent_->make_call();
53 this->apply_(this->parent_, call, x...);
54 call.perform();
55 }
56
57 protected:
60};
61
62template<bool HasTransitionLength, typename... Ts> class DimRelativeAction : public Action<Ts...> {
63 public:
64 explicit DimRelativeAction(LightState *parent) : parent_(parent) {}
65
66 TEMPLATABLE_VALUE(float, relative_brightness)
67
68 template<typename V> void set_transition_length(V value) requires(HasTransitionLength) {
69 this->transition_length_ = value;
70 }
71
72 void play(const Ts &...x) override {
73 auto call = this->parent_->make_call();
74 float rel = this->relative_brightness_.value(x...);
75 float cur;
77 if ((limit_mode_ == LimitMode::DO_NOTHING) && ((cur < min_brightness_) || (cur > max_brightness_))) {
78 return;
79 }
80 float new_brightness = clamp(cur + rel, min_brightness_, max_brightness_);
81 call.set_state(new_brightness != 0.0f);
82 call.set_brightness(new_brightness);
83
84 if constexpr (HasTransitionLength) {
85 call.set_transition_length(this->transition_length_.optional_value(x...));
86 }
87 call.perform();
88 }
89
90 void set_min_max_brightness(float min, float max) {
91 this->min_brightness_ = min;
92 this->max_brightness_ = max;
93 }
94
95 void set_limit_mode(LimitMode limit_mode) { this->limit_mode_ = limit_mode; }
96
97 protected:
99 float min_brightness_{0.0};
100 float max_brightness_{1.0};
102 struct NoTransition {};
103 [[no_unique_address]] std::conditional_t<HasTransitionLength, TemplatableFn<uint32_t, Ts...>, NoTransition>
105};
106
107template<typename... Ts> class LightIsOnCondition : public Condition<Ts...> {
108 public:
110 bool check(const Ts &...x) override { return this->state_->current_values.is_on(); }
111
112 protected:
114};
115template<typename... Ts> class LightIsOffCondition : public Condition<Ts...> {
116 public:
118 bool check(const Ts &...x) override { return !this->state_->current_values.is_on(); }
119
120 protected:
122};
123
125 public:
126 explicit LightTurnOnTrigger(LightState *a_light) : light_(a_light) {
127 a_light->add_remote_values_listener(this);
128 this->last_on_ = a_light->current_values.is_on();
129 }
130
132 // using the remote value because of transitions we need to trigger as early as possible
133 auto is_on = this->light_->remote_values.is_on();
134 // only trigger when going from off to on
135 auto should_trigger = is_on && !this->last_on_;
136 // Set new state immediately so that trigger() doesn't devolve
137 // into infinite loop
138 this->last_on_ = is_on;
139 if (should_trigger) {
140 this->trigger();
141 }
142 }
143
144 protected:
147};
148
150 public:
151 explicit LightTurnOffTrigger(LightState *a_light) : light_(a_light) {
153 }
154
156 auto is_on = this->light_->current_values.is_on();
157 // only trigger when going from on to off
158 if (!is_on) {
159 this->trigger();
160 }
161 }
162
163 protected:
165};
166
168 public:
169 explicit LightStateTrigger(LightState *a_light) { a_light->add_remote_values_listener(this); }
170
171 void on_light_remote_values_update() override { this->trigger(); }
172};
173
174// This is slightly ugly, but we can't log in headers, and can't make this a static method on AddressableSet
175// due to the template. It's just a temporary warning anyway.
176void addressableset_warn_about_scale(const char *field);
177
178template<typename... Ts> class AddressableSet : public Action<Ts...> {
179 public:
180 explicit AddressableSet(LightState *parent) : parent_(parent) {}
181
182 TEMPLATABLE_VALUE(int32_t, range_from)
183 TEMPLATABLE_VALUE(int32_t, range_to)
184 TEMPLATABLE_VALUE(float, color_brightness)
185 TEMPLATABLE_VALUE(float, red)
186 TEMPLATABLE_VALUE(float, green)
187 TEMPLATABLE_VALUE(float, blue)
188 TEMPLATABLE_VALUE(float, white)
189
190 void play(const Ts &...x) override {
191 auto *out = (AddressableLight *) this->parent_->get_output();
192 int32_t range_from = interpret_index(this->range_from_.value_or(x..., 0), out->size());
193 if (range_from < 0 || range_from >= out->size())
194 range_from = 0;
195
196 int32_t range_to = interpret_index(this->range_to_.value_or(x..., out->size() - 1) + 1, out->size());
197 if (range_to < 0 || range_to >= out->size())
198 range_to = out->size();
199
200 uint8_t color_brightness =
201 to_uint8_scale(this->color_brightness_.value_or(x..., this->parent_->remote_values.get_color_brightness()));
202 auto range = out->range(range_from, range_to);
203 if (this->red_.has_value())
204 range.set_red(esp_scale8(to_uint8_compat(this->red_.value(x...), "red"), color_brightness));
205 if (this->green_.has_value())
206 range.set_green(esp_scale8(to_uint8_compat(this->green_.value(x...), "green"), color_brightness));
207 if (this->blue_.has_value())
208 range.set_blue(esp_scale8(to_uint8_compat(this->blue_.value(x...), "blue"), color_brightness));
209 if (this->white_.has_value())
210 range.set_white(to_uint8_compat(this->white_.value(x...), "white"));
211 out->schedule_show();
212 }
213
214 protected:
216
217 // Historically, this action required uint8_t (0-255) for RGBW values from lambdas. Keep compatibility.
218 static inline uint8_t to_uint8_compat(float value, const char *field) {
219 if (value > 1.0f) {
221 return static_cast<uint8_t>(value);
222 }
223 return to_uint8_scale(value);
224 }
225};
226
227} // namespace esphome::light
virtual void play(const Ts &...x)=0
Base class for all automation conditions.
Definition automation.h:459
Function-pointer-only templatable storage (4 bytes on 32-bit).
Definition automation.h:40
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Definition automation.h:482
static uint8_t to_uint8_compat(float value, const char *field)
Definition automation.h:218
AddressableSet(LightState *parent)
Definition automation.h:180
TEMPLATABLE_VALUE(int32_t, range_from) TEMPLATABLE_VALUE(int32_t
void play(const Ts &...x) override
Definition automation.h:72
TEMPLATABLE_VALUE(float, relative_brightness) template< typename V > void set_transition_length(V value)
Definition automation.h:66
void set_limit_mode(LimitMode limit_mode)
Definition automation.h:95
std::conditional_t< HasTransitionLength, TemplatableFn< uint32_t, Ts... >, NoTransition > transition_length_
Definition automation.h:104
DimRelativeAction(LightState *parent)
Definition automation.h:64
void set_min_max_brightness(float min, float max)
Definition automation.h:90
This class represents a requested change in a light state.
Definition light_call.h:22
bool is_on() const
Get the binary true/false state of these light color values.
void as_brightness(float *brightness) const
Convert these light color values to a brightness-only representation and write them to brightness.
LightControlAction(LightState *parent, ApplyFn apply)
Definition automation.h:49
void(*)(LightState *, LightCall &, const std::remove_cvref_t< Ts > &...) ApplyFn
Definition automation.h:48
void play(const Ts &...x) override
Definition automation.h:51
bool check(const Ts &...x) override
Definition automation.h:118
LightIsOffCondition(LightState *state)
Definition automation.h:117
LightIsOnCondition(LightState *state)
Definition automation.h:109
bool check(const Ts &...x) override
Definition automation.h:110
Listener interface for light remote value changes.
Definition light_state.h:31
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Definition light_state.h:93
void add_remote_values_listener(LightRemoteValuesListener *listener)
Add a listener for remote values changes.
LightColorValues remote_values
The remote color values reported to the frontend.
LightOutput * get_output() const
Get the light output associated with this object.
void add_target_state_reached_listener(LightTargetStateReachedListener *listener)
Add a listener for target state reached.
LightColorValues current_values
The current values of the light as outputted to the light.
void on_light_remote_values_update() override
Definition automation.h:171
LightStateTrigger(LightState *a_light)
Definition automation.h:169
Listener interface for light target state reached.
Definition light_state.h:42
void on_light_target_state_reached() override
Definition automation.h:155
LightTurnOffTrigger(LightState *a_light)
Definition automation.h:151
LightTurnOnTrigger(LightState *a_light)
Definition automation.h:126
void on_light_remote_values_update() override
Definition automation.h:131
std::conditional_t< HasTransitionLength, TemplatableFn< uint32_t, Ts... >, NoTransition > transition_length_
Definition automation.h:31
void play(const Ts &...x) override
Definition automation.h:19
void set_transition_length(V value)
Definition automation.h:15
ToggleAction(LightState *state)
Definition automation.h:13
void apply(Climate *climate)
Apply these settings to the climate device.
bool state
Definition fan.h:2
Range range
Definition msa3xx.h:0
void addressableset_warn_about_scale(const char *field)
Definition automation.cpp:8
int32_t HOT interpret_index(int32_t index, int32_t size)
if(written< 0)
Definition helpers.h:1047
uint16_t x
Definition tt21100.cpp:5