mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 22:48:10 +01:00
PCF85063 RTC chip (#3873)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
8237e13c44
commit
119a6920f2
6 changed files with 265 additions and 0 deletions
|
@ -167,6 +167,7 @@ esphome/components/number/* @esphome/core
|
||||||
esphome/components/ota/* @esphome/core
|
esphome/components/ota/* @esphome/core
|
||||||
esphome/components/output/* @esphome/core
|
esphome/components/output/* @esphome/core
|
||||||
esphome/components/pca9554/* @hwstar
|
esphome/components/pca9554/* @hwstar
|
||||||
|
esphome/components/pcf85063/* @brogon
|
||||||
esphome/components/pid/* @OttoWinter
|
esphome/components/pid/* @OttoWinter
|
||||||
esphome/components/pipsolar/* @andreashergert1984
|
esphome/components/pipsolar/* @andreashergert1984
|
||||||
esphome/components/pm1006/* @habbie
|
esphome/components/pm1006/* @habbie
|
||||||
|
|
0
esphome/components/pcf85063/__init__.py
Normal file
0
esphome/components/pcf85063/__init__.py
Normal file
105
esphome/components/pcf85063/pcf85063.cpp
Normal file
105
esphome/components/pcf85063/pcf85063.cpp
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
#include "pcf85063.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
// Datasheet:
|
||||||
|
// - https://datasheets.maximintegrated.com/en/ds/DS1307.pdf
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace pcf85063 {
|
||||||
|
|
||||||
|
static const char *const TAG = "pcf85063";
|
||||||
|
|
||||||
|
void PCF85063Component::setup() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Setting up PCF85063...");
|
||||||
|
if (!this->read_rtc_()) {
|
||||||
|
this->mark_failed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCF85063Component::update() { this->read_time(); }
|
||||||
|
|
||||||
|
void PCF85063Component::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "PCF85063:");
|
||||||
|
LOG_I2C_DEVICE(this);
|
||||||
|
if (this->is_failed()) {
|
||||||
|
ESP_LOGE(TAG, "Communication with PCF85063 failed!");
|
||||||
|
}
|
||||||
|
ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
float PCF85063Component::get_setup_priority() const { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
void PCF85063Component::read_time() {
|
||||||
|
if (!this->read_rtc_()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pcf85063_.reg.osc_stop) {
|
||||||
|
ESP_LOGW(TAG, "RTC halted, not syncing to system clock.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
time::ESPTime rtc_time{.second = uint8_t(pcf85063_.reg.second + 10 * pcf85063_.reg.second_10),
|
||||||
|
.minute = uint8_t(pcf85063_.reg.minute + 10u * pcf85063_.reg.minute_10),
|
||||||
|
.hour = uint8_t(pcf85063_.reg.hour + 10u * pcf85063_.reg.hour_10),
|
||||||
|
.day_of_week = uint8_t(pcf85063_.reg.weekday),
|
||||||
|
.day_of_month = uint8_t(pcf85063_.reg.day + 10u * pcf85063_.reg.day_10),
|
||||||
|
.day_of_year = 1, // ignored by recalc_timestamp_utc(false)
|
||||||
|
.month = uint8_t(pcf85063_.reg.month + 10u * pcf85063_.reg.month_10),
|
||||||
|
.year = uint16_t(pcf85063_.reg.year + 10u * pcf85063_.reg.year_10 + 2000)};
|
||||||
|
rtc_time.recalc_timestamp_utc(false);
|
||||||
|
if (!rtc_time.is_valid()) {
|
||||||
|
ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
time::RealTimeClock::synchronize_epoch_(rtc_time.timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCF85063Component::write_time() {
|
||||||
|
auto now = time::RealTimeClock::utcnow();
|
||||||
|
if (!now.is_valid()) {
|
||||||
|
ESP_LOGE(TAG, "Invalid system time, not syncing to RTC.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pcf85063_.reg.year = (now.year - 2000) % 10;
|
||||||
|
pcf85063_.reg.year_10 = (now.year - 2000) / 10 % 10;
|
||||||
|
pcf85063_.reg.month = now.month % 10;
|
||||||
|
pcf85063_.reg.month_10 = now.month / 10;
|
||||||
|
pcf85063_.reg.day = now.day_of_month % 10;
|
||||||
|
pcf85063_.reg.day_10 = now.day_of_month / 10;
|
||||||
|
pcf85063_.reg.weekday = now.day_of_week;
|
||||||
|
pcf85063_.reg.hour = now.hour % 10;
|
||||||
|
pcf85063_.reg.hour_10 = now.hour / 10;
|
||||||
|
pcf85063_.reg.minute = now.minute % 10;
|
||||||
|
pcf85063_.reg.minute_10 = now.minute / 10;
|
||||||
|
pcf85063_.reg.second = now.second % 10;
|
||||||
|
pcf85063_.reg.second_10 = now.second / 10;
|
||||||
|
pcf85063_.reg.osc_stop = false;
|
||||||
|
|
||||||
|
this->write_rtc_();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PCF85063Component::read_rtc_() {
|
||||||
|
if (!this->read_bytes(0, this->pcf85063_.raw, sizeof(this->pcf85063_.raw))) {
|
||||||
|
ESP_LOGE(TAG, "Can't read I2C data.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "Read %0u%0u:%0u%0u:%0u%0u 20%0u%0u-%0u%0u-%0u%0u OSC:%s CLKOUT:%0u", pcf85063_.reg.hour_10,
|
||||||
|
pcf85063_.reg.hour, pcf85063_.reg.minute_10, pcf85063_.reg.minute, pcf85063_.reg.second_10,
|
||||||
|
pcf85063_.reg.second, pcf85063_.reg.year_10, pcf85063_.reg.year, pcf85063_.reg.month_10, pcf85063_.reg.month,
|
||||||
|
pcf85063_.reg.day_10, pcf85063_.reg.day, ONOFF(!pcf85063_.reg.osc_stop), pcf85063_.reg.clkout_control);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PCF85063Component::write_rtc_() {
|
||||||
|
if (!this->write_bytes(0, this->pcf85063_.raw, sizeof(this->pcf85063_.raw))) {
|
||||||
|
ESP_LOGE(TAG, "Can't write I2C data.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "Write %0u%0u:%0u%0u:%0u%0u 20%0u%0u-%0u%0u-%0u%0u OSC:%s CLKOUT:%0u", pcf85063_.reg.hour_10,
|
||||||
|
pcf85063_.reg.hour, pcf85063_.reg.minute_10, pcf85063_.reg.minute, pcf85063_.reg.second_10,
|
||||||
|
pcf85063_.reg.second, pcf85063_.reg.year_10, pcf85063_.reg.year, pcf85063_.reg.month_10, pcf85063_.reg.month,
|
||||||
|
pcf85063_.reg.day_10, pcf85063_.reg.day, ONOFF(!pcf85063_.reg.osc_stop), pcf85063_.reg.clkout_control);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace pcf85063
|
||||||
|
} // namespace esphome
|
96
esphome/components/pcf85063/pcf85063.h
Normal file
96
esphome/components/pcf85063/pcf85063.h
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/i2c/i2c.h"
|
||||||
|
#include "esphome/components/time/real_time_clock.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace pcf85063 {
|
||||||
|
|
||||||
|
class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
|
||||||
|
public:
|
||||||
|
void setup() override;
|
||||||
|
void update() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
void read_time();
|
||||||
|
void write_time();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool read_rtc_();
|
||||||
|
bool write_rtc_();
|
||||||
|
union PCF85063Reg {
|
||||||
|
struct {
|
||||||
|
// Control_1 register
|
||||||
|
bool cap_12pf : 1;
|
||||||
|
bool am_pm : 1;
|
||||||
|
bool correction_int_enable : 1;
|
||||||
|
bool : 1;
|
||||||
|
bool soft_reset : 1;
|
||||||
|
bool stop : 1;
|
||||||
|
bool : 1;
|
||||||
|
bool ext_test : 1;
|
||||||
|
|
||||||
|
// Control_2 register
|
||||||
|
uint8_t clkout_control : 3;
|
||||||
|
bool timer_flag : 1;
|
||||||
|
bool halfminute_int : 1;
|
||||||
|
bool minute_int : 1;
|
||||||
|
bool alarm_flag : 1;
|
||||||
|
bool alarm_int : 1;
|
||||||
|
|
||||||
|
// Offset register
|
||||||
|
uint8_t offset : 7;
|
||||||
|
bool coarse_mode : 1;
|
||||||
|
|
||||||
|
// nvRAM register
|
||||||
|
uint8_t nvram : 8;
|
||||||
|
|
||||||
|
// Seconds register
|
||||||
|
uint8_t second : 4;
|
||||||
|
uint8_t second_10 : 3;
|
||||||
|
bool osc_stop : 1;
|
||||||
|
|
||||||
|
// Minutes register
|
||||||
|
uint8_t minute : 4;
|
||||||
|
uint8_t minute_10 : 3;
|
||||||
|
uint8_t : 1;
|
||||||
|
|
||||||
|
// Hours register
|
||||||
|
uint8_t hour : 4;
|
||||||
|
uint8_t hour_10 : 2;
|
||||||
|
uint8_t : 2;
|
||||||
|
|
||||||
|
// Days register
|
||||||
|
uint8_t day : 4;
|
||||||
|
uint8_t day_10 : 2;
|
||||||
|
uint8_t : 2;
|
||||||
|
|
||||||
|
// Weekdays register
|
||||||
|
uint8_t weekday : 3;
|
||||||
|
uint8_t unused_3 : 5;
|
||||||
|
|
||||||
|
// Months register
|
||||||
|
uint8_t month : 4;
|
||||||
|
uint8_t month_10 : 1;
|
||||||
|
uint8_t : 3;
|
||||||
|
|
||||||
|
// Years register
|
||||||
|
uint8_t year : 4;
|
||||||
|
uint8_t year_10 : 4;
|
||||||
|
} reg;
|
||||||
|
mutable uint8_t raw[sizeof(reg)];
|
||||||
|
} pcf85063_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class WriteAction : public Action<Ts...>, public Parented<PCF85063Component> {
|
||||||
|
public:
|
||||||
|
void play(Ts... x) override { this->parent_->write_time(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class ReadAction : public Action<Ts...>, public Parented<PCF85063Component> {
|
||||||
|
public:
|
||||||
|
void play(Ts... x) override { this->parent_->read_time(); }
|
||||||
|
};
|
||||||
|
} // namespace pcf85063
|
||||||
|
} // namespace esphome
|
60
esphome/components/pcf85063/time.py
Normal file
60
esphome/components/pcf85063/time.py
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome import automation
|
||||||
|
from esphome.components import i2c, time
|
||||||
|
from esphome.const import CONF_ID
|
||||||
|
|
||||||
|
|
||||||
|
CODEOWNERS = ["@brogon"]
|
||||||
|
DEPENDENCIES = ["i2c"]
|
||||||
|
pcf85063_ns = cg.esphome_ns.namespace("pcf85063")
|
||||||
|
PCF85063Component = pcf85063_ns.class_(
|
||||||
|
"PCF85063Component", time.RealTimeClock, i2c.I2CDevice
|
||||||
|
)
|
||||||
|
WriteAction = pcf85063_ns.class_("WriteAction", automation.Action)
|
||||||
|
ReadAction = pcf85063_ns.class_("ReadAction", automation.Action)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = time.TIME_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(PCF85063Component),
|
||||||
|
}
|
||||||
|
).extend(i2c.i2c_device_schema(0x51))
|
||||||
|
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"pcf85063.write_time",
|
||||||
|
WriteAction,
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.use_id(PCF85063Component),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def pcf85063_write_time_to_code(config, action_id, template_arg, args):
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg)
|
||||||
|
await cg.register_parented(var, config[CONF_ID])
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"pcf85063.read_time",
|
||||||
|
ReadAction,
|
||||||
|
automation.maybe_simple_id(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.use_id(PCF85063Component),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def pcf85063_read_time_to_code(config, action_id, template_arg, args):
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg)
|
||||||
|
await cg.register_parented(var, config[CONF_ID])
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
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)
|
|
@ -517,6 +517,9 @@ display:
|
||||||
lambda: |-
|
lambda: |-
|
||||||
it.print("81818181");
|
it.print("81818181");
|
||||||
|
|
||||||
|
time:
|
||||||
|
- platform: pcf85063
|
||||||
|
|
||||||
text_sensor:
|
text_sensor:
|
||||||
- platform: ezo_pmp
|
- platform: ezo_pmp
|
||||||
dosing_mode:
|
dosing_mode:
|
||||||
|
|
Loading…
Reference in a new issue