ESPHome  2024.4.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 struct Ext1Wakeup {
38  uint64_t mask;
39  esp_sleep_ext1_wakeup_mode_t wakeup_mode;
40 };
41 
43  // Run duration if woken up by timer or any other reason besides those below.
44  uint32_t default_cause;
45  // Run duration if woken up by touch pads.
46  uint32_t touch_cause;
47  // Run duration if woken up by GPIO pins.
48  uint32_t gpio_cause;
49 };
50 
51 #endif
52 
53 template<typename... Ts> class EnterDeepSleepAction;
54 
55 template<typename... Ts> class PreventDeepSleepAction;
56 
63 class DeepSleepComponent : public Component {
64  public:
66  void set_sleep_duration(uint32_t time_ms);
67 #if defined(USE_ESP32)
68 
71  void set_wakeup_pin(InternalGPIOPin *pin) { this->wakeup_pin_ = pin; }
72 
73  void set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode);
74 #endif
75 
76 #if defined(USE_ESP32)
77 #if !defined(USE_ESP32_VARIANT_ESP32C3)
78 
79  void set_ext1_wakeup(Ext1Wakeup ext1_wakeup);
80 
81  void set_touch_wakeup(bool touch_wakeup);
82 
83 #endif
84  // Set the duration in ms for how long the code should run before entering
85  // deep sleep mode, according to the cause the ESP32 has woken.
86  void set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration);
87 #endif
88 
90  void set_run_duration(uint32_t time_ms);
91 
92  void setup() override;
93  void dump_config() override;
94  void loop() override;
95  float get_loop_priority() const override;
96  float get_setup_priority() const override;
97 
99  void begin_sleep(bool manual = false);
100 
101  void prevent_deep_sleep();
102  void allow_deep_sleep();
103 
104  protected:
105  // Returns nullopt if no run duration is set. Otherwise, returns the run
106  // duration before entering deep sleep.
107  optional<uint32_t> get_run_duration_() const;
108 
110 #ifdef USE_ESP32
116 #endif
118  bool next_enter_deep_sleep_{false};
119  bool prevent_{false};
120 };
121 
122 extern bool global_has_deep_sleep; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
123 
124 template<typename... Ts> class EnterDeepSleepAction : public Action<Ts...> {
125  public:
126  EnterDeepSleepAction(DeepSleepComponent *deep_sleep) : deep_sleep_(deep_sleep) {}
127  TEMPLATABLE_VALUE(uint32_t, sleep_duration);
128 
129 #ifdef USE_TIME
130  void set_until(uint8_t hour, uint8_t minute, uint8_t second) {
131  this->hour_ = hour;
132  this->minute_ = minute;
133  this->second_ = second;
134  }
135 
136  void set_time(time::RealTimeClock *time) { this->time_ = time; }
137 #endif
138 
139  void play(Ts... x) override {
140  if (this->sleep_duration_.has_value()) {
141  this->deep_sleep_->set_sleep_duration(this->sleep_duration_.value(x...));
142  }
143 #ifdef USE_TIME
144 
145  if (this->hour_.has_value()) {
146  auto time = this->time_->now();
147  const uint32_t timestamp_now = time.timestamp;
148 
149  bool after_time = false;
150  if (time.hour > this->hour_) {
151  after_time = true;
152  } else {
153  if (time.hour == this->hour_) {
154  if (time.minute > this->minute_) {
155  after_time = true;
156  } else {
157  if (time.minute == this->minute_) {
158  if (time.second > this->second_) {
159  after_time = true;
160  }
161  }
162  }
163  }
164  }
165 
166  time.hour = *this->hour_;
167  time.minute = *this->minute_;
168  time.second = *this->second_;
169  time.recalc_timestamp_utc();
170 
171  time_t timestamp = time.timestamp; // timestamp in local time zone
172 
173  if (after_time)
174  timestamp += 60 * 60 * 24;
175 
176  int32_t offset = ESPTime::timezone_offset();
177  timestamp -= offset; // Change timestamp to utc
178  const uint32_t ms_left = (timestamp - timestamp_now) * 1000;
179  this->deep_sleep_->set_sleep_duration(ms_left);
180  }
181 #endif
182  this->deep_sleep_->begin_sleep(true);
183  }
184 
185  protected:
187 #ifdef USE_TIME
191 
193 #endif
194 };
195 
196 template<typename... Ts> class PreventDeepSleepAction : public Action<Ts...>, public Parented<DeepSleepComponent> {
197  public:
198  void play(Ts... x) override { this->parent_->prevent_deep_sleep(); }
199 };
200 
201 template<typename... Ts> class AllowDeepSleepAction : public Action<Ts...>, public Parented<DeepSleepComponent> {
202  public:
203  void play(Ts... x) override { this->parent_->allow_deep_sleep(); }
204 };
205 
206 } // namespace deep_sleep
207 } // 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:181
optional< WakeupCauseToRunDuration > wakeup_cause_to_run_duration_
The RealTimeClock class exposes common timekeeping functions via the device&#39;s local real-time clock...
uint8_t minute
Definition: time_entity.h:148
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.
Ignore the fact that we will wake up when going into deep sleep.
uint16_t timestamp
Definition: tt21100.cpp:14
uint8_t second
Definition: time_entity.h:149
uint8_t hour
Definition: time_entity.h:147
void set_time(time::RealTimeClock *time)
EnterDeepSleepAction(DeepSleepComponent *deep_sleep)
As long as the wakeup pin is still in the wakeup state, keep awake.
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
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:515
void set_wakeup_pin(InternalGPIOPin *pin)
Set the pin to wake up to on the ESP32 once it&#39;s in deep sleep mode.