ESPHome 2026.5.0-dev
Loading...
Searching...
No Matches
automation.h
Go to the documentation of this file.
1#pragma once
2
9#include <concepts>
10#include <functional>
11#include <utility>
12#include <vector>
13
14namespace esphome {
15
16// C++20 std::index_sequence is now used for tuple unpacking
17// Legacy seq<>/gens<> pattern deprecated but kept for backwards compatibility
18// https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer/7858971#7858971
19// Remove before 2026.6.0
20// NOLINTBEGIN(readability-identifier-naming)
21#if defined(__GNUC__) || defined(__clang__)
22#pragma GCC diagnostic push
23#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
24#endif
25
26template<int...> struct ESPDEPRECATED("Use std::index_sequence instead. Removed in 2026.6.0", "2025.12.0") seq {};
27template<int N, int... S>
28struct ESPDEPRECATED("Use std::make_index_sequence instead. Removed in 2026.6.0", "2025.12.0") gens
29 : gens<N - 1, N - 1, S...> {};
30template<int... S> struct gens<0, S...> { using type = seq<S...>; };
31
32#if defined(__GNUC__) || defined(__clang__)
33#pragma GCC diagnostic pop
34#endif
35// NOLINTEND(readability-identifier-naming)
36
40template<typename T, typename... X> class TemplatableFn {
41 public:
42 TemplatableFn() = default;
43 TemplatableFn(std::nullptr_t) = delete;
44
45 // Exact return type match — direct function pointer storage
46 template<typename F> TemplatableFn(F f) requires std::convertible_to<F, T (*)(X...)> : f_(f) {}
47
48 // Convertible return type (e.g., int -> uint8_t) — casting trampoline.
49 // Stateless lambdas are default-constructible in C++20, so F{} recreates the lambda inside
50 // the trampoline without capturing. This compiles to the same code as a direct call + cast.
51 // Deprecated: codegen should use the correct output type to avoid the trampoline.
52 template<typename F>
53 [[deprecated("Lambda return type does not match TemplatableFn<T> — use the correct type in "
54 "codegen")]] TemplatableFn(F) requires(!std::convertible_to<F, T (*)(X...)>) &&
55 std::invocable<F, X...> &&std::convertible_to<std::invoke_result_t<F, X...>, T> &&std::is_empty_v<F>
56 &&std::default_initializable<F> : f_([](X... x) -> T { return static_cast<T>(F{}(x...)); }) {}
57
58 // Reject any callable that didn't match the above (stateful lambdas or inconvertible return types)
59 template<typename F>
60 TemplatableFn(F) requires std::invocable<F, X...> &&
61 (!std::convertible_to<F, T (*)(X...)>) &&(!std::is_empty_v<F> ||
62 !std::convertible_to<std::invoke_result_t<F, X...>, T> ||
63 !std::default_initializable<F>) = delete;
64
65 // Reject raw (non-callable) values with a helpful diagnostic pointing at the Python-side fix.
66 // TemplatableFn stores only a function pointer (4 bytes), so constants must be wrapped in a
67 // stateless lambda by codegen. External components hitting this error should use
68 // `cg.templatable(value, args, type)` in their Python __init__.py before passing to the setter.
69 template<typename V> TemplatableFn(V) requires(!std::invocable<V, X...>) && (!std::convertible_to<V, T (*)(X...)>) {
70 static_assert(sizeof(V) == 0, "Missing cg.templatable(...) in Python codegen for this TEMPLATABLE_VALUE "
71 "field. The wrapper was always required; it worked by accident because the old "
72 "TemplatableValue implicitly converted raw constants. TemplatableFn cannot. See "
73 "https://developers.esphome.io/blog/2026/04/09/"
74 "templatablefn-4-byte-templatable-storage-for-trivially-copyable-types/");
75 }
76
77 bool has_value() const { return this->f_ != nullptr; }
78
79 T value(X... x) const { return this->f_ ? this->f_(x...) : T{}; }
80
81 optional<T> optional_value(X... x) const {
82 if (!this->f_)
83 return {};
84 return this->f_(x...);
85 }
86
87 T value_or(X... x, T default_value) const { return this->f_ ? this->f_(x...) : default_value; }
88
89 protected:
90 T (*f_)(X...){nullptr};
91};
92
93// Forward declaration for TemplatableValue (string specialization needs it)
94template<typename T, typename... X> class TemplatableValue;
95
99template<typename T, typename... X>
101 std::conditional_t<std::is_trivially_copyable_v<T>, TemplatableFn<T, X...>, TemplatableValue<T, X...>>;
102
103#define TEMPLATABLE_VALUE_(type, name) \
104 protected: \
105 TemplatableStorage<type, Ts...> name##_{}; \
106\
107 public: \
108 template<typename V> void set_##name(V name) { this->name##_ = name; }
109
110#define TEMPLATABLE_VALUE(type, name) TEMPLATABLE_VALUE_(type, name)
111
115template<typename T, typename... X> class TemplatableValue {
116 public:
117 TemplatableValue() = default;
118 TemplatableValue(std::nullptr_t) = delete;
119
120 // Accept raw constants
121 template<typename V> TemplatableValue(V value) requires(!std::invocable<V, X...>) : tag_(VALUE) {
122 new (&this->storage_.value_) T(static_cast<T>(std::move(value)));
123 }
124
125 // Accept stateless lambdas (convertible to function pointer)
126 template<typename F> TemplatableValue(F f) requires std::convertible_to<F, T (*)(X...)> : tag_(FN) {
127 this->storage_.f_ = f;
128 }
129
130 // Convertible return type (e.g., int -> uint8_t) — casting trampoline
131 template<typename F>
132 [[deprecated("Lambda return type does not match TemplatableValue<T> — use the correct type in "
133 "codegen")]] TemplatableValue(F) requires(!std::convertible_to<F, T (*)(X...)>) &&
134 std::invocable<F, X...> &&std::convertible_to<std::invoke_result_t<F, X...>, T> &&std::is_empty_v<F>
135 &&std::default_initializable<F> : tag_(FN) {
136 this->storage_.f_ = [](X... x) -> T { return static_cast<T>(F{}(x...)); };
137 }
138
139 // Reject any callable that didn't match the above
140 template<typename F>
141 TemplatableValue(F) requires std::invocable<F, X...> &&
142 (!std::convertible_to<F, T (*)(X...)>) &&(!std::is_empty_v<F> ||
143 !std::convertible_to<std::invoke_result_t<F, X...>, T> ||
144 !std::default_initializable<F>) = delete;
145
146 TemplatableValue(const TemplatableValue &other) : tag_(other.tag_) {
147 if (this->tag_ == VALUE) {
148 new (&this->storage_.value_) T(other.storage_.value_);
149 } else if (this->tag_ == FN) {
150 this->storage_.f_ = other.storage_.f_;
151 }
152 }
153
154 TemplatableValue(TemplatableValue &&other) noexcept : tag_(other.tag_) {
155 if (this->tag_ == VALUE) {
156 new (&this->storage_.value_) T(std::move(other.storage_.value_));
157 other.destroy_();
158 } else if (this->tag_ == FN) {
159 this->storage_.f_ = other.storage_.f_;
160 }
161 other.tag_ = NONE;
162 }
163
165 if (this != &other) {
166 this->destroy_();
167 this->tag_ = other.tag_;
168 if (this->tag_ == VALUE) {
169 new (&this->storage_.value_) T(other.storage_.value_);
170 } else if (this->tag_ == FN) {
171 this->storage_.f_ = other.storage_.f_;
172 }
173 }
174 return *this;
175 }
176
178 if (this != &other) {
179 this->destroy_();
180 this->tag_ = other.tag_;
181 if (this->tag_ == VALUE) {
182 new (&this->storage_.value_) T(std::move(other.storage_.value_));
183 other.destroy_();
184 } else if (this->tag_ == FN) {
185 this->storage_.f_ = other.storage_.f_;
186 }
187 other.tag_ = NONE;
188 }
189 return *this;
190 }
191
192 ~TemplatableValue() { this->destroy_(); }
193
194 bool has_value() const { return this->tag_ != NONE; }
195
196 T value(X... x) const {
197 if (this->tag_ == FN)
198 return this->storage_.f_(x...);
199 if (this->tag_ == VALUE)
200 return this->storage_.value_;
201 return T{};
202 }
203
204 optional<T> optional_value(X... x) const {
205 if (this->tag_ == NONE)
206 return {};
207 return this->value(x...);
208 }
209
210 T value_or(X... x, T default_value) const {
211 if (this->tag_ == NONE)
212 return default_value;
213 return this->value(x...);
214 }
215
216 protected:
217 void destroy_() {
218 if constexpr (!std::is_trivially_destructible_v<T>) {
219 if (this->tag_ == VALUE)
220 this->storage_.value_.~T();
221 }
222 }
223
224 enum Tag : uint8_t { NONE, VALUE, FN } tag_{NONE};
225 // Union with explicit ctor/dtor to support non-trivially-constructible/destructible T
226 // (e.g., std::vector<uint8_t>). Lifetime of value_ is managed externally via
227 // placement new and destroy_().
228 union Storage {
229 constexpr Storage() : f_(nullptr) {}
230 constexpr ~Storage() {}
232 T (*f_)(X...);
233 } storage_;
234};
235
238template<typename... X> class TemplatableValue<std::string, X...> {
239 public:
240 TemplatableValue() : type_(NONE) {}
241
242 // For const char*: store pointer directly, no heap allocation.
243 // String remains in flash and is only converted to std::string when value() is called.
244 TemplatableValue(const char *str) : type_(STATIC_STRING) { this->static_str_ = str; }
245
246#ifdef USE_ESP8266
247 // On ESP8266, __FlashStringHelper* is a distinct type from const char*.
248 // ESPHOME_F(s) expands to F(s) which returns __FlashStringHelper* pointing to PROGMEM.
249 // Store as FLASH_STRING — value()/is_empty()/ref_or_copy_to() use _P functions.
250 TemplatableValue(const __FlashStringHelper *str) : type_(FLASH_STRING) {
251 this->static_str_ = reinterpret_cast<const char *>(str);
252 }
253#endif
254
255 template<typename F> TemplatableValue(F value) requires(!std::invocable<F, X...>) : type_(VALUE) {
256 this->value_ = new std::string(std::move(value));
257 }
258
259 // For stateless lambdas (convertible to function pointer): use function pointer
260 template<typename F>
261 TemplatableValue(F f) requires std::invocable<F, X...> && std::convertible_to<F, std::string (*)(X...)>
262 : type_(STATELESS_LAMBDA) {
263 this->stateless_f_ = f; // Implicit conversion to function pointer
264 }
265
266 // For stateful lambdas (not convertible to function pointer): use std::function
267 template<typename F>
268 TemplatableValue(F f) requires std::invocable<F, X...> &&(!std::convertible_to<F, std::string (*)(X...)>)
269 : type_(LAMBDA) {
270 this->f_ = new std::function<std::string(X...)>(std::move(f));
271 }
272
273 // Copy constructor
274 TemplatableValue(const TemplatableValue &other) : type_(other.type_) {
275 if (this->type_ == VALUE) {
276 this->value_ = new std::string(*other.value_);
277 } else if (this->type_ == LAMBDA) {
278 this->f_ = new std::function<std::string(X...)>(*other.f_);
279 } else if (this->type_ == STATELESS_LAMBDA) {
280 this->stateless_f_ = other.stateless_f_;
281 } else if (this->type_ == STATIC_STRING || this->type_ == FLASH_STRING) {
282 this->static_str_ = other.static_str_;
283 }
284 }
285
286 // Move constructor
287 TemplatableValue(TemplatableValue &&other) noexcept : type_(other.type_) {
288 if (this->type_ == VALUE) {
289 this->value_ = other.value_;
290 other.value_ = nullptr;
291 } else if (this->type_ == LAMBDA) {
292 this->f_ = other.f_;
293 other.f_ = nullptr;
294 } else if (this->type_ == STATELESS_LAMBDA) {
295 this->stateless_f_ = other.stateless_f_;
296 } else if (this->type_ == STATIC_STRING || this->type_ == FLASH_STRING) {
297 this->static_str_ = other.static_str_;
298 }
299 other.type_ = NONE;
300 }
301
302 // Assignment operators
304 if (this != &other) {
305 this->~TemplatableValue();
306 new (this) TemplatableValue(other);
307 }
308 return *this;
309 }
310
312 if (this != &other) {
313 this->~TemplatableValue();
314 new (this) TemplatableValue(std::move(other));
315 }
316 return *this;
317 }
318
320 if (this->type_ == VALUE) {
321 delete this->value_;
322 } else if (this->type_ == LAMBDA) {
323 delete this->f_;
324 }
325 // STATELESS_LAMBDA/STATIC_STRING/FLASH_STRING/NONE: no cleanup needed (pointers, not heap-allocated)
326 }
327
328 bool has_value() const { return this->type_ != NONE; }
329
330 std::string value(X... x) const {
331 switch (this->type_) {
332 case STATELESS_LAMBDA:
333 return this->stateless_f_(x...); // Direct function pointer call
334 case LAMBDA:
335 return (*this->f_)(x...); // std::function call
336 case VALUE:
337 return *this->value_;
338 case STATIC_STRING:
339 return std::string(this->static_str_);
340#ifdef USE_ESP8266
341 case FLASH_STRING: {
342 // PROGMEM pointer — must use _P functions to access on ESP8266
343 size_t len = strlen_P(this->static_str_);
344 std::string result(len, '\0');
345 memcpy_P(result.data(), this->static_str_, len);
346 return result;
347 }
348#endif
349 case NONE:
350 default:
351 return {};
352 }
353 }
354
355 optional<std::string> optional_value(X... x) const {
356 if (!this->has_value())
357 return {};
358 return this->value(x...);
359 }
360
361 std::string value_or(X... x, std::string default_value) const {
362 if (!this->has_value())
363 return default_value;
364 return this->value(x...);
365 }
366
370 bool is_static_string() const { return this->type_ == STATIC_STRING; }
371
374 const char *get_static_string() const { return this->static_str_; }
375
379 bool is_empty() const {
380 switch (this->type_) {
381 case NONE:
382 return true;
383 case STATIC_STRING:
384 return this->static_str_ == nullptr || this->static_str_[0] == '\0';
385#ifdef USE_ESP8266
386 case FLASH_STRING:
387 // PROGMEM pointer — must use progmem_read_byte on ESP8266
388 return this->static_str_ == nullptr ||
389 progmem_read_byte(reinterpret_cast<const uint8_t *>(this->static_str_)) == '\0';
390#endif
391 case VALUE:
392 return this->value_->empty();
393 default: // LAMBDA/STATELESS_LAMBDA - must call value()
394 return this->value().empty();
395 }
396 }
397
405 StringRef ref_or_copy_to(char *lambda_buf, size_t lambda_buf_size) const {
406 switch (this->type_) {
407 case NONE:
408 return StringRef();
409 case STATIC_STRING:
410 if (this->static_str_ == nullptr)
411 return StringRef();
412 return StringRef(this->static_str_, strlen(this->static_str_));
413#ifdef USE_ESP8266
414 case FLASH_STRING:
415 if (this->static_str_ == nullptr)
416 return StringRef();
417 {
418 // PROGMEM pointer — copy to buffer via _P functions
419 size_t len = strlen_P(this->static_str_);
420 size_t copy_len = std::min(len, lambda_buf_size - 1);
421 memcpy_P(lambda_buf, this->static_str_, copy_len);
422 lambda_buf[copy_len] = '\0';
423 return StringRef(lambda_buf, copy_len);
424 }
425#endif
426 case VALUE:
427 return StringRef(this->value_->data(), this->value_->size());
428 default: { // LAMBDA/STATELESS_LAMBDA - must call value() and copy
429 std::string result = this->value();
430 size_t copy_len = std::min(result.size(), lambda_buf_size - 1);
431 memcpy(lambda_buf, result.data(), copy_len);
432 lambda_buf[copy_len] = '\0';
433 return StringRef(lambda_buf, copy_len);
434 }
435 }
436 }
437
438 protected:
439 enum : uint8_t {
444 STATIC_STRING, // For const char* — avoids heap allocation
445 FLASH_STRING, // PROGMEM pointer on ESP8266; never set on other platforms
446 } type_;
447 union {
448 std::string *value_; // Heap-allocated string (VALUE)
449 std::function<std::string(X...)> *f_; // Heap-allocated std::function (LAMBDA)
450 std::string (*stateless_f_)(X...); // Function pointer (STATELESS_LAMBDA)
451 const char *static_str_; // For STATIC_STRING and FLASH_STRING types
452 };
453};
454
459template<typename... Ts> class Condition {
460 public:
462 virtual bool check(const Ts &...x) = 0;
463
465 bool check_tuple(const std::tuple<Ts...> &tuple) {
466 return this->check_tuple_(tuple, std::make_index_sequence<sizeof...(Ts)>{});
467 }
468
469 protected:
470 template<size_t... S> bool check_tuple_(const std::tuple<Ts...> &tuple, std::index_sequence<S...> /*unused*/) {
471 return this->check(std::get<S>(tuple)...);
472 }
473};
474
475template<typename... Ts> class Automation;
476
477template<typename... Ts> class Trigger {
478 public:
480 // Force-inline: collapses the Trigger→Automation→ActionList forwarding
481 // chain into a single frame, reducing automation call stack depth.
482 inline void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE {
483 if (this->automation_parent_ == nullptr)
484 return;
485 this->automation_parent_->trigger(x...);
486 }
487 void set_automation_parent(Automation<Ts...> *automation_parent) { this->automation_parent_ = automation_parent; }
488
490 void stop_action() {
491 if (this->automation_parent_ == nullptr)
492 return;
493 this->automation_parent_->stop();
494 }
497 if (this->automation_parent_ == nullptr)
498 return false;
499 return this->automation_parent_->is_running();
500 }
501
502 protected:
503 Automation<Ts...> *automation_parent_{nullptr};
504};
505
506template<typename... Ts> class ActionList;
507
508template<typename... Ts> class Action {
509 public:
510 virtual void play_complex(const Ts &...x) {
511 this->num_running_++;
512 this->play(x...);
513 this->play_next_(x...);
514 }
515 virtual void stop_complex() {
516 if (num_running_) {
517 this->stop();
518 this->num_running_ = 0;
519 }
520 this->stop_next_();
521 }
523 virtual bool is_running() { return this->num_running_ > 0 || this->is_running_next_(); }
524
528 int total = this->num_running_;
529 if (this->next_ != nullptr)
530 total += this->next_->num_running_total();
531 return total;
532 }
533
534 protected:
535 friend ActionList<Ts...>;
536 template<typename... Us> friend class ContinuationAction;
537
538 virtual void play(const Ts &...x) = 0;
539 void play_next_(const Ts &...x) {
540 if (this->num_running_ > 0) {
541 this->num_running_--;
542 if (this->next_ != nullptr) {
543 this->next_->play_complex(x...);
544 }
545 }
546 }
547 template<size_t... S> void play_next_tuple_(const std::tuple<Ts...> &tuple, std::index_sequence<S...> /*unused*/) {
548 this->play_next_(std::get<S>(tuple)...);
549 }
550 void play_next_tuple_(const std::tuple<Ts...> &tuple) {
551 this->play_next_tuple_(tuple, std::make_index_sequence<sizeof...(Ts)>{});
552 }
553
554 virtual void stop() {}
555 void stop_next_() {
556 if (this->next_ != nullptr) {
557 this->next_->stop_complex();
558 }
559 }
560
562 if (this->next_ == nullptr)
563 return false;
564 return this->next_->is_running();
565 }
566
567 Action<Ts...> *next_{nullptr};
568
571 int num_running_{0};
572};
573
574template<typename... Ts> class ActionList {
575 public:
576 void add_action(Action<Ts...> *action) {
577 // Walk to end of chain - action lists are short and only built during setup()
578 Action<Ts...> **tail = &this->actions_;
579 while (*tail != nullptr)
580 tail = &(*tail)->next_;
581 *tail = action;
582 }
583 void add_actions(const std::initializer_list<Action<Ts...> *> &actions) {
584 // Find tail once, then append all actions in a single pass
585 Action<Ts...> **tail = &this->actions_;
586 while (*tail != nullptr)
587 tail = &(*tail)->next_;
588 for (auto *action : actions) {
589 *tail = action;
590 tail = &action->next_;
591 }
592 }
593 // Force-inline: part of the Trigger→Automation→ActionList forwarding
594 // chain collapsed to reduce automation call stack depth.
595 inline void play(const Ts &...x) ESPHOME_ALWAYS_INLINE {
596 if (this->actions_ != nullptr)
597 this->actions_->play_complex(x...);
598 }
599 void play_tuple(const std::tuple<Ts...> &tuple) {
600 this->play_tuple_(tuple, std::make_index_sequence<sizeof...(Ts)>{});
601 }
602 void stop() {
603 if (this->actions_ != nullptr)
604 this->actions_->stop_complex();
605 }
606 bool empty() const { return this->actions_ == nullptr; }
607
609 bool is_running() {
610 if (this->actions_ == nullptr)
611 return false;
612 return this->actions_->is_running();
613 }
616 if (this->actions_ == nullptr)
617 return 0;
618 return this->actions_->num_running_total();
619 }
620
621 protected:
622 template<size_t... S> void play_tuple_(const std::tuple<Ts...> &tuple, std::index_sequence<S...> /*unused*/) {
623 this->play(std::get<S>(tuple)...);
624 }
625
626 Action<Ts...> *actions_{nullptr};
627};
628
629template<typename... Ts> class Automation {
630 public:
632 Automation() = default;
633 explicit Automation(Trigger<Ts...> *trigger) { trigger->set_automation_parent(this); }
634
635 void add_action(Action<Ts...> *action) { this->actions_.add_action(action); }
636 void add_actions(const std::initializer_list<Action<Ts...> *> &actions) { this->actions_.add_actions(actions); }
637
638 void stop() { this->actions_.stop(); }
639
640 // Force-inline: part of the Trigger→Automation→ActionList forwarding
641 // chain collapsed to reduce automation call stack depth.
642 inline void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE { this->actions_.play(x...); }
643
644 bool is_running() { return this->actions_.is_running(); }
645
647 int num_running() { return this->actions_.num_running(); }
648
649 protected:
651};
652
656template<typename... Ts> struct TriggerForwarder {
658 void operator()(const Ts &...args) const { this->automation->trigger(args...); }
659};
660
665 void operator()(bool state) const {
666 if (state)
667 this->automation->trigger();
668 }
669};
670
675 void operator()(bool state) const {
676 if (!state)
677 this->automation->trigger();
678 }
679};
680
681// Ensure forwarders fit in Callback::ctx_ (pointer-sized inline storage).
682// If these fail, the forwarder would heap-allocate in Callback::create().
683static_assert(sizeof(TriggerForwarder<>) <= sizeof(void *));
684static_assert(sizeof(TriggerOnTrueForwarder) <= sizeof(void *));
685static_assert(sizeof(TriggerOnFalseForwarder) <= sizeof(void *));
686static_assert(std::is_trivially_copyable_v<TriggerForwarder<>>);
687static_assert(std::is_trivially_copyable_v<TriggerOnTrueForwarder>);
688static_assert(std::is_trivially_copyable_v<TriggerOnFalseForwarder>);
689
690} // namespace esphome
virtual bool is_running()
Check if this or any of the following actions are currently running.
Definition automation.h:523
Action< Ts... > * next_
Definition automation.h:567
void play_next_(const Ts &...x)
Definition automation.h:539
virtual void stop_complex()
Definition automation.h:515
virtual void play(const Ts &...x)=0
void play_next_tuple_(const std::tuple< Ts... > &tuple)
Definition automation.h:550
virtual void stop()
Definition automation.h:554
bool is_running_next_()
Definition automation.h:561
int num_running_total()
The total number of actions that are currently running in this plus any of the following actions in t...
Definition automation.h:527
void play_next_tuple_(const std::tuple< Ts... > &tuple, std::index_sequence< S... >)
Definition automation.h:547
virtual void play_complex(const Ts &...x)
Definition automation.h:510
void add_action(Action< Ts... > *action)
Definition automation.h:576
void play_tuple(const std::tuple< Ts... > &tuple)
Definition automation.h:599
bool is_running()
Check if any action in this action list is currently running.
Definition automation.h:609
bool empty() const
Definition automation.h:606
void add_actions(const std::initializer_list< Action< Ts... > * > &actions)
Definition automation.h:583
void play_tuple_(const std::tuple< Ts... > &tuple, std::index_sequence< S... >)
Definition automation.h:622
void play(const Ts &...x) ESPHOME_ALWAYS_INLINE
Definition automation.h:595
int num_running()
Return the number of actions in this action list that are currently running.
Definition automation.h:615
void add_action(Action< Ts... > *action)
Definition automation.h:635
Automation()=default
Default constructor for use with TriggerForwarder (no Trigger object needed).
int num_running()
Return the number of actions in the action part of this automation that are currently running.
Definition automation.h:647
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Definition automation.h:642
Automation(Trigger< Ts... > *trigger)
Definition automation.h:633
void add_actions(const std::initializer_list< Action< Ts... > * > &actions)
Definition automation.h:636
ActionList< Ts... > actions_
Definition automation.h:650
Base class for all automation conditions.
Definition automation.h:459
bool check_tuple_(const std::tuple< Ts... > &tuple, std::index_sequence< S... >)
Definition automation.h:470
bool check_tuple(const std::tuple< Ts... > &tuple)
Call check with a tuple of values as parameter.
Definition automation.h:465
virtual bool check(const Ts &...x)=0
Check whether this condition passes. This condition check must be instant, and not cause any delays.
Simple continuation action that calls play_next_ on a parent action.
StringRef is a reference to a string owned by something else.
Definition string_ref.h:26
Function-pointer-only templatable storage (4 bytes on 32-bit).
Definition automation.h:40
T value_or(X... x, T default_value) const
Definition automation.h:87
bool has_value() const
Definition automation.h:77
TemplatableFn(std::nullptr_t)=delete
optional< T > optional_value(X... x) const
Definition automation.h:81
T value(X... x) const
Definition automation.h:79
TemplatableValue(const __FlashStringHelper *str)
Definition automation.h:250
TemplatableValue(TemplatableValue &&other) noexcept
Definition automation.h:287
TemplatableValue & operator=(const TemplatableValue &other)
Definition automation.h:303
bool is_empty() const
Check if the string value is empty without allocating.
Definition automation.h:379
bool is_static_string() const
Check if this holds a static string (const char* stored without allocation) The pointer is always dir...
Definition automation.h:370
TemplatableValue(const TemplatableValue &other)
Definition automation.h:274
TemplatableValue & operator=(TemplatableValue &&other) noexcept
Definition automation.h:311
StringRef ref_or_copy_to(char *lambda_buf, size_t lambda_buf_size) const
Get a StringRef to the string value without heap allocation when possible.
Definition automation.h:405
std::string value_or(X... x, std::string default_value) const
Definition automation.h:361
const char * get_static_string() const
Get the static string pointer (only valid if is_static_string() returns true) The pointer is always d...
Definition automation.h:374
optional< std::string > optional_value(X... x) const
Definition automation.h:355
std::function< std::string(X...)> * f_
Definition automation.h:449
Primary TemplatableValue: stores either a constant value or a function pointer.
Definition automation.h:115
TemplatableValue(const TemplatableValue &other)
Definition automation.h:146
TemplatableValue & operator=(TemplatableValue &&other) noexcept
Definition automation.h:177
union esphome::TemplatableValue::Storage storage_
TemplatableValue(TemplatableValue &&other) noexcept
Definition automation.h:154
T value(X... x) const
Definition automation.h:196
optional< T > optional_value(X... x) const
Definition automation.h:204
TemplatableValue & operator=(const TemplatableValue &other)
Definition automation.h:164
T value_or(X... x, T default_value) const
Definition automation.h:210
TemplatableValue(std::nullptr_t)=delete
void stop_action()
Stop any action connected to this trigger.
Definition automation.h:490
bool is_action_running()
Returns true if any action connected to this trigger is running.
Definition automation.h:496
void set_automation_parent(Automation< Ts... > *automation_parent)
Definition automation.h:487
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Inform the parent automation that the event has triggered.
Definition automation.h:482
bool state
Definition fan.h:2
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
const char int const __FlashStringHelper va_list args
Definition log.h:74
std::conditional_t< std::is_trivially_copyable_v< T >, TemplatableFn< T, X... >, TemplatableValue< T, X... > > TemplatableStorage
Selects TemplatableFn (4 bytes) for trivially copyable types, TemplatableValue (8 bytes) otherwise.
Definition automation.h:100
struct ESPDEPRECATED("Use std::index_sequence instead. Removed in 2026.6.0", "2025.12.0") seq
Definition automation.h:26
uint8_t progmem_read_byte(const uint8_t *addr)
Definition core.cpp:34
Callback forwarder that triggers an Automation directly.
Definition automation.h:656
Automation< Ts... > * automation
Definition automation.h:657
void operator()(const Ts &...args) const
Definition automation.h:658
Callback forwarder that triggers an Automation<> only when the bool arg is false.
Definition automation.h:673
void operator()(bool state) const
Definition automation.h:675
Callback forwarder that triggers an Automation<> only when the bool arg is true.
Definition automation.h:663
void operator()(bool state) const
Definition automation.h:665
uint16_t seq
uint32_t len
uint16_t x
Definition tt21100.cpp:5