ESPHome 2025.5.0
Loading...
Searching...
No Matches
base_automation.h
Go to the documentation of this file.
1#pragma once
2
5#include "esphome/core/hal.h"
8
9#include <vector>
10
11namespace esphome {
12
13template<typename... Ts> class AndCondition : public Condition<Ts...> {
14 public:
15 explicit AndCondition(const std::vector<Condition<Ts...> *> &conditions) : conditions_(conditions) {}
16 bool check(Ts... x) override {
17 for (auto *condition : this->conditions_) {
18 if (!condition->check(x...))
19 return false;
20 }
21
22 return true;
23 }
24
25 protected:
26 std::vector<Condition<Ts...> *> conditions_;
27};
28
29template<typename... Ts> class OrCondition : public Condition<Ts...> {
30 public:
31 explicit OrCondition(const std::vector<Condition<Ts...> *> &conditions) : conditions_(conditions) {}
32 bool check(Ts... x) override {
33 for (auto *condition : this->conditions_) {
34 if (condition->check(x...))
35 return true;
36 }
37
38 return false;
39 }
40
41 protected:
42 std::vector<Condition<Ts...> *> conditions_;
43};
44
45template<typename... Ts> class NotCondition : public Condition<Ts...> {
46 public:
47 explicit NotCondition(Condition<Ts...> *condition) : condition_(condition) {}
48 bool check(Ts... x) override { return !this->condition_->check(x...); }
49
50 protected:
52};
53
54template<typename... Ts> class XorCondition : public Condition<Ts...> {
55 public:
56 explicit XorCondition(const std::vector<Condition<Ts...> *> &conditions) : conditions_(conditions) {}
57 bool check(Ts... x) override {
58 size_t result = 0;
59 for (auto *condition : this->conditions_) {
60 result += condition->check(x...);
61 }
62
63 return result == 1;
64 }
65
66 protected:
67 std::vector<Condition<Ts...> *> conditions_;
68};
69
70template<typename... Ts> class LambdaCondition : public Condition<Ts...> {
71 public:
72 explicit LambdaCondition(std::function<bool(Ts...)> &&f) : f_(std::move(f)) {}
73 bool check(Ts... x) override { return this->f_(x...); }
74
75 protected:
76 std::function<bool(Ts...)> f_;
77};
78
79template<typename... Ts> class ForCondition : public Condition<Ts...>, public Component {
80 public:
81 explicit ForCondition(Condition<> *condition) : condition_(condition) {}
82
83 TEMPLATABLE_VALUE(uint32_t, time);
84
85 void loop() override { this->check_internal(); }
86 float get_setup_priority() const override { return setup_priority::DATA; }
88 bool cond = this->condition_->check();
89 if (!cond)
90 this->last_inactive_ = millis();
91 return cond;
92 }
93
94 bool check(Ts... x) override {
95 if (!this->check_internal())
96 return false;
97 return millis() - this->last_inactive_ >= this->time_.value(x...);
98 }
99
100 protected:
102 uint32_t last_inactive_{0};
103};
104
105class StartupTrigger : public Trigger<>, public Component {
106 public:
107 explicit StartupTrigger(float setup_priority) : setup_priority_(setup_priority) {}
108 void setup() override { this->trigger(); }
109 float get_setup_priority() const override { return this->setup_priority_; }
110
111 protected:
113};
114
115class ShutdownTrigger : public Trigger<>, public Component {
116 public:
117 explicit ShutdownTrigger(float setup_priority) : setup_priority_(setup_priority) {}
118 void on_shutdown() override { this->trigger(); }
119 float get_setup_priority() const override { return this->setup_priority_; }
120
121 protected:
123};
124
125class LoopTrigger : public Trigger<>, public Component {
126 public:
127 void loop() override { this->trigger(); }
128 float get_setup_priority() const override { return setup_priority::DATA; }
129};
130
131#ifdef ESPHOME_PROJECT_NAME
132class ProjectUpdateTrigger : public Trigger<std::string>, public Component {
133 public:
134 void setup() override {
135 uint32_t hash = fnv1_hash(ESPHOME_PROJECT_NAME);
136 ESPPreferenceObject pref = global_preferences->make_preference<char[30]>(hash, true);
137 char previous_version[30];
138 char current_version[30] = ESPHOME_PROJECT_VERSION_30;
139 if (pref.load(&previous_version)) {
140 int cmp = strcmp(previous_version, current_version);
141 if (cmp < 0) {
142 this->trigger(previous_version);
143 }
144 }
145 pref.save(&current_version);
147 }
148 float get_setup_priority() const override { return setup_priority::PROCESSOR; }
149};
150#endif
151
152template<typename... Ts> class DelayAction : public Action<Ts...>, public Component {
153 public:
154 explicit DelayAction() = default;
155
157
158 void play_complex(Ts... x) override {
159 auto f = std::bind(&DelayAction<Ts...>::play_next_, this, x...);
160 this->num_running_++;
161 this->set_timeout(this->delay_.value(x...), f);
162 }
163 float get_setup_priority() const override { return setup_priority::HARDWARE; }
164
165 void play(Ts... x) override { /* ignore - see play_complex */
166 }
167
168 void stop() override { this->cancel_timeout(""); }
169};
170
171template<typename... Ts> class LambdaAction : public Action<Ts...> {
172 public:
173 explicit LambdaAction(std::function<void(Ts...)> &&f) : f_(std::move(f)) {}
174
175 void play(Ts... x) override { this->f_(x...); }
176
177 protected:
178 std::function<void(Ts...)> f_;
179};
180
181template<typename... Ts> class IfAction : public Action<Ts...> {
182 public:
183 explicit IfAction(Condition<Ts...> *condition) : condition_(condition) {}
184
185 void add_then(const std::vector<Action<Ts...> *> &actions) {
186 this->then_.add_actions(actions);
187 this->then_.add_action(new LambdaAction<Ts...>([this](Ts... x) { this->play_next_(x...); }));
188 }
189
190 void add_else(const std::vector<Action<Ts...> *> &actions) {
191 this->else_.add_actions(actions);
192 this->else_.add_action(new LambdaAction<Ts...>([this](Ts... x) { this->play_next_(x...); }));
193 }
194
195 void play_complex(Ts... x) override {
196 this->num_running_++;
197 bool res = this->condition_->check(x...);
198 if (res) {
199 if (this->then_.empty()) {
200 this->play_next_(x...);
201 } else if (this->num_running_ > 0) {
202 this->then_.play(x...);
203 }
204 } else {
205 if (this->else_.empty()) {
206 this->play_next_(x...);
207 } else if (this->num_running_ > 0) {
208 this->else_.play(x...);
209 }
210 }
211 }
212
213 void play(Ts... x) override { /* ignore - see play_complex */
214 }
215
216 void stop() override {
217 this->then_.stop();
218 this->else_.stop();
219 }
220
221 protected:
225};
226
227template<typename... Ts> class WhileAction : public Action<Ts...> {
228 public:
229 WhileAction(Condition<Ts...> *condition) : condition_(condition) {}
230
231 void add_then(const std::vector<Action<Ts...> *> &actions) {
232 this->then_.add_actions(actions);
233 this->then_.add_action(new LambdaAction<Ts...>([this](Ts... x) {
234 if (this->num_running_ > 0 && this->condition_->check_tuple(this->var_)) {
235 // play again
236 if (this->num_running_ > 0) {
237 this->then_.play_tuple(this->var_);
238 }
239 } else {
240 // condition false, play next
241 this->play_next_tuple_(this->var_);
242 }
243 }));
244 }
245
246 void play_complex(Ts... x) override {
247 this->num_running_++;
248 // Store loop parameters
249 this->var_ = std::make_tuple(x...);
250 // Initial condition check
251 if (!this->condition_->check_tuple(this->var_)) {
252 // If new condition check failed, stop loop if running
253 this->then_.stop();
254 this->play_next_tuple_(this->var_);
255 return;
256 }
257
258 if (this->num_running_ > 0) {
259 this->then_.play_tuple(this->var_);
260 }
261 }
262
263 void play(Ts... x) override { /* ignore - see play_complex */
264 }
265
266 void stop() override { this->then_.stop(); }
267
268 protected:
271 std::tuple<Ts...> var_{};
272};
273
274template<typename... Ts> class RepeatAction : public Action<Ts...> {
275 public:
276 TEMPLATABLE_VALUE(uint32_t, count)
277
278 void add_then(const std::vector<Action<uint32_t, Ts...> *> &actions) {
279 this->then_.add_actions(actions);
280 this->then_.add_action(new LambdaAction<uint32_t, Ts...>([this](uint32_t iteration, Ts... x) {
281 iteration++;
282 if (iteration >= this->count_.value(x...)) {
283 this->play_next_tuple_(this->var_);
284 } else {
285 this->then_.play(iteration, x...);
286 }
287 }));
288 }
289
290 void play_complex(Ts... x) override {
291 this->num_running_++;
292 this->var_ = std::make_tuple(x...);
293 if (this->count_.value(x...) > 0) {
294 this->then_.play(0, x...);
295 } else {
296 this->play_next_tuple_(this->var_);
297 }
298 }
299
300 void play(Ts... x) override { /* ignore - see play_complex */
301 }
302
303 void stop() override { this->then_.stop(); }
304
305 protected:
306 ActionList<uint32_t, Ts...> then_;
307 std::tuple<Ts...> var_;
308};
309
310template<typename... Ts> class WaitUntilAction : public Action<Ts...>, public Component {
311 public:
312 WaitUntilAction(Condition<Ts...> *condition) : condition_(condition) {}
313
314 TEMPLATABLE_VALUE(uint32_t, timeout_value)
315
316 void play_complex(Ts... x) override {
317 this->num_running_++;
318 // Check if we can continue immediately.
319 if (this->condition_->check(x...)) {
320 if (this->num_running_ > 0) {
321 this->play_next_(x...);
322 }
323 return;
324 }
325 this->var_ = std::make_tuple(x...);
326
327 if (this->timeout_value_.has_value()) {
328 auto f = std::bind(&WaitUntilAction<Ts...>::play_next_, this, x...);
329 this->set_timeout("timeout", this->timeout_value_.value(x...), f);
330 }
331
332 this->loop();
333 }
334
335 void loop() override {
336 if (this->num_running_ == 0)
337 return;
338
339 if (!this->condition_->check_tuple(this->var_)) {
340 return;
341 }
342
343 this->cancel_timeout("timeout");
344
345 this->play_next_tuple_(this->var_);
346 }
347
348 float get_setup_priority() const override { return setup_priority::DATA; }
349
350 void play(Ts... x) override { /* ignore - see play_complex */
351 }
352
353 void stop() override { this->cancel_timeout("timeout"); }
354
355 protected:
357 std::tuple<Ts...> var_{};
358};
359
360template<typename... Ts> class UpdateComponentAction : public Action<Ts...> {
361 public:
362 UpdateComponentAction(PollingComponent *component) : component_(component) {}
363
364 void play(Ts... x) override {
365 if (!this->component_->is_ready())
366 return;
367 this->component_->update();
368 }
369
370 protected:
372};
373
374template<typename... Ts> class SuspendComponentAction : public Action<Ts...> {
375 public:
376 SuspendComponentAction(PollingComponent *component) : component_(component) {}
377
378 void play(Ts... x) override {
379 if (!this->component_->is_ready())
380 return;
381 this->component_->stop_poller();
382 }
383
384 protected:
386};
387
388template<typename... Ts> class ResumeComponentAction : public Action<Ts...> {
389 public:
390 ResumeComponentAction(PollingComponent *component) : component_(component) {}
391 TEMPLATABLE_VALUE(uint32_t, update_interval)
392
393 void play(Ts... x) override {
394 if (!this->component_->is_ready()) {
395 return;
396 }
397 optional<uint32_t> update_interval = this->update_interval_.optional_value(x...);
398 if (update_interval.has_value()) {
399 this->component_->set_update_interval(update_interval.value());
400 }
401 this->component_->start_poller();
402 }
403
404 protected:
406};
407
408} // namespace esphome
virtual void play_complex(Ts... x)
Definition automation.h:124
void play_next_(Ts... x)
Definition automation.h:152
void add_action(Action< Ts... > *action)
Definition automation.h:189
void play(Ts... x)
Definition automation.h:202
void add_actions(const std::vector< Action< Ts... > * > &actions)
Definition automation.h:197
bool empty() const
Definition automation.h:211
AndCondition(const std::vector< Condition< Ts... > * > &conditions)
std::vector< Condition< Ts... > * > conditions_
bool check(Ts... x) override
bool cancel_timeout(const std::string &name)
Cancel a timeout function.
Definition component.cpp:76
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.cpp:72
Base class for all automation conditions.
Definition automation.h:75
virtual bool check(Ts... x)=0
Check whether this condition passes. This condition check must be instant, and not cause any delays.
void play(Ts... x) override
float get_setup_priority() const override
TEMPLATABLE_VALUE(uint32_t, delay) void play_complex(Ts... x) override
bool save(const T *src)
Definition preferences.h:21
virtual bool sync()=0
Commit pending writes to flash.
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
ForCondition(Condition<> *condition)
float get_setup_priority() const override
bool check(Ts... x) override
TEMPLATABLE_VALUE(uint32_t, time)
Condition< Ts... > * condition_
void play_complex(Ts... x) override
void stop() override
ActionList< Ts... > else_
void add_else(const std::vector< Action< Ts... > * > &actions)
void play(Ts... x) override
void add_then(const std::vector< Action< Ts... > * > &actions)
ActionList< Ts... > then_
IfAction(Condition< Ts... > *condition)
LambdaAction(std::function< void(Ts...)> &&f)
std::function< void(Ts...)> f_
void play(Ts... x) override
bool check(Ts... x) override
LambdaCondition(std::function< bool(Ts...)> &&f)
std::function< bool(Ts...)> f_
float get_setup_priority() const override
bool check(Ts... x) override
Condition< Ts... > * condition_
NotCondition(Condition< Ts... > *condition)
std::vector< Condition< Ts... > * > conditions_
bool check(Ts... x) override
OrCondition(const std::vector< Condition< Ts... > * > &conditions)
This class simplifies creating components that periodically check a state.
Definition component.h:301
float get_setup_priority() const override
ActionList< uint32_t, Ts... > then_
TEMPLATABLE_VALUE(uint32_t, count) void add_then(const std
void play(Ts... x) override
std::tuple< Ts... > var_
void play_complex(Ts... x) override
ResumeComponentAction(PollingComponent *component)
TEMPLATABLE_VALUE(uint32_t, update_interval) void play(Ts... x) override
ShutdownTrigger(float setup_priority)
float get_setup_priority() const override
float get_setup_priority() const override
StartupTrigger(float setup_priority)
SuspendComponentAction(PollingComponent *component)
void trigger(Ts... x)
Definition automation.h:96
void play(Ts... x) override
UpdateComponentAction(PollingComponent *component)
WaitUntilAction(Condition< Ts... > *condition)
void play(Ts... x) override
Condition< Ts... > * condition_
TEMPLATABLE_VALUE(uint32_t, timeout_value) void play_complex(Ts... x) override
float get_setup_priority() const override
WhileAction(Condition< Ts... > *condition)
void play(Ts... x) override
void play_complex(Ts... x) override
void add_then(const std::vector< Action< Ts... > * > &actions)
Condition< Ts... > * condition_
ActionList< Ts... > then_
bool check(Ts... x) override
std::vector< Condition< Ts... > * > conditions_
XorCondition(const std::vector< Condition< Ts... > * > &conditions)
bool has_value() const
Definition optional.h:87
value_type const & value() const
Definition optional.h:89
void loop()
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:19
const float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition component.cpp:18
const float PROCESSOR
For components that use data from sensors like displays.
Definition component.cpp:20
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint32_t fnv1_hash(const std::string &str)
Calculate a FNV-1 hash of str.
Definition helpers.cpp:186
ESPPreferences * global_preferences
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:28
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:27
uint16_t x
Definition tt21100.cpp:5