ESPHome  2022.8.0
base_automation.h
Go to the documentation of this file.
1 #pragma once
2 
5 
6 namespace esphome {
7 
8 template<typename... Ts> class AndCondition : public Condition<Ts...> {
9  public:
10  explicit AndCondition(const std::vector<Condition<Ts...> *> &conditions) : conditions_(conditions) {}
11  bool check(Ts... x) override {
12  for (auto *condition : this->conditions_) {
13  if (!condition->check(x...))
14  return false;
15  }
16 
17  return true;
18  }
19 
20  protected:
21  std::vector<Condition<Ts...> *> conditions_;
22 };
23 
24 template<typename... Ts> class OrCondition : public Condition<Ts...> {
25  public:
26  explicit OrCondition(const std::vector<Condition<Ts...> *> &conditions) : conditions_(conditions) {}
27  bool check(Ts... x) override {
28  for (auto *condition : this->conditions_) {
29  if (condition->check(x...))
30  return true;
31  }
32 
33  return false;
34  }
35 
36  protected:
37  std::vector<Condition<Ts...> *> conditions_;
38 };
39 
40 template<typename... Ts> class NotCondition : public Condition<Ts...> {
41  public:
42  explicit NotCondition(Condition<Ts...> *condition) : condition_(condition) {}
43  bool check(Ts... x) override { return !this->condition_->check(x...); }
44 
45  protected:
47 };
48 
49 template<typename... Ts> class LambdaCondition : public Condition<Ts...> {
50  public:
51  explicit LambdaCondition(std::function<bool(Ts...)> &&f) : f_(std::move(f)) {}
52  bool check(Ts... x) override { return this->f_(x...); }
53 
54  protected:
55  std::function<bool(Ts...)> f_;
56 };
57 
58 template<typename... Ts> class ForCondition : public Condition<Ts...>, public Component {
59  public:
60  explicit ForCondition(Condition<> *condition) : condition_(condition) {}
61 
62  TEMPLATABLE_VALUE(uint32_t, time);
63 
64  void loop() override { this->check_internal(); }
65  float get_setup_priority() const override { return setup_priority::DATA; }
66  bool check_internal() {
67  bool cond = this->condition_->check();
68  if (!cond)
69  this->last_inactive_ = millis();
70  return cond;
71  }
72 
73  bool check(Ts... x) override {
74  if (!this->check_internal())
75  return false;
76  return millis() - this->last_inactive_ >= this->time_.value(x...);
77  }
78 
79  protected:
81  uint32_t last_inactive_{0};
82 };
83 
84 class StartupTrigger : public Trigger<>, public Component {
85  public:
86  explicit StartupTrigger(float setup_priority) : setup_priority_(setup_priority) {}
87  void setup() override { this->trigger(); }
88  float get_setup_priority() const override { return this->setup_priority_; }
89 
90  protected:
92 };
93 
94 class ShutdownTrigger : public Trigger<>, public Component {
95  public:
96  explicit ShutdownTrigger(float setup_priority) : setup_priority_(setup_priority) {}
97  void on_shutdown() override { this->trigger(); }
98  float get_setup_priority() const override { return this->setup_priority_; }
99 
100  protected:
102 };
103 
104 class LoopTrigger : public Trigger<>, public Component {
105  public:
106  void loop() override { this->trigger(); }
107  float get_setup_priority() const override { return setup_priority::DATA; }
108 };
109 
110 template<typename... Ts> class DelayAction : public Action<Ts...>, public Component {
111  public:
112  explicit DelayAction() = default;
113 
115 
116  void play_complex(Ts... x) override {
117  auto f = std::bind(&DelayAction<Ts...>::play_next_, this, x...);
118  this->num_running_++;
119  this->set_timeout(this->delay_.value(x...), f);
120  }
121  float get_setup_priority() const override { return setup_priority::HARDWARE; }
122 
123  void play(Ts... x) override { /* ignore - see play_complex */
124  }
125 
126  void stop() override { this->cancel_timeout(""); }
127 };
128 
129 template<typename... Ts> class LambdaAction : public Action<Ts...> {
130  public:
131  explicit LambdaAction(std::function<void(Ts...)> &&f) : f_(std::move(f)) {}
132 
133  void play(Ts... x) override { this->f_(x...); }
134 
135  protected:
136  std::function<void(Ts...)> f_;
137 };
138 
139 template<typename... Ts> class IfAction : public Action<Ts...> {
140  public:
141  explicit IfAction(Condition<Ts...> *condition) : condition_(condition) {}
142 
143  void add_then(const std::vector<Action<Ts...> *> &actions) {
144  this->then_.add_actions(actions);
145  this->then_.add_action(new LambdaAction<Ts...>([this](Ts... x) { this->play_next_(x...); }));
146  }
147 
148  void add_else(const std::vector<Action<Ts...> *> &actions) {
149  this->else_.add_actions(actions);
150  this->else_.add_action(new LambdaAction<Ts...>([this](Ts... x) { this->play_next_(x...); }));
151  }
152 
153  void play_complex(Ts... x) override {
154  this->num_running_++;
155  bool res = this->condition_->check(x...);
156  if (res) {
157  if (this->then_.empty()) {
158  this->play_next_(x...);
159  } else if (this->num_running_ > 0) {
160  this->then_.play(x...);
161  }
162  } else {
163  if (this->else_.empty()) {
164  this->play_next_(x...);
165  } else if (this->num_running_ > 0) {
166  this->else_.play(x...);
167  }
168  }
169  }
170 
171  void play(Ts... x) override { /* ignore - see play_complex */
172  }
173 
174  void stop() override {
175  this->then_.stop();
176  this->else_.stop();
177  }
178 
179  protected:
183 };
184 
185 template<typename... Ts> class WhileAction : public Action<Ts...> {
186  public:
187  WhileAction(Condition<Ts...> *condition) : condition_(condition) {}
188 
189  void add_then(const std::vector<Action<Ts...> *> &actions) {
190  this->then_.add_actions(actions);
191  this->then_.add_action(new LambdaAction<Ts...>([this](Ts... x) {
192  if (this->num_running_ > 0 && this->condition_->check_tuple(this->var_)) {
193  // play again
194  if (this->num_running_ > 0) {
195  this->then_.play_tuple(this->var_);
196  }
197  } else {
198  // condition false, play next
199  this->play_next_tuple_(this->var_);
200  }
201  }));
202  }
203 
204  void play_complex(Ts... x) override {
205  this->num_running_++;
206  // Store loop parameters
207  this->var_ = std::make_tuple(x...);
208  // Initial condition check
209  if (!this->condition_->check_tuple(this->var_)) {
210  // If new condition check failed, stop loop if running
211  this->then_.stop();
212  this->play_next_tuple_(this->var_);
213  return;
214  }
215 
216  if (this->num_running_ > 0) {
217  this->then_.play_tuple(this->var_);
218  }
219  }
220 
221  void play(Ts... x) override { /* ignore - see play_complex */
222  }
223 
224  void stop() override { this->then_.stop(); }
225 
226  protected:
229  std::tuple<Ts...> var_{};
230 };
231 
232 template<typename... Ts> class RepeatAction : public Action<Ts...> {
233  public:
234  TEMPLATABLE_VALUE(uint32_t, count)
235 
236  void add_then(const std::vector<Action<Ts...> *> &actions) {
237  this->then_.add_actions(actions);
238  this->then_.add_action(new LambdaAction<Ts...>([this](Ts... x) {
239  this->iteration_++;
240  if (this->iteration_ == this->count_.value(x...))
241  this->play_next_tuple_(this->var_);
242  else
243  this->then_.play_tuple(this->var_);
244  }));
245  }
246 
247  void play_complex(Ts... x) override {
248  this->num_running_++;
249  this->var_ = std::make_tuple(x...);
250  this->iteration_ = 0;
251  this->then_.play_tuple(this->var_);
252  }
253 
254  void play(Ts... x) override { /* ignore - see play_complex */
255  }
256 
257  void stop() override { this->then_.stop(); }
258 
259  protected:
260  uint32_t iteration_;
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_failed())
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
ActionList< Ts... > then_
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:266
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:26
void stop() override
float get_setup_priority() const override
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:27
std::function< bool(Ts...)> f_