ESPHome  2024.4.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  void play_complex(Ts... x) override {
289  this->num_running_++;
290  this->var_ = std::make_tuple(x...);
291  if (this->count_.value(x...) > 0) {
292  this->then_.play(0, x...);
293  } else {
294  this->play_next_tuple_(this->var_);
295  }
296  }
297 
298  void play(Ts... x) override { /* ignore - see play_complex */
299  }
300 
301  void stop() override { this->then_.stop(); }
302 
303  protected:
304  ActionList<uint32_t, Ts...> then_;
305  std::tuple<Ts...> var_;
306 };
307 
308 template<typename... Ts> class WaitUntilAction : public Action<Ts...>, public Component {
309  public:
310  WaitUntilAction(Condition<Ts...> *condition) : condition_(condition) {}
311 
312  TEMPLATABLE_VALUE(uint32_t, timeout_value)
313 
314  void play_complex(Ts... x) override {
315  this->num_running_++;
316  // Check if we can continue immediately.
317  if (this->condition_->check(x...)) {
318  if (this->num_running_ > 0) {
319  this->play_next_(x...);
320  }
321  return;
322  }
323  this->var_ = std::make_tuple(x...);
324 
325  if (this->timeout_value_.has_value()) {
326  auto f = std::bind(&WaitUntilAction<Ts...>::play_next_, this, x...);
327  this->set_timeout("timeout", this->timeout_value_.value(x...), f);
328  }
329 
330  this->loop();
331  }
332 
333  void loop() override {
334  if (this->num_running_ == 0)
335  return;
336 
337  if (!this->condition_->check_tuple(this->var_)) {
338  return;
339  }
340 
341  this->cancel_timeout("timeout");
342 
343  this->play_next_tuple_(this->var_);
344  }
345 
346  float get_setup_priority() const override { return setup_priority::DATA; }
347 
348  void play(Ts... x) override { /* ignore - see play_complex */
349  }
350 
351  void stop() override { this->cancel_timeout("timeout"); }
352 
353  protected:
355  std::tuple<Ts...> var_{};
356 };
357 
358 template<typename... Ts> class UpdateComponentAction : public Action<Ts...> {
359  public:
360  UpdateComponentAction(PollingComponent *component) : component_(component) {}
361 
362  void play(Ts... x) override {
363  if (!this->component_->is_ready())
364  return;
365  this->component_->update();
366  }
367 
368  protected:
370 };
371 
372 template<typename... Ts> class SuspendComponentAction : public Action<Ts...> {
373  public:
374  SuspendComponentAction(PollingComponent *component) : component_(component) {}
375 
376  void play(Ts... x) override {
377  if (!this->component_->is_ready())
378  return;
379  this->component_->stop_poller();
380  }
381 
382  protected:
384 };
385 
386 template<typename... Ts> class ResumeComponentAction : public Action<Ts...> {
387  public:
388  ResumeComponentAction(PollingComponent *component) : component_(component) {}
389  TEMPLATABLE_VALUE(uint32_t, update_interval)
390 
391  void play(Ts... x) override {
392  if (!this->component_->is_ready()) {
393  return;
394  }
395  optional<uint32_t> update_interval = this->update_interval_.optional_value(x...);
396  if (update_interval.has_value()) {
397  this->component_->set_update_interval(update_interval.value());
398  }
399  this->component_->start_poller();
400  }
401 
402  protected:
404 };
405 
406 } // 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
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
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_