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