ESPHome  2022.5.1
automation.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <vector>
5 #include "esphome/core/helpers.h"
6 #include "esphome/core/defines.h"
8 
9 namespace esphome {
10 
11 // https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer/7858971#7858971
12 template<int...> struct seq {}; // NOLINT
13 template<int N, int... S> struct gens : gens<N - 1, N - 1, S...> {}; // NOLINT
14 template<int... S> struct gens<0, S...> { using type = seq<S...>; }; // NOLINT
15 
16 #define TEMPLATABLE_VALUE_(type, name) \
17  protected: \
18  TemplatableValue<type, Ts...> name##_{}; \
19 \
20  public: \
21  template<typename V> void set_##name(V name) { this->name##_ = name; }
22 
23 #define TEMPLATABLE_VALUE(type, name) TEMPLATABLE_VALUE_(type, name)
24 
25 template<typename T, typename... X> class TemplatableValue {
26  public:
27  TemplatableValue() : type_(EMPTY) {}
28 
29  template<typename F, enable_if_t<!is_invocable<F, X...>::value, int> = 0>
30  TemplatableValue(F value) : type_(VALUE), value_(value) {}
31 
32  template<typename F, enable_if_t<is_invocable<F, X...>::value, int> = 0>
33  TemplatableValue(F f) : type_(LAMBDA), f_(f) {}
34 
35  bool has_value() { return this->type_ != EMPTY; }
36 
37  T value(X... x) {
38  if (this->type_ == LAMBDA) {
39  return this->f_(x...);
40  }
41  // return value also when empty
42  return this->value_;
43  }
44 
46  if (!this->has_value()) {
47  return {};
48  }
49  return this->value(x...);
50  }
51 
52  T value_or(X... x, T default_value) {
53  if (!this->has_value()) {
54  return default_value;
55  }
56  return this->value(x...);
57  }
58 
59  protected:
60  enum {
64  } type_;
65 
66  T value_{};
67  std::function<T(X...)> f_{};
68 };
69 
74 template<typename... Ts> class Condition {
75  public:
77  virtual bool check(Ts... x) = 0;
78 
80  bool check_tuple(const std::tuple<Ts...> &tuple) {
81  return this->check_tuple_(tuple, typename gens<sizeof...(Ts)>::type());
82  }
83 
84  protected:
85  template<int... S> bool check_tuple_(const std::tuple<Ts...> &tuple, seq<S...>) {
86  return this->check(std::get<S>(tuple)...);
87  }
88 };
89 
90 template<typename... Ts> class Automation;
91 
92 template<typename... Ts> class Trigger {
93  public:
95  void trigger(Ts... x) {
96  if (this->automation_parent_ == nullptr)
97  return;
98  this->automation_parent_->trigger(x...);
99  }
100  void set_automation_parent(Automation<Ts...> *automation_parent) { this->automation_parent_ = automation_parent; }
101 
103  void stop_action() {
104  if (this->automation_parent_ == nullptr)
105  return;
106  this->automation_parent_->stop();
107  }
110  if (this->automation_parent_ == nullptr)
111  return false;
112  return this->automation_parent_->is_running();
113  }
114 
115  protected:
116  Automation<Ts...> *automation_parent_{nullptr};
117 };
118 
119 template<typename... Ts> class ActionList;
120 
121 template<typename... Ts> class Action {
122  public:
123  virtual void play_complex(Ts... x) {
124  this->num_running_++;
125  this->play(x...);
126  this->play_next_(x...);
127  }
128  virtual void stop_complex() {
129  if (num_running_) {
130  this->stop();
131  this->num_running_ = 0;
132  }
133  this->stop_next_();
134  }
136  virtual bool is_running() { return this->num_running_ > 0 || this->is_running_next_(); }
137 
141  int total = this->num_running_;
142  if (this->next_ != nullptr)
143  total += this->next_->num_running_total();
144  return total;
145  }
146 
147  protected:
148  friend ActionList<Ts...>;
149 
150  virtual void play(Ts... x) = 0;
151  void play_next_(Ts... x) {
152  if (this->num_running_ > 0) {
153  this->num_running_--;
154  if (this->next_ != nullptr) {
155  this->next_->play_complex(x...);
156  }
157  }
158  }
159  template<int... S> void play_next_tuple_(const std::tuple<Ts...> &tuple, seq<S...>) {
160  this->play_next_(std::get<S>(tuple)...);
161  }
162  void play_next_tuple_(const std::tuple<Ts...> &tuple) {
163  this->play_next_tuple_(tuple, typename gens<sizeof...(Ts)>::type());
164  }
165 
166  virtual void stop() {}
167  void stop_next_() {
168  if (this->next_ != nullptr) {
169  this->next_->stop_complex();
170  }
171  }
172 
174  if (this->next_ == nullptr)
175  return false;
176  return this->next_->is_running();
177  }
178 
179  Action<Ts...> *next_ = nullptr;
180 
183  int num_running_{0};
184 };
185 
186 template<typename... Ts> class ActionList {
187  public:
188  void add_action(Action<Ts...> *action) {
189  if (this->actions_end_ == nullptr) {
190  this->actions_begin_ = action;
191  } else {
192  this->actions_end_->next_ = action;
193  }
194  this->actions_end_ = action;
195  }
196  void add_actions(const std::vector<Action<Ts...> *> &actions) {
197  for (auto *action : actions) {
198  this->add_action(action);
199  }
200  }
201  void play(Ts... x) {
202  if (this->actions_begin_ != nullptr)
203  this->actions_begin_->play_complex(x...);
204  }
205  void play_tuple(const std::tuple<Ts...> &tuple) { this->play_tuple_(tuple, typename gens<sizeof...(Ts)>::type()); }
206  void stop() {
207  if (this->actions_begin_ != nullptr)
208  this->actions_begin_->stop_complex();
209  }
210  bool empty() const { return this->actions_begin_ == nullptr; }
211 
213  bool is_running() {
214  if (this->actions_begin_ == nullptr)
215  return false;
216  return this->actions_begin_->is_running();
217  }
219  int num_running() {
220  if (this->actions_begin_ == nullptr)
221  return false;
222  return this->actions_begin_->num_running_total();
223  }
224 
225  protected:
226  template<int... S> void play_tuple_(const std::tuple<Ts...> &tuple, seq<S...>) { this->play(std::get<S>(tuple)...); }
227 
228  Action<Ts...> *actions_begin_{nullptr};
229  Action<Ts...> *actions_end_{nullptr};
230 };
231 
232 template<typename... Ts> class Automation {
233  public:
234  explicit Automation(Trigger<Ts...> *trigger) : trigger_(trigger) { this->trigger_->set_automation_parent(this); }
235 
236  Action<Ts...> *add_action(Action<Ts...> *action) { this->actions_.add_action(action); }
237  void add_actions(const std::vector<Action<Ts...> *> &actions) { this->actions_.add_actions(actions); }
238 
239  void stop() { this->actions_.stop(); }
240 
241  void trigger(Ts... x) { this->actions_.play(x...); }
242 
243  bool is_running() { return this->actions_.is_running(); }
244 
246  int num_running() { return this->actions_.num_running(); }
247 
248  protected:
249  Trigger<Ts...> *trigger_;
251 };
252 
253 } // namespace esphome
virtual void stop()
Definition: automation.h:166
bool is_running_next_()
Definition: automation.h:173
void trigger(Ts... x)
Definition: automation.h:241
void add_action(Action< Ts... > *action)
Definition: automation.h:188
T value_or(X... x, T default_value)
Definition: automation.h:52
Action< Ts... > * next_
Definition: automation.h:179
virtual void play_complex(Ts... x)
Definition: automation.h:123
typename std::enable_if< B, T >::type enable_if_t
Definition: helpers.h:77
int num_running()
Return the number of actions in the action part of this automation that are currently running...
Definition: automation.h:246
virtual void stop_complex()
Definition: automation.h:128
int num_running_total()
The total number of actions that are currently running in this plus any of the following actions in t...
Definition: automation.h:140
void play_tuple_(const std::tuple< Ts... > &tuple, seq< S... >)
Definition: automation.h:226
bool check_tuple_(const std::tuple< Ts... > &tuple, seq< S... >)
Definition: automation.h:85
bool is_running()
Check if any action in this action list is currently running.
Definition: automation.h:213
bool is_action_running()
Returns true if any action connected to this trigger is running.
Definition: automation.h:109
void trigger(Ts... x)
Inform the parent automation that the event has triggered.
Definition: automation.h:95
void play_next_tuple_(const std::tuple< Ts... > &tuple)
Definition: automation.h:162
Trigger< Ts... > * trigger_
Definition: automation.h:249
void play(Ts... x)
Definition: automation.h:201
void stop_next_()
Definition: automation.h:167
void play_next_tuple_(const std::tuple< Ts... > &tuple, seq< S... >)
Definition: automation.h:159
void play_tuple(const std::tuple< Ts... > &tuple)
Definition: automation.h:205
Base class for all automation conditions.
Definition: automation.h:74
void add_actions(const std::vector< Action< Ts... > *> &actions)
Definition: automation.h:196
Action< Ts... > * add_action(Action< Ts... > *action)
Definition: automation.h:236
uint8_t type
ActionList< Ts... > actions_
Definition: automation.h:250
int num_running()
Return the number of actions in this action list that are currently running.
Definition: automation.h:219
optional< T > optional_value(X... x)
Definition: automation.h:45
bool check_tuple(const std::tuple< Ts... > &tuple)
Call check with a tuple of values as parameter.
Definition: automation.h:80
virtual bool is_running()
Check if this or any of the following actions are currently running.
Definition: automation.h:136
void set_automation_parent(Automation< Ts... > *automation_parent)
Definition: automation.h:100
Automation(Trigger< Ts... > *trigger)
Definition: automation.h:234
Definition: a4988.cpp:4
void play_next_(Ts... x)
Definition: automation.h:151
void add_actions(const std::vector< Action< Ts... > *> &actions)
Definition: automation.h:237
bool empty() const
Definition: automation.h:210
void stop_action()
Stop any action connected to this trigger.
Definition: automation.h:103