ESPHome 2026.8.0-dev
Loading...
Searching...
No Matches
deep_sleep_component.h
Go to the documentation of this file.
1#pragma once
2
5#include "esphome/core/hal.h"
7#ifdef USE_ESP32
8#include <esp_sleep.h>
9#endif
10
11#ifdef USE_TIME
13#include "esphome/core/time.h"
14#endif
15
16#include <cinttypes>
17
18namespace esphome::deep_sleep {
19
20#if defined(USE_ESP32) || defined(USE_BK72XX)
21
34#endif
35
36#if defined(USE_BK72XX)
42#endif // USE_BK72XX
43
44#ifdef USE_ESP32
45#if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3)
46struct Ext1Wakeup {
47 uint64_t mask;
48 esp_sleep_ext1_wakeup_mode_t wakeup_mode;
49};
50#endif
51
53 // Run duration if woken up by timer or any other reason besides those below.
55 // Run duration if woken up by touch pads.
57 // Run duration if woken up by GPIO pins.
59};
60
61#endif // USE_ESP32
62
63#ifdef USE_DEEP_SLEEP_ON_WAKE
64
78
81
88inline constexpr float ON_WAKE_TRIGGER_SETUP_PRIORITY = 700.0f;
89
91class WakeTrigger : public Trigger<WakeupCause>, public Component {
92 public:
93 void setup() override {
94 const WakeupCause cause = get_wakeup_cause();
95 if (cause != WAKEUP_CAUSE_NONE) {
96 this->trigger(cause);
97 }
98 }
99 float get_setup_priority() const override { return ON_WAKE_TRIGGER_SETUP_PRIORITY; }
100};
101
102#if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3)
104class Ext1WakeTrigger : public Trigger<>, public Component {
105 public:
106 explicit Ext1WakeTrigger(uint8_t pin) : pin_(pin) {}
107 void setup() override {
108 if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT1 &&
109 (esp_sleep_get_ext1_wakeup_status() & (1ULL << this->pin_))) {
110 this->trigger();
111 }
112 }
113 float get_setup_priority() const override { return ON_WAKE_TRIGGER_SETUP_PRIORITY; }
114
115 protected:
116 uint8_t pin_;
117};
118#endif
119
120#endif // USE_DEEP_SLEEP_ON_WAKE
121
122template<typename... Ts> class EnterDeepSleepAction;
123
124template<typename... Ts> class PreventDeepSleepAction;
125
132class DeepSleepComponent final : public Component {
133 public:
135 void set_sleep_duration(uint32_t time_ms);
136#if defined(USE_ESP32)
140 void set_wakeup_pin(InternalGPIOPin *pin) { this->wakeup_pin_ = pin; }
141
142 void set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode);
143#endif // USE_ESP32
144
145#if defined(USE_BK72XX)
146 void init_wakeup_pins(size_t capacity) { this->wakeup_pins_.init(capacity); }
147 void add_wakeup_pin(InternalGPIOPin *wakeup_pin, WakeupPinMode wakeup_pin_mode) {
148 this->wakeup_pins_.emplace_back(WakeUpPinItem{wakeup_pin, wakeup_pin_mode, !wakeup_pin->is_inverted()});
149 }
150#endif // USE_BK72XX
151
152#if defined(USE_ESP32)
153#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3)
154 void set_ext1_wakeup(Ext1Wakeup ext1_wakeup);
155#endif
156
157#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) && \
158 !defined(USE_ESP32_VARIANT_ESP32C5) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
159 !defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2)
160 void set_touch_wakeup(bool touch_wakeup);
161#endif
162
163 // Set the duration in ms for how long the code should run before entering
164 // deep sleep mode, according to the cause the ESP32 has woken.
165 void set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration);
166#endif // USE_ESP32
167
169 void set_run_duration(uint32_t time_ms);
170
171 void setup() override;
172 void dump_config() override;
173 void loop() override;
174 float get_setup_priority() const override;
175
177 void begin_sleep(bool manual = false);
178
179 void prevent_deep_sleep();
180 void allow_deep_sleep();
181
182 protected:
183 // Returns nullopt if no run duration is set. Otherwise, returns the run
184 // duration before entering deep sleep.
185 optional<uint32_t> get_run_duration_() const;
186
188 bool prepare_to_sleep_();
189 void deep_sleep_();
190 void schedule_sleep_();
191 bool should_teardown_();
192
193#ifdef USE_BK72XX
194 bool pin_prevents_sleep_(WakeUpPinItem &pin_item) const;
195 bool get_real_pin_state_(InternalGPIOPin &pin) const { return (pin.digital_read() ^ pin.is_inverted()); }
196#endif // USE_BK72XX
197
198 optional<uint64_t> sleep_duration_;
199
200#ifdef USE_BK72XX
202#endif // USE_BK72XX
203
204#ifdef USE_ESP32
207
208#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3)
209 optional<Ext1Wakeup> ext1_wakeup_;
210#endif
211
212 optional<bool> touch_wakeup_;
213
214 optional<WakeupCauseToRunDuration> wakeup_cause_to_run_duration_;
215#endif // USE_ESP32
216
217 optional<uint32_t> run_duration_;
219 bool prevent_{false};
220};
221
222extern bool global_has_deep_sleep; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
223
224template<typename... Ts> class EnterDeepSleepAction final : public Action<Ts...> {
225 public:
227 TEMPLATABLE_VALUE(uint32_t, sleep_duration);
228
229#ifdef USE_TIME
230 void set_until(uint8_t hour, uint8_t minute, uint8_t second) {
231 this->hour_ = hour;
232 this->minute_ = minute;
233 this->second_ = second;
234 }
235
236 void set_time(time::RealTimeClock *time) { this->time_ = time; }
237#endif
238
239 void play(const Ts &...x) override {
240 if (this->sleep_duration_.has_value()) {
241 this->deep_sleep_->set_sleep_duration(this->sleep_duration_.value(x...));
242 }
243#ifdef USE_TIME
244
245 if (this->hour_.has_value()) {
246 auto time = this->time_->now();
247 const uint32_t timestamp_now = time.timestamp;
248
249 bool after_time = false;
250 if (time.hour > this->hour_) {
251 after_time = true;
252 } else {
253 if (time.hour == this->hour_) {
254 if (time.minute > this->minute_) {
255 after_time = true;
256 } else {
257 if (time.minute == this->minute_) {
258 if (time.second > this->second_) {
259 after_time = true;
260 }
261 }
262 }
263 }
264 }
265
266 time.hour = *this->hour_;
267 time.minute = *this->minute_;
268 time.second = *this->second_;
269 time.recalc_timestamp_utc();
270
271 time_t timestamp = time.timestamp; // timestamp in local time zone
272
273 if (after_time)
274 timestamp += 60 * 60 * 24;
275
276 int32_t offset = ESPTime::timezone_offset();
277 timestamp -= offset; // Change timestamp to utc
278 const uint32_t ms_left = (timestamp - timestamp_now) * 1000;
279 this->deep_sleep_->set_sleep_duration(ms_left);
280 }
281#endif
282 this->deep_sleep_->begin_sleep(true);
283 }
284
285 protected:
287#ifdef USE_TIME
288 optional<uint8_t> hour_;
289 optional<uint8_t> minute_;
290 optional<uint8_t> second_;
291
293#endif
294};
295
296template<typename... Ts>
297class PreventDeepSleepAction final : public Action<Ts...>, public Parented<DeepSleepComponent> {
298 public:
299 void play(const Ts &...x) override { this->parent_->prevent_deep_sleep(); }
300};
301
302template<typename... Ts> class AllowDeepSleepAction final : public Action<Ts...>, public Parented<DeepSleepComponent> {
303 public:
304 void play(const Ts &...x) override { this->parent_->allow_deep_sleep(); }
305};
306
307} // namespace esphome::deep_sleep
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
Definition helpers.h:534
virtual bool digital_read()=0
virtual bool is_inverted() const =0
Helper class to easily give an object a parent of type T.
Definition helpers.h:1881
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Definition automation.h:461
This component allows setting up the node to go into deep sleep mode to conserve battery.
void set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration)
bool pin_prevents_sleep_(WakeUpPinItem &pin_item) const
optional< uint32_t > get_run_duration_() const
void set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode)
bool get_real_pin_state_(InternalGPIOPin &pin) const
void add_wakeup_pin(InternalGPIOPin *wakeup_pin, WakeupPinMode wakeup_pin_mode)
void begin_sleep(bool manual=false)
Helper to enter deep sleep mode.
void set_wakeup_pin(InternalGPIOPin *pin)
Set the pin to wake up to on the ESP32 once it's in deep sleep mode.
void set_sleep_duration(uint32_t time_ms)
Set the duration in ms the component should sleep once it's in deep sleep mode.
void set_ext1_wakeup(Ext1Wakeup ext1_wakeup)
optional< WakeupCauseToRunDuration > wakeup_cause_to_run_duration_
EnterDeepSleepAction(DeepSleepComponent *deep_sleep)
TEMPLATABLE_VALUE(uint32_t, sleep_duration)
void set_until(uint8_t hour, uint8_t minute, uint8_t second)
Fires once on boot when the device was woken from deep sleep by the given ext1 pin.
Fires once on boot when the device woke from deep sleep, with the wakeup cause.
float get_setup_priority() const override
The RealTimeClock class exposes common timekeeping functions via the device's local real-time clock.
ESPTime now()
Get the time in the currently defined timezone.
uint8_t second
uint8_t minute
uint8_t hour
WakeupPinMode
The values of this enum define what should be done if deep sleep is set up with a wakeup pin on the E...
@ WAKEUP_PIN_MODE_KEEP_AWAKE
As long as the wakeup pin is still in the wakeup state, keep awake.
@ WAKEUP_PIN_MODE_INVERT_WAKEUP
Automatically invert the wakeup level.
@ WAKEUP_PIN_MODE_IGNORE
Ignore the fact that we will wake up when going into deep sleep.
constexpr float ON_WAKE_TRIGGER_SETUP_PRIORITY
Setup priority of on_wake triggers.
WakeupCause get_wakeup_cause()
Return why the device woke from deep sleep. Implemented per platform.
WakeupCause
Why the device woke from deep sleep. Passed to on_wake automations.
@ WAKEUP_CAUSE_TOUCH
The device was woken by a touch pad.
@ WAKEUP_CAUSE_GPIO
The device was woken by a GPIO pin (wakeup_pin or esp32_ext1_wakeup).
@ WAKEUP_CAUSE_TIMER
The device was woken by the sleep timer.
@ WAKEUP_CAUSE_UNKNOWN
The device woke from deep sleep, but the source could not be identified.
@ WAKEUP_CAUSE_NONE
The device did not wake from deep sleep (for example a cold boot, reset or OTA restart).
uint16_t uint16_t & capacity
Definition helpers.cpp:25
static void uint32_t
static int32_t timezone_offset()
Definition time.cpp:353
time_t timestamp
unix epoch time (seconds since UTC Midnight January 1, 1970)
Definition time.h:48
esp_sleep_ext1_wakeup_mode_t wakeup_mode
uint16_t x
Definition tt21100.cpp:5
uint16_t timestamp
Definition tt21100.cpp:2