[RX8025T] add RX8025T realtime clock (#13274)

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
This commit is contained in:
Remco van Essen
2026-09-23 17:19:09 +01:00
committed by GitHub
co-authored by pre-commit-ci-lite[bot] Claude Sonnet 4.6 J. Nick Koston J. Nick Koston J. Nick Koston
parent 35607e99a7
commit f6e97b7ada
10 changed files with 220 additions and 0 deletions
+1
View File
@@ -457,6 +457,7 @@ esphome/components/rtl87xx/* @kuba2k2
esphome/components/rtttl/* @glmnet @ximex
esphome/components/runtime_image/* @clydebarrow @guillempages @kahrendt
esphome/components/runtime_stats/* @bdraco
esphome/components/rx8025t/* @remcom
esphome/components/rx8130/* @beormund
esphome/components/safe_mode/* @jsuanet @kbx81 @paulmonigatti
esphome/components/scd4x/* @martgras @sjtrny
+128
View File
@@ -0,0 +1,128 @@
#include "rx8025t.h"
#include "esphome/core/log.h"
// Datasheet:
// - https://support.epson.biz/td/api/doc_check.php?dl=app_RX8025T
namespace esphome::rx8025t {
static constexpr uint8_t RX8025T_REG_SEC = 0x00;
static constexpr uint8_t RX8025T_REG_FLAG = 0x0E;
static constexpr uint8_t RX8025T_FLAG_VDET = 0x01;
static constexpr uint8_t RX8025T_FLAG_VLF = 0x02;
static const char *const TAG = "rx8025t";
constexpr uint8_t bcd2dec(uint8_t val) { return (val >> 4) * 10 + (val & 0x0f); }
constexpr uint8_t dec2bcd(uint8_t val) { return ((val / 10) << 4) + (val % 10); }
void RX8025TComponent::setup() {
uint8_t flags;
if (!this->read_flags_(&flags)) {
this->mark_failed();
return;
}
if (flags & RX8025T_FLAG_VLF) {
ESP_LOGW(TAG, "VLF flag is set - Loss of oscillator detected. Time may be invalid.");
}
}
void RX8025TComponent::update() { this->read_time(); }
void RX8025TComponent::dump_config() {
ESP_LOGCONFIG(TAG, "RX8025T:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
time::RealTimeClock::dump_config();
}
bool RX8025TComponent::read_flags_(uint8_t *flags) {
if (!this->read_byte(RX8025T_REG_FLAG, flags)) {
ESP_LOGE(TAG, "Can't read flag register.");
this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
return false;
}
return true;
}
void RX8025TComponent::read_time() {
uint8_t flags;
if (!this->read_flags_(&flags)) {
return;
}
uint8_t date[7];
if (!this->read_bytes(RX8025T_REG_SEC, date, sizeof(date))) {
ESP_LOGE(TAG, "Can't read I2C data.");
this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
return;
}
this->status_clear_warning();
if (flags & RX8025T_FLAG_VLF) {
ESP_LOGW(TAG, "VLF flag is set - time data may be invalid, not syncing to system clock.");
return;
}
ESPTime rtc_time{
.second = bcd2dec(date[0] & 0x7f),
.minute = bcd2dec(date[1] & 0x7f),
.hour = bcd2dec(date[2] & 0x3f),
.day_of_week = static_cast<uint8_t>((date[3] & 0x7f) ? __builtin_ctz(date[3] & 0x7f) + 1 : 1),
.day_of_month = bcd2dec(date[4] & 0x3f),
.day_of_year = 1,
.month = bcd2dec(date[5] & 0x1f),
.year = static_cast<uint16_t>(bcd2dec(date[6]) + 2000),
.is_dst = false,
.timestamp = 0,
};
rtc_time.recalc_timestamp_utc(false);
if (!rtc_time.is_valid(/*check_day_of_week=*/true, /*check_day_of_year=*/false)) {
ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");
return;
}
ESP_LOGD(TAG, "Read UTC time: %04d-%02d-%02d %02d:%02d:%02d VDET:%s", rtc_time.year, rtc_time.month,
rtc_time.day_of_month, rtc_time.hour, rtc_time.minute, rtc_time.second, ONOFF(flags & RX8025T_FLAG_VDET));
this->synchronize_epoch_(rtc_time.timestamp);
}
void RX8025TComponent::write_time() {
auto now = this->utcnow();
if (!now.is_valid()) {
ESP_LOGE(TAG, "Invalid system time, not syncing to RTC.");
return;
}
uint8_t buff[7];
buff[0] = dec2bcd(now.second);
buff[1] = dec2bcd(now.minute);
buff[2] = dec2bcd(now.hour);
buff[3] = 1 << (now.day_of_week - 1);
buff[4] = dec2bcd(now.day_of_month);
buff[5] = dec2bcd(now.month);
buff[6] = dec2bcd(now.year % 100);
if (!this->write_bytes(RX8025T_REG_SEC, buff, sizeof(buff))) {
ESP_LOGE(TAG, "Can't write I2C data.");
this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
return;
}
ESP_LOGD(TAG, "Wrote UTC time: %04d-%02d-%02d %02d:%02d:%02d", now.year, now.month, now.day_of_month, now.hour,
now.minute, now.second);
// Clear VLF and VDET flags via read-modify-write of flag register
uint8_t flags;
if (!this->read_flags_(&flags)) {
return;
}
flags &= ~(RX8025T_FLAG_VLF | RX8025T_FLAG_VDET);
if (!this->write_byte(RX8025T_REG_FLAG, flags)) {
this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
return;
}
this->status_clear_warning();
}
} // namespace esphome::rx8025t
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/components/time/real_time_clock.h"
namespace esphome::rx8025t {
class RX8025TComponent : public time::RealTimeClock, public i2c::I2CDevice {
public:
void setup() override;
void update() override;
void dump_config() override;
void read_time();
void write_time();
protected:
bool read_flags_(uint8_t *flags);
};
} // namespace esphome::rx8025t
+42
View File
@@ -0,0 +1,42 @@
from esphome import automation
import esphome.codegen as cg
from esphome.components import i2c, time
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.types import ConfigType
CODEOWNERS = ["@remcom"]
DEPENDENCIES = ["i2c"]
rx8025t_ns = cg.esphome_ns.namespace("rx8025t")
RX8025TComponent = rx8025t_ns.class_(
"RX8025TComponent", time.RealTimeClock, i2c.I2CDevice
)
CONFIG_SCHEMA = time.TIME_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(RX8025TComponent),
}
).extend(i2c.i2c_device_schema(0x32))
for _name, _call in (
("rx8025t.write_time", "write_time()"),
("rx8025t.read_time", "read_time()"),
):
automation.register_apply_action(
_name,
automation.maybe_simple_id(
{
cv.GenerateID(): cv.use_id(RX8025TComponent),
}
),
automation.ApplyCall(_call),
)
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
await time.register_time(var, config)
+12
View File
@@ -0,0 +1,12 @@
esphome:
on_boot:
then:
- rx8025t.write_time: rx8025t_time
- rx8025t.read_time:
id: rx8025t_time
time:
- platform: rx8025t
i2c_id: i2c_bus
id: rx8025t_time
update_interval: never
@@ -0,0 +1,4 @@
packages:
i2c: !include ../../test_build_components/common/i2c/esp32-idf.yaml
<<: !include common.yaml
@@ -0,0 +1,4 @@
packages:
i2c: !include ../../test_build_components/common/i2c/esp8266-ard.yaml
<<: !include common.yaml
@@ -0,0 +1,4 @@
packages:
i2c: !include ../../test_build_components/common/i2c/nrf52.yaml
<<: !include common.yaml
@@ -0,0 +1,4 @@
packages:
i2c: !include ../../test_build_components/common/i2c/rp2040-ard.yaml
<<: !include common.yaml