ESPHome  2023.5.5
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 LambdaCondition : public Condition<Ts...> {
52  public:
53  explicit LambdaCondition(std::function<bool(Ts...)> &&f) : f_(std::move(f)) {}
54  bool check(Ts... x) override { return this->f_(x...); }
55 
56  protected:
57  std::function<bool(Ts...)> f_;
58 };
59 
60 template<typename... Ts> class ForCondition : public Condition<Ts...>, public Component {
61  public:
62  explicit ForCondition(Condition<> *condition) : condition_(condition) {}
63 
64  TEMPLATABLE_VALUE(uint32_t, time);
65 
66  void loop() override { this->check_internal(); }
67  float get_setup_priority() const override { return setup_priority::DATA; }
68  bool check_internal() {
69  bool cond = this->condition_->check();
70  if (!cond)
71  this->last_inactive_ = millis();
72  return cond;
73  }
74 
75  bool check(Ts... x) override {
76  if (!this->check_internal())
77  return false;
78  return millis() - this->last_inactive_ >= this->time_.value(x...);
79  }
80 
81  protected:
83  uint32_t last_inactive_{0};
84 };
85 
86 class StartupTrigger : public Trigger<>, public Component {
87  public:
88  explicit StartupTrigger(float setup_priority) : setup_priority_(setup_priority) {}
89  void setup() override { this->trigger(); }
90  float get_setup_priority() const override { return this->setup_priority_; }
91 
92  protected:
94 };
95 
96 class ShutdownTrigger : public Trigger<>, public Component {
97  public:
98  explicit ShutdownTrigger(float setup_priority) : setup_priority_(setup_priority) {}
99  void on_shutdown() override { this->trigger(); }
100  float get_setup_priority() const override { return this->setup_priority_; }
101 
102  protected:
104 };
105 
106 class LoopTrigger : public Trigger<>, public Component {
107  public:
108  void loop() override { this->trigger(); }
109  float get_setup_priority() const override { return setup_priority::DATA; }
110 };
111 
112 template<typename... Ts> class DelayAction : public Action<Ts...>, public Component {
113  public:
114  explicit DelayAction() = default;
115 
117 
118  void play_complex(Ts... x) override {
119  auto f = std::bind(&DelayAction<Ts...>::play_next_, this, x...);
120  this->num_running_++;
121  this->set_timeout(this->delay_.value(x...), f);
122  }
123  float get_setup_priority() const override { return setup_priority::HARDWARE; }
124 
125  void play(Ts... x) override { /* ignore - see play_complex */
126  }
127 
128  void stop() override { this->cancel_timeout(""); }
129 };
130 
131 template<typename... Ts> class LambdaAction : public Action<Ts...> {
132  public:
133  explicit LambdaAction(std::function<void(Ts...)> &&f) : f_(std::move(f)) {}
134 
135  void play(Ts... x) override { this->f_(x...); }
136 
137  protected:
138  std::function<void(Ts...)> f_;
139 };
140 
141 template<typename... Ts> class IfAction : public Action<Ts...> {
142  public:
143  explicit IfAction(Condition<Ts...> *condition) : condition_(condition) {}
144 
145  void add_then(const std::vector<Action<Ts...> *> &actions) {
146  this->then_.add_actions(actions);
147  this->then_.add_action(new LambdaAction<Ts...>([this](Ts... x) { this->play_next_(x...); }));
148  }
149 
150  void add_else(const std::vector<Action<Ts...> *> &actions) {
151  this->else_.add_actions(actions);
152  this->else_.add_action(new LambdaAction<Ts...>([this](Ts... x) { this->play_next_(x...); }));
153  }
154 
155  void play_complex(Ts... x) override {
156  this->num_running_++;
157  bool res = this->condition_->check(x...);
158  if (res) {
159  if (this->then_.empty()) {
160  this->play_next_(x...);
161  } else if (this->num_running_ > 0) {
162  this->then_.play(x...);
163  }
164  } else {
165  if (this->else_.empty()) {
166  this->play_next_(x...);
167  } else if (this->num_running_ > 0) {
168  this->else_.play(x...);
169  }
170  }
171  }
172 
173  void play(Ts... x) override { /* ignore - see play_complex */
174  }
175 
176  void stop() override {
177  this->then_.stop();
178  this->else_.stop();
179  }
180 
181  protected:
185 };
186 
187 template<typename... Ts> class WhileAction : public Action<Ts...> {
188  public:
189  WhileAction(Condition<Ts...> *condition) : condition_(condition) {}
190 
191  void add_then(const std::vector<Action<Ts...> *> &actions) {
192  this->then_.add_actions(actions);
193  this->then_.add_action(new LambdaAction<Ts...>([this](Ts... x) {
194  if (this->num_running_ > 0 && this->condition_->check_tuple(this->var_)) {
195  // play again
196  if (this->num_running_ > 0) {
197  this->then_.play_tuple(this->var_);
198  }
199  } else {
200  // condition false, play next
201  this->play_next_tuple_(this->var_);
202  }
203  }));
204  }
205 
206  void play_complex(Ts... x) override {
207  this->num_running_++;
208  // Store loop parameters
209  this->var_ = std::make_tuple(x...);
210  // Initial condition check
211  if (!this->condition_->check_tuple(this->var_)) {
212  // If new condition check failed, stop loop if running
213  this->then_.stop();
214  this->play_next_tuple_(this->var_);
215  return;
216  }
217 
218  if (this->num_running_ > 0) {
219  this->then_.play_tuple(this->var_);
220  }
221  }
222 
223  void play(Ts... x) override { /* ignore - see play_complex */
224  }
225 
226  void stop() override { this->then_.stop(); }
227 
228  protected:
231  std::tuple<Ts...> var_{};
232 };
233 
234 template<typename... Ts> class RepeatAction : public Action<Ts...> {
235  public:
236  TEMPLATABLE_VALUE(uint32_t, count)
237 
238  void add_then(const std::vector<Action<uint32_t, Ts...> *> &actions) {
239  this->then_.add_actions(actions);
240  this->then_.add_action(new LambdaAction<uint32_t, Ts...>([this](uint32_t iteration, Ts... x) {
241  iteration++;
242  if (iteration >= this->count_.value(x...))
243  this->play_next_tuple_(this->var_);
244  else
245  this->then_.play(iteration, x...);
246  }));
247  }
248 
249  void play_complex(Ts... x) override {
250  this->num_running_++;
251  this->var_ = std::make_tuple(x...);
252  this->then_.play(0, x...);
253  }
254 
255  void play(Ts... x) override { /* ignore - see play_complex */
256  }
257 
258  void stop() override { this->then_.stop(); }
259 
260  protected:
261  ActionList<uint32_t, Ts...> then_;
262  std::tuple<Ts...> var_;
263 };
264 
265 template<typename... Ts> class WaitUntilAction : public Action<Ts...>, public Component {
266  public:
267  WaitUntilAction(Condition<Ts...> *condition) : condition_(condition) {}
268 
269  TEMPLATABLE_VALUE(uint32_t, timeout_value)
270 
271  void play_complex(Ts... x) override {
272  this->num_running_++;
273  // Check if we can continue immediately.
274  if (this->condition_->check(x...)) {
275  if (this->num_running_ > 0) {
276  this->play_next_(x...);
277  }
278  return;
279  }
280  this->var_ = std::make_tuple(x...);
281 
282  if (this->timeout_value_.has_value()) {
283  auto f = std::bind(&WaitUntilAction<Ts...>::play_next_, this, x...);
284  this->set_timeout("timeout", this->timeout_value_.value(x...), f);
285  }
286 
287  this->loop();
288  }
289 
290  void loop() override {
291  if (this->num_running_ == 0)
292  return;
293 
294  if (!this->condition_->check_tuple(this->var_)) {
295  return;
296  }
297 
298  this->cancel_timeout("timeout");
299 
300  this->play_next_tuple_(this->var_);
301  }
302 
303  float get_setup_priority() const override { return setup_priority::DATA; }
304 
305  void play(Ts... x) override { /* ignore - see play_complex */
306  }
307 
308  void stop() override { this->cancel_timeout("timeout"); }
309 
310  protected:
312  std::tuple<Ts...> var_{};
313 };
314 
315 template<typename... Ts> class UpdateComponentAction : public Action<Ts...> {
316  public:
317  UpdateComponentAction(PollingComponent *component) : component_(component) {}
318 
319  void play(Ts... x) override {
320  if (!this->component_->is_ready())
321  return;
322  this->component_->update();
323  }
324 
325  protected:
327 };
328 
329 } // namespace esphome
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_
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:282
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:27
void stop() override
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)
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
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)
void play(Ts... x) override
bool check(Ts... x) override
Definition: a4988.cpp:4
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:28
std::function< bool(Ts...)> f_