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