mirror of
https://github.com/esphome/esphome.git
synced 2024-11-22 11:47:30 +01:00
Allow specifying deep sleep wakup clock time (#3312)
This commit is contained in:
parent
b622a8fa58
commit
8be704e591
@ -1,13 +1,18 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import time
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins, automation
|
||||
from esphome.const import (
|
||||
CONF_HOUR,
|
||||
CONF_ID,
|
||||
CONF_MINUTE,
|
||||
CONF_MODE,
|
||||
CONF_NUMBER,
|
||||
CONF_PINS,
|
||||
CONF_RUN_DURATION,
|
||||
CONF_SECOND,
|
||||
CONF_SLEEP_DURATION,
|
||||
CONF_TIME_ID,
|
||||
CONF_WAKEUP_PIN,
|
||||
)
|
||||
|
||||
@ -112,6 +117,7 @@ CONF_TOUCH_WAKEUP = "touch_wakeup"
|
||||
CONF_DEFAULT = "default"
|
||||
CONF_GPIO_WAKEUP_REASON = "gpio_wakeup_reason"
|
||||
CONF_TOUCH_WAKEUP_REASON = "touch_wakeup_reason"
|
||||
CONF_UNTIL = "until"
|
||||
|
||||
WAKEUP_CAUSES_SCHEMA = cv.Schema(
|
||||
{
|
||||
@ -202,13 +208,19 @@ async def to_code(config):
|
||||
cg.add_define("USE_DEEP_SLEEP")
|
||||
|
||||
|
||||
DEEP_SLEEP_ENTER_SCHEMA = automation.maybe_simple_id(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(DeepSleepComponent),
|
||||
cv.Optional(CONF_SLEEP_DURATION): cv.templatable(
|
||||
cv.positive_time_period_milliseconds
|
||||
),
|
||||
}
|
||||
DEEP_SLEEP_ENTER_SCHEMA = cv.All(
|
||||
automation.maybe_simple_id(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(DeepSleepComponent),
|
||||
cv.Exclusive(CONF_SLEEP_DURATION, "time"): cv.templatable(
|
||||
cv.positive_time_period_milliseconds
|
||||
),
|
||||
# Only on ESP32 due to how long the RTC on ESP8266 can stay asleep
|
||||
cv.Exclusive(CONF_UNTIL, "time"): cv.All(cv.only_on_esp32, cv.time_of_day),
|
||||
cv.Optional(CONF_TIME_ID): cv.use_id(time.RealTimeClock),
|
||||
}
|
||||
),
|
||||
cv.has_none_or_all_keys(CONF_UNTIL, CONF_TIME_ID),
|
||||
)
|
||||
|
||||
|
||||
@ -228,6 +240,14 @@ async def deep_sleep_enter_to_code(config, action_id, template_arg, args):
|
||||
if CONF_SLEEP_DURATION in config:
|
||||
template_ = await cg.templatable(config[CONF_SLEEP_DURATION], args, cg.int32)
|
||||
cg.add(var.set_sleep_duration(template_))
|
||||
|
||||
if CONF_UNTIL in config:
|
||||
until = config[CONF_UNTIL]
|
||||
cg.add(var.set_until(until[CONF_HOUR], until[CONF_MINUTE], until[CONF_SECOND]))
|
||||
|
||||
time_ = await cg.get_variable(config[CONF_TIME_ID])
|
||||
cg.add(var.set_time(time_))
|
||||
|
||||
return var
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "deep_sleep_component.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <cinttypes>
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
#include <Esp.h>
|
||||
@ -101,6 +102,8 @@ void DeepSleepComponent::begin_sleep(bool manual) {
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Beginning Deep Sleep");
|
||||
if (this->sleep_duration_.has_value())
|
||||
ESP_LOGI(TAG, "Sleeping for %" PRId64 "us", *this->sleep_duration_);
|
||||
|
||||
App.run_safe_shutdown_hooks();
|
||||
|
||||
|
@ -9,6 +9,10 @@
|
||||
#include <esp_sleep.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace deep_sleep {
|
||||
|
||||
@ -116,15 +120,71 @@ template<typename... Ts> class EnterDeepSleepAction : public Action<Ts...> {
|
||||
EnterDeepSleepAction(DeepSleepComponent *deep_sleep) : deep_sleep_(deep_sleep) {}
|
||||
TEMPLATABLE_VALUE(uint32_t, sleep_duration);
|
||||
|
||||
#ifdef USE_TIME
|
||||
void set_until(uint8_t hour, uint8_t minute, uint8_t second) {
|
||||
this->hour_ = hour;
|
||||
this->minute_ = minute;
|
||||
this->second_ = second;
|
||||
}
|
||||
|
||||
void set_time(time::RealTimeClock *time) { this->time_ = time; }
|
||||
#endif
|
||||
|
||||
void play(Ts... x) override {
|
||||
if (this->sleep_duration_.has_value()) {
|
||||
this->deep_sleep_->set_sleep_duration(this->sleep_duration_.value(x...));
|
||||
}
|
||||
#ifdef USE_TIME
|
||||
|
||||
if (this->hour_.has_value()) {
|
||||
auto time = this->time_->now();
|
||||
const uint32_t timestamp_now = time.timestamp;
|
||||
|
||||
bool after_time = false;
|
||||
if (time.hour > this->hour_) {
|
||||
after_time = true;
|
||||
} else {
|
||||
if (time.hour == this->hour_) {
|
||||
if (time.minute > this->minute_) {
|
||||
after_time = true;
|
||||
} else {
|
||||
if (time.minute == this->minute_) {
|
||||
if (time.second > this->second_) {
|
||||
after_time = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
time.hour = *this->hour_;
|
||||
time.minute = *this->minute_;
|
||||
time.second = *this->second_;
|
||||
time.recalc_timestamp_utc();
|
||||
|
||||
time_t timestamp = time.timestamp; // timestamp in local time zone
|
||||
|
||||
if (after_time)
|
||||
timestamp += 60 * 60 * 24;
|
||||
|
||||
int32_t offset = time::ESPTime::timezone_offset();
|
||||
timestamp -= offset; // Change timestamp to utc
|
||||
const uint32_t ms_left = (timestamp - timestamp_now) * 1000;
|
||||
this->deep_sleep_->set_sleep_duration(ms_left);
|
||||
}
|
||||
#endif
|
||||
this->deep_sleep_->begin_sleep(true);
|
||||
}
|
||||
|
||||
protected:
|
||||
DeepSleepComponent *deep_sleep_;
|
||||
#ifdef USE_TIME
|
||||
optional<uint8_t> hour_;
|
||||
optional<uint8_t> minute_;
|
||||
optional<uint8_t> second_;
|
||||
|
||||
time::RealTimeClock *time_;
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename... Ts> class PreventDeepSleepAction : public Action<Ts...> {
|
||||
|
@ -176,6 +176,31 @@ void ESPTime::recalc_timestamp_utc(bool use_day_of_year) {
|
||||
res += this->second;
|
||||
this->timestamp = res;
|
||||
}
|
||||
|
||||
int32_t ESPTime::timezone_offset() {
|
||||
int32_t offset = 0;
|
||||
time_t now = ::time(nullptr);
|
||||
auto local = ESPTime::from_epoch_local(now);
|
||||
auto utc = ESPTime::from_epoch_utc(now);
|
||||
bool negative = utc.hour > local.hour && local.day_of_year <= utc.day_of_year;
|
||||
|
||||
if (utc.minute > local.minute) {
|
||||
local.minute += 60;
|
||||
local.hour -= 1;
|
||||
}
|
||||
offset += (local.minute - utc.minute) * 60;
|
||||
|
||||
if (negative) {
|
||||
offset -= (utc.hour - local.hour) * 3600;
|
||||
} else {
|
||||
if (utc.hour > local.hour) {
|
||||
local.hour += 24;
|
||||
}
|
||||
offset += (local.hour - utc.hour) * 3600;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool ESPTime::operator<(ESPTime other) { return this->timestamp < other.timestamp; }
|
||||
bool ESPTime::operator<=(ESPTime other) { return this->timestamp <= other.timestamp; }
|
||||
bool ESPTime::operator==(ESPTime other) { return this->timestamp == other.timestamp; }
|
||||
|
@ -88,6 +88,8 @@ struct ESPTime {
|
||||
/// Convert this ESPTime instance back to a tm struct.
|
||||
struct tm to_c_tm();
|
||||
|
||||
static int32_t timezone_offset();
|
||||
|
||||
/// Increment this clock instance by one second.
|
||||
void increment_second();
|
||||
/// Increment this clock instance by one day.
|
||||
|
Loading…
Reference in New Issue
Block a user