diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 6683a2d499..f227dbe2de 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -276,6 +276,7 @@ class APIConnection final : public APIServerConnectionBase { App.schedule_dump_config(); #ifdef USE_ESP32_CRASH_HANDLER esp32::crash_handler_log(); + esp32::crash_handler_clear(); #endif #ifdef USE_RP2040_CRASH_HANDLER rp2040::crash_handler_log(); diff --git a/esphome/components/esp32/crash_handler.cpp b/esphome/components/esp32/crash_handler.cpp index 4ac72b820a..ed61b61936 100644 --- a/esphome/components/esp32/crash_handler.cpp +++ b/esphome/components/esp32/crash_handler.cpp @@ -169,12 +169,19 @@ void crash_handler_read_and_clear() { s_raw_crash_data.other_reg_frame_count = s_raw_crash_data.other_backtrace_count; #endif } - // Clear magic regardless so we don't re-report on next normal reboot - s_raw_crash_data.magic = 0; + // Don't clear magic here — crash data must survive OTA rollback reboots. + // Magic is cleared by crash_handler_clear() after an API client receives the data. } bool crash_handler_has_data() { return s_crash_data_valid; } +void crash_handler_clear() { + // Only clear the magic so data doesn't survive the next reboot. + // Keep s_crash_data_valid so crash_handler_log() still works for + // additional API clients connecting during this boot session. + s_raw_crash_data.magic = 0; +} + // Look up the exception cause as a human-readable string. // Tables mirror ESP-IDF's panic_arch_fill_info() which uses local static arrays // not exposed via any public API. diff --git a/esphome/components/esp32/crash_handler.h b/esphome/components/esp32/crash_handler.h index 97a4d4e116..c5e7d145ec 100644 --- a/esphome/components/esp32/crash_handler.h +++ b/esphome/components/esp32/crash_handler.h @@ -4,12 +4,18 @@ namespace esphome::esp32 { -/// Read crash data from NOINIT memory and clear the magic marker. +/// Read and validate crash data from NOINIT memory. +/// Does not clear the magic marker — call crash_handler_clear() after +/// the data has been delivered to an API client so it survives OTA rollback reboots. void crash_handler_read_and_clear(); /// Log crash data if a crash was detected on previous boot. void crash_handler_log(); +/// Clear the magic marker and mark crash data as consumed. +/// Call after the data has been delivered to an API client. +void crash_handler_clear(); + /// Returns true if crash data was found this boot. bool crash_handler_has_data();