ESPHome 2025.6.2
Loading...
Searching...
No Matches
component.cpp
Go to the documentation of this file.
2
3#include <cinttypes>
4#include <limits>
5#include <utility>
7#include "esphome/core/hal.h"
9#include "esphome/core/log.h"
10
11namespace esphome {
12
13static const char *const TAG = "component";
14
15namespace setup_priority {
16
17const float BUS = 1000.0f;
18const float IO = 900.0f;
19const float HARDWARE = 800.0f;
20const float DATA = 600.0f;
21const float PROCESSOR = 400.0;
22const float BLUETOOTH = 350.0f;
23const float AFTER_BLUETOOTH = 300.0f;
24const float WIFI = 250.0f;
25const float ETHERNET = 250.0f;
26const float BEFORE_CONNECTION = 220.0f;
27const float AFTER_WIFI = 200.0f;
28const float AFTER_CONNECTION = 100.0f;
29const float LATE = -100.0f;
30
31} // namespace setup_priority
32
33// Component state uses bits 0-1 (4 states)
34const uint8_t COMPONENT_STATE_MASK = 0x03;
35const uint8_t COMPONENT_STATE_CONSTRUCTION = 0x00;
36const uint8_t COMPONENT_STATE_SETUP = 0x01;
37const uint8_t COMPONENT_STATE_LOOP = 0x02;
38const uint8_t COMPONENT_STATE_FAILED = 0x03;
39// Status LED uses bits 2-3
40const uint8_t STATUS_LED_MASK = 0x0C;
41const uint8_t STATUS_LED_OK = 0x00;
42const uint8_t STATUS_LED_WARNING = 0x04; // Bit 2
43const uint8_t STATUS_LED_ERROR = 0x08; // Bit 3
44
45const uint16_t WARN_IF_BLOCKING_OVER_MS = 50U;
46const uint16_t WARN_IF_BLOCKING_INCREMENT_MS = 10U;
47
48uint32_t global_state = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
49
50float Component::get_loop_priority() const { return 0.0f; }
51
53
55
57
58void Component::set_interval(const std::string &name, uint32_t interval, std::function<void()> &&f) { // NOLINT
59 App.scheduler.set_interval(this, name, interval, std::move(f));
60}
61
62bool Component::cancel_interval(const std::string &name) { // NOLINT
63 return App.scheduler.cancel_interval(this, name);
64}
65
66void Component::set_retry(const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts,
67 std::function<RetryResult(uint8_t)> &&f, float backoff_increase_factor) { // NOLINT
68 App.scheduler.set_retry(this, name, initial_wait_time, max_attempts, std::move(f), backoff_increase_factor);
69}
70
71bool Component::cancel_retry(const std::string &name) { // NOLINT
72 return App.scheduler.cancel_retry(this, name);
73}
74
75void Component::set_timeout(const std::string &name, uint32_t timeout, std::function<void()> &&f) { // NOLINT
76 App.scheduler.set_timeout(this, name, timeout, std::move(f));
77}
78
79bool Component::cancel_timeout(const std::string &name) { // NOLINT
80 return App.scheduler.cancel_timeout(this, name);
81}
82
83void Component::call_loop() { this->loop(); }
84void Component::call_setup() { this->setup(); }
86 this->dump_config();
87 if (this->is_failed()) {
88 ESP_LOGE(TAG, " Component %s is marked FAILED: %s", this->get_component_source(), this->error_message_.c_str());
89 }
90}
91
92uint8_t Component::get_component_state() const { return this->component_state_; }
95 switch (state) {
97 // State Construction: Call setup and set state to setup
98 this->component_state_ &= ~COMPONENT_STATE_MASK;
100 this->call_setup();
101 break;
103 // State setup: Call first loop and set state to loop
104 this->component_state_ &= ~COMPONENT_STATE_MASK;
106 this->call_loop();
107 break;
109 // State loop: Call loop
110 this->call_loop();
111 break;
112 case COMPONENT_STATE_FAILED: // NOLINT(bugprone-branch-clone)
113 // State failed: Do nothing
114 break;
115 default:
116 break;
117 }
118}
120 if (this->component_source_ == nullptr)
121 return "<unknown>";
122 return this->component_source_;
123}
124bool Component::should_warn_of_blocking(uint32_t blocking_time) {
125 if (blocking_time > this->warn_if_blocking_over_) {
126 // Prevent overflow when adding increment - if we're about to overflow, just max out
127 if (blocking_time + WARN_IF_BLOCKING_INCREMENT_MS < blocking_time ||
128 blocking_time + WARN_IF_BLOCKING_INCREMENT_MS > std::numeric_limits<uint16_t>::max()) {
129 this->warn_if_blocking_over_ = std::numeric_limits<uint16_t>::max();
130 } else {
131 this->warn_if_blocking_over_ = static_cast<uint16_t>(blocking_time + WARN_IF_BLOCKING_INCREMENT_MS);
132 }
133 return true;
134 }
135 return false;
136}
138 ESP_LOGE(TAG, "Component %s was marked as failed.", this->get_component_source());
139 this->component_state_ &= ~COMPONENT_STATE_MASK;
141 this->status_set_error();
142}
144 if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) {
145 ESP_LOGI(TAG, "Component %s is being reset to construction state.", this->get_component_source());
146 this->component_state_ &= ~COMPONENT_STATE_MASK;
148 // Clear error status when resetting
149 this->status_clear_error();
150 }
151}
153 return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP;
154}
155void Component::defer(std::function<void()> &&f) { // NOLINT
156 App.scheduler.set_timeout(this, "", 0, std::move(f));
157}
158bool Component::cancel_defer(const std::string &name) { // NOLINT
159 return App.scheduler.cancel_timeout(this, name);
160}
161void Component::defer(const std::string &name, std::function<void()> &&f) { // NOLINT
162 App.scheduler.set_timeout(this, name, 0, std::move(f));
163}
164void Component::set_timeout(uint32_t timeout, std::function<void()> &&f) { // NOLINT
165 App.scheduler.set_timeout(this, "", timeout, std::move(f));
166}
167void Component::set_interval(uint32_t interval, std::function<void()> &&f) { // NOLINT
168 App.scheduler.set_interval(this, "", interval, std::move(f));
169}
170void Component::set_retry(uint32_t initial_wait_time, uint8_t max_attempts, std::function<RetryResult(uint8_t)> &&f,
171 float backoff_increase_factor) { // NOLINT
172 App.scheduler.set_retry(this, "", initial_wait_time, max_attempts, std::move(f), backoff_increase_factor);
173}
174bool Component::is_failed() const { return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED; }
176 return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP ||
177 (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_SETUP;
178}
179bool Component::can_proceed() { return true; }
182void Component::status_set_warning(const char *message) {
183 // Don't spam the log. This risks missing different warning messages though.
184 if ((this->component_state_ & STATUS_LED_WARNING) != 0)
185 return;
188 ESP_LOGW(TAG, "Component %s set Warning flag: %s", this->get_component_source(), message);
189}
190void Component::status_set_error(const char *message) {
191 if ((this->component_state_ & STATUS_LED_ERROR) != 0)
192 return;
195 ESP_LOGE(TAG, "Component %s set Error flag: %s", this->get_component_source(), message);
196 if (strcmp(message, "unspecified") != 0)
197 this->error_message_ = message;
198}
200 if ((this->component_state_ & STATUS_LED_WARNING) == 0)
201 return;
202 this->component_state_ &= ~STATUS_LED_WARNING;
203 ESP_LOGW(TAG, "Component %s cleared Warning flag", this->get_component_source());
204}
206 if ((this->component_state_ & STATUS_LED_ERROR) == 0)
207 return;
208 this->component_state_ &= ~STATUS_LED_ERROR;
209 ESP_LOGE(TAG, "Component %s cleared Error flag", this->get_component_source());
210}
211void Component::status_momentary_warning(const std::string &name, uint32_t length) {
212 this->status_set_warning();
213 this->set_timeout(name, length, [this]() { this->status_clear_warning(); });
214}
215void Component::status_momentary_error(const std::string &name, uint32_t length) {
216 this->status_set_error();
217 this->set_timeout(name, length, [this]() { this->status_clear_error(); });
218}
221 if (std::isnan(this->setup_priority_override_))
222 return this->get_setup_priority();
223 return this->setup_priority_override_;
224}
226
228#if defined(USE_HOST) || defined(CLANG_TIDY)
229 bool loop_overridden = true;
230 bool call_loop_overridden = true;
231#else
232#pragma GCC diagnostic push
233#pragma GCC diagnostic ignored "-Wpmf-conversions"
234 bool loop_overridden = (void *) (this->*(&Component::loop)) != (void *) (&Component::loop);
235 bool call_loop_overridden = (void *) (this->*(&Component::call_loop)) != (void *) (&Component::call_loop);
236#pragma GCC diagnostic pop
237#endif
238 return loop_overridden || call_loop_overridden;
239}
240
241PollingComponent::PollingComponent(uint32_t update_interval) : update_interval_(update_interval) {}
242
244 // Let the polling component subclass setup their HW.
245 this->setup();
246
247 // init the poller
248 this->start_poller();
249}
250
252 // Register interval.
253 this->set_interval("update", this->get_update_interval(), [this]() { this->update(); });
254}
255
257 // Clear the interval to suspend component
258 this->cancel_interval("update");
259}
260
262void PollingComponent::set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; }
263
265 : started_(start_time), component_(component) {}
267 uint32_t curr_time = millis();
268
269 uint32_t blocking_time = curr_time - this->started_;
270 bool should_warn;
271 if (this->component_ != nullptr) {
272 should_warn = this->component_->should_warn_of_blocking(blocking_time);
273 } else {
274 should_warn = blocking_time > WARN_IF_BLOCKING_OVER_MS;
275 }
276 if (should_warn) {
277 const char *src = component_ == nullptr ? "<null>" : component_->get_component_source();
278 ESP_LOGW(TAG, "Component %s took a long time for an operation (%" PRIu32 " ms).", src, blocking_time);
279 ESP_LOGW(TAG, "Components should block for at most 30 ms.");
280 }
281
282 return curr_time;
283}
284
286
287} // namespace esphome
virtual void mark_failed()
Mark this component as failed.
virtual void call_dump_config()
Definition component.cpp:85
virtual float get_setup_priority() const
priority of setup().
Definition component.cpp:52
virtual void setup()
Where the component's initialization should happen.
Definition component.cpp:54
float get_actual_setup_priority() const
bool has_overridden_loop() const
bool is_failed() const
uint8_t get_component_state() const
Definition component.cpp:92
void set_interval(const std::string &name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a unique name.
Definition component.cpp:58
bool should_warn_of_blocking(uint32_t blocking_time)
virtual bool can_proceed()
bool cancel_timeout(const std::string &name)
Cancel a timeout function.
Definition component.cpp:79
virtual float get_loop_priority() const
priority of loop().
Definition component.cpp:50
bool is_in_loop_state() const
Check if this component has completed setup and is in the loop state.
void status_momentary_error(const std::string &name, uint32_t length=5000)
const char * get_component_source() const
Get the integration where this component was declared as a string.
uint16_t warn_if_blocking_over_
Warn if blocked for this many ms (max 65.5s)
Definition component.h:321
bool cancel_retry(const std::string &name)
Cancel a retry function.
Definition component.cpp:71
uint8_t component_state_
State of this component - each bit has a purpose: Bits 0-1: Component state (0x00=CONSTRUCTION,...
Definition component.h:318
void status_momentary_warning(const std::string &name, uint32_t length=5000)
bool is_ready() const
virtual void dump_config()
bool status_has_warning() const
bool status_has_error() const
bool cancel_interval(const std::string &name)
Cancel an interval function.
Definition component.cpp:62
void status_set_warning(const char *message="unspecified")
bool cancel_defer(const std::string &name)
Cancel a defer callback using the specified name, name must not be empty.
virtual void loop()
This method will be called repeatedly.
Definition component.cpp:56
void status_set_error(const char *message="unspecified")
void reset_to_construction_state()
Reset this component back to the construction state to allow setup to run again.
const char * component_source_
Definition component.h:320
void set_setup_priority(float priority)
void defer(const std::string &name, std::function< void()> &&f)
Defer a callback to the next loop() call.
virtual void call_loop()
Definition component.cpp:83
float setup_priority_override_
Definition component.h:319
void status_clear_warning()
virtual void call_setup()
Definition component.cpp:84
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.cpp:75
std::string error_message_
Definition component.h:322
void set_retry(const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts, std::function< RetryResult(uint8_t)> &&f, float backoff_increase_factor=1.0f)
Set an retry function with a unique name.
Definition component.cpp:66
virtual uint32_t get_update_interval() const
Get the update interval in ms of this sensor.
void call_setup() override
virtual void set_update_interval(uint32_t update_interval)
Manually set the update interval in ms for this polling object.
virtual void update()=0
bool cancel_retry(Component *component, const std::string &name)
void set_retry(Component *component, const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts, std::function< RetryResult(uint8_t)> func, float backoff_increase_factor=1.0f)
bool cancel_timeout(Component *component, const std::string &name)
Definition scheduler.cpp:47
bool cancel_interval(Component *component, const std::string &name)
Definition scheduler.cpp:79
void set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function< void()> func)
Definition scheduler.cpp:25
void set_interval(Component *component, const std::string &name, uint32_t interval, std::function< void()> func)
Definition scheduler.cpp:50
WarnIfComponentBlockingGuard(Component *component, uint32_t start_time)
uint8_t priority
bool state
Definition fan.h:0
const float BUS
For communication buses like i2c/spi.
Definition component.cpp:17
const float AFTER_CONNECTION
For components that should be initialized after a data connection (API/MQTT) is connected.
Definition component.cpp:28
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:20
const float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition component.cpp:19
const float BEFORE_CONNECTION
For components that should be initialized after WiFi and before API is connected.
Definition component.cpp:26
const float IO
For components that represent GPIO pins like PCF8573.
Definition component.cpp:18
const float LATE
For components that should be initialized at the very end of the setup process.
Definition component.cpp:29
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition component.cpp:27
const float PROCESSOR
For components that use data from sensors like displays.
Definition component.cpp:21
const float AFTER_BLUETOOTH
Definition component.cpp:23
const char *const TAG
Definition spi.cpp:8
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
const uint8_t COMPONENT_STATE_SETUP
Definition component.cpp:36
const uint8_t COMPONENT_STATE_CONSTRUCTION
Definition component.cpp:35
const uint8_t STATUS_LED_MASK
Definition component.cpp:40
const uint16_t WARN_IF_BLOCKING_INCREMENT_MS
How long the blocking time must be larger to warn again.
Definition component.cpp:46
const uint8_t COMPONENT_STATE_FAILED
Definition component.cpp:38
const uint8_t COMPONENT_STATE_MASK
Definition component.cpp:34
const uint8_t COMPONENT_STATE_LOOP
Definition component.cpp:37
const uint16_t WARN_IF_BLOCKING_OVER_MS
Initial blocking time allowed without warning.
Definition component.cpp:45
uint32_t global_state
Definition component.cpp:48
const uint8_t STATUS_LED_OK
Definition component.cpp:41
const uint8_t STATUS_LED_WARNING
Definition component.cpp:42
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:28
Application App
Global storage of Application pointer - only one Application can exist.
const uint8_t STATUS_LED_ERROR
Definition component.cpp:43
uint16_t length
Definition tt21100.cpp:0