mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 13:34:54 +01:00
DS1307 real time clock component (#1441)
* initial support for DS1307 real time clock * add simple test, make sync functions public * cleanup lint * add sync to/from rtc actions * changes action names * Update esphome/components/ds1307/ds1307.cpp Co-authored-by: Guillermo Ruffino <glm.net@gmail.com> * Update esphome/components/ds1307/time.py Co-authored-by: Guillermo Ruffino <glm.net@gmail.com> * fix suggested change Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
This commit is contained in:
parent
585bb6dac8
commit
dcd3d2084d
6 changed files with 232 additions and 0 deletions
|
@ -29,6 +29,7 @@ esphome/components/ct_clamp/* @jesserockz
|
|||
esphome/components/debug/* @OttoWinter
|
||||
esphome/components/dfplayer/* @glmnet
|
||||
esphome/components/dht/* @OttoWinter
|
||||
esphome/components/ds1307/* @badbadc0ffee
|
||||
esphome/components/exposure_notifications/* @OttoWinter
|
||||
esphome/components/ezo/* @ssieb
|
||||
esphome/components/fastled_base/* @OttoWinter
|
||||
|
|
0
esphome/components/ds1307/__init__.py
Normal file
0
esphome/components/ds1307/__init__.py
Normal file
104
esphome/components/ds1307/ds1307.cpp
Normal file
104
esphome/components/ds1307/ds1307.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include "ds1307.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
// Datasheet:
|
||||
// - https://datasheets.maximintegrated.com/en/ds/DS1307.pdf
|
||||
|
||||
namespace esphome {
|
||||
namespace ds1307 {
|
||||
|
||||
static const char *TAG = "ds1307";
|
||||
|
||||
void DS1307Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up DS1307...");
|
||||
if (!this->read_rtc_()) {
|
||||
this->mark_failed();
|
||||
}
|
||||
this->set_interval(15 * 60 * 1000, [&]() { this->read(); });
|
||||
}
|
||||
|
||||
void DS1307Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "DS1307:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, "Communication with DS1307 failed!");
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str());
|
||||
}
|
||||
|
||||
float DS1307Component::get_setup_priority() const { return setup_priority::DATA; }
|
||||
|
||||
void DS1307Component::read() {
|
||||
if (!this->read_rtc_()) {
|
||||
return;
|
||||
}
|
||||
if (ds1307_.reg.ch) {
|
||||
ESP_LOGW(TAG, "RTC halted, not syncing to system clock.");
|
||||
return;
|
||||
}
|
||||
time::ESPTime rtc_time{.second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10),
|
||||
.minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10),
|
||||
.hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10),
|
||||
.day_of_week = uint8_t(ds1307_.reg.weekday),
|
||||
.day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10),
|
||||
.day_of_year = 1, // ignored by recalc_timestamp_utc(false)
|
||||
.month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10),
|
||||
.year = uint16_t(ds1307_.reg.year + 10u * ds1307_.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 DS1307Component::write() {
|
||||
auto now = time::RealTimeClock::utcnow();
|
||||
if (!now.is_valid()) {
|
||||
ESP_LOGE(TAG, "Invalid system time, not syncing to RTC.");
|
||||
return;
|
||||
}
|
||||
ds1307_.reg.year = (now.year - 2000) % 10;
|
||||
ds1307_.reg.year_10 = (now.year - 2000) / 10 % 10;
|
||||
ds1307_.reg.month = now.month % 10;
|
||||
ds1307_.reg.month_10 = now.month / 10;
|
||||
ds1307_.reg.day = now.day_of_month % 10;
|
||||
ds1307_.reg.day_10 = now.day_of_month / 10;
|
||||
ds1307_.reg.weekday = now.day_of_week;
|
||||
ds1307_.reg.hour = now.hour % 10;
|
||||
ds1307_.reg.hour_10 = now.hour / 10;
|
||||
ds1307_.reg.minute = now.minute % 10;
|
||||
ds1307_.reg.minute_10 = now.minute / 10;
|
||||
ds1307_.reg.second = now.second % 10;
|
||||
ds1307_.reg.second_10 = now.second / 10;
|
||||
ds1307_.reg.ch = false;
|
||||
|
||||
this->write_rtc_();
|
||||
}
|
||||
|
||||
bool DS1307Component::read_rtc_() {
|
||||
if (!this->read_bytes(0, this->ds1307_.raw, sizeof(this->ds1307_.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 CH:%s RS:%0u SQWE:%s OUT:%s", ds1307_.reg.hour_10,
|
||||
ds1307_.reg.hour, ds1307_.reg.minute_10, ds1307_.reg.minute, ds1307_.reg.second_10, ds1307_.reg.second,
|
||||
ds1307_.reg.year_10, ds1307_.reg.year, ds1307_.reg.month_10, ds1307_.reg.month, ds1307_.reg.day_10,
|
||||
ds1307_.reg.day, ONOFF(ds1307_.reg.ch), ds1307_.reg.rs, ONOFF(ds1307_.reg.sqwe), ONOFF(ds1307_.reg.out));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DS1307Component::write_rtc_() {
|
||||
if (!this->write_bytes(0, this->ds1307_.raw, sizeof(this->ds1307_.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 CH:%s RS:%0u SQWE:%s OUT:%s", ds1307_.reg.hour_10,
|
||||
ds1307_.reg.hour, ds1307_.reg.minute_10, ds1307_.reg.minute, ds1307_.reg.second_10, ds1307_.reg.second,
|
||||
ds1307_.reg.year_10, ds1307_.reg.year, ds1307_.reg.month_10, ds1307_.reg.month, ds1307_.reg.day_10,
|
||||
ds1307_.reg.day, ONOFF(ds1307_.reg.ch), ds1307_.reg.rs, ONOFF(ds1307_.reg.sqwe), ONOFF(ds1307_.reg.out));
|
||||
return true;
|
||||
}
|
||||
} // namespace ds1307
|
||||
} // namespace esphome
|
69
esphome/components/ds1307/ds1307.h
Normal file
69
esphome/components/ds1307/ds1307.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ds1307 {
|
||||
|
||||
class DS1307Component : public time::RealTimeClock, public i2c::I2CDevice {
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
void read();
|
||||
void write();
|
||||
|
||||
protected:
|
||||
bool read_rtc_();
|
||||
bool write_rtc_();
|
||||
union DS1307Reg {
|
||||
struct {
|
||||
uint8_t second : 4;
|
||||
uint8_t second_10 : 3;
|
||||
bool ch : 1;
|
||||
|
||||
uint8_t minute : 4;
|
||||
uint8_t minute_10 : 3;
|
||||
uint8_t unused_1 : 1;
|
||||
|
||||
uint8_t hour : 4;
|
||||
uint8_t hour_10 : 2;
|
||||
uint8_t unused_2 : 2;
|
||||
|
||||
uint8_t weekday : 3;
|
||||
uint8_t unused_3 : 5;
|
||||
|
||||
uint8_t day : 4;
|
||||
uint8_t day_10 : 2;
|
||||
uint8_t unused_4 : 2;
|
||||
|
||||
uint8_t month : 4;
|
||||
uint8_t month_10 : 1;
|
||||
uint8_t unused_5 : 3;
|
||||
|
||||
uint8_t year : 4;
|
||||
uint8_t year_10 : 4;
|
||||
|
||||
uint8_t rs : 2;
|
||||
uint8_t unused_6 : 2;
|
||||
bool sqwe : 1;
|
||||
uint8_t unused_7 : 2;
|
||||
bool out : 1;
|
||||
} reg;
|
||||
mutable uint8_t raw[sizeof(reg)];
|
||||
} ds1307_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class WriteAction : public Action<Ts...>, public Parented<DS1307Component> {
|
||||
public:
|
||||
void play(Ts... x) override { this->parent_->write(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class ReadAction : public Action<Ts...>, public Parented<DS1307Component> {
|
||||
public:
|
||||
void play(Ts... x) override { this->parent_->read(); }
|
||||
};
|
||||
} // namespace ds1307
|
||||
} // namespace esphome
|
44
esphome/components/ds1307/time.py
Normal file
44
esphome/components/ds1307/time.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
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 = ['@badbadc0ffee']
|
||||
DEPENDENCIES = ['i2c']
|
||||
ds1307_ns = cg.esphome_ns.namespace('ds1307')
|
||||
DS1307Component = ds1307_ns.class_('DS1307Component', time.RealTimeClock, i2c.I2CDevice)
|
||||
WriteAction = ds1307_ns.class_('WriteAction', automation.Action)
|
||||
ReadAction = ds1307_ns.class_('ReadAction', automation.Action)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = time.TIME_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_id(DS1307Component),
|
||||
}).extend(i2c.i2c_device_schema(0x68))
|
||||
|
||||
|
||||
@automation.register_action('ds1307.write', WriteAction, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(DS1307Component),
|
||||
}))
|
||||
def ds1307_write_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('ds1307.read', ReadAction, automation.maybe_simple_id({
|
||||
cv.GenerateID(): cv.use_id(DS1307Component),
|
||||
}))
|
||||
def ds1307_read_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
yield time.register_time(var, config)
|
|
@ -1837,6 +1837,20 @@ time:
|
|||
then:
|
||||
- lambda: 'ESP_LOGD("main", "time");'
|
||||
- platform: gps
|
||||
on_time:
|
||||
seconds: 0
|
||||
minutes: /15
|
||||
then:
|
||||
ds1307.write:
|
||||
id: ds1307_time
|
||||
- platform: ds1307
|
||||
id: ds1307_time
|
||||
on_time:
|
||||
seconds: 0
|
||||
then:
|
||||
ds1307.read
|
||||
|
||||
|
||||
|
||||
cover:
|
||||
- platform: template
|
||||
|
|
Loading…
Reference in a new issue