From 7b60543afd02960058e2cff58c70acebf68acc57 Mon Sep 17 00:00:00 2001 From: NMartin354 Date: Tue, 11 Jun 2024 19:38:20 -0500 Subject: [PATCH] [safe_mode] Allow user-defined interval for successful boot (#6882) Co-authored-by: Keith Burzinski --- esphome/components/safe_mode/__init__.py | 8 +++++++- esphome/components/safe_mode/safe_mode.cpp | 8 ++++++-- esphome/components/safe_mode/safe_mode.h | 13 +++++++------ tests/components/safe_mode/common.yaml | 1 + 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/esphome/components/safe_mode/__init__.py b/esphome/components/safe_mode/__init__.py index 92b285e279..881937890d 100644 --- a/esphome/components/safe_mode/__init__.py +++ b/esphome/components/safe_mode/__init__.py @@ -16,6 +16,7 @@ from esphome import automation CODEOWNERS = ["@paulmonigatti", "@jsuanet", "@kbx81"] +CONF_BOOT_IS_GOOD_AFTER = "boot_is_good_after" CONF_ON_SAFE_MODE = "on_safe_mode" safe_mode_ns = cg.esphome_ns.namespace("safe_mode") @@ -34,6 +35,9 @@ CONFIG_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(SafeModeComponent), + cv.Optional( + CONF_BOOT_IS_GOOD_AFTER, default="1min" + ): cv.positive_time_period_milliseconds, cv.Optional(CONF_DISABLED, default=False): cv.boolean, cv.Optional(CONF_NUM_ATTEMPTS, default="10"): cv.positive_not_null_int, cv.Optional( @@ -63,7 +67,9 @@ async def to_code(config): await automation.build_automation(trigger, [], conf) condition = var.should_enter_safe_mode( - config[CONF_NUM_ATTEMPTS], config[CONF_REBOOT_TIMEOUT] + config[CONF_NUM_ATTEMPTS], + config[CONF_REBOOT_TIMEOUT], + config[CONF_BOOT_IS_GOOD_AFTER], ) cg.add(RawExpression(f"if ({condition}) return")) CORE.data[CONF_SAFE_MODE] = {} diff --git a/esphome/components/safe_mode/safe_mode.cpp b/esphome/components/safe_mode/safe_mode.cpp index 6934dcb9d9..aa1a4b6822 100644 --- a/esphome/components/safe_mode/safe_mode.cpp +++ b/esphome/components/safe_mode/safe_mode.cpp @@ -16,6 +16,8 @@ static const char *const TAG = "safe_mode"; void SafeModeComponent::dump_config() { ESP_LOGCONFIG(TAG, "Safe Mode:"); + ESP_LOGCONFIG(TAG, " Boot considered successful after %" PRIu32 " seconds", + this->safe_mode_boot_is_good_after_ / 1000); // because milliseconds ESP_LOGCONFIG(TAG, " Invoke after %u boot attempts", this->safe_mode_num_attempts_); ESP_LOGCONFIG(TAG, " Remain in safe mode for %" PRIu32 " seconds", this->safe_mode_enable_time_ / 1000); // because milliseconds @@ -34,7 +36,7 @@ void SafeModeComponent::dump_config() { float SafeModeComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; } void SafeModeComponent::loop() { - if (!this->boot_successful_ && (millis() - this->safe_mode_start_time_) > this->safe_mode_enable_time_) { + 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(); @@ -60,9 +62,11 @@ bool SafeModeComponent::get_safe_mode_pending() { return this->read_rtc_() == SafeModeComponent::ENTER_SAFE_MODE_MAGIC; } -bool SafeModeComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time) { +bool SafeModeComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time, + uint32_t boot_is_good_after) { this->safe_mode_start_time_ = millis(); this->safe_mode_enable_time_ = enable_time; + this->safe_mode_boot_is_good_after_ = boot_is_good_after; this->safe_mode_num_attempts_ = num_attempts; this->rtc_ = global_preferences->make_preference(233825507UL, false); this->safe_mode_rtc_value_ = this->read_rtc_(); diff --git a/esphome/components/safe_mode/safe_mode.h b/esphome/components/safe_mode/safe_mode.h index 0ec3c29529..37e2c3a3d6 100644 --- a/esphome/components/safe_mode/safe_mode.h +++ b/esphome/components/safe_mode/safe_mode.h @@ -11,7 +11,7 @@ namespace safe_mode { /// SafeModeComponent provides a safe way to recover from repeated boot failures class SafeModeComponent : public Component { public: - bool should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time); + bool should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time, uint32_t boot_is_good_after); /// Set to true if the next startup will enter safe mode void set_safe_mode_pending(const bool &pending); @@ -33,11 +33,12 @@ class SafeModeComponent : public Component { void write_rtc_(uint32_t val); uint32_t read_rtc_(); - bool boot_successful_{false}; ///< set to true after boot is considered successful - uint32_t safe_mode_start_time_; ///< stores when safe mode was enabled - uint32_t safe_mode_enable_time_{60000}; ///< The time safe mode should remain active for - uint32_t safe_mode_rtc_value_; - uint8_t safe_mode_num_attempts_; + bool boot_successful_{false}; ///< set to true after boot is considered successful + uint32_t safe_mode_boot_is_good_after_{60000}; ///< The amount of time after which the boot is considered successful + uint32_t safe_mode_enable_time_{60000}; ///< The time safe mode should remain active for + uint32_t safe_mode_rtc_value_{0}; + uint32_t safe_mode_start_time_{0}; ///< stores when safe mode was enabled + uint8_t safe_mode_num_attempts_{0}; ESPPreferenceObject rtc_; CallbackManager safe_mode_callback_{}; diff --git a/tests/components/safe_mode/common.yaml b/tests/components/safe_mode/common.yaml index ce8bf2f0cf..c24f49e6b6 100644 --- a/tests/components/safe_mode/common.yaml +++ b/tests/components/safe_mode/common.yaml @@ -3,6 +3,7 @@ wifi: password: password1 safe_mode: + boot_is_good_after: 2min num_attempts: 3 reboot_timeout: 2min on_safe_mode: