Compare commits

...

2 commits

3 changed files with 98 additions and 1 deletions

View file

@ -81,6 +81,52 @@ void PCF85063Component::write_time() {
this->write_rtc_(); this->write_rtc_();
} }
void PCF85063Component::write_nvram(uint8_t data) {
this->pcf85063_.reg.nvram = data;
this->write_bytes(0x03, &this->pcf85063_.raw[0x03], 1);
}
uint8_t PCF85063Component::read_nvram() {
this->read_bytes(0x03, &this->pcf85063_.raw[0x03], 1);
return this->pcf85063_.reg.nvram;
}
/*
TIMER_CLOCK_MINUTE 60 15300 1m 4h15m
TIMER_CLOCK_SECOND 1 255 1s 4m15s
*/
bool PCF85063Component::set_timer_interval(uint16_t interval_seconds) {
if (interval_seconds < 256) {
pcf85063_.reg.timer_clock_frequency = TIMER_CLOCK_SECOND;
pcf85063_.reg.timer_value = interval_seconds;
pcf85063_.reg.timer_enable = true;
return this->write_timer_();
} else if (interval_seconds > 15300) {
ESP_LOGE(TAG, "Specified interval is longer than max allowed, clamping to 4h15m.");
interval_seconds = 15300;
}
div_t dm = div(interval_seconds, 60);
if (dm.rem) {
ESP_LOGI(TAG, "Interval out of seconds range, rounding down to closest whole minute.");
}
pcf85063_.reg.timer_clock_frequency = TIMER_CLOCK_MINUTE;
pcf85063_.reg.timer_value = dm.quot;
pcf85063_.reg.timer_enable = true;
return this->write_timer_();
}
bool PCF85063Component::write_timer_() {
if (!this->write_bytes(0x10, &this->pcf85063_.raw[0x03], 2)) {
ESP_LOGE(TAG, "Can't write I2C data.");
return false;
}
ESP_LOGD(TAG, "Write timer %s %0u CLOCK=%0u IR=%s %0u",
ONOFF(pcf85063_.reg.timer_enable), pcf85063_.reg.timer_value, pcf85063_.reg.timer_clock_frequency,
ONOFF(pcf85063_.reg.timer_interrupt_enable), pcf85063_.reg.timer_interrupt_mode);
return true;
}
bool PCF85063Component::read_rtc_() { bool PCF85063Component::read_rtc_() {
if (!this->read_bytes(0, this->pcf85063_.raw, sizeof(this->pcf85063_.raw))) { if (!this->read_bytes(0, this->pcf85063_.raw, sizeof(this->pcf85063_.raw))) {
ESP_LOGE(TAG, "Can't read I2C data."); ESP_LOGE(TAG, "Can't read I2C data.");

View file

@ -27,8 +27,14 @@ class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
float get_setup_priority() const override; float get_setup_priority() const override;
void read_time(); void read_time();
void write_time(); void write_time();
void write_nvram(uint8_t);
uint8_t read_nvram();
bool set_timer_interval(uint16_t interval);
protected: protected:
bool write_timer_();
bool read_rtc_(); bool read_rtc_();
bool write_rtc_(); bool write_rtc_();
union PCF85063Reg { union PCF85063Reg {
@ -133,6 +139,16 @@ class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
} pcf85063_; } pcf85063_;
}; };
template<typename... Ts> class StartTimerAction : public Action<Ts...>, public Parented<PCF85063Component> {
public:
TEMPLATABLE_VALUE(uint16_t, timer_seconds);
void play(Ts... x) override {
this->parent_->pcf85063_.reg.timer_interrupt_enable = true;
this->parent_->pcf85063_.reg.timer_interrupt_mode = TIMER_INTERRUPT_MODE_FLAG;
this->parent_->set_timer_interval(this->timer_seconds_.value(x...));
}
};
template<typename... Ts> class WriteAction : public Action<Ts...>, public Parented<PCF85063Component> { template<typename... Ts> class WriteAction : public Action<Ts...>, public Parented<PCF85063Component> {
public: public:
void play(Ts... x) override { this->parent_->write_time(); } void play(Ts... x) override { this->parent_->write_time(); }

View file

@ -2,7 +2,7 @@ import esphome.config_validation as cv
import esphome.codegen as cg import esphome.codegen as cg
from esphome import automation from esphome import automation
from esphome.components import i2c, time from esphome.components import i2c, time
from esphome.const import CONF_ID from esphome.const import CONF_ID, CONF_INTERVAL
CODEOWNERS = ["@brogon"] CODEOWNERS = ["@brogon"]
@ -13,6 +13,7 @@ PCF85063Component = pcf85063_ns.class_(
) )
WriteAction = pcf85063_ns.class_("WriteAction", automation.Action) WriteAction = pcf85063_ns.class_("WriteAction", automation.Action)
ReadAction = pcf85063_ns.class_("ReadAction", automation.Action) ReadAction = pcf85063_ns.class_("ReadAction", automation.Action)
StartTimerAction = pcf85063_ns.class_("StartTimerAction", automation.Action)
CONFIG_SCHEMA = time.TIME_SCHEMA.extend( CONFIG_SCHEMA = time.TIME_SCHEMA.extend(
@ -52,6 +53,40 @@ async def pcf85063_read_time_to_code(config, action_id, template_arg, args):
return var return var
def validate_timer_seconds(value):
value: cv.TimePeriodSeconds = cv.positive_time_period_seconds(value)
min_interval = cv.TimePeriod(seconds=1)
max_interval = cv.TimePeriod(minutes=255)
if value < min_interval:
raise cv.Invalid(
f"This timer interval is not possible, please choose a larger interval (at least {min_interval})"
)
if value > max_interval:
raise cv.Invalid(
f"This timer interval is not possible, please choose a lower interval (at most {max_interval})"
)
return value
@automation.register_action(
"pcf85063.start_timer",
StartTimerAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(PCF85063Component),
cv.Required(CONF_INTERVAL): cv.templatable(validate_timer_seconds),
}
),
)
async def pcf85063_start_timer_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
template_ = await cg.templatable(config[CONF_INTERVAL], args, cv.TimePeriodSeconds)
cg.add(var.start_timer(template_))
await cg.register_parented(var, config[CONF_ID])
return var
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])