mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	[safe_mode] Allow user-defined interval for successful boot (#6882)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
This commit is contained in:
		| @@ -16,6 +16,7 @@ from esphome import automation | |||||||
|  |  | ||||||
| CODEOWNERS = ["@paulmonigatti", "@jsuanet", "@kbx81"] | CODEOWNERS = ["@paulmonigatti", "@jsuanet", "@kbx81"] | ||||||
|  |  | ||||||
|  | CONF_BOOT_IS_GOOD_AFTER = "boot_is_good_after" | ||||||
| CONF_ON_SAFE_MODE = "on_safe_mode" | 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") | ||||||
| @@ -34,6 +35,9 @@ CONFIG_SCHEMA = cv.All( | |||||||
|     cv.Schema( |     cv.Schema( | ||||||
|         { |         { | ||||||
|             cv.GenerateID(): cv.declare_id(SafeModeComponent), |             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_DISABLED, default=False): cv.boolean, | ||||||
|             cv.Optional(CONF_NUM_ATTEMPTS, default="10"): cv.positive_not_null_int, |             cv.Optional(CONF_NUM_ATTEMPTS, default="10"): cv.positive_not_null_int, | ||||||
|             cv.Optional( |             cv.Optional( | ||||||
| @@ -63,7 +67,9 @@ async def to_code(config): | |||||||
|         await automation.build_automation(trigger, [], conf) |         await automation.build_automation(trigger, [], conf) | ||||||
|  |  | ||||||
|     condition = var.should_enter_safe_mode( |     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")) |     cg.add(RawExpression(f"if ({condition}) return")) | ||||||
|     CORE.data[CONF_SAFE_MODE] = {} |     CORE.data[CONF_SAFE_MODE] = {} | ||||||
|   | |||||||
| @@ -16,6 +16,8 @@ static const char *const TAG = "safe_mode"; | |||||||
|  |  | ||||||
| void SafeModeComponent::dump_config() { | void SafeModeComponent::dump_config() { | ||||||
|   ESP_LOGCONFIG(TAG, "Safe Mode:"); |   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, "  Invoke after %u boot attempts", this->safe_mode_num_attempts_); | ||||||
|   ESP_LOGCONFIG(TAG, "  Remain in safe mode for %" PRIu32 " seconds", |   ESP_LOGCONFIG(TAG, "  Remain in safe mode for %" PRIu32 " seconds", | ||||||
|                 this->safe_mode_enable_time_ / 1000);  // because milliseconds |                 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; } | float SafeModeComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; } | ||||||
|  |  | ||||||
| void SafeModeComponent::loop() { | 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 |     // successful boot, reset counter | ||||||
|     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(); | ||||||
| @@ -60,9 +62,11 @@ bool SafeModeComponent::get_safe_mode_pending() { | |||||||
|   return this->read_rtc_() == SafeModeComponent::ENTER_SAFE_MODE_MAGIC; |   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_start_time_ = millis(); | ||||||
|   this->safe_mode_enable_time_ = enable_time; |   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->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); | ||||||
|   this->safe_mode_rtc_value_ = this->read_rtc_(); |   this->safe_mode_rtc_value_ = this->read_rtc_(); | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ namespace safe_mode { | |||||||
| /// SafeModeComponent provides a safe way to recover from repeated boot failures | /// SafeModeComponent provides a safe way to recover from repeated boot failures | ||||||
| class SafeModeComponent : public Component { | class SafeModeComponent : public Component { | ||||||
|  public: |  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 |   /// Set to true if the next startup will enter safe mode | ||||||
|   void set_safe_mode_pending(const bool &pending); |   void set_safe_mode_pending(const bool &pending); | ||||||
| @@ -34,10 +34,11 @@ class SafeModeComponent : public Component { | |||||||
|   uint32_t read_rtc_(); |   uint32_t read_rtc_(); | ||||||
|  |  | ||||||
|   bool boot_successful_{false};                   ///< set to true after boot is considered successful |   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_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_enable_time_{60000};         ///< The time safe mode should remain active for | ||||||
|   uint32_t safe_mode_rtc_value_; |   uint32_t safe_mode_rtc_value_{0}; | ||||||
|   uint8_t safe_mode_num_attempts_; |   uint32_t safe_mode_start_time_{0};  ///< stores when safe mode was enabled | ||||||
|  |   uint8_t safe_mode_num_attempts_{0}; | ||||||
|   ESPPreferenceObject rtc_; |   ESPPreferenceObject rtc_; | ||||||
|   CallbackManager<void()> safe_mode_callback_{}; |   CallbackManager<void()> safe_mode_callback_{}; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ wifi: | |||||||
|   password: password1 |   password: password1 | ||||||
|  |  | ||||||
| safe_mode: | safe_mode: | ||||||
|  |   boot_is_good_after: 2min | ||||||
|   num_attempts: 3 |   num_attempts: 3 | ||||||
|   reboot_timeout: 2min |   reboot_timeout: 2min | ||||||
|   on_safe_mode: |   on_safe_mode: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user