ESPHome 2026.5.0-dev
Loading...
Searching...
No Matches
automation.cpp
Go to the documentation of this file.
1#include "automation.h"
2
3#include "esphome/core/log.h"
4
5#include <cinttypes>
6
7namespace esphome::time {
8
9static const char *const TAG = "automation";
10static const int MAX_TIMESTAMP_DRIFT = 900; // how far can the clock drift before we consider
11 // there has been a drastic time synchronization
12
13void CronTrigger::add_second(uint8_t second) { this->seconds_[second] = true; }
14void CronTrigger::add_minute(uint8_t minute) { this->minutes_[minute] = true; }
15void CronTrigger::add_hour(uint8_t hour) { this->hours_[hour] = true; }
16void CronTrigger::add_day_of_month(uint8_t day_of_month) { this->days_of_month_[day_of_month] = true; }
17void CronTrigger::add_month(uint8_t month) { this->months_[month] = true; }
18void CronTrigger::add_day_of_week(uint8_t day_of_week) { this->days_of_week_[day_of_week] = true; }
19bool CronTrigger::matches(const ESPTime &time) {
20 return time.is_valid() && this->seconds_[time.second] && this->minutes_[time.minute] && this->hours_[time.hour] &&
21 this->days_of_month_[time.day_of_month] && this->months_[time.month] && this->days_of_week_[time.day_of_week];
22}
24 // Cron resolution is 1 second — check once per second instead of every loop iteration
25 this->set_interval(1000, [this]() { this->check_time_(); });
26}
27
29 ESPTime time = this->rtc_->now();
30 if (!time.is_valid())
31 return;
32
33 if (this->last_check_.has_value()) {
34 if (*this->last_check_ > time && this->last_check_->timestamp - time.timestamp > MAX_TIMESTAMP_DRIFT) {
35 // We went back in time (a lot), probably caused by time synchronization
36 ESP_LOGW(TAG, "Time has jumped back!");
37 } else if (*this->last_check_ >= time) {
38 // already handled this one
39 return;
40 } else if (time > *this->last_check_ && time.timestamp - this->last_check_->timestamp > MAX_TIMESTAMP_DRIFT) {
41 // We went ahead in time (a lot), probably caused by time synchronization
42 ESP_LOGW(TAG, "Time has jumped ahead!");
43 this->last_check_ = time;
44 return;
45 }
46
47 while (true) {
48 this->last_check_->increment_second();
49 if (*this->last_check_ >= time)
50 break;
51
52 if (this->matches(*this->last_check_))
53 this->trigger();
54 }
55 }
56
57 this->last_check_ = time;
58 if (!time.fields_in_range()) {
59 ESP_LOGW(TAG, "Time is out of range!");
60 ESP_LOGD(TAG, "Second=%02u Minute=%02u Hour=%02u DayOfWeek=%u DayOfMonth=%u DayOfYear=%u Month=%u time=%" PRId64,
61 time.second, time.minute, time.hour, time.day_of_week, time.day_of_month, time.day_of_year, time.month,
62 (int64_t) time.timestamp);
63 }
64
65 if (this->matches(time))
66 this->trigger();
67}
69void CronTrigger::add_seconds(const std::vector<uint8_t> &seconds) {
70 for (uint8_t it : seconds)
71 this->add_second(it);
72}
73void CronTrigger::add_minutes(const std::vector<uint8_t> &minutes) {
74 for (uint8_t it : minutes)
75 this->add_minute(it);
76}
77void CronTrigger::add_hours(const std::vector<uint8_t> &hours) {
78 for (uint8_t it : hours)
79 this->add_hour(it);
80}
81void CronTrigger::add_days_of_month(const std::vector<uint8_t> &days_of_month) {
82 for (uint8_t it : days_of_month)
83 this->add_day_of_month(it);
84}
85void CronTrigger::add_months(const std::vector<uint8_t> &months) {
86 for (uint8_t it : months)
87 this->add_month(it);
88}
89void CronTrigger::add_days_of_week(const std::vector<uint8_t> &days_of_week) {
90 for (uint8_t it : days_of_week)
91 this->add_day_of_week(it);
92}
94
96 rtc->add_on_time_sync_callback([this]() { this->trigger(); });
97}
98
99} // namespace esphome::time
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_interval(const std voi set_interval)(const char *name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a unique name.
Definition component.h:417
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Definition automation.h:482
void add_second(uint8_t second)
void add_minutes(const std::vector< uint8_t > &minutes)
void add_month(uint8_t month)
std::bitset< 8 > days_of_week_
Definition automation.h:39
void add_hour(uint8_t hour)
void add_day_of_month(uint8_t day_of_month)
void add_seconds(const std::vector< uint8_t > &seconds)
bool matches(const ESPTime &time)
void add_months(const std::vector< uint8_t > &months)
float get_setup_priority() const override
void add_days_of_month(const std::vector< uint8_t > &days_of_month)
std::bitset< 32 > days_of_month_
Definition automation.h:37
std::bitset< 61 > seconds_
Definition automation.h:34
CronTrigger(RealTimeClock *rtc)
void add_minute(uint8_t minute)
std::bitset< 24 > hours_
Definition automation.h:36
optional< ESPTime > last_check_
Definition automation.h:41
void add_days_of_week(const std::vector< uint8_t > &days_of_week)
void add_day_of_week(uint8_t day_of_week)
std::bitset< 60 > minutes_
Definition automation.h:35
std::bitset< 13 > months_
Definition automation.h:38
void add_hours(const std::vector< uint8_t > &hours)
The RealTimeClock class exposes common timekeeping functions via the device's local real-time clock.
ESPTime now()
Get the time in the currently defined timezone.
void add_on_time_sync_callback(F &&callback)
SyncTrigger(RealTimeClock *rtc)
uint8_t month
Definition date_entity.h:1
uint8_t second
uint8_t minute
uint8_t hour
constexpr float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition component.h:40
A more user-friendly version of struct tm from time.h.
Definition time.h:23
uint8_t minute
minutes after the hour [0-59]
Definition time.h:32
uint8_t second
seconds after the minute [0-60]
Definition time.h:30
bool fields_in_range(bool check_day_of_week=true, bool check_day_of_year=true) const
Check if time fields are in range.
Definition time.h:89
uint8_t hour
hours since midnight [0-23]
Definition time.h:34
time_t timestamp
unix epoch time (seconds since UTC Midnight January 1, 1970)
Definition time.h:48
uint16_t day_of_year
day of the year [1-366]
Definition time.h:40
bool is_valid(bool check_day_of_week=true, bool check_day_of_year=true) const
Check if this ESPTime is valid (year >= 2019 and the requested fields are in range).
Definition time.h:82
uint8_t day_of_month
day of the month [1-31]
Definition time.h:38
uint8_t month
month; january=1 [1-12]
Definition time.h:42
uint8_t day_of_week
day of the week; sunday=1 [1-7]
Definition time.h:36