1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-11 15:52:20 +01:00

Reduce CPU overhead by allowing components to disable their loop() (#9089)

This commit is contained in:
J. Nick Koston
2025-06-18 11:49:25 +02:00
committed by GitHub
parent fedb54bb38
commit 2e534ce41e
28 changed files with 646 additions and 29 deletions

View File

@@ -30,17 +30,18 @@ const float LATE = -100.0f;
} // namespace setup_priority
// Component state uses bits 0-1 (4 states)
const uint8_t COMPONENT_STATE_MASK = 0x03;
// Component state uses bits 0-2 (8 states, 5 used)
const uint8_t COMPONENT_STATE_MASK = 0x07;
const uint8_t COMPONENT_STATE_CONSTRUCTION = 0x00;
const uint8_t COMPONENT_STATE_SETUP = 0x01;
const uint8_t COMPONENT_STATE_LOOP = 0x02;
const uint8_t COMPONENT_STATE_FAILED = 0x03;
// Status LED uses bits 2-3
const uint8_t STATUS_LED_MASK = 0x0C;
const uint8_t COMPONENT_STATE_LOOP_DONE = 0x04;
// Status LED uses bits 3-4
const uint8_t STATUS_LED_MASK = 0x18;
const uint8_t STATUS_LED_OK = 0x00;
const uint8_t STATUS_LED_WARNING = 0x04; // Bit 2
const uint8_t STATUS_LED_ERROR = 0x08; // Bit 3
const uint8_t STATUS_LED_WARNING = 0x08; // Bit 3
const uint8_t STATUS_LED_ERROR = 0x10; // Bit 4
const uint16_t WARN_IF_BLOCKING_OVER_MS = 50U; ///< Initial blocking time allowed without warning
const uint16_t WARN_IF_BLOCKING_INCREMENT_MS = 10U; ///< How long the blocking time must be larger to warn again
@@ -113,6 +114,9 @@ void Component::call() {
case COMPONENT_STATE_FAILED: // NOLINT(bugprone-branch-clone)
// State failed: Do nothing
break;
case COMPONENT_STATE_LOOP_DONE: // NOLINT(bugprone-branch-clone)
// State loop done: Do nothing, component has finished its work
break;
default:
break;
}
@@ -136,14 +140,30 @@ bool Component::should_warn_of_blocking(uint32_t blocking_time) {
return false;
}
void Component::mark_failed() {
ESP_LOGE(TAG, "Component %s was marked as failed.", this->get_component_source());
ESP_LOGE(TAG, "Component %s was marked as failed", this->get_component_source());
this->component_state_ &= ~COMPONENT_STATE_MASK;
this->component_state_ |= COMPONENT_STATE_FAILED;
this->status_set_error();
// Also remove from loop since failed components shouldn't loop
App.disable_component_loop_(this);
}
void Component::disable_loop() {
ESP_LOGD(TAG, "%s loop disabled", this->get_component_source());
this->component_state_ &= ~COMPONENT_STATE_MASK;
this->component_state_ |= COMPONENT_STATE_LOOP_DONE;
App.disable_component_loop_(this);
}
void Component::enable_loop() {
if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP_DONE) {
ESP_LOGD(TAG, "%s loop enabled", this->get_component_source());
this->component_state_ &= ~COMPONENT_STATE_MASK;
this->component_state_ |= COMPONENT_STATE_LOOP;
App.enable_component_loop_(this);
}
}
void Component::reset_to_construction_state() {
if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) {
ESP_LOGI(TAG, "Component %s is being reset to construction state.", this->get_component_source());
ESP_LOGI(TAG, "Component %s is being reset to construction state", this->get_component_source());
this->component_state_ &= ~COMPONENT_STATE_MASK;
this->component_state_ |= COMPONENT_STATE_CONSTRUCTION;
// Clear error status when resetting
@@ -276,8 +296,8 @@ uint32_t WarnIfComponentBlockingGuard::finish() {
}
if (should_warn) {
const char *src = component_ == nullptr ? "<null>" : component_->get_component_source();
ESP_LOGW(TAG, "Component %s took a long time for an operation (%" PRIu32 " ms).", src, blocking_time);
ESP_LOGW(TAG, "Components should block for at most 30 ms.");
ESP_LOGW(TAG, "Component %s took a long time for an operation (%" PRIu32 " ms)", src, blocking_time);
ESP_LOGW(TAG, "Components should block for at most 30 ms");
}
return curr_time;