1
0
mirror of https://github.com/esphome/esphome.git synced 2025-06-16 15:26:58 +02:00

Merge branch 'component_state_oversized' into integration

This commit is contained in:
J. Nick Koston 2025-06-14 17:03:31 -05:00
commit c56af9d52b
No known key found for this signature in database
9 changed files with 65 additions and 36 deletions

View File

@ -93,9 +93,8 @@ void BME280Component::setup() {
// Mark as not failed before initializing. Some devices will turn off sensors to save on batteries // Mark as not failed before initializing. Some devices will turn off sensors to save on batteries
// and when they come back on, the COMPONENT_STATE_FAILED bit must be unset on the component. // and when they come back on, the COMPONENT_STATE_FAILED bit must be unset on the component.
if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) { if (this->is_failed()) {
this->component_state_ &= ~COMPONENT_STATE_MASK; this->reset_to_construction_state();
this->component_state_ |= COMPONENT_STATE_CONSTRUCTION;
} }
if (!this->read_byte(BME280_REGISTER_CHIPID, &chip_id)) { if (!this->read_byte(BME280_REGISTER_CHIPID, &chip_id)) {

View File

@ -19,9 +19,8 @@ void KMeterISOComponent::setup() {
// Mark as not failed before initializing. Some devices will turn off sensors to save on batteries // Mark as not failed before initializing. Some devices will turn off sensors to save on batteries
// and when they come back on, the COMPONENT_STATE_FAILED bit must be unset on the component. // and when they come back on, the COMPONENT_STATE_FAILED bit must be unset on the component.
if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) { if (this->is_failed()) {
this->component_state_ &= ~COMPONENT_STATE_MASK; this->reset_to_construction_state();
this->component_state_ |= COMPONENT_STATE_CONSTRUCTION;
} }
auto err = this->bus_->writev(this->address_, nullptr, 0); auto err = this->bus_->writev(this->address_, nullptr, 0);

View File

@ -9,10 +9,10 @@ namespace status_led {
static const char *const TAG = "status_led"; static const char *const TAG = "status_led";
void StatusLEDLightOutput::loop() { void StatusLEDLightOutput::loop() {
uint32_t new_state = App.get_app_state() & STATUS_LED_MASK; uint8_t new_state = App.get_app_state() & STATUS_LED_MASK;
if (new_state != this->last_app_state_) { if (new_state != this->last_app_state_) {
ESP_LOGV(TAG, "New app state 0x%08" PRIX32, new_state); ESP_LOGV(TAG, "New app state 0x%02X", new_state);
} }
if ((new_state & STATUS_LED_ERROR) != 0u) { if ((new_state & STATUS_LED_ERROR) != 0u) {

View File

@ -36,7 +36,7 @@ class StatusLEDLightOutput : public light::LightOutput, public Component {
GPIOPin *pin_{nullptr}; GPIOPin *pin_{nullptr};
output::BinaryOutput *output_{nullptr}; output::BinaryOutput *output_{nullptr};
light::LightState *lightstate_{}; light::LightState *lightstate_{};
uint32_t last_app_state_{0xFFFF}; uint8_t last_app_state_{0xFF};
void output_state_(bool state); void output_state_(bool state);
}; };

View File

@ -102,7 +102,7 @@ WeikaiRegister &WeikaiRegister::operator|=(uint8_t value) {
// The WeikaiComponent methods // The WeikaiComponent methods
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void WeikaiComponent::loop() { void WeikaiComponent::loop() {
if ((this->component_state_ & COMPONENT_STATE_MASK) != COMPONENT_STATE_LOOP) if (!this->is_in_loop_state())
return; return;
// If there are some bytes in the receive FIFO we transfers them to the ring buffers // If there are some bytes in the receive FIFO we transfers them to the ring buffers

View File

@ -66,7 +66,7 @@ void Application::setup() {
[](Component *a, Component *b) { return a->get_loop_priority() > b->get_loop_priority(); }); [](Component *a, Component *b) { return a->get_loop_priority() > b->get_loop_priority(); });
do { do {
uint32_t new_app_state = STATUS_LED_WARNING; uint8_t new_app_state = STATUS_LED_WARNING;
this->scheduler.call(); this->scheduler.call();
this->feed_wdt(); this->feed_wdt();
for (uint32_t j = 0; j <= i; j++) { for (uint32_t j = 0; j <= i; j++) {
@ -87,7 +87,7 @@ void Application::setup() {
this->calculate_looping_components_(); this->calculate_looping_components_();
} }
void Application::loop() { void Application::loop() {
uint32_t new_app_state = 0; uint8_t new_app_state = 0;
this->scheduler.call(); this->scheduler.call();

View File

@ -332,7 +332,7 @@ class Application {
*/ */
void teardown_components(uint32_t timeout_ms); void teardown_components(uint32_t timeout_ms);
uint32_t get_app_state() const { return this->app_state_; } uint8_t get_app_state() const { return this->app_state_; }
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
const std::vector<binary_sensor::BinarySensor *> &get_binary_sensors() { return this->binary_sensors_; } const std::vector<binary_sensor::BinarySensor *> &get_binary_sensors() { return this->binary_sensors_; }
@ -653,7 +653,7 @@ class Application {
uint32_t last_loop_{0}; uint32_t last_loop_{0};
uint32_t loop_interval_{16}; uint32_t loop_interval_{16};
size_t dump_config_at_{SIZE_MAX}; size_t dump_config_at_{SIZE_MAX};
uint32_t app_state_{0}; uint8_t app_state_{0};
Component *current_component_{nullptr}; Component *current_component_{nullptr};
uint32_t loop_component_start_time_{0}; uint32_t loop_component_start_time_{0};

View File

@ -30,15 +30,17 @@ const float LATE = -100.0f;
} // namespace setup_priority } // namespace setup_priority
const uint32_t COMPONENT_STATE_MASK = 0xFF; // Component state uses bits 0-1 (4 states)
const uint32_t COMPONENT_STATE_CONSTRUCTION = 0x00; const uint8_t COMPONENT_STATE_MASK = 0x03;
const uint32_t COMPONENT_STATE_SETUP = 0x01; const uint8_t COMPONENT_STATE_CONSTRUCTION = 0x00;
const uint32_t COMPONENT_STATE_LOOP = 0x02; const uint8_t COMPONENT_STATE_SETUP = 0x01;
const uint32_t COMPONENT_STATE_FAILED = 0x03; const uint8_t COMPONENT_STATE_LOOP = 0x02;
const uint32_t STATUS_LED_MASK = 0xFF00; const uint8_t COMPONENT_STATE_FAILED = 0x03;
const uint32_t STATUS_LED_OK = 0x0000; // Status LED uses bits 2-3
const uint32_t STATUS_LED_WARNING = 0x0100; const uint8_t STATUS_LED_MASK = 0x0C;
const uint32_t STATUS_LED_ERROR = 0x0200; 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 uint16_t WARN_IF_BLOCKING_OVER_MS = 50U; ///< Initial blocking time allowed without warning 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 const uint16_t WARN_IF_BLOCKING_INCREMENT_MS = 10U; ///< How long the blocking time must be larger to warn again
@ -88,9 +90,9 @@ void Component::call_dump_config() {
} }
} }
uint32_t Component::get_component_state() const { return this->component_state_; } uint8_t Component::get_component_state() const { return this->component_state_; }
void Component::call() { void Component::call() {
uint32_t state = this->component_state_ & COMPONENT_STATE_MASK; uint8_t state = this->component_state_ & COMPONENT_STATE_MASK;
switch (state) { switch (state) {
case COMPONENT_STATE_CONSTRUCTION: case COMPONENT_STATE_CONSTRUCTION:
// State Construction: Call setup and set state to setup // State Construction: Call setup and set state to setup
@ -139,6 +141,18 @@ void Component::mark_failed() {
this->component_state_ |= COMPONENT_STATE_FAILED; this->component_state_ |= COMPONENT_STATE_FAILED;
this->status_set_error(); this->status_set_error();
} }
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());
this->component_state_ &= ~COMPONENT_STATE_MASK;
this->component_state_ |= COMPONENT_STATE_CONSTRUCTION;
// Clear error status when resetting
this->status_clear_error();
}
}
bool Component::is_in_loop_state() const {
return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP;
}
void Component::defer(std::function<void()> &&f) { // NOLINT void Component::defer(std::function<void()> &&f) { // NOLINT
App.scheduler.set_timeout(this, "", 0, std::move(f)); App.scheduler.set_timeout(this, "", 0, std::move(f));
} }

View File

@ -53,15 +53,15 @@ static const uint32_t SCHEDULER_DONT_RUN = 4294967295UL;
ESP_LOGCONFIG(TAG, " Update Interval: %.1fs", this->get_update_interval() / 1000.0f); \ ESP_LOGCONFIG(TAG, " Update Interval: %.1fs", this->get_update_interval() / 1000.0f); \
} }
extern const uint32_t COMPONENT_STATE_MASK; extern const uint8_t COMPONENT_STATE_MASK;
extern const uint32_t COMPONENT_STATE_CONSTRUCTION; extern const uint8_t COMPONENT_STATE_CONSTRUCTION;
extern const uint32_t COMPONENT_STATE_SETUP; extern const uint8_t COMPONENT_STATE_SETUP;
extern const uint32_t COMPONENT_STATE_LOOP; extern const uint8_t COMPONENT_STATE_LOOP;
extern const uint32_t COMPONENT_STATE_FAILED; extern const uint8_t COMPONENT_STATE_FAILED;
extern const uint32_t STATUS_LED_MASK; extern const uint8_t STATUS_LED_MASK;
extern const uint32_t STATUS_LED_OK; extern const uint8_t STATUS_LED_OK;
extern const uint32_t STATUS_LED_WARNING; extern const uint8_t STATUS_LED_WARNING;
extern const uint32_t STATUS_LED_ERROR; extern const uint8_t STATUS_LED_ERROR;
enum class RetryResult { DONE, RETRY }; enum class RetryResult { DONE, RETRY };
@ -123,7 +123,19 @@ class Component {
*/ */
virtual void on_powerdown() {} virtual void on_powerdown() {}
uint32_t get_component_state() const; uint8_t get_component_state() const;
/** Reset this component back to the construction state to allow setup to run again.
*
* This can be used by components that have recoverable failures to attempt setup again.
*/
void reset_to_construction_state();
/** Check if this component has completed setup and is in the loop state.
*
* @return True if in loop state, false otherwise.
*/
bool is_in_loop_state() const;
/** Mark this component as failed. Any future timeouts/intervals/setup/loop will no longer be called. /** Mark this component as failed. Any future timeouts/intervals/setup/loop will no longer be called.
* *
@ -298,7 +310,12 @@ class Component {
/// Cancel a defer callback using the specified name, name must not be empty. /// Cancel a defer callback using the specified name, name must not be empty.
bool cancel_defer(const std::string &name); // NOLINT bool cancel_defer(const std::string &name); // NOLINT
uint32_t component_state_{0x0000}; ///< State of this component. /// State of this component - each bit has a purpose:
/// Bits 0-1: Component state (0x00=CONSTRUCTION, 0x01=SETUP, 0x02=LOOP, 0x03=FAILED)
/// Bit 2: STATUS_LED_WARNING
/// Bit 3: STATUS_LED_ERROR
/// Bits 4-7: Unused - reserved for future expansion (50% of the bits are free)
uint8_t component_state_{0x00};
float setup_priority_override_{NAN}; float setup_priority_override_{NAN};
const char *component_source_{nullptr}; const char *component_source_{nullptr};
uint16_t warn_if_blocking_over_{WARN_IF_BLOCKING_OVER_MS}; ///< Warn if blocked for this many ms (max 65.5s) uint16_t warn_if_blocking_over_{WARN_IF_BLOCKING_OVER_MS}; ///< Warn if blocked for this many ms (max 65.5s)