ESPHome 2025.5.0
Loading...
Searching...
No Matches
safe_mode.cpp
Go to the documentation of this file.
1#include "safe_mode.h"
2
4#include "esphome/core/hal.h"
5#include "esphome/core/log.h"
6#include "esphome/core/util.h"
7
8#include <cerrno>
9#include <cinttypes>
10#include <cstdio>
11
12namespace esphome {
13namespace safe_mode {
14
15static const char *const TAG = "safe_mode";
16
18 ESP_LOGCONFIG(TAG, "Safe Mode:");
19 ESP_LOGCONFIG(TAG, " Boot considered successful after %" PRIu32 " seconds",
20 this->safe_mode_boot_is_good_after_ / 1000); // because milliseconds
21 ESP_LOGCONFIG(TAG, " Invoke after %u boot attempts", this->safe_mode_num_attempts_);
22 ESP_LOGCONFIG(TAG, " Remain in safe mode for %" PRIu32 " seconds",
23 this->safe_mode_enable_time_ / 1000); // because milliseconds
24
26 auto remaining_restarts = this->safe_mode_num_attempts_ - this->safe_mode_rtc_value_;
27 if (remaining_restarts) {
28 ESP_LOGW(TAG, "Last reset occurred too quickly; safe mode will be invoked in %" PRIu32 " restarts",
29 remaining_restarts);
30 } else {
31 ESP_LOGW(TAG, "SAFE MODE IS ACTIVE");
32 }
33 }
34}
35
37
40 // successful boot, reset counter
41 ESP_LOGI(TAG, "Boot seems successful; resetting boot loop counter");
42 this->clean_rtc();
43 this->boot_successful_ = true;
44 }
45}
46
48 uint32_t current_rtc = this->read_rtc_();
49
50 if (pending && current_rtc != SafeModeComponent::ENTER_SAFE_MODE_MAGIC) {
51 ESP_LOGI(TAG, "Device will enter safe mode on next boot");
53 }
54
55 if (!pending && current_rtc == SafeModeComponent::ENTER_SAFE_MODE_MAGIC) {
56 ESP_LOGI(TAG, "Safe mode pending has been cleared");
57 this->clean_rtc();
58 }
59}
60
64
65bool SafeModeComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time,
66 uint32_t boot_is_good_after) {
68 this->safe_mode_enable_time_ = enable_time;
69 this->safe_mode_boot_is_good_after_ = boot_is_good_after;
70 this->safe_mode_num_attempts_ = num_attempts;
71 this->rtc_ = global_preferences->make_preference<uint32_t>(233825507UL, false);
72 this->safe_mode_rtc_value_ = this->read_rtc_();
73
74 bool is_manual_safe_mode = this->safe_mode_rtc_value_ == SafeModeComponent::ENTER_SAFE_MODE_MAGIC;
75
76 if (is_manual_safe_mode) {
77 ESP_LOGI(TAG, "Safe mode invoked manually");
78 } else {
79 ESP_LOGCONFIG(TAG, "There have been %" PRIu32 " suspected unsuccessful boot attempts", this->safe_mode_rtc_value_);
80 }
81
82 if (this->safe_mode_rtc_value_ >= num_attempts || is_manual_safe_mode) {
83 this->clean_rtc();
84
85 if (!is_manual_safe_mode) {
86 ESP_LOGE(TAG, "Boot loop detected. Proceeding to safe mode");
87 }
88
89 this->status_set_error();
90 this->set_timeout(enable_time, []() {
91 ESP_LOGW(TAG, "Safe mode enable time has elapsed -- restarting");
92 App.reboot();
93 });
94
95 // Delay here to allow power to stabilize before Wi-Fi/Ethernet is initialised
96 delay(300); // NOLINT
97 App.setup();
98
99 ESP_LOGW(TAG, "SAFE MODE IS ACTIVE");
100
101 this->safe_mode_callback_.call();
102
103 return true;
104 } else {
105 // increment counter
106 this->write_rtc_(this->safe_mode_rtc_value_ + 1);
107 return false;
108 }
109}
110
112 this->rtc_.save(&val);
114}
115
117 uint32_t val;
118 if (!this->rtc_.load(&val))
119 return 0;
120 return val;
121}
122
124
129
130} // namespace safe_mode
131} // namespace esphome
void setup()
Set up all the registered components. Call this at the end of your setup() function.
void status_set_error(const char *message="unspecified")
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.cpp:72
bool save(const T *src)
Definition preferences.h:21
virtual bool sync()=0
Commit pending writes to flash.
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
bool should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time, uint32_t boot_is_good_after)
Definition safe_mode.cpp:65
uint32_t safe_mode_enable_time_
The time safe mode should remain active for.
Definition safe_mode.h:38
bool boot_successful_
set to true after boot is considered successful
Definition safe_mode.h:36
uint32_t safe_mode_start_time_
stores when safe mode was enabled
Definition safe_mode.h:40
uint32_t safe_mode_boot_is_good_after_
The amount of time after which the boot is considered successful.
Definition safe_mode.h:37
float get_setup_priority() const override
Definition safe_mode.cpp:36
void set_safe_mode_pending(const bool &pending)
Set to true if the next startup will enter safe mode.
Definition safe_mode.cpp:47
static const uint32_t ENTER_SAFE_MODE_MAGIC
a magic number to indicate that safe mode should be entered on next boot
Definition safe_mode.h:45
CallbackManager< void()> safe_mode_callback_
Definition safe_mode.h:43
mopeka_std_values val[4]
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition component.cpp:26
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
ESPPreferences * global_preferences
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:28
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:27
Application App
Global storage of Application pointer - only one Application can exist.