ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
real_time_clock.h
Go to the documentation of this file.
1#pragma once
2
3#include <bitset>
4#include <cstdlib>
8#include "esphome/core/time.h"
9#ifdef USE_TIME_TIMEZONE
10#include "posix_tz.h"
11#endif
12
13namespace esphome::time {
14
22 public:
23 explicit RealTimeClock();
24
27
30
32 virtual time_t timestamp_now() { return ::time(nullptr); }
33
34 template<typename F> void add_on_time_sync_callback(F &&callback) {
35 this->time_sync_callback_.add(std::forward<F>(callback));
36 }
37
38 void dump_config() override;
39
40 protected:
42 void synchronize_epoch_(uint32_t epoch);
43
45};
46
48enum class BcdWeekday : uint8_t {
49 ONE_HOT,
50 FROM_1,
51 FROM_0,
52};
53
60 bool century_bit{false};
62 bool hour_12h{false};
63
64 constexpr size_t weekday_index() const { return this->weekday_before_day ? 3 : 4; }
65 constexpr size_t day_index() const { return this->weekday_before_day ? 4 : 3; }
66};
67
72 .weekday = BcdWeekday::FROM_1, .century_bit = true, .hour_12h = true};
74inline constexpr BcdCalendarLayout PCF_BCD_CALENDAR{.weekday = BcdWeekday::FROM_0, .weekday_before_day = false};
75
79template<BcdCalendarLayout LAYOUT> __attribute__((noinline)) ESPTime decode_bcd_calendar(const uint8_t *raw) {
80 uint8_t day_of_week;
81 if constexpr (LAYOUT.weekday == BcdWeekday::ONE_HOT) {
82 const uint8_t weekday = raw[LAYOUT.weekday_index()] & 0x7F;
83 day_of_week = weekday ? __builtin_ctz(weekday) + 1 : 1;
84 } else if constexpr (LAYOUT.weekday == BcdWeekday::FROM_1) {
85 day_of_week = raw[LAYOUT.weekday_index()] & 0x07;
86 } else {
87 day_of_week = (raw[LAYOUT.weekday_index()] & 0x07) + 1;
88 }
89 uint8_t hour = bcd_to_uint8(raw[2] & 0x3F);
90 if constexpr (LAYOUT.hour_12h) {
91 if ((raw[2] & 0x40) != 0) {
92 // 12-hour mode, e.g. set by another library: 12 AM reads as 12 with PM clear, 12 PM as 12 with PM set.
93 hour = bcd_to_uint8(raw[2] & 0x1F) % 12 + ((raw[2] & 0x20) != 0 ? 12 : 0);
94 }
95 }
96 uint16_t year = 2000 + bcd_to_uint8(raw[6]);
97 if constexpr (LAYOUT.century_bit) {
98 if ((raw[5] & 0x80) != 0)
99 year += 100;
100 }
101 ESPTime time{
102 .second = bcd_to_uint8(raw[0] & 0x7F),
103 .minute = bcd_to_uint8(raw[1] & 0x7F),
104 .hour = hour,
105 .day_of_week = day_of_week,
106 .day_of_month = bcd_to_uint8(raw[LAYOUT.day_index()] & 0x3F),
107 .day_of_year = 1,
108 .month = bcd_to_uint8(raw[5] & 0x1F),
109 .year = year,
110 .is_dst = false,
111 .timestamp = 0,
112 };
113 time.recalc_timestamp_utc(false);
114 return time;
115}
116
119template<BcdCalendarLayout LAYOUT>
120__attribute__((noinline)) void encode_bcd_calendar(const ESPTime &time, uint8_t *raw) {
121 uint8_t value[7] = {time.second, time.minute, time.hour, 0, 0, time.month, static_cast<uint8_t>(time.year % 100)};
122 value[LAYOUT.day_index()] = time.day_of_month;
123 for (size_t i = 0; i < 7; i++)
124 raw[i] = uint8_to_bcd(value[i]);
125 if constexpr (LAYOUT.weekday == BcdWeekday::ONE_HOT) {
126 raw[LAYOUT.weekday_index()] = 1 << (time.day_of_week - 1);
127 } else if constexpr (LAYOUT.weekday == BcdWeekday::FROM_1) {
128 raw[LAYOUT.weekday_index()] = time.day_of_week;
129 } else {
130 raw[LAYOUT.weekday_index()] = time.day_of_week - 1;
131 }
132 if constexpr (LAYOUT.century_bit) {
133 if (time.year >= 2100)
134 raw[5] |= 0x80;
135 }
136}
137
138} // namespace esphome::time
This class simplifies creating components that periodically check a state.
Definition component.h:519
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.
ESPTime utcnow()
Get the time without any time zone or DST corrections.
virtual time_t timestamp_now()
Get the current time as the UTC epoch since January 1st 1970.
LazyCallbackManager< void()> time_sync_callback_
void add_on_time_sync_callback(F &&callback)
void synchronize_epoch_(uint32_t epoch)
Report a unix epoch as current time.
uint16_t year
Definition date_entity.h:0
uint8_t hour
value[LAYOUT.day_index()]
ESPTime __attribute__((noinline)) RealTimeClock
constexpr BcdCalendarLayout EPSON_BCD_CALENDAR
Epson RX8025T, RX8111, RX8130.
BcdWeekday
How the weekday byte of a BCD calendar names the day, Sunday first.
@ ONE_HOT
one bit per day, bit 0 is Sunday
constexpr BcdCalendarLayout PCF_BCD_CALENDAR
PCF8563, PCF85063, BM8563.
constexpr BcdCalendarLayout DS_BCD_CALENDAR
DS1307, DS3231.
constexpr uint8_t uint8_to_bcd(uint8_t value)
Encode a value from 0 to 99 as a two-digit packed BCD byte, e.g. 59 to 0x59.
Definition helpers.h:1068
constexpr uint8_t bcd_to_uint8(uint8_t bcd)
Decode a two-digit packed BCD byte (tens in the high nibble) to its value, e.g. 0x59 to 59.
Definition helpers.h:1066
static void uint32_t
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
void recalc_timestamp_utc(bool use_day_of_year=true)
Recalculate the timestamp field from the other fields of this ESPTime instance (must be UTC).
Definition time.cpp:280
uint8_t second
seconds after the minute [0-60]
Definition time.h:30
uint8_t hour
hours since midnight [0-23]
Definition time.h:34
static ESPTime from_epoch_utc(time_t epoch)
Convert an UTC epoch timestamp to a UTC time ESPTime instance.
Definition time.h:143
uint8_t day_of_month
day of the month [1-31]
Definition time.h:38
uint16_t year
year
Definition time.h:44
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
Layout of a 7-byte BCD calendar: second, minute, hour, weekday and day of the month in either order,...
bool century_bit
Bit 7 of the month byte is set from the year 2100 on. Chips without the bit read it as 0.
constexpr size_t day_index() const
bool hour_12h
Bit 6 of the hour byte selects 12-hour mode, with PM in bit 5; decoded only, encoding writes 24-hour ...
constexpr size_t weekday_index() const