automation.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #pragma once
  2. #include <vector>
  3. #include "esphome/core/component.h"
  4. #include "esphome/core/helpers.h"
  5. #include "esphome/core/defines.h"
  6. #include "esphome/core/preferences.h"
  7. namespace esphome {
  8. #define TEMPLATABLE_VALUE_(type, name) \
  9. protected: \
  10. TemplatableValue<type, Ts...> name##_{}; \
  11. \
  12. public: \
  13. template<typename V> void set_##name(V name) { this->name##_ = name; }
  14. #define TEMPLATABLE_VALUE(type, name) TEMPLATABLE_VALUE_(type, name)
  15. #define TEMPLATABLE_STRING_VALUE_(name) \
  16. protected: \
  17. TemplatableStringValue<Ts...> name##_{}; \
  18. \
  19. public: \
  20. template<typename V> void set_##name(V name) { this->name##_ = name; }
  21. #define TEMPLATABLE_STRING_VALUE(name) TEMPLATABLE_STRING_VALUE_(name)
  22. /** Base class for all automation conditions.
  23. *
  24. * @tparam Ts The template parameters to pass when executing.
  25. */
  26. template<typename... Ts> class Condition {
  27. public:
  28. /// Check whether this condition passes. This condition check must be instant, and not cause any delays.
  29. virtual bool check(Ts... x) = 0;
  30. /// Call check with a tuple of values as parameter.
  31. bool check_tuple(const std::tuple<Ts...> &tuple) {
  32. return this->check_tuple_(tuple, typename gens<sizeof...(Ts)>::type());
  33. }
  34. protected:
  35. template<int... S> bool check_tuple_(const std::tuple<Ts...> &tuple, seq<S...>) {
  36. return this->check(std::get<S>(tuple)...);
  37. }
  38. };
  39. template<typename... Ts> class Automation;
  40. template<typename... Ts> class Trigger {
  41. public:
  42. /// Inform the parent automation that the event has triggered.
  43. void trigger(Ts... x) {
  44. if (this->automation_parent_ == nullptr)
  45. return;
  46. this->automation_parent_->trigger(x...);
  47. }
  48. void set_automation_parent(Automation<Ts...> *automation_parent) { this->automation_parent_ = automation_parent; }
  49. /// Stop any action connected to this trigger.
  50. void stop_action() {
  51. if (this->automation_parent_ == nullptr)
  52. return;
  53. this->automation_parent_->stop();
  54. }
  55. /// Returns true if any action connected to this trigger is running.
  56. bool is_action_running() {
  57. if (this->automation_parent_ == nullptr)
  58. return false;
  59. return this->automation_parent_->is_running();
  60. }
  61. protected:
  62. Automation<Ts...> *automation_parent_{nullptr};
  63. };
  64. template<typename... Ts> class ActionList;
  65. template<typename... Ts> class Action {
  66. public:
  67. virtual void play_complex(Ts... x) {
  68. this->num_running_++;
  69. this->play(x...);
  70. this->play_next_(x...);
  71. }
  72. virtual void stop_complex() {
  73. if (num_running_) {
  74. this->stop();
  75. this->num_running_ = 0;
  76. }
  77. this->stop_next_();
  78. }
  79. /// Check if this or any of the following actions are currently running.
  80. virtual bool is_running() { return this->num_running_ > 0 || this->is_running_next_(); }
  81. /// The total number of actions that are currently running in this plus any of
  82. /// the following actions in the chain.
  83. int num_running_total() {
  84. int total = this->num_running_;
  85. if (this->next_ != nullptr)
  86. total += this->next_->num_running_total();
  87. return total;
  88. }
  89. protected:
  90. friend ActionList<Ts...>;
  91. virtual void play(Ts... x) = 0;
  92. void play_next_(Ts... x) {
  93. if (this->num_running_ > 0) {
  94. this->num_running_--;
  95. if (this->next_ != nullptr) {
  96. this->next_->play_complex(x...);
  97. }
  98. }
  99. }
  100. template<int... S> void play_next_tuple_(const std::tuple<Ts...> &tuple, seq<S...>) {
  101. this->play_next_(std::get<S>(tuple)...);
  102. }
  103. void play_next_tuple_(const std::tuple<Ts...> &tuple) {
  104. this->play_next_tuple_(tuple, typename gens<sizeof...(Ts)>::type());
  105. }
  106. virtual void stop() {}
  107. void stop_next_() {
  108. if (this->next_ != nullptr) {
  109. this->next_->stop_complex();
  110. }
  111. }
  112. bool is_running_next_() {
  113. if (this->next_ == nullptr)
  114. return false;
  115. return this->next_->is_running();
  116. }
  117. Action<Ts...> *next_ = nullptr;
  118. /// The number of instances of this sequence in the list of actions
  119. /// that is currently being executed.
  120. int num_running_{0};
  121. };
  122. template<typename... Ts> class ActionList {
  123. public:
  124. void add_action(Action<Ts...> *action) {
  125. if (this->actions_end_ == nullptr) {
  126. this->actions_begin_ = action;
  127. } else {
  128. this->actions_end_->next_ = action;
  129. }
  130. this->actions_end_ = action;
  131. }
  132. void add_actions(const std::vector<Action<Ts...> *> &actions) {
  133. for (auto *action : actions) {
  134. this->add_action(action);
  135. }
  136. }
  137. void play(Ts... x) {
  138. if (this->actions_begin_ != nullptr)
  139. this->actions_begin_->play_complex(x...);
  140. }
  141. void play_tuple(const std::tuple<Ts...> &tuple) { this->play_tuple_(tuple, typename gens<sizeof...(Ts)>::type()); }
  142. void stop() {
  143. if (this->actions_begin_ != nullptr)
  144. this->actions_begin_->stop_complex();
  145. }
  146. bool empty() const { return this->actions_begin_ == nullptr; }
  147. /// Check if any action in this action list is currently running.
  148. bool is_running() {
  149. if (this->actions_begin_ == nullptr)
  150. return false;
  151. return this->actions_begin_->is_running();
  152. }
  153. /// Return the number of actions in this action list that are currently running.
  154. int num_running() {
  155. if (this->actions_begin_ == nullptr)
  156. return false;
  157. return this->actions_begin_->num_running_total();
  158. }
  159. protected:
  160. template<int... S> void play_tuple_(const std::tuple<Ts...> &tuple, seq<S...>) { this->play(std::get<S>(tuple)...); }
  161. Action<Ts...> *actions_begin_{nullptr};
  162. Action<Ts...> *actions_end_{nullptr};
  163. };
  164. template<typename... Ts> class Automation {
  165. public:
  166. explicit Automation(Trigger<Ts...> *trigger) : trigger_(trigger) { this->trigger_->set_automation_parent(this); }
  167. Action<Ts...> *add_action(Action<Ts...> *action) { this->actions_.add_action(action); }
  168. void add_actions(const std::vector<Action<Ts...> *> &actions) { this->actions_.add_actions(actions); }
  169. void stop() { this->actions_.stop(); }
  170. void trigger(Ts... x) { this->actions_.play(x...); }
  171. bool is_running() { return this->actions_.is_running(); }
  172. /// Return the number of actions in the action part of this automation that are currently running.
  173. int num_running() { return this->actions_.num_running(); }
  174. protected:
  175. Trigger<Ts...> *trigger_;
  176. ActionList<Ts...> actions_;
  177. };
  178. } // namespace esphome