ESPHome  2022.9.1
deep_sleep_component.h
Go to the documentation of this file.
1 #pragma once
2 
4 #include "esphome/core/helpers.h"
6 #include "esphome/core/hal.h"
7 
8 #ifdef USE_ESP32
9 #include <esp_sleep.h>
10 #endif
11 
12 #ifdef USE_TIME
14 #endif
15 
16 namespace esphome {
17 namespace deep_sleep {
18 
19 #ifdef USE_ESP32
20 
27 
32 };
33 
34 struct Ext1Wakeup {
35  uint64_t mask;
36  esp_sleep_ext1_wakeup_mode_t wakeup_mode;
37 };
38 
40  // Run duration if woken up by timer or any other reason besides those below.
41  uint32_t default_cause;
42  // Run duration if woken up by touch pads.
43  uint32_t touch_cause;
44  // Run duration if woken up by GPIO pins.
45  uint32_t gpio_cause;
46 };
47 
48 #endif
49 
50 template<typename... Ts> class EnterDeepSleepAction;
51 
52 template<typename... Ts> class PreventDeepSleepAction;
53 
60 class DeepSleepComponent : public Component {
61  public:
63  void set_sleep_duration(uint32_t time_ms);
64 #if defined(USE_ESP32)
65 
68  void set_wakeup_pin(InternalGPIOPin *pin) { this->wakeup_pin_ = pin; }
69 
70  void set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode);
71 #endif
72 
73 #if defined(USE_ESP32)
74 #if !defined(USE_ESP32_VARIANT_ESP32C3)
75 
76  void set_ext1_wakeup(Ext1Wakeup ext1_wakeup);
77 
78  void set_touch_wakeup(bool touch_wakeup);
79 
80 #endif
81  // Set the duration in ms for how long the code should run before entering
82  // deep sleep mode, according to the cause the ESP32 has woken.
83  void set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration);
84 #endif
85 
87  void set_run_duration(uint32_t time_ms);
88 
89  void setup() override;
90  void dump_config() override;
91  void loop() override;
92  float get_loop_priority() const override;
93  float get_setup_priority() const override;
94 
96  void begin_sleep(bool manual = false);
97 
98  void prevent_deep_sleep();
99  void allow_deep_sleep();
100 
101  protected:
102  // Returns nullopt if no run duration is set. Otherwise, returns the run
103  // duration before entering deep sleep.
104  optional<uint32_t> get_run_duration_() const;
105 
107 #ifdef USE_ESP32
113 #endif
115  bool next_enter_deep_sleep_{false};
116  bool prevent_{false};
117 };
118 
119 extern bool global_has_deep_sleep; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
120 
121 template<typename... Ts> class EnterDeepSleepAction : public Action<Ts...> {
122  public:
123  EnterDeepSleepAction(DeepSleepComponent *deep_sleep) : deep_sleep_(deep_sleep) {}
124  TEMPLATABLE_VALUE(uint32_t, sleep_duration);
125 
126 #ifdef USE_TIME
127  void set_until(uint8_t hour, uint8_t minute, uint8_t second) {
128  this->hour_ = hour;
129  this->minute_ = minute;
130  this->second_ = second;
131  }
132 
133  void set_time(time::RealTimeClock *time) { this->time_ = time; }
134 #endif
135 
136  void play(Ts... x) override {
137  if (this->sleep_duration_.has_value()) {
138  this->deep_sleep_->set_sleep_duration(this->sleep_duration_.value(x...));
139  }
140 #ifdef USE_TIME
141 
142  if (this->hour_.has_value()) {
143  auto time = this->time_->now();
144  const uint32_t timestamp_now = time.timestamp;
145 
146  bool after_time = false;
147  if (time.hour > this->hour_) {
148  after_time = true;
149  } else {
150  if (time.hour == this->hour_) {
151  if (time.minute > this->minute_) {
152  after_time = true;
153  } else {
154  if (time.minute == this->minute_) {
155  if (time.second > this->second_) {
156  after_time = true;
157  }
158  }
159  }
160  }
161  }
162 
163  time.hour = *this->hour_;
164  time.minute = *this->minute_;
165  time.second = *this->second_;
166  time.recalc_timestamp_utc();
167 
168  time_t timestamp = time.timestamp; // timestamp in local time zone
169 
170  if (after_time)
171  timestamp += 60 * 60 * 24;
172 
173  int32_t offset = time::ESPTime::timezone_offset();
174  timestamp -= offset; // Change timestamp to utc
175  const uint32_t ms_left = (timestamp - timestamp_now) * 1000;
176  this->deep_sleep_->set_sleep_duration(ms_left);
177  }
178 #endif
179  this->deep_sleep_->begin_sleep(true);
180  }
181 
182  protected:
184 #ifdef USE_TIME
188 
190 #endif
191 };
192 
193 template<typename... Ts> class PreventDeepSleepAction : public Action<Ts...>, public Parented<DeepSleepComponent> {
194  public:
195  void play(Ts... x) override { this->parent_->prevent_deep_sleep(); }
196 };
197 
198 template<typename... Ts> class AllowDeepSleepAction : public Action<Ts...>, public Parented<DeepSleepComponent> {
199  public:
200  void play(Ts... x) override { this->parent_->allow_deep_sleep(); }
201 };
202 
203 } // namespace deep_sleep
204 } // namespace esphome
void setup()
void loop()
void set_until(uint8_t hour, uint8_t minute, uint8_t second)
optional< WakeupCauseToRunDuration > wakeup_cause_to_run_duration_
The RealTimeClock class exposes common timekeeping functions via the device&#39;s local real-time clock...
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.
void set_time(time::RealTimeClock *time)
EnterDeepSleepAction(DeepSleepComponent *deep_sleep)
As long as the wakeup pin is still in the wakeup state, keep awake.
Definition: a4988.cpp:4
Automatically invert the wakeup level.
esp_sleep_ext1_wakeup_mode_t wakeup_mode
static int32_t timezone_offset()
Helper class to easily give an object a parent of type T.
Definition: helpers.h:500
void set_wakeup_pin(InternalGPIOPin *pin)
Set the pin to wake up to on the ESP32 once it&#39;s in deep sleep mode.