diff --git a/esphome/components/deep_sleep/deep_sleep_component.cpp b/esphome/components/deep_sleep/deep_sleep_component.cpp index 38a12e8e90..84fc102b66 100644 --- a/esphome/components/deep_sleep/deep_sleep_component.cpp +++ b/esphome/components/deep_sleep/deep_sleep_component.cpp @@ -67,6 +67,7 @@ void DeepSleepComponent::begin_sleep(bool manual) { // It's critical to teardown components cleanly for deep sleep to ensure // Home Assistant sees a clean disconnect instead of marking the device unavailable App.teardown_components(TEARDOWN_TIMEOUT_DEEP_SLEEP_MS); + App.run_powerdown_hooks(); this->deep_sleep_(); } diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index fb178431d5..7a205d89f0 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -56,7 +56,7 @@ class EthernetComponent : public Component { void dump_config() override; float get_setup_priority() const override; bool can_proceed() override; - void on_shutdown() override { powerdown(); } + void on_powerdown() override { powerdown(); } bool is_connected(); #ifdef USE_ETHERNET_SPI diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 0babcedc48..629bbb41cb 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -89,7 +89,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, void dump_config() override; void setup() override; - void on_shutdown() override { this->command(ILI9XXX_SLPIN); } + void on_powerdown() override { this->command(ILI9XXX_SLPIN); } display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, diff --git a/esphome/components/pn532/pn532.h b/esphome/components/pn532/pn532.h index 8194d86477..c8e9a40008 100644 --- a/esphome/components/pn532/pn532.h +++ b/esphome/components/pn532/pn532.h @@ -38,7 +38,7 @@ class PN532 : public PollingComponent { float get_setup_priority() const override; void loop() override; - void on_shutdown() override { powerdown(); } + void on_powerdown() override { powerdown(); } void register_tag(PN532BinarySensor *tag) { this->binary_sensors_.push_back(tag); } void register_ontag_trigger(nfc::NfcOnTagTrigger *trig) { this->triggers_ontag_.push_back(trig); } diff --git a/esphome/components/power_supply/power_supply.cpp b/esphome/components/power_supply/power_supply.cpp index 141159b9c8..6fbadc73ae 100644 --- a/esphome/components/power_supply/power_supply.cpp +++ b/esphome/components/power_supply/power_supply.cpp @@ -52,7 +52,7 @@ void PowerSupply::unrequest_high_power() { }); } } -void PowerSupply::on_shutdown() { +void PowerSupply::on_powerdown() { this->active_requests_ = 0; this->pin_->digital_write(false); } diff --git a/esphome/components/power_supply/power_supply.h b/esphome/components/power_supply/power_supply.h index 0b06105ae9..3959f6f299 100644 --- a/esphome/components/power_supply/power_supply.h +++ b/esphome/components/power_supply/power_supply.h @@ -32,7 +32,7 @@ class PowerSupply : public Component { /// Hardware setup priority (+1). float get_setup_priority() const override; - void on_shutdown() override; + void on_powerdown() override; protected: GPIOPin *pin_; diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index aa3a2fe829..c96b2d37a1 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -169,6 +169,7 @@ void Application::safe_reboot() { ESP_LOGI(TAG, "Rebooting safely"); run_safe_shutdown_hooks(); teardown_components(TEARDOWN_TIMEOUT_REBOOT_MS); + run_powerdown_hooks(); arch_restart(); } @@ -181,6 +182,12 @@ void Application::run_safe_shutdown_hooks() { } } +void Application::run_powerdown_hooks() { + for (auto it = this->components_.rbegin(); it != this->components_.rend(); ++it) { + (*it)->on_powerdown(); + } +} + void Application::teardown_components(uint32_t timeout_ms) { uint32_t start_time = millis(); diff --git a/esphome/core/application.h b/esphome/core/application.h index 90aa175edc..8f62bc10f7 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -257,6 +257,8 @@ class Application { void run_safe_shutdown_hooks(); + void run_powerdown_hooks(); + /** Teardown all components with a timeout. * * @param timeout_ms Maximum time to wait for teardown in milliseconds diff --git a/esphome/core/component.h b/esphome/core/component.h index a8c6b156b2..ce9f0289d0 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -116,6 +116,13 @@ class Component { */ virtual bool teardown() { return true; } + /** Called after teardown is complete to power down hardware. + * + * This is called after all components have finished their teardown process, + * making it safe to power down hardware like ethernet PHY. + */ + virtual void on_powerdown() {} + uint32_t get_component_state() const; /** Mark this component as failed. Any future timeouts/intervals/setup/loop will no longer be called.