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 <cinttypes>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#ifdef USE_OTA_ROLLBACK
|
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
|
||||||
#include <esp_ota_ops.h>
|
#include <esp_ota_ops.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -26,6 +26,17 @@ void SafeModeComponent::dump_config() {
|
|||||||
this->safe_mode_boot_is_good_after_ / 1000, // because milliseconds
|
this->safe_mode_boot_is_good_after_ / 1000, // because milliseconds
|
||||||
this->safe_mode_num_attempts_,
|
this->safe_mode_num_attempts_,
|
||||||
this->safe_mode_enable_time_ / 1000); // because milliseconds
|
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) {
|
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_;
|
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();
|
const esp_partition_t *last_invalid = esp_ota_get_last_invalid_partition();
|
||||||
if (last_invalid != nullptr) {
|
if (last_invalid != nullptr) {
|
||||||
ESP_LOGW(TAG,
|
ESP_LOGW(TAG,
|
||||||
@@ -55,7 +66,7 @@ void SafeModeComponent::loop() {
|
|||||||
ESP_LOGI(TAG, "Boot seems successful; resetting boot loop counter");
|
ESP_LOGI(TAG, "Boot seems successful; resetting boot loop counter");
|
||||||
this->clean_rtc();
|
this->clean_rtc();
|
||||||
this->boot_successful_ = true;
|
this->boot_successful_ = true;
|
||||||
#ifdef USE_OTA_ROLLBACK
|
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
|
||||||
// Mark OTA partition as valid to prevent rollback
|
// Mark OTA partition as valid to prevent rollback
|
||||||
esp_ota_mark_app_valid_cancel_rollback();
|
esp_ota_mark_app_valid_cancel_rollback();
|
||||||
#endif
|
#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->safe_mode_num_attempts_ = num_attempts;
|
||||||
this->rtc_ = global_preferences->make_preference<uint32_t>(233825507UL, false);
|
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_();
|
uint32_t rtc_val = this->read_rtc_();
|
||||||
this->safe_mode_rtc_value_ = rtc_val;
|
this->safe_mode_rtc_value_ = rtc_val;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/preferences.h"
|
#include "esphome/core/preferences.h"
|
||||||
|
|
||||||
|
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
|
||||||
|
#include <esp_ota_ops.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome::safe_mode {
|
namespace esphome::safe_mode {
|
||||||
|
|
||||||
/// SafeModeComponent provides a safe way to recover from repeated boot failures
|
/// 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
|
// Group 1-byte members together to minimize padding
|
||||||
bool boot_successful_{false}; ///< set to true after boot is considered successful
|
bool boot_successful_{false}; ///< set to true after boot is considered successful
|
||||||
uint8_t safe_mode_num_attempts_{0};
|
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
|
// Larger objects at the end
|
||||||
ESPPreferenceObject rtc_;
|
ESPPreferenceObject rtc_;
|
||||||
#ifdef USE_SAFE_MODE_CALLBACK
|
#ifdef USE_SAFE_MODE_CALLBACK
|
||||||
|
|||||||
Reference in New Issue
Block a user