Merge remote-tracking branch 'upstream-ssh/status-led-disable-loop-idle' into integration

This commit is contained in:
J. Nick Koston
2026-04-11 00:16:56 -10:00
3 changed files with 31 additions and 6 deletions
+15 -4
View File
@@ -7,6 +7,11 @@ namespace status_led {
static const char *const TAG = "status_led";
static constexpr uint32_t ERROR_PERIOD_MS = 250;
static constexpr uint32_t ERROR_ON_MS = 150;
static constexpr uint32_t WARNING_PERIOD_MS = 1500;
static constexpr uint32_t WARNING_ON_MS = 250;
StatusLED *global_status_led = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
StatusLED::StatusLED(GPIOPin *pin) : pin_(pin) { global_status_led = this; }
@@ -19,12 +24,18 @@ void StatusLED::dump_config() {
LOG_PIN(" Pin: ", this->pin_);
}
void StatusLED::loop() {
if ((App.get_app_state() & STATUS_LED_ERROR) != 0u) {
this->pin_->digital_write(millis() % 250u < 150u);
} else if ((App.get_app_state() & STATUS_LED_WARNING) != 0u) {
this->pin_->digital_write(millis() % 1500u < 250u);
const uint32_t app_state = App.get_app_state();
// Use millis() rather than App.get_loop_component_start_time() because this loop is also
// dispatched from Application::feed_wdt() during long blocking operations, where the cached
// per-component timestamp doesn't advance and would freeze the blink pattern.
const uint32_t now = millis();
if ((app_state & STATUS_LED_ERROR) != 0u) {
this->pin_->digital_write(now % ERROR_PERIOD_MS < ERROR_ON_MS);
} else if ((app_state & STATUS_LED_WARNING) != 0u) {
this->pin_->digital_write(now % WARNING_PERIOD_MS < WARNING_ON_MS);
} else {
this->pin_->digital_write(false);
this->disable_loop();
}
}
float StatusLED::get_setup_priority() const { return setup_priority::HARDWARE; }
+15 -1
View File
@@ -206,7 +206,21 @@ void HOT Application::feed_wdt(uint32_t time) {
last_feed = now;
#ifdef USE_STATUS_LED
if (status_led::global_status_led != nullptr) {
status_led::global_status_led->call();
auto *sl = status_led::global_status_led;
uint8_t sl_state = sl->get_component_state() & COMPONENT_STATE_MASK;
if (sl_state == COMPONENT_STATE_LOOP_DONE) {
// status_led only transitions to LOOP_DONE from inside its own loop() (after the
// first idle-path dispatch), so its pin is already initialized by pre_setup() and
// its setup() has already run. Re-dispatch only if an error or warning bit has been
// set since; otherwise skip entirely.
if ((this->app_state_ & STATUS_LED_MASK) == 0)
return;
sl->enable_loop();
} else if (sl_state != COMPONENT_STATE_LOOP) {
// CONSTRUCTION/SETUP/FAILED: not our job — App::setup() drives the lifecycle.
return;
}
sl->loop();
}
#endif
}
+1 -1
View File
@@ -19,7 +19,7 @@ ruamel.yaml==0.19.1 # dashboard_import
ruamel.yaml.clib==0.2.15 # dashboard_import
esphome-glyphsets==0.2.0
pillow==12.2.0
resvg-py==0.3.0
resvg-py==0.3.1
freetype-py==2.5.1
jinja2==3.1.6
bleak==2.1.1