12#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
13#include <esp_ota_ops.h>
18static const char *
const TAG =
"safe_mode";
23 " Successful after: %" PRIu32
"s\n"
24 " Invoke after: %u attempts\n"
25 " Duration: %" PRIu32
"s",
29#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
30 const char *state_str;
32 state_str =
"not supported";
33 }
else if (this->
ota_state_ == ESP_OTA_IMG_PENDING_VERIFY) {
34 state_str =
"supported";
36 state_str =
"support unknown";
38 ESP_LOGCONFIG(TAG,
" Bootloader rollback: %s", state_str);
43 if (remaining_restarts) {
44 ESP_LOGW(TAG,
"Last reset too quick; invoke in %" PRIu32
" restarts", remaining_restarts);
46 ESP_LOGW(TAG,
"SAFE MODE IS ACTIVE");
50#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
51 const esp_partition_t *last_invalid = esp_ota_get_last_invalid_partition();
52 if (last_invalid !=
nullptr) {
54 "OTA rollback detected! Rolled back from partition '%s'\n"
55 "The device reset before the boot was marked successful",
66 ESP_LOGI(TAG,
"Boot seems successful; resetting boot loop counter");
69#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
71 esp_ota_mark_app_valid_cancel_rollback();
82 ESP_LOGI(TAG,
"Device will enter on next boot");
87 ESP_LOGI(TAG,
"Safe mode pending has been cleared");
97 uint32_t boot_is_good_after) {
104#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
106 const esp_partition_t *running = esp_ota_get_running_partition();
107 esp_ota_get_state_partition(running, &this->
ota_state_);
116 ESP_LOGI(TAG,
"Manual mode");
118 ESP_LOGCONFIG(TAG,
"Unsuccessful boot attempts: %" PRIu32, rtc_val);
121 if (rtc_val < num_attempts && !is_manual) {
130 ESP_LOGE(TAG,
"Boot loop detected");
135 ESP_LOGW(TAG,
"Timeout, restarting");
143 ESP_LOGW(TAG,
"SAFE MODE IS ACTIVE");
145#ifdef USE_SAFE_MODE_CALLBACK
void setup()
Set up all the registered components. Call this at the end of your setup() function.
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
void disable_loop()
Disable this component's loop.
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)
uint32_t safe_mode_enable_time_
The time safe mode should remain active for.
void on_safe_shutdown() override
bool boot_successful_
set to true after boot is considered successful
uint32_t safe_mode_start_time_
stores when safe mode was enabled
uint32_t safe_mode_boot_is_good_after_
The amount of time after which the boot is considered successful.
float get_setup_priority() const override
esp_ota_img_states_t ota_state_
uint32_t safe_mode_rtc_value_
void dump_config() override
void set_safe_mode_pending(const bool &pending)
Set to true if the next startup will enter safe mode.
void write_rtc_(uint32_t val)
bool get_safe_mode_pending()
static const uint32_t ENTER_SAFE_MODE_MAGIC
a magic number to indicate that safe mode should be entered on next boot
CallbackManager< void()> safe_mode_callback_
uint8_t safe_mode_num_attempts_
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
ESPPreferences * global_preferences
void IRAM_ATTR HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.