ESPHome 2025.12.0-dev
Loading...
Searching...
No Matches
time_entity.cpp
Go to the documentation of this file.
1#include "time_entity.h"
4#ifdef USE_DATETIME_TIME
5
6#include "esphome/core/log.h"
7
8namespace esphome {
9namespace datetime {
10
11static const char *const TAG = "datetime.time_entity";
12
14 if (this->hour_ > 23) {
15 this->set_has_state(false);
16 ESP_LOGE(TAG, "Hour must be between 0 and 23");
17 return;
18 }
19 if (this->minute_ > 59) {
20 this->set_has_state(false);
21 ESP_LOGE(TAG, "Minute must be between 0 and 59");
22 return;
23 }
24 if (this->second_ > 59) {
25 this->set_has_state(false);
26 ESP_LOGE(TAG, "Second must be between 0 and 59");
27 return;
28 }
29 this->set_has_state(true);
30 ESP_LOGD(TAG, "'%s': Sending time %02d:%02d:%02d", this->get_name().c_str(), this->hour_, this->minute_,
31 this->second_);
32 this->state_callback_.call();
33#if defined(USE_DATETIME_TIME) && defined(USE_CONTROLLER_REGISTRY)
35#endif
36}
37
39
41 if (this->hour_.has_value() && this->hour_ > 23) {
42 ESP_LOGE(TAG, "Hour must be between 0 and 23");
43 this->hour_.reset();
44 }
45 if (this->minute_.has_value() && this->minute_ > 59) {
46 ESP_LOGE(TAG, "Minute must be between 0 and 59");
47 this->minute_.reset();
48 }
49 if (this->second_.has_value() && this->second_ > 59) {
50 ESP_LOGE(TAG, "Second must be between 0 and 59");
51 this->second_.reset();
52 }
53}
54
56 this->validate_();
57 ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
58 if (this->hour_.has_value()) {
59 ESP_LOGD(TAG, " Hour: %d", *this->hour_);
60 }
61 if (this->minute_.has_value()) {
62 ESP_LOGD(TAG, " Minute: %d", *this->minute_);
63 }
64 if (this->second_.has_value()) {
65 ESP_LOGD(TAG, " Second: %d", *this->second_);
66 }
67 this->parent_->control(*this);
68}
69
70TimeCall &TimeCall::set_time(uint8_t hour, uint8_t minute, uint8_t second) {
71 this->hour_ = hour;
72 this->minute_ = minute;
73 this->second_ = second;
74 return *this;
75};
76
77TimeCall &TimeCall::set_time(ESPTime time) { return this->set_time(time.hour, time.minute, time.second); };
78
79TimeCall &TimeCall::set_time(const std::string &time) {
80 ESPTime val{};
81 if (!ESPTime::strptime(time, val)) {
82 ESP_LOGE(TAG, "Could not convert the time string to an ESPTime object");
83 return *this;
84 }
85 return this->set_time(val);
86}
87
89 TimeCall call = time->make_call();
90 call.set_time(this->hour, this->minute, this->second);
91 return call;
92}
93
95 time->hour_ = this->hour;
96 time->minute_ = this->minute;
97 time->second_ = this->second;
98 time->publish_state();
99}
100
101#ifdef USE_TIME
102static const int MAX_TIMESTAMP_DRIFT = 900; // how far can the clock drift before we consider
103 // there has been a drastic time synchronization
104
106 if (!this->parent_->has_state()) {
107 return;
108 }
109 ESPTime time = this->parent_->rtc_->now();
110 if (!time.is_valid()) {
111 return;
112 }
113 if (this->last_check_.has_value()) {
114 if (*this->last_check_ > time && this->last_check_->timestamp - time.timestamp > MAX_TIMESTAMP_DRIFT) {
115 // We went back in time (a lot), probably caused by time synchronization
116 ESP_LOGW(TAG, "Time has jumped back!");
117 } else if (*this->last_check_ >= time) {
118 // already handled this one
119 return;
120 } else if (time > *this->last_check_ && time.timestamp - this->last_check_->timestamp > MAX_TIMESTAMP_DRIFT) {
121 // We went ahead in time (a lot), probably caused by time synchronization
122 ESP_LOGW(TAG, "Time has jumped ahead!");
123 this->last_check_ = time;
124 return;
125 }
126
127 while (true) {
128 this->last_check_->increment_second();
129 if (*this->last_check_ >= time)
130 break;
131
132 if (this->matches_(*this->last_check_)) {
133 this->trigger();
134 break;
135 }
136 }
137 }
138
139 this->last_check_ = time;
140 if (!time.fields_in_range()) {
141 ESP_LOGW(TAG, "Time is out of range!");
142 ESP_LOGD(TAG, "Second=%02u Minute=%02u Hour=%02u", time.second, time.minute, time.hour);
143 }
144
145 if (this->matches_(time))
146 this->trigger();
147}
148
149bool OnTimeTrigger::matches_(const ESPTime &time) const {
150 return time.is_valid() && time.hour == this->parent_->hour && time.minute == this->parent_->minute &&
151 time.second == this->parent_->second;
152}
153#endif
154
155} // namespace datetime
156} // namespace esphome
157
158#endif // USE_DATETIME_TIME
static void notify_time_update(datetime::TimeEntity *obj)
const StringRef & get_name() const
void set_has_state(bool state)
Definition entity_base.h:93
constexpr const char * c_str() const
Definition string_ref.h:69
void trigger(const Ts &...x)
Definition automation.h:169
CallbackManager< void()> state_callback_
bool matches_(const ESPTime &time) const
optional< ESPTime > last_check_
optional< uint8_t > second_
Definition time_entity.h:99
optional< uint8_t > hour_
Definition time_entity.h:97
optional< uint8_t > minute_
Definition time_entity.h:98
TimeCall & set_time(uint8_t hour, uint8_t minute, uint8_t second)
virtual void control(const TimeCall &call)=0
bool has_value() const
Definition optional.h:92
uint8_t second
uint8_t minute
uint8_t hour
mopeka_std_values val[4]
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
A more user-friendly version of struct tm from time.h.
Definition time.h:15
uint8_t minute
minutes after the hour [0-59]
Definition time.h:21
uint8_t second
seconds after the minute [0-60]
Definition time.h:19
uint8_t hour
hours since midnight [0-23]
Definition time.h:23
time_t timestamp
unix epoch time (seconds since UTC Midnight January 1, 1970)
Definition time.h:37
static bool strptime(const std::string &time_to_parse, ESPTime &esp_time)
Convert a string to ESPTime struct as specified by the format argument.
Definition time.cpp:61
bool is_valid() const
Check if this ESPTime is valid (all fields in range and year is greater than 2018)
Definition time.h:61
bool fields_in_range() const
Check if all time fields of this ESPTime are in range.
Definition time.h:64