ESPHome 2025.9.0-dev
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,
20 " Boot considered successful after %" PRIu32 " seconds\n"
21 " Invoke after %u boot attempts\n"
22 " Remain for %" PRIu32 " seconds",
23 this->safe_mode_boot_is_good_after_ / 1000, // because milliseconds
25 this->safe_mode_enable_time_ / 1000); // because milliseconds
26
28 auto remaining_restarts = this->safe_mode_num_attempts_ - this->safe_mode_rtc_value_;
29 if (remaining_restarts) {
30 ESP_LOGW(TAG, "Last reset occurred too quickly; will be invoked in %" PRIu32 " restarts", remaining_restarts);
31 } else {
32 ESP_LOGW(TAG, "SAFE MODE IS ACTIVE");
33 }
34 }
35}
36
38
41 // successful boot, reset counter
42 ESP_LOGI(TAG, "Boot seems successful; resetting boot loop counter");
43 this->clean_rtc();
44 this->boot_successful_ = true;
45 // Disable loop since we no longer need to check
46 this->disable_loop();
47 }
48}
49
51 uint32_t current_rtc = this->read_rtc_();
52
53 if (pending && current_rtc != SafeModeComponent::ENTER_SAFE_MODE_MAGIC) {
54 ESP_LOGI(TAG, "Device will enter on next boot");
56 }
57
58 if (!pending && current_rtc == SafeModeComponent::ENTER_SAFE_MODE_MAGIC) {
59 ESP_LOGI(TAG, "Safe mode pending has been cleared");
60 this->clean_rtc();
61 }
62}
63
67
68bool SafeModeComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time,
69 uint32_t boot_is_good_after) {
71 this->safe_mode_enable_time_ = enable_time;
72 this->safe_mode_boot_is_good_after_ = boot_is_good_after;
73 this->safe_mode_num_attempts_ = num_attempts;
74 this->rtc_ = global_preferences->make_preference<uint32_t>(233825507UL, false);
75 this->safe_mode_rtc_value_ = this->read_rtc_();
76
77 bool is_manual_safe_mode = this->safe_mode_rtc_value_ == SafeModeComponent::ENTER_SAFE_MODE_MAGIC;
78
79 if (is_manual_safe_mode) {
80 ESP_LOGI(TAG, "Safe mode invoked manually");
81 } else {
82 ESP_LOGCONFIG(TAG, "There have been %" PRIu32 " suspected unsuccessful boot attempts", this->safe_mode_rtc_value_);
83 }
84
85 if (this->safe_mode_rtc_value_ >= num_attempts || is_manual_safe_mode) {
86 this->clean_rtc();
87
88 if (!is_manual_safe_mode) {
89 ESP_LOGE(TAG, "Boot loop detected. Proceeding");
90 }
91
92 this->status_set_error();
93 this->set_timeout(enable_time, []() {
94 ESP_LOGW(TAG, "Safe mode enable time has elapsed -- restarting");
95 App.reboot();
96 });
97
98 // Delay here to allow power to stabilize before Wi-Fi/Ethernet is initialised
99 delay(300); // NOLINT
100 App.setup();
101
102 ESP_LOGW(TAG, "SAFE MODE IS ACTIVE");
103
104 this->safe_mode_callback_.call();
105
106 return true;
107 } else {
108 // increment counter
109 this->write_rtc_(this->safe_mode_rtc_value_ + 1);
110 return false;
111 }
112}
113
115 this->rtc_.save(&val);
117}
118
120 uint32_t val;
121 if (!this->rtc_.load(&val))
122 return 0;
123 return val;
124}
125
127
132
133} // namespace safe_mode
134} // namespace esphome
void setup()
Set up all the registered components. Call this at the end of your setup() function.
void disable_loop()
Disable this component's loop.
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
void status_set_error(const char *message=nullptr)
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:68
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:42
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:37
void set_safe_mode_pending(const bool &pending)
Set to true if the next startup will enter safe mode.
Definition safe_mode.cpp:50
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:48
CallbackManager< void()> safe_mode_callback_
Definition safe_mode.h:46
mopeka_std_values val[4]
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition component.cpp:57
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:29
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:28
Application App
Global storage of Application pointer - only one Application can exist.