ESPHome  2024.11.0
deep_sleep_component.h
Go to the documentation of this file.
1 #pragma once
2 
5 #include "esphome/core/hal.h"
6 #include "esphome/core/helpers.h"
7 
8 #ifdef USE_ESP32
9 #include <esp_sleep.h>
10 #endif
11 
12 #ifdef USE_TIME
14 #include "esphome/core/time.h"
15 #endif
16 
17 #include <cinttypes>
18 
19 namespace esphome {
20 namespace deep_sleep {
21 
22 #ifdef USE_ESP32
23 
30 
35 };
36 
37 #if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C3)
38 struct Ext1Wakeup {
39  uint64_t mask;
40  esp_sleep_ext1_wakeup_mode_t wakeup_mode;
41 };
42 #endif
43 
45  // Run duration if woken up by timer or any other reason besides those below.
46  uint32_t default_cause;
47  // Run duration if woken up by touch pads.
48  uint32_t touch_cause;
49  // Run duration if woken up by GPIO pins.
50  uint32_t gpio_cause;
51 };
52 
53 #endif
54 
55 template<typename... Ts> class EnterDeepSleepAction;
56 
57 template<typename... Ts> class PreventDeepSleepAction;
58 
65 class DeepSleepComponent : public Component {
66  public:
68  void set_sleep_duration(uint32_t time_ms);
69 #if defined(USE_ESP32)
70 
73  void set_wakeup_pin(InternalGPIOPin *pin) { this->wakeup_pin_ = pin; }
74 
75  void set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode);
76 #endif
77 
78 #if defined(USE_ESP32)
79 #if !defined(USE_ESP32_VARIANT_ESP32C3)
80 
81  void set_ext1_wakeup(Ext1Wakeup ext1_wakeup);
82 
83  void set_touch_wakeup(bool touch_wakeup);
84 
85 #endif
86  // Set the duration in ms for how long the code should run before entering
87  // deep sleep mode, according to the cause the ESP32 has woken.
88  void set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration);
89 #endif
90 
92  void set_run_duration(uint32_t time_ms);
93 
94  void setup() override;
95  void dump_config() override;
96  void loop() override;
97  float get_loop_priority() const override;
98  float get_setup_priority() const override;
99 
101  void begin_sleep(bool manual = false);
102 
103  void prevent_deep_sleep();
104  void allow_deep_sleep();
105 
106  protected:
107  // Returns nullopt if no run duration is set. Otherwise, returns the run
108  // duration before entering deep sleep.
109  optional<uint32_t> get_run_duration_() const;
110 
111  void dump_config_platform_();
112  bool prepare_to_sleep_();
113  void deep_sleep_();
114 
116 #ifdef USE_ESP32
119 
120 #if !defined(USE_ESP32_VARIANT_ESP32C3)
122 #endif
123 
126 #endif
128  bool next_enter_deep_sleep_{false};
129  bool prevent_{false};
130 };
131 
132 extern bool global_has_deep_sleep; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
133 
134 template<typename... Ts> class EnterDeepSleepAction : public Action<Ts...> {
135  public:
136  EnterDeepSleepAction(DeepSleepComponent *deep_sleep) : deep_sleep_(deep_sleep) {}
137  TEMPLATABLE_VALUE(uint32_t, sleep_duration);
138 
139 #ifdef USE_TIME
140  void set_until(uint8_t hour, uint8_t minute, uint8_t second) {
141  this->hour_ = hour;
142  this->minute_ = minute;
143  this->second_ = second;
144  }
145 
146  void set_time(time::RealTimeClock *time) { this->time_ = time; }
147 #endif
148 
149  void play(Ts... x) override {
150  if (this->sleep_duration_.has_value()) {
151  this->deep_sleep_->set_sleep_duration(this->sleep_duration_.value(x...));
152  }
153 #ifdef USE_TIME
154 
155  if (this->hour_.has_value()) {
156  auto time = this->time_->now();
157  const uint32_t timestamp_now = time.timestamp;
158 
159  bool after_time = false;
160  if (time.hour > this->hour_) {
161  after_time = true;
162  } else {
163  if (time.hour == this->hour_) {
164  if (time.minute > this->minute_) {
165  after_time = true;
166  } else {
167  if (time.minute == this->minute_) {
168  if (time.second > this->second_) {
169  after_time = true;
170  }
171  }
172  }
173  }
174  }
175 
176  time.hour = *this->hour_;
177  time.minute = *this->minute_;
178  time.second = *this->second_;
179  time.recalc_timestamp_utc();
180 
181  time_t timestamp = time.timestamp; // timestamp in local time zone
182 
183  if (after_time)
184  timestamp += 60 * 60 * 24;
185 
186  int32_t offset = ESPTime::timezone_offset();
187  timestamp -= offset; // Change timestamp to utc
188  const uint32_t ms_left = (timestamp - timestamp_now) * 1000;
189  this->deep_sleep_->set_sleep_duration(ms_left);
190  }
191 #endif
192  this->deep_sleep_->begin_sleep(true);
193  }
194 
195  protected:
197 #ifdef USE_TIME
201 
203 #endif
204 };
205 
206 template<typename... Ts> class PreventDeepSleepAction : public Action<Ts...>, public Parented<DeepSleepComponent> {
207  public:
208  void play(Ts... x) override { this->parent_->prevent_deep_sleep(); }
209 };
210 
211 template<typename... Ts> class AllowDeepSleepAction : public Action<Ts...>, public Parented<DeepSleepComponent> {
212  public:
213  void play(Ts... x) override { this->parent_->allow_deep_sleep(); }
214 };
215 
216 } // namespace deep_sleep
217 } // namespace esphome
void setup()
void loop()
void set_until(uint8_t hour, uint8_t minute, uint8_t second)
static int32_t timezone_offset()
Definition: time.cpp:200
optional< WakeupCauseToRunDuration > wakeup_cause_to_run_duration_
The RealTimeClock class exposes common timekeeping functions via the device&#39;s local real-time clock...
uint16_t x
Definition: tt21100.cpp:17
WakeupPinMode
The values of this enum define what should be done if deep sleep is set up with a wakeup pin on the E...
This component allows setting up the node to go into deep sleep mode to conserve battery.
uint8_t minute
Ignore the fact that we will wake up when going into deep sleep.
uint8_t hour
uint8_t second
uint16_t timestamp
Definition: tt21100.cpp:14
void set_time(time::RealTimeClock *time)
EnterDeepSleepAction(DeepSleepComponent *deep_sleep)
As long as the wakeup pin is still in the wakeup state, keep awake.
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
Automatically invert the wakeup level.
esp_sleep_ext1_wakeup_mode_t wakeup_mode
Helper class to easily give an object a parent of type T.
Definition: helpers.h:522
void set_wakeup_pin(InternalGPIOPin *pin)
Set the pin to wake up to on the ESP32 once it&#39;s in deep sleep mode.