[safe_mode] Add feature to explicitly mark a boot as successful (#14306)

Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
This commit is contained in:
Michael Cassaniti
2026-02-28 05:23:02 +11:00
committed by GitHub
parent c3a0eeceec
commit 4ae7633418
5 changed files with 43 additions and 14 deletions
+17
View File
@@ -21,6 +21,7 @@ CONF_ON_SAFE_MODE = "on_safe_mode"
safe_mode_ns = cg.esphome_ns.namespace("safe_mode") safe_mode_ns = cg.esphome_ns.namespace("safe_mode")
SafeModeComponent = safe_mode_ns.class_("SafeModeComponent", cg.Component) SafeModeComponent = safe_mode_ns.class_("SafeModeComponent", cg.Component)
SafeModeTrigger = safe_mode_ns.class_("SafeModeTrigger", automation.Trigger.template()) SafeModeTrigger = safe_mode_ns.class_("SafeModeTrigger", automation.Trigger.template())
MarkSuccessfulAction = safe_mode_ns.class_("MarkSuccessfulAction", automation.Action)
def _remove_id_if_disabled(value): def _remove_id_if_disabled(value):
@@ -53,6 +54,22 @@ CONFIG_SCHEMA = cv.All(
) )
@automation.register_action(
"safe_mode.mark_successful",
MarkSuccessfulAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(SafeModeComponent),
}
),
)
async def safe_mode_mark_successful_to_code(config, action_id, template_arg, args):
parent = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg)
cg.add(var.set_parent(parent))
return var
@coroutine_with_priority(CoroPriority.APPLICATION) @coroutine_with_priority(CoroPriority.APPLICATION)
async def to_code(config): async def to_code(config):
if not config[CONF_DISABLED]: if not config[CONF_DISABLED]:
+8 -6
View File
@@ -1,20 +1,22 @@
#pragma once #pragma once
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#ifdef USE_SAFE_MODE_CALLBACK
#include "safe_mode.h"
#include "esphome/core/automation.h" #include "esphome/core/automation.h"
#include "safe_mode.h"
namespace esphome::safe_mode { namespace esphome::safe_mode {
#ifdef USE_SAFE_MODE_CALLBACK
class SafeModeTrigger final : public Trigger<> { class SafeModeTrigger final : public Trigger<> {
public: public:
explicit SafeModeTrigger(SafeModeComponent *parent) { explicit SafeModeTrigger(SafeModeComponent *parent) {
parent->add_on_safe_mode_callback([this]() { trigger(); }); parent->add_on_safe_mode_callback([this]() { trigger(); });
} }
}; };
#endif // USE_SAFE_MODE_CALLBACK
template<typename... Ts> class MarkSuccessfulAction : public Action<Ts...>, public Parented<SafeModeComponent> {
public:
void play(const Ts &...x) override { this->parent_->mark_successful(); }
};
} // namespace esphome::safe_mode } // namespace esphome::safe_mode
#endif // USE_SAFE_MODE_CALLBACK
+8 -4
View File
@@ -63,10 +63,7 @@ void SafeModeComponent::dump_config() {
float SafeModeComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; } float SafeModeComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
void SafeModeComponent::loop() { void SafeModeComponent::mark_successful() {
if (!this->boot_successful_ && (millis() - this->safe_mode_start_time_) > this->safe_mode_boot_is_good_after_) {
// successful boot, reset 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;
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK) #if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
@@ -75,6 +72,13 @@ void SafeModeComponent::loop() {
#endif #endif
// Disable loop since we no longer need to check // Disable loop since we no longer need to check
this->disable_loop(); this->disable_loop();
}
void SafeModeComponent::loop() {
if (!this->boot_successful_ && (millis() - this->safe_mode_start_time_) > this->safe_mode_boot_is_good_after_) {
// successful boot, reset counter
ESP_LOGI(TAG, "Boot seems successful; resetting boot loop counter");
this->mark_successful();
} }
} }
+2
View File
@@ -31,6 +31,8 @@ class SafeModeComponent final : public Component {
void on_safe_shutdown() override; void on_safe_shutdown() override;
void mark_successful();
#ifdef USE_SAFE_MODE_CALLBACK #ifdef USE_SAFE_MODE_CALLBACK
void add_on_safe_mode_callback(std::function<void()> &&callback) { void add_on_safe_mode_callback(std::function<void()> &&callback) {
this->safe_mode_callback_.add(std::move(callback)); this->safe_mode_callback_.add(std::move(callback));
@@ -16,3 +16,7 @@ button:
switch: switch:
- platform: safe_mode - platform: safe_mode
name: Safe Mode Switch name: Safe Mode Switch
esphome:
on_boot:
- safe_mode.mark_successful