11#ifdef USE_SOCKET_SELECT_SUPPORT
14#ifdef USE_SOCKET_IMPL_LWIP_SOCKETS
16#include <lwip/sockets.h>
17#elif defined(USE_SOCKET_IMPL_BSD_SOCKETS)
21#include <lwip/sockets.h>
24#include <sys/select.h>
31static const char *
const TAG =
"app";
34 if (comp ==
nullptr) {
35 ESP_LOGW(TAG,
"Tried to register null component!");
41 ESP_LOGW(TAG,
"Component %s already registered! (%p)", c->get_component_source(), c);
45 this->components_.push_back(comp);
48 ESP_LOGI(TAG,
"Running through setup()");
49 ESP_LOGV(TAG,
"Sorting components by setup priority");
51 return a->get_actual_setup_priority() > b->get_actual_setup_priority();
54 for (uint32_t i = 0; i < this->
components_.size(); i++) {
65 std::stable_sort(this->
components_.begin(), this->components_.begin() + i + 1,
66 [](
Component *a,
Component *b) { return a->get_loop_priority() > b->get_loop_priority(); });
72 for (uint32_t j = 0; j <= i; j++) {
76 new_app_state |= this->
components_[j]->get_component_state();
85 ESP_LOGI(TAG,
"setup() finished successfully!");
90 uint8_t new_app_state = 0;
95 uint32_t last_op_end_time =
millis();
109 last_op_end_time = guard.
finish();
111 new_app_state |= component->get_component_state();
118 auto elapsed = last_op_end_time - this->
last_loop_;
128 next_schedule = std::max(next_schedule, delay_time / 2);
129 delay_time = std::min(next_schedule, delay_time);
133 this->last_loop_ = last_op_end_time;
137 ESP_LOGI(TAG,
"ESPHome version " ESPHOME_VERSION
" compiled on %s", this->
compilation_time_);
138#ifdef ESPHOME_PROJECT_NAME
139 ESP_LOGI(TAG,
"Project " ESPHOME_PROJECT_NAME
" version " ESPHOME_PROJECT_VERSION);
149 static uint32_t last_feed = 0;
151 uint32_t now = time ? time :
millis();
153 if (now - last_feed > 3) {
164 ESP_LOGI(TAG,
"Forcing a reboot");
165 for (
auto it = this->
components_.rbegin(); it != this->components_.rend(); ++it) {
166 (*it)->on_shutdown();
171 ESP_LOGI(TAG,
"Rebooting safely");
179 for (
auto it = this->
components_.rbegin(); it != this->components_.rend(); ++it) {
180 (*it)->on_safe_shutdown();
182 for (
auto it = this->
components_.rbegin(); it != this->components_.rend(); ++it) {
183 (*it)->on_shutdown();
188 for (
auto it = this->
components_.rbegin(); it != this->components_.rend(); ++it) {
189 (*it)->on_powerdown();
194 uint32_t start_time =
millis();
200 std::vector<Component *> pending_components(this->
components_.rbegin(), this->components_.rend());
202 uint32_t now = start_time;
203 while (!pending_components.empty() && (now - start_time) < timeout_ms) {
208 for (
auto it = pending_components.begin(); it != pending_components.end();) {
209 if ((*it)->teardown()) {
211 it = pending_components.erase(it);
219 if (!pending_components.empty()) {
227 if (!pending_components.empty()) {
230 for (
auto *component : pending_components) {
231 ESP_LOGW(TAG,
"%s did not complete teardown within %" PRIu32
" ms", component->get_component_source(),
239 if (obj->has_overridden_loop())
244#ifdef USE_SOCKET_SELECT_SUPPORT
251 if (fd >= FD_SETSIZE) {
252 ESP_LOGE(TAG,
"Cannot monitor socket fd %d: exceeds FD_SETSIZE (%d)", fd, FD_SETSIZE);
253 ESP_LOGE(TAG,
"Socket will not be monitored for data - may cause performance issues!");
273 auto it = std::find(this->
socket_fds_.begin(), this->socket_fds_.end(), fd);
288 this->
max_fd_ = *std::max_element(this->
socket_fds_.begin(), this->socket_fds_.end());
298 if (fd < 0 || fd >= FD_SETSIZE)
308#ifdef USE_SOCKET_SELECT_SUPPORT
314 if (fd >= 0 && fd < FD_SETSIZE) {
326 tv.tv_sec = delay_ms / 1000;
327 tv.tv_usec = (delay_ms - tv.tv_sec * 1000) * 1000;
330#if defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || (defined(USE_ESP32) && defined(USE_SOCKET_IMPL_BSD_SOCKETS))
331 int ret = lwip_select(this->
max_fd_ + 1, &this->
read_fds_,
nullptr,
nullptr, &tv);
333 int ret = ::select(this->
max_fd_ + 1, &this->
read_fds_,
nullptr,
nullptr, &tv);
340 if (ret < 0 && errno != EINTR) {
342 ESP_LOGW(TAG,
"select() failed with errno %d", errno);
void setup()
Set up all the registered components. Call this at the end of your setup() function.
void set_current_component(Component *component)
bool is_socket_ready(int fd) const
Check if there's data available on a socket without blocking This function is thread-safe for reading...
std::vector< int > socket_fds_
std::vector< Component * > components_
uint32_t loop_component_start_time_
void teardown_components(uint32_t timeout_ms)
Teardown all components with a timeout.
const char * compilation_time_
std::vector< Component * > looping_components_
void schedule_dump_config()
void run_safe_shutdown_hooks()
void feed_wdt(uint32_t time=0)
void loop()
Make a loop iteration. Call this in your loop() function.
void unregister_socket_fd(int fd)
bool register_socket_fd(int fd)
Register/unregister a socket file descriptor to be monitored for read events.
void calculate_looping_components_()
void yield_with_select_(uint32_t delay_ms)
Perform a delay while also monitoring socket file descriptors for readiness.
void run_powerdown_hooks()
void register_component_(Component *comp)
virtual bool can_proceed()
static bool is_high_frequency()
Check whether the loop is running continuously.
optional< uint32_t > next_schedule_in()
value_type value_or(U const &v) const
StatusLED * global_status_led
Providing packet encoding functions for exchanging data with a remote host.
void IRAM_ATTR HOT yield()
void IRAM_ATTR HOT arch_feed_wdt()
const uint8_t STATUS_LED_WARNING
void IRAM_ATTR HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.