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