ESPHome 2026.1.4
Loading...
Searching...
No Matches
real_time_clock.cpp
Go to the documentation of this file.
1#include "real_time_clock.h"
2#include "esphome/core/log.h"
3#ifdef USE_HOST
4#include <sys/time.h>
5#elif defined(USE_ZEPHYR)
6#include <zephyr/posix/time.h>
7#else
8#include "lwip/opt.h"
9#endif
10#ifdef USE_ESP8266
11#include "sys/time.h"
12#endif
13#if defined(USE_RP2040) || defined(USE_ZEPHYR)
14#include <sys/time.h>
15#endif
16#include <cerrno>
17
18#include <cinttypes>
19
20namespace esphome::time {
21
22static const char *const TAG = "time";
23
25
27#ifdef USE_TIME_TIMEZONE
28 ESP_LOGCONFIG(TAG, "Timezone: '%s'", this->timezone_.c_str());
29#endif
30}
31
33 ESP_LOGVV(TAG, "Got epoch %" PRIu32, epoch);
34 // Skip if time is already synchronized to avoid unnecessary writes, log spam,
35 // and prevent clock jumping backwards due to network latency
36 constexpr time_t min_valid_epoch = 1546300800; // January 1, 2019
37 time_t current_time = this->timestamp_now();
38 // Check if time is valid (year >= 2019) before comparing
39 if (current_time >= min_valid_epoch) {
40 // Unsigned subtraction handles wraparound correctly, then cast to signed
41 int32_t diff = static_cast<int32_t>(epoch - static_cast<uint32_t>(current_time));
42 if (diff >= -1 && diff <= 1) {
43 // Time is already synchronized, but still call callbacks so components
44 // waiting for time sync (e.g., uptime timestamp sensor) can initialize
45 this->time_sync_callback_.call();
46 return;
47 }
48 }
49 // Update UTC epoch time.
50#ifdef USE_ZEPHYR
51 struct timespec ts;
52 ts.tv_nsec = 0;
53 ts.tv_sec = static_cast<time_t>(epoch);
54
55 int ret = clock_settime(CLOCK_REALTIME, &ts);
56
57 if (ret != 0) {
58 ESP_LOGW(TAG, "clock_settime() failed with code %d", ret);
59 }
60#else
61 struct timeval timev {
62 .tv_sec = static_cast<time_t>(epoch), .tv_usec = 0,
63 };
64 struct timezone tz = {0, 0};
65 int ret = settimeofday(&timev, &tz);
66 if (ret == EINVAL) {
67 // Some ESP8266 frameworks abort when timezone parameter is not NULL
68 // while ESP32 expects it not to be NULL
69 ret = settimeofday(&timev, nullptr);
70 }
71
72#ifdef USE_TIME_TIMEZONE
73 // Move timezone back to local timezone.
74 this->apply_timezone_();
75#endif
76
77 if (ret != 0) {
78 ESP_LOGW(TAG, "setimeofday() failed with code %d", ret);
79 }
80#endif
81 auto time = this->now();
82 ESP_LOGD(TAG, "Synchronized time: %04d-%02d-%02d %02d:%02d:%02d", time.year, time.month, time.day_of_month, time.hour,
83 time.minute, time.second);
84
85 this->time_sync_callback_.call();
86}
87
88#ifdef USE_TIME_TIMEZONE
90 setenv("TZ", this->timezone_.c_str(), 1);
91 tzset();
92}
93#endif
94
95} // namespace esphome::time
CallbackManager< void()> time_sync_callback_
time_t timestamp_now()
Get the current time as the UTC epoch since January 1st 1970.
ESPTime now()
Get the time in the currently defined timezone.
void synchronize_epoch_(uint32_t epoch)
Report a unix epoch as current time.
const char *const TAG
Definition spi.cpp:7