mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[safe_mode] Detect bootloader rollback support at runtime (#13230)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef USE_OTA_ROLLBACK
|
||||
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
|
||||
#include <esp_ota_ops.h>
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,17 @@ void SafeModeComponent::dump_config() {
|
||||
this->safe_mode_boot_is_good_after_ / 1000, // because milliseconds
|
||||
this->safe_mode_num_attempts_,
|
||||
this->safe_mode_enable_time_ / 1000); // because milliseconds
|
||||
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
|
||||
const char *state_str;
|
||||
if (this->ota_state_ == ESP_OTA_IMG_NEW) {
|
||||
state_str = "not supported";
|
||||
} else if (this->ota_state_ == ESP_OTA_IMG_PENDING_VERIFY) {
|
||||
state_str = "supported";
|
||||
} else {
|
||||
state_str = "support unknown";
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Bootloader rollback: %s", state_str);
|
||||
#endif
|
||||
|
||||
if (this->safe_mode_rtc_value_ > 1 && this->safe_mode_rtc_value_ != SafeModeComponent::ENTER_SAFE_MODE_MAGIC) {
|
||||
auto remaining_restarts = this->safe_mode_num_attempts_ - this->safe_mode_rtc_value_;
|
||||
@@ -36,7 +47,7 @@ void SafeModeComponent::dump_config() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_OTA_ROLLBACK
|
||||
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
|
||||
const esp_partition_t *last_invalid = esp_ota_get_last_invalid_partition();
|
||||
if (last_invalid != nullptr) {
|
||||
ESP_LOGW(TAG,
|
||||
@@ -55,7 +66,7 @@ void SafeModeComponent::loop() {
|
||||
ESP_LOGI(TAG, "Boot seems successful; resetting boot loop counter");
|
||||
this->clean_rtc();
|
||||
this->boot_successful_ = true;
|
||||
#ifdef USE_OTA_ROLLBACK
|
||||
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
|
||||
// Mark OTA partition as valid to prevent rollback
|
||||
esp_ota_mark_app_valid_cancel_rollback();
|
||||
#endif
|
||||
@@ -90,6 +101,12 @@ bool SafeModeComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t en
|
||||
this->safe_mode_num_attempts_ = num_attempts;
|
||||
this->rtc_ = global_preferences->make_preference<uint32_t>(233825507UL, false);
|
||||
|
||||
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
|
||||
// Check partition state to detect if bootloader supports rollback
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
esp_ota_get_state_partition(running, &this->ota_state_);
|
||||
#endif
|
||||
|
||||
uint32_t rtc_val = this->read_rtc_();
|
||||
this->safe_mode_rtc_value_ = rtc_val;
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
|
||||
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
|
||||
#include <esp_ota_ops.h>
|
||||
#endif
|
||||
|
||||
namespace esphome::safe_mode {
|
||||
|
||||
/// SafeModeComponent provides a safe way to recover from repeated boot failures
|
||||
@@ -42,6 +46,9 @@ class SafeModeComponent : public Component {
|
||||
// Group 1-byte members together to minimize padding
|
||||
bool boot_successful_{false}; ///< set to true after boot is considered successful
|
||||
uint8_t safe_mode_num_attempts_{0};
|
||||
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
|
||||
esp_ota_img_states_t ota_state_{ESP_OTA_IMG_UNDEFINED};
|
||||
#endif
|
||||
// Larger objects at the end
|
||||
ESPPreferenceObject rtc_;
|
||||
#ifdef USE_SAFE_MODE_CALLBACK
|
||||
|
||||
Reference in New Issue
Block a user