ESPHome 2026.1.0-dev
Loading...
Searching...
No Matches
bm8563.cpp
Go to the documentation of this file.
1#include "bm8563.h"
2#include "esphome/core/log.h"
3
4namespace esphome::bm8563 {
5
6static const char *const TAG = "bm8563";
7
8static constexpr uint8_t CONTROL_STATUS_1_REG = 0x00;
9static constexpr uint8_t CONTROL_STATUS_2_REG = 0x01;
10static constexpr uint8_t TIME_FIRST_REG = 0x02; // Time uses reg 2, 3, 4
11static constexpr uint8_t DATE_FIRST_REG = 0x05; // Date uses reg 5, 6, 7, 8
12static constexpr uint8_t TIMER_CONTROL_REG = 0x0E;
13static constexpr uint8_t TIMER_VALUE_REG = 0x0F;
14static constexpr uint8_t CLOCK_1_HZ = 0x82;
15static constexpr uint8_t CLOCK_1_60_HZ = 0x83;
16// Maximum duration: 255 minutes (at 1/60 Hz) = 15300 seconds
17static constexpr uint32_t MAX_TIMER_DURATION_S = 255 * 60;
18
20 if (!this->write_byte_16(CONTROL_STATUS_1_REG, 0)) {
21 this->mark_failed();
22 return;
23 }
24}
25
26void BM8563::update() { this->read_time(); }
27
29 ESP_LOGCONFIG(TAG, "BM8563:");
30 LOG_I2C_DEVICE(this);
31 if (this->is_failed()) {
32 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
33 }
34}
35
36void BM8563::start_timer(uint32_t duration_s) {
37 this->clear_irq_();
38 this->set_timer_irq_(duration_s);
39}
40
43 if (!now.is_valid()) {
44 ESP_LOGE(TAG, "Invalid system time, not syncing to RTC.");
45 return;
46 }
47
48 ESP_LOGD(TAG, "Writing time: %i-%i-%i %i, %i:%i:%i", now.year, now.month, now.day_of_month, now.day_of_week, now.hour,
50
51 this->set_time_(now);
52 this->set_date_(now);
53}
54
56 ESPTime rtc_time;
57 this->get_time_(rtc_time);
58 this->get_date_(rtc_time);
59 rtc_time.day_of_year = 1; // unused by recalc_timestamp_utc, but needs to be valid
60 ESP_LOGD(TAG, "Read time: %i-%i-%i %i, %i:%i:%i", rtc_time.year, rtc_time.month, rtc_time.day_of_month,
61 rtc_time.day_of_week, rtc_time.hour, rtc_time.minute, rtc_time.second);
62
63 rtc_time.recalc_timestamp_utc(false);
64 if (!rtc_time.is_valid()) {
65 ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");
66 return;
67 }
69}
70
71uint8_t BM8563::bcd2_to_byte_(uint8_t value) {
72 const uint8_t tmp = ((value & 0xF0) >> 0x4) * 10;
73 return tmp + (value & 0x0F);
74}
75
76uint8_t BM8563::byte_to_bcd2_(uint8_t value) {
77 const uint8_t bcdhigh = value / 10;
78 value -= bcdhigh * 10;
79 return (bcdhigh << 4) | value;
80}
81
82void BM8563::get_time_(ESPTime &time) {
83 uint8_t buf[3] = {0};
84 this->read_register(TIME_FIRST_REG, buf, 3);
85
86 time.second = this->bcd2_to_byte_(buf[0] & 0x7f);
87 time.minute = this->bcd2_to_byte_(buf[1] & 0x7f);
88 time.hour = this->bcd2_to_byte_(buf[2] & 0x3f);
89}
90
91void BM8563::set_time_(const ESPTime &time) {
92 uint8_t buf[3] = {this->byte_to_bcd2_(time.second), this->byte_to_bcd2_(time.minute), this->byte_to_bcd2_(time.hour)};
93 this->write_register_(TIME_FIRST_REG, buf, 3);
94}
95
96void BM8563::get_date_(ESPTime &time) {
97 uint8_t buf[4] = {0};
98 this->read_register(DATE_FIRST_REG, buf, sizeof(buf));
99
100 time.day_of_month = this->bcd2_to_byte_(buf[0] & 0x3f);
101 time.day_of_week = this->bcd2_to_byte_(buf[1] & 0x07);
102 time.month = this->bcd2_to_byte_(buf[2] & 0x1f);
103
104 uint8_t year_byte = this->bcd2_to_byte_(buf[3] & 0xff);
105
106 if (buf[2] & 0x80) {
107 time.year = 1900 + year_byte;
108 } else {
109 time.year = 2000 + year_byte;
110 }
111}
112
113void BM8563::set_date_(const ESPTime &time) {
114 uint8_t buf[4] = {
115 this->byte_to_bcd2_(time.day_of_month),
116 this->byte_to_bcd2_(time.day_of_week),
117 this->byte_to_bcd2_(time.month),
118 this->byte_to_bcd2_(time.year % 100),
119 };
120
121 if (time.year < 2000) {
122 buf[2] = buf[2] | 0x80;
123 }
124
125 this->write_register_(DATE_FIRST_REG, buf, 4);
126}
127
128void BM8563::write_byte_(uint8_t reg, uint8_t value) {
129 if (!this->write_byte(reg, value)) {
130 ESP_LOGE(TAG, "Failed to write byte 0x%02X with value 0x%02X", reg, value);
131 }
132}
133
134void BM8563::write_register_(uint8_t reg, const uint8_t *data, size_t len) {
135 if (auto error = this->write_register(reg, data, len); error != i2c::ErrorCode::NO_ERROR) {
136 ESP_LOGE(TAG, "Failed to write register 0x%02X with %zu bytes", reg, len);
137 }
138}
139
140optional<uint8_t> BM8563::read_register_(uint8_t reg) {
141 uint8_t data;
142 if (auto error = this->read_register(reg, &data, 1); error != i2c::ErrorCode::NO_ERROR) {
143 ESP_LOGE(TAG, "Failed to read register 0x%02X", reg);
144 return {};
145 }
146 return data;
147}
148
149void BM8563::set_timer_irq_(uint32_t duration_s) {
150 ESP_LOGI(TAG, "Timer Duration: %u s", duration_s);
151
152 if (duration_s > MAX_TIMER_DURATION_S) {
153 ESP_LOGW(TAG, "Timer duration %u s exceeds maximum %u s", duration_s, MAX_TIMER_DURATION_S);
154 return;
155 }
156
157 if (duration_s > 255) {
158 uint8_t duration_minutes = duration_s / 60;
159 this->write_byte_(TIMER_VALUE_REG, duration_minutes);
160 this->write_byte_(TIMER_CONTROL_REG, CLOCK_1_60_HZ);
161 } else {
162 this->write_byte_(TIMER_VALUE_REG, duration_s);
163 this->write_byte_(TIMER_CONTROL_REG, CLOCK_1_HZ);
164 }
165
166 auto maybe_ctrl_status_2 = this->read_register_(CONTROL_STATUS_2_REG);
167 if (!maybe_ctrl_status_2.has_value()) {
168 ESP_LOGE(TAG, "Failed to read CONTROL_STATUS_2_REG");
169 return;
170 }
171 uint8_t ctrl_status_2_reg_value = maybe_ctrl_status_2.value();
172 ctrl_status_2_reg_value |= (1 << 0);
173 ctrl_status_2_reg_value &= ~(1 << 7);
174 this->write_byte_(CONTROL_STATUS_2_REG, ctrl_status_2_reg_value);
175}
176
177void BM8563::clear_irq_() {
178 auto maybe_data = this->read_register_(CONTROL_STATUS_2_REG);
179 if (!maybe_data.has_value()) {
180 ESP_LOGE(TAG, "Failed to read CONTROL_STATUS_2_REG");
181 return;
182 }
183 uint8_t data = maybe_data.value();
184 this->write_byte_(CONTROL_STATUS_2_REG, data & 0xf3);
185}
186
187void BM8563::disable_irq_() {
188 this->clear_irq_();
189 auto maybe_data = this->read_register_(CONTROL_STATUS_2_REG);
190 if (!maybe_data.has_value()) {
191 ESP_LOGE(TAG, "Failed to read CONTROL_STATUS_2_REG");
192 return;
193 }
194 uint8_t data = maybe_data.value();
195 this->write_byte_(CONTROL_STATUS_2_REG, data & 0xfc);
196}
197
198} // namespace esphome::bm8563
virtual void mark_failed()
Mark this component as failed.
bool is_failed() const
void update() override
Definition bm8563.cpp:26
void dump_config() override
Definition bm8563.cpp:28
void start_timer(uint32_t duration_s)
Definition bm8563.cpp:36
void setup() override
Definition bm8563.cpp:19
ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len) const
writes an array of bytes to a specific register in the I²C device
Definition i2c.cpp:44
bool write_byte(uint8_t a_register, uint8_t data) const
Definition i2c.h:266
I2CRegister reg(uint8_t a_register)
calls the I2CRegister constructor
Definition i2c.h:153
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:35
bool write_byte_16(uint8_t a_register, uint16_t data) const
Definition i2c.h:268
uint8_t size_t len
Definition i2c.h:273
ESPTime now()
Get the time in the currently defined timezone.
ESPTime utcnow()
Get the time without any time zone or DST corrections.
void synchronize_epoch_(uint32_t epoch)
Report a unix epoch as current time.
@ NO_ERROR
No error found during execution of method.
Definition i2c_bus.h:32
std::string size_t len
Definition helpers.h:533
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
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:158
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
uint16_t day_of_year
day of the year [1-366]
Definition time.h:29
bool is_valid() const
Check if this ESPTime is valid (all fields in range and year is greater than 2018)
Definition time.h:61
uint8_t day_of_month
day of the month [1-31]
Definition time.h:27
uint16_t year
year
Definition time.h:33
uint8_t month
month; january=1 [1-12]
Definition time.h:31
uint8_t day_of_week
day of the week; sunday=1 [1-7]
Definition time.h:25