diff --git a/esphome/components/sntp/sntp_component.cpp b/esphome/components/sntp/sntp_component.cpp index 641d66091c..4050609dd8 100644 --- a/esphome/components/sntp/sntp_component.cpp +++ b/esphome/components/sntp/sntp_component.cpp @@ -54,6 +54,7 @@ void SNTPComponent::loop() { char buf[128]; time.strftime(buf, sizeof(buf), "%c"); ESP_LOGD(TAG, "Synchronized time: %s", buf); + this->time_sync_callback_.call(); this->has_time_ = true; } diff --git a/esphome/components/time/__init__.py b/esphome/components/time/__init__.py index e5ed5034ab..5f30a8f2ee 100644 --- a/esphome/components/time/__init__.py +++ b/esphome/components/time/__init__.py @@ -11,8 +11,8 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.const import CONF_ID, CONF_CRON, CONF_DAYS_OF_MONTH, CONF_DAYS_OF_WEEK, CONF_HOURS, \ - CONF_MINUTES, CONF_MONTHS, CONF_ON_TIME, CONF_SECONDS, CONF_TIMEZONE, CONF_TRIGGER_ID, \ - CONF_AT, CONF_SECOND, CONF_HOUR, CONF_MINUTE + CONF_MINUTES, CONF_MONTHS, CONF_ON_TIME, CONF_ON_TIME_SYNC, CONF_SECONDS, CONF_TIMEZONE, \ + CONF_TRIGGER_ID, CONF_AT, CONF_SECOND, CONF_HOUR, CONF_MINUTE from esphome.core import coroutine, coroutine_with_priority from esphome.automation import Condition @@ -24,6 +24,7 @@ IS_PLATFORM_COMPONENT = True time_ns = cg.esphome_ns.namespace('time') RealTimeClock = time_ns.class_('RealTimeClock', cg.PollingComponent) CronTrigger = time_ns.class_('CronTrigger', automation.Trigger.template(), cg.Component) +SyncTrigger = time_ns.class_('SyncTrigger', automation.Trigger.template(), cg.Component) ESPTime = time_ns.struct('ESPTime') TimeHasTimeCondition = time_ns.class_('TimeHasTimeCondition', Condition) @@ -294,6 +295,9 @@ TIME_SCHEMA = cv.Schema({ cv.Optional(CONF_CRON): validate_cron_raw, cv.Optional(CONF_AT): validate_time_at, }, validate_cron_keys), + cv.Optional(CONF_ON_TIME_SYNC): automation.validate_automation({ + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SyncTrigger), + }), }).extend(cv.polling_component_schema('15min')) @@ -320,6 +324,12 @@ def setup_time_core_(time_var, config): yield cg.register_component(trigger, conf) yield automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_TIME_SYNC, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], time_var) + + yield cg.register_component(trigger, conf) + yield automation.build_automation(trigger, [], conf) + @coroutine def register_time(time_var, config): diff --git a/esphome/components/time/automation.cpp b/esphome/components/time/automation.cpp index 1232e6f834..8e41fba0da 100644 --- a/esphome/components/time/automation.cpp +++ b/esphome/components/time/automation.cpp @@ -75,5 +75,9 @@ void CronTrigger::add_days_of_week(const std::vector &days_of_week) { } float CronTrigger::get_setup_priority() const { return setup_priority::HARDWARE; } +SyncTrigger::SyncTrigger(RealTimeClock *rtc) : rtc_(rtc) { + rtc->add_on_time_sync_callback([this]() { this->trigger(); }); +} + } // namespace time } // namespace esphome diff --git a/esphome/components/time/automation.h b/esphome/components/time/automation.h index 978d25fbd4..6167aac4f7 100644 --- a/esphome/components/time/automation.h +++ b/esphome/components/time/automation.h @@ -37,5 +37,12 @@ class CronTrigger : public Trigger<>, public Component { optional last_check_; }; +class SyncTrigger : public Trigger<>, public Component { + public: + explicit SyncTrigger(RealTimeClock *rtc); + + protected: + RealTimeClock *rtc_; +}; } // namespace time } // namespace esphome diff --git a/esphome/components/time/real_time_clock.cpp b/esphome/components/time/real_time_clock.cpp index 7d7c1013dd..44ff505ecc 100644 --- a/esphome/components/time/real_time_clock.cpp +++ b/esphome/components/time/real_time_clock.cpp @@ -38,6 +38,8 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) { char buf[128]; time.strftime(buf, sizeof(buf), "%c"); ESP_LOGD(TAG, "Synchronized time: %s", buf); + + this->time_sync_callback_.call(); } size_t ESPTime::strftime(char *buffer, size_t buffer_len, const char *format) { diff --git a/esphome/components/time/real_time_clock.h b/esphome/components/time/real_time_clock.h index 880a4e9d5c..a809401c33 100644 --- a/esphome/components/time/real_time_clock.h +++ b/esphome/components/time/real_time_clock.h @@ -127,11 +127,17 @@ class RealTimeClock : public PollingComponent { void call_setup() override; + void add_on_time_sync_callback(std::function callback) { + this->time_sync_callback_.add(std::move(callback)); + }; + protected: /// Report a unix epoch as current time. void synchronize_epoch_(uint32_t epoch); std::string timezone_{}; + + CallbackManager time_sync_callback_; }; template class TimeHasTimeCondition : public Condition { diff --git a/esphome/const.py b/esphome/const.py index 8ab739768f..184954b4c6 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -350,6 +350,7 @@ CONF_ON_SHUTDOWN = 'on_shutdown' CONF_ON_STATE = 'on_state' CONF_ON_TAG = 'on_tag' CONF_ON_TIME = 'on_time' +CONF_ON_TIME_SYNC = 'on_time_sync' CONF_ON_TURN_OFF = 'on_turn_off' CONF_ON_TURN_ON = 'on_turn_on' CONF_ON_VALUE = 'on_value' diff --git a/tests/test1.yaml b/tests/test1.yaml index f2ebca05ab..ae10e0e0c7 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1854,10 +1854,7 @@ time: then: - lambda: 'ESP_LOGD("main", "time");' - platform: gps - update_interval: 1h - on_time: - seconds: 0 - minutes: /15 + on_time_sync: then: ds1307.write: id: ds1307_time