ESPHome  2025.2.0
base_automation.h
Go to the documentation of this file.
1 #pragma once
2 
5 #include "esphome/core/hal.h"
6 #include "esphome/core/defines.h"
8 
9 #include <vector>
10 
11 namespace esphome {
12 
13 template<typename... Ts> class AndCondition : public Condition<Ts...> {
14  public:
15  explicit AndCondition(const std::vector<Condition<Ts...> *> &conditions) : conditions_(conditions) {}
16  bool check(Ts... x) override {
17  for (auto *condition : this->conditions_) {
18  if (!condition->check(x...))
19  return false;
20  }
21 
22  return true;
23  }
24 
25  protected:
26  std::vector<Condition<Ts...> *> conditions_;
27 };
28 
29 template<typename... Ts> class OrCondition : public Condition<Ts...> {
30  public:
31  explicit OrCondition(const std::vector<Condition<Ts...> *> &conditions) : conditions_(conditions) {}
32  bool check(Ts... x) override {
33  for (auto *condition : this->conditions_) {
34  if (condition->check(x...))
35  return true;
36  }
37 
38  return false;
39  }
40 
41  protected:
42  std::vector<Condition<Ts...> *> conditions_;
43 };
44 
45 template<typename... Ts> class NotCondition : public Condition<Ts...> {
46  public:
47  explicit NotCondition(Condition<Ts...> *condition) : condition_(condition) {}
48  bool check(Ts... x) override { return !this->condition_->check(x...); }
49 
50  protected:
52 };
53 
54 template<typename... Ts> class XorCondition : public Condition<Ts...> {
55  public:
56  explicit XorCondition(const std::vector<Condition<Ts...> *> &conditions) : conditions_(conditions) {}
57  bool check(Ts... x) override {
58  size_t result = 0;
59  for (auto *condition : this->conditions_) {
60  result += condition->check(x...);
61  }
62 
63  return result == 1;
64  }
65 
66  protected:
67  std::vector<Condition<Ts...> *> conditions_;
68 };
69 
70 template<typename... Ts> class LambdaCondition : public Condition<Ts...> {
71  public:
72  explicit LambdaCondition(std::function<bool(Ts...)> &&f) : f_(std::move(f)) {}
73  bool check(Ts... x) override { return this->f_(x...); }
74 
75  protected:
76  std::function<bool(Ts...)> f_;
77 };
78 
79 template<typename... Ts> class ForCondition : public Condition<Ts...>, public Component {
80  public:
81  explicit ForCondition(Condition<> *condition) : condition_(condition) {}
82 
83  TEMPLATABLE_VALUE(uint32_t, time);
84 
85  void loop() override { this->check_internal(); }
86  float get_setup_priority() const override { return setup_priority::DATA; }
87  bool check_internal() {
88  bool cond = this->condition_->check();
89  if (!cond)
90  this->last_inactive_ = millis();
91  return cond;
92  }
93 
94  bool check(Ts... x) override {
95  if (!this->check_internal())
96  return false;
97  return millis() - this->last_inactive_ >= this->time_.value(x...);
98  }
99 
100  protected:
102  uint32_t last_inactive_{0};
103 };
104 
105 class StartupTrigger : public Trigger<>, public Component {
106  public:
107  explicit StartupTrigger(float setup_priority) : setup_priority_(setup_priority) {}
108  void setup() override { this->trigger(); }
109  float get_setup_priority() const override { return this->setup_priority_; }
110 
111  protected:
113 };
114 
115 class ShutdownTrigger : public Trigger<>, public Component {
116  public:
117  explicit ShutdownTrigger(float setup_priority) : setup_priority_(setup_priority) {}
118  void on_shutdown() override { this->trigger(); }
119  float get_setup_priority() const override { return this->setup_priority_; }
120 
121  protected:
123 };
124 
125 class LoopTrigger : public Trigger<>, public Component {
126  public:
127  void loop() override { this->trigger(); }
128  float get_setup_priority() const override { return setup_priority::DATA; }
129 };
130 
131 #ifdef ESPHOME_PROJECT_NAME
132 class ProjectUpdateTrigger : public Trigger<std::string>, public Component {
133  public:
134  void setup() override {
135  uint32_t hash = fnv1_hash(ESPHOME_PROJECT_NAME);
136  ESPPreferenceObject pref = global_preferences->make_preference<char[30]>(hash, true);
137  char previous_version[30];
138  char current_version[30] = ESPHOME_PROJECT_VERSION_30;
139  if (pref.load(&previous_version)) {
140  int cmp = strcmp(previous_version, current_version);
141  if (cmp < 0) {
142  this->trigger(previous_version);
143  }
144  }
145  pref.save(&current_version);
147  }
148  float get_setup_priority() const override { return setup_priority::PROCESSOR; }
149 };
150 #endif
151 
152 template<typename... Ts> class DelayAction : public Action<Ts...>, public Component {
153  public:
154  explicit DelayAction() = default;
155 
157 
158  void play_complex(Ts... x) override {
159  auto f = std::bind(&DelayAction<Ts...>::play_next_, this, x...);
160  this->num_running_++;
161  this->set_timeout(this->delay_.value(x...), f);
162  }
163  float get_setup_priority() const override { return setup_priority::HARDWARE; }
164 
165  void play(Ts... x) override { /* ignore - see play_complex */
166  }
167 
168  void stop() override { this->cancel_timeout(""); }
169 };
170 
171 template<typename... Ts> class LambdaAction : public Action<Ts...> {
172  public:
173  explicit LambdaAction(std::function<void(Ts...)> &&f) : f_(std::move(f)) {}
174 
175  void play(Ts... x) override { this->f_(x...); }
176 
177  protected:
178  std::function<void(Ts...)> f_;
179 };
180 
181 template<typename... Ts> class IfAction : public Action<Ts...> {
182  public:
183  explicit IfAction(Condition<Ts...> *condition) : condition_(condition) {}
184 
185  void add_then(const std::vector<Action<Ts...> *> &actions) {
186  this->then_.add_actions(actions);
187  this->then_.add_action(new LambdaAction<Ts...>([this](Ts... x) { this->play_next_(x...); }));
188  }
189 
190  void add_else(const std::vector<Action<Ts...> *> &actions) {
191  this->else_.add_actions(actions);
192  this->else_.add_action(new LambdaAction<Ts...>([this](Ts... x) { this->play_next_(x...); }));
193  }
194 
195  void play_complex(Ts... x) override {
196  this->num_running_++;
197  bool res = this->condition_->check(x...);
198  if (res) {
199  if (this->then_.empty()) {
200  this->play_next_(x...);
201  } else if (this->num_running_ > 0) {
202  this->then_.play(x...);
203  }
204  } else {
205  if (this->else_.empty()) {
206  this->play_next_(x...);
207  } else if (this->num_running_ > 0) {
208  this->else_.play(x...);
209  }
210  }
211  }
212 
213  void play(Ts... x) override { /* ignore - see play_complex */
214  }
215 
216  void stop() override {
217  this->then_.stop();
218  this->else_.stop();
219  }
220 
221  protected:
225 };
226 
227 template<typename... Ts> class WhileAction : public Action<Ts...> {
228  public:
229  WhileAction(Condition<Ts...> *condition) : condition_(condition) {}
230 
231  void add_then(const std::vector<Action<Ts...> *> &actions) {
232  this->then_.add_actions(actions);
233  this->then_.add_action(new LambdaAction<Ts...>([this](Ts... x) {
234  if (this->num_running_ > 0 && this->condition_->check_tuple(this->var_)) {
235  // play again
236  if (this->num_running_ > 0) {
237  this->then_.play_tuple(this->var_);
238  }
239  } else {
240  // condition false, play next
241  this->play_next_tuple_(this->var_);
242  }
243  }));
244  }
245 
246  void play_complex(Ts... x) override {
247  this->num_running_++;
248  // Store loop parameters
249  this->var_ = std::make_tuple(x...);
250  // Initial condition check
251  if (!this->condition_->check_tuple(this->var_)) {
252  // If new condition check failed, stop loop if running
253  this->then_.stop();
254  this->play_next_tuple_(this->var_);
255  return;
256  }
257 
258  if (this->num_running_ > 0) {
259  this->then_.play_tuple(this->var_);
260  }
261  }
262 
263  void play(Ts... x) override { /* ignore - see play_complex */
264  }
265 
266  void stop() override { this->then_.stop(); }
267 
268  protected:
271  std::tuple<Ts...> var_{};
272 };
273 
274 template<typename... Ts> class RepeatAction : public Action<Ts...> {
275  public:
276  TEMPLATABLE_VALUE(uint32_t, count)
277 
278  void add_then(const std::vector<Action<uint32_t, Ts...> *> &actions) {
279  this->then_.add_actions(actions);
280  this->then_.add_action(new LambdaAction<uint32_t, Ts...>([this](uint32_t iteration, Ts... x) {
281  iteration++;
282  if (iteration >= this->count_.value(x...)) {
283  this->play_next_tuple_(this->var_);
284  } else {
285  this->then_.play(iteration, x...);
286  }
287  }));
288  }
289 
290  void play_complex(Ts... x) override {
291  this->num_running_++;
292  this->var_ = std::make_tuple(x...);
293  if (this->count_.value(x...) > 0) {
294  this->then_.play(0, x...);
295  } else {
296  this->play_next_tuple_(this->var_);
297  }
298  }
299 
300  void play(Ts... x) override { /* ignore - see play_complex */
301  }
302 
303  void stop() override { this->then_.stop(); }
304 
305  protected:
306  ActionList<uint32_t, Ts...> then_;
307  std::tuple<Ts...> var_;
308 };
309 
310 template<typename... Ts> class WaitUntilAction : public Action<Ts...>, public Component {
311  public:
312  WaitUntilAction(Condition<Ts...> *condition) : condition_(condition) {}
313 
314  TEMPLATABLE_VALUE(uint32_t, timeout_value)
315 
316  void play_complex(Ts... x) override {
317  this->num_running_++;
318  // Check if we can continue immediately.
319  if (this->condition_->check(x...)) {
320  if (this->num_running_ > 0) {
321  this->play_next_(x...);
322  }
323  return;
324  }
325  this->var_ = std::make_tuple(x...);
326 
327  if (this->timeout_value_.has_value()) {
328  auto f = std::bind(&WaitUntilAction<Ts...>::play_next_, this, x...);
329  this->set_timeout("timeout", this->timeout_value_.value(x...), f);
330  }
331 
332  this->loop();
333  }
334 
335  void loop() override {
336  if (this->num_running_ == 0)
337  return;
338 
339  if (!this->condition_->check_tuple(this->var_)) {
340  return;
341  }
342 
343  this->cancel_timeout("timeout");
344 
345  this->play_next_tuple_(this->var_);
346  }
347 
348  float get_setup_priority() const override { return setup_priority::DATA; }
349 
350  void play(Ts... x) override { /* ignore - see play_complex */
351  }
352 
353  void stop() override { this->cancel_timeout("timeout"); }
354 
355  protected:
357  std::tuple<Ts...> var_{};
358 };
359 
360 template<typename... Ts> class UpdateComponentAction : public Action<Ts...> {
361  public:
362  UpdateComponentAction(PollingComponent *component) : component_(component) {}
363 
364  void play(Ts... x) override {
365  if (!this->component_->is_ready())
366  return;
367  this->component_->update();
368  }
369 
370  protected:
372 };
373 
374 template<typename... Ts> class SuspendComponentAction : public Action<Ts...> {
375  public:
376  SuspendComponentAction(PollingComponent *component) : component_(component) {}
377 
378  void play(Ts... x) override {
379  if (!this->component_->is_ready())
380  return;
381  this->component_->stop_poller();
382  }
383 
384  protected:
386 };
387 
388 template<typename... Ts> class ResumeComponentAction : public Action<Ts...> {
389  public:
390  ResumeComponentAction(PollingComponent *component) : component_(component) {}
391  TEMPLATABLE_VALUE(uint32_t, update_interval)
392 
393  void play(Ts... x) override {
394  if (!this->component_->is_ready()) {
395  return;
396  }
397  optional<uint32_t> update_interval = this->update_interval_.optional_value(x...);
398  if (update_interval.has_value()) {
399  this->component_->set_update_interval(update_interval.value());
400  }
401  this->component_->start_poller();
402  }
403 
404  protected:
406 };
407 
408 } // namespace esphome
value_type const & value() const
Definition: optional.h:89
SuspendComponentAction(PollingComponent *component)
void loop()
ForCondition(Condition<> *condition)
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:19
void play(Ts... x) override
float get_setup_priority() const override
TEMPLATABLE_VALUE(uint32_t, count) void add_then(const std
void stop() override
NotCondition(Condition< Ts... > *condition)
Condition< Ts... > * condition_
void play(Ts... x) override
Condition< Ts... > * condition_
uint16_t x
Definition: tt21100.cpp:17
void play_complex(Ts... x) override
void loop() override
ActionList< Ts... > else_
Condition< Ts... > * condition_
float get_setup_priority() const override
IfAction(Condition< Ts... > *condition)
STL namespace.
void stop() override
ActionList< Ts... > then_
bool check(Ts... x) override
This class simplifies creating components that periodically check a state.
Definition: component.h:283
bool has_value() const
Definition: optional.h:87
void on_shutdown() override
void add_then(const std::vector< Action< Ts... > *> &actions)
std::function< void(Ts...)> f_
void play(Ts... x) override
float get_setup_priority() const override
void play(Ts... x) override
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
std::vector< Condition< Ts... > * > conditions_
void stop() override
bool save(const T *src)
Definition: preferences.h:21
ResumeComponentAction(PollingComponent *component)
float get_setup_priority() const override
ActionList< uint32_t, Ts... > then_
void play(Ts... x) override
WhileAction(Condition< Ts... > *condition)
Base class for all automation conditions.
Definition: automation.h:74
std::vector< Condition< Ts... > * > conditions_
ESPPreferences * global_preferences
LambdaAction(std::function< void(Ts...)> &&f)
bool check(Ts... x) override
void add_else(const std::vector< Action< Ts... > *> &actions)
ActionList< Ts... > then_
const float PROCESSOR
For components that use data from sensors like displays.
Definition: component.cpp:20
bool check(Ts... x) override
TEMPLATABLE_VALUE(uint32_t, delay) void play_complex(Ts... x) override
AndCondition(const std::vector< Condition< Ts... > *> &conditions)
bool check(Ts... x) override
ShutdownTrigger(float setup_priority)
LambdaCondition(std::function< bool(Ts...)> &&f)
TEMPLATABLE_VALUE(uint32_t, timeout_value) void play_complex(Ts... x) override
void play_complex(Ts... x) override
void add_then(const std::vector< Action< Ts... > *> &actions)
float get_setup_priority() const override
void play_complex(Ts... x) override
XorCondition(const std::vector< Condition< Ts... > *> &conditions)
void play(Ts... x) override
const float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition: component.cpp:18
StartupTrigger(float setup_priority)
TEMPLATABLE_VALUE(uint32_t, update_interval) void play(Ts... x) override
void play(Ts... x) override
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
uint32_t fnv1_hash(const std::string &str)
Calculate a FNV-1 hash of str.
Definition: helpers.cpp:187
void play(Ts... x) override
bool check(Ts... x) override
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
WaitUntilAction(Condition< Ts... > *condition)
float get_setup_priority() const override
Condition< Ts... > * condition_
UpdateComponentAction(PollingComponent *component)
virtual bool sync()=0
Commit pending writes to flash.
std::tuple< Ts... > var_
float get_setup_priority() const override
OrCondition(const std::vector< Condition< Ts... > *> &conditions)
bool check(Ts... x) override
void stop() override
std::vector< Condition< Ts... > * > conditions_
void loop() override
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26
std::function< bool(Ts...)> f_