ESPHome 2026.2.0
Loading...
Searching...
No Matches
api_server.cpp
Go to the documentation of this file.
1#include "api_server.h"
2#ifdef USE_API
3#include <cerrno>
4#include "api_connection.h"
9#include "esphome/core/hal.h"
10#include "esphome/core/log.h"
11#include "esphome/core/util.h"
13#ifdef USE_API_HOMEASSISTANT_SERVICES
15#endif
16
17#ifdef USE_LOGGER
19#endif
20
21#include <algorithm>
22#include <utility>
23
24namespace esphome::api {
25
26static const char *const TAG = "api";
27
28// APIServer
29APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
30
32 global_api_server = this;
33 // Pre-allocate shared write buffer
34 shared_write_buffer_.reserve(64);
35}
36
39
40#ifdef USE_API_NOISE
41 uint32_t hash = 88491486UL;
42
44
45#ifndef USE_API_NOISE_PSK_FROM_YAML
46 // Only load saved PSK if not set from YAML
47 SavedNoisePsk noise_pref_saved{};
48 if (this->noise_pref_.load(&noise_pref_saved)) {
49 ESP_LOGD(TAG, "Loaded saved Noise PSK");
50 this->set_noise_psk(noise_pref_saved.psk);
51 }
52#endif
53#endif
54
55 this->socket_ = socket::socket_ip_loop_monitored(SOCK_STREAM, 0); // monitored for incoming connections
56 if (this->socket_ == nullptr) {
57 ESP_LOGW(TAG, "Could not create socket");
58 this->mark_failed();
59 return;
60 }
61 int enable = 1;
62 int err = this->socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
63 if (err != 0) {
64 ESP_LOGW(TAG, "Socket unable to set reuseaddr: errno %d", err);
65 // we can still continue
66 }
67 err = this->socket_->setblocking(false);
68 if (err != 0) {
69 ESP_LOGW(TAG, "Socket unable to set nonblocking mode: errno %d", err);
70 this->mark_failed();
71 return;
72 }
73
74 struct sockaddr_storage server;
75
76 socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), this->port_);
77 if (sl == 0) {
78 ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno);
79 this->mark_failed();
80 return;
81 }
82
83 err = this->socket_->bind((struct sockaddr *) &server, sl);
84 if (err != 0) {
85 ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno);
86 this->mark_failed();
87 return;
88 }
89
90 err = this->socket_->listen(this->listen_backlog_);
91 if (err != 0) {
92 ESP_LOGW(TAG, "Socket unable to listen: errno %d", errno);
93 this->mark_failed();
94 return;
95 }
96
97#ifdef USE_LOGGER
98 if (logger::global_logger != nullptr) {
100 }
101#endif
102
103#ifdef USE_CAMERA
104 if (camera::Camera::instance() != nullptr && !camera::Camera::instance()->is_internal()) {
106 }
107#endif
108
109 // Initialize last_connected_ for reboot timeout tracking
111 // Set warning status if reboot timeout is enabled
112 if (this->reboot_timeout_ != 0) {
113 this->status_set_warning();
114 }
115}
116
118 // Accept new clients only if the socket exists and has incoming connections
119 if (this->socket_ && this->socket_->ready()) {
120 this->accept_new_connections_();
121 }
122
123 if (this->clients_.empty()) {
124 // Check reboot timeout - done in loop to avoid scheduler heap churn
125 // (cancelled scheduler items sit in heap memory until their scheduled time)
126 if (this->reboot_timeout_ != 0) {
127 const uint32_t now = App.get_loop_component_start_time();
128 if (now - this->last_connected_ > this->reboot_timeout_) {
129 ESP_LOGE(TAG, "No clients; rebooting");
130 App.reboot();
131 }
132 }
133 return;
134 }
135
136 // Process clients and remove disconnected ones in a single pass
137 // Check network connectivity once for all clients
138 if (!network::is_connected()) {
139 // Network is down - disconnect all clients
140 for (auto &client : this->clients_) {
141 client->on_fatal_error();
142 client->log_client_(ESPHOME_LOG_LEVEL_WARN, LOG_STR("Network down; disconnect"));
143 }
144 // Continue to process and clean up the clients below
145 }
146
147 size_t client_index = 0;
148 while (client_index < this->clients_.size()) {
149 auto &client = this->clients_[client_index];
150
151 // Common case: process active client
152 if (!client->flags_.remove) {
153 client->loop();
154 }
155 // Handle disconnection promptly - close socket to free LWIP PCB
156 // resources and prevent retransmit crashes on ESP8266.
157 if (client->flags_.remove) {
158 // Rare case: handle disconnection (don't increment - swapped element needs processing)
159 this->remove_client_(client_index);
160 } else {
161 client_index++;
162 }
163 }
164}
165
166void APIServer::remove_client_(size_t client_index) {
167 auto &client = this->clients_[client_index];
168
169#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
171#endif
172 ESP_LOGV(TAG, "Remove connection %s", client->get_name());
173
174#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
175 // Save client info before closing socket and removal for the trigger
176 char peername_buf[socket::SOCKADDR_STR_LEN];
177 std::string client_name(client->get_name());
178 std::string client_peername(client->get_peername_to(peername_buf));
179#endif
180
181 // Close socket now (was deferred from on_fatal_error to allow getpeername)
182 client->helper_->close();
183
184 // Swap with the last element and pop (avoids expensive vector shifts)
185 if (client_index < this->clients_.size() - 1) {
186 std::swap(this->clients_[client_index], this->clients_.back());
187 }
188 this->clients_.pop_back();
189
190 // Last client disconnected - set warning and start tracking for reboot timeout
191 if (this->clients_.empty() && this->reboot_timeout_ != 0) {
192 this->status_set_warning();
194 }
195
196#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
197 // Fire trigger after client is removed so api.connected reflects the true state
198 this->client_disconnected_trigger_.trigger(client_name, client_peername);
199#endif
200}
201
202void APIServer::accept_new_connections_() {
203 while (true) {
204 struct sockaddr_storage source_addr;
205 socklen_t addr_len = sizeof(source_addr);
206
207 auto sock = this->socket_->accept_loop_monitored((struct sockaddr *) &source_addr, &addr_len);
208 if (!sock)
209 break;
210
211 char peername[socket::SOCKADDR_STR_LEN];
212 sock->getpeername_to(peername);
213
214 // Check if we're at the connection limit
215 if (this->clients_.size() >= this->max_connections_) {
216 ESP_LOGW(TAG, "Max connections (%d), rejecting %s", this->max_connections_, peername);
217 // Immediately close - socket destructor will handle cleanup
218 sock.reset();
219 continue;
220 }
221
222 ESP_LOGD(TAG, "Accept %s", peername);
223
224 auto *conn = new APIConnection(std::move(sock), this);
225 this->clients_.emplace_back(conn);
226 conn->start();
227
228 // First client connected - clear warning and update timestamp
229 if (this->clients_.size() == 1 && this->reboot_timeout_ != 0) {
230 this->status_clear_warning();
232 }
233 }
234}
235
237 ESP_LOGCONFIG(TAG,
238 "Server:\n"
239 " Address: %s:%u\n"
240 " Listen backlog: %u\n"
241 " Max connections: %u",
243#ifdef USE_API_NOISE
244 ESP_LOGCONFIG(TAG, " Noise encryption: %s", YESNO(this->noise_ctx_.has_psk()));
245 if (!this->noise_ctx_.has_psk()) {
246 ESP_LOGCONFIG(TAG, " Supports encryption: YES");
247 }
248#else
249 ESP_LOGCONFIG(TAG, " Noise encryption: NO");
250#endif
251}
252
254
255// Macro for controller update dispatch
256#define API_DISPATCH_UPDATE(entity_type, entity_name) \
257 void APIServer::on_##entity_name##_update(entity_type *obj) { /* NOLINT(bugprone-macro-parentheses) */ \
258 if (obj->is_internal()) \
259 return; \
260 for (auto &c : this->clients_) { \
261 if (c->flags_.state_subscription) \
262 c->send_##entity_name##_state(obj); \
263 } \
264 }
265
266#ifdef USE_BINARY_SENSOR
268#endif
269
270#ifdef USE_COVER
272#endif
273
274#ifdef USE_FAN
276#endif
277
278#ifdef USE_LIGHT
280#endif
281
282#ifdef USE_SENSOR
284#endif
285
286#ifdef USE_SWITCH
288#endif
289
290#ifdef USE_TEXT_SENSOR
292#endif
293
294#ifdef USE_CLIMATE
296#endif
297
298#ifdef USE_NUMBER
300#endif
301
302#ifdef USE_DATETIME_DATE
304#endif
305
306#ifdef USE_DATETIME_TIME
308#endif
309
310#ifdef USE_DATETIME_DATETIME
312#endif
313
314#ifdef USE_TEXT
316#endif
317
318#ifdef USE_SELECT
320#endif
321
322#ifdef USE_LOCK
324#endif
325
326#ifdef USE_VALVE
328#endif
329
330#ifdef USE_MEDIA_PLAYER
332#endif
333
334#ifdef USE_WATER_HEATER
336#endif
337
338#ifdef USE_EVENT
340 if (obj->is_internal())
341 return;
342 for (auto &c : this->clients_) {
343 if (c->flags_.state_subscription)
344 c->send_event(obj);
345 }
346}
347#endif
348
349#ifdef USE_UPDATE
350// Update is a special case - the method is called on_update, not on_update_update
352 if (obj->is_internal())
353 return;
354 for (auto &c : this->clients_) {
355 if (c->flags_.state_subscription)
356 c->send_update_state(obj);
357 }
358}
359#endif
360
361#ifdef USE_ZWAVE_PROXY
363 // We could add code to manage a second subscription type, but, since this message type is
364 // very infrequent and small, we simply send it to all clients
365 for (auto &c : this->clients_)
366 c->send_message(msg, api::ZWaveProxyRequest::MESSAGE_TYPE);
367}
368#endif
369
370#ifdef USE_IR_RF
371void APIServer::send_infrared_rf_receive_event([[maybe_unused]] uint32_t device_id, uint32_t key,
372 const std::vector<int32_t> *timings) {
374#ifdef USE_DEVICES
375 resp.device_id = device_id;
376#endif
377 resp.key = key;
378 resp.timings = timings;
379
380 for (auto &c : this->clients_)
381 c->send_infrared_rf_receive_event(resp);
382}
383#endif
384
385#ifdef USE_ALARM_CONTROL_PANEL
387#endif
388
390
391void APIServer::set_port(uint16_t port) { this->port_ = port; }
392
393void APIServer::set_batch_delay(uint16_t batch_delay) { this->batch_delay_ = batch_delay; }
394
395#ifdef USE_API_HOMEASSISTANT_SERVICES
397 for (auto &client : this->clients_) {
398 client->send_homeassistant_action(call);
399 }
400}
401#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
403 this->action_response_callbacks_.push_back({call_id, std::move(callback)});
404}
405
406void APIServer::handle_action_response(uint32_t call_id, bool success, StringRef error_message) {
407 for (auto it = this->action_response_callbacks_.begin(); it != this->action_response_callbacks_.end(); ++it) {
408 if (it->call_id == call_id) {
409 auto callback = std::move(it->callback);
410 this->action_response_callbacks_.erase(it);
411 ActionResponse response(success, error_message);
412 callback(response);
413 return;
414 }
415 }
416}
417#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
418void APIServer::handle_action_response(uint32_t call_id, bool success, StringRef error_message,
419 const uint8_t *response_data, size_t response_data_len) {
420 for (auto it = this->action_response_callbacks_.begin(); it != this->action_response_callbacks_.end(); ++it) {
421 if (it->call_id == call_id) {
422 auto callback = std::move(it->callback);
423 this->action_response_callbacks_.erase(it);
424 ActionResponse response(success, error_message, response_data, response_data_len);
425 callback(response);
426 return;
427 }
428 }
429}
430#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
431#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES
432#endif // USE_API_HOMEASSISTANT_SERVICES
433
434#ifdef USE_API_HOMEASSISTANT_STATES
435// Helper to add subscription (reduces duplication)
436void APIServer::add_state_subscription_(const char *entity_id, const char *attribute, std::function<void(StringRef)> f,
437 bool once) {
439 .entity_id = entity_id, .attribute = attribute, .callback = std::move(f), .once = once,
440 // entity_id_dynamic_storage and attribute_dynamic_storage remain nullptr (no heap allocation)
441 });
442}
443
444// Helper to add subscription with heap-allocated strings (reduces duplication)
445void APIServer::add_state_subscription_(std::string entity_id, optional<std::string> attribute,
446 std::function<void(StringRef)> f, bool once) {
448 // Allocate heap storage for the strings
449 sub.entity_id_dynamic_storage = std::make_unique<std::string>(std::move(entity_id));
450 sub.entity_id = sub.entity_id_dynamic_storage->c_str();
451
452 if (attribute.has_value()) {
453 sub.attribute_dynamic_storage = std::make_unique<std::string>(std::move(attribute.value()));
454 sub.attribute = sub.attribute_dynamic_storage->c_str();
455 } else {
456 sub.attribute = nullptr;
457 }
458
459 sub.callback = std::move(f);
460 sub.once = once;
461 this->state_subs_.push_back(std::move(sub));
462}
463
464// New const char* overload (for internal components - zero allocation)
465void APIServer::subscribe_home_assistant_state(const char *entity_id, const char *attribute,
466 std::function<void(StringRef)> f) {
467 this->add_state_subscription_(entity_id, attribute, std::move(f), false);
468}
469
470void APIServer::get_home_assistant_state(const char *entity_id, const char *attribute,
471 std::function<void(StringRef)> f) {
472 this->add_state_subscription_(entity_id, attribute, std::move(f), true);
473}
474
475// std::string overload with StringRef callback (zero-allocation callback)
477 std::function<void(StringRef)> f) {
478 this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), false);
479}
480
481void APIServer::get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
482 std::function<void(StringRef)> f) {
483 this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), true);
484}
485
486// Legacy helper: wraps std::string callback and delegates to StringRef version
487void APIServer::add_state_subscription_(std::string entity_id, optional<std::string> attribute,
488 std::function<void(const std::string &)> f, bool once) {
489 // Wrap callback to convert StringRef -> std::string, then delegate
490 this->add_state_subscription_(std::move(entity_id), std::move(attribute),
491 std::function<void(StringRef)>([f = std::move(f)](StringRef state) { f(state.str()); }),
492 once);
493}
494
495// Legacy std::string overload (for custom_api_device.h - converts StringRef to std::string)
497 std::function<void(const std::string &)> f) {
498 this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), false);
499}
500
501void APIServer::get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
502 std::function<void(const std::string &)> f) {
503 this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), true);
504}
505
506const std::vector<APIServer::HomeAssistantStateSubscription> &APIServer::get_state_subs() const {
507 return this->state_subs_;
508}
509#endif
510
511uint16_t APIServer::get_port() const { return this->port_; }
512
513void APIServer::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
514
515#ifdef USE_API_NOISE
516bool APIServer::update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg,
517 const LogString *fail_log_msg, const psk_t &active_psk, bool make_active) {
518 if (!this->noise_pref_.save(&new_psk)) {
519 ESP_LOGW(TAG, "%s", LOG_STR_ARG(fail_log_msg));
520 return false;
521 }
522 // ensure it's written immediately
523 if (!global_preferences->sync()) {
524 ESP_LOGW(TAG, "Failed to sync preferences");
525 return false;
526 }
527 ESP_LOGD(TAG, "%s", LOG_STR_ARG(save_log_msg));
528 if (make_active) {
529 this->set_timeout(100, [this, active_psk]() {
530 ESP_LOGW(TAG, "Disconnecting all clients to reset PSK");
531 this->set_noise_psk(active_psk);
532 for (auto &c : this->clients_) {
534 c->send_message(req, DisconnectRequest::MESSAGE_TYPE);
535 }
536 });
537 }
538 return true;
539}
540
541bool APIServer::save_noise_psk(psk_t psk, bool make_active) {
542#ifdef USE_API_NOISE_PSK_FROM_YAML
543 // When PSK is set from YAML, this function should never be called
544 // but if it is, reject the change
545 ESP_LOGW(TAG, "Key set in YAML");
546 return false;
547#else
548 auto &old_psk = this->noise_ctx_.get_psk();
549 if (std::equal(old_psk.begin(), old_psk.end(), psk.begin())) {
550 ESP_LOGW(TAG, "New PSK matches old");
551 return true;
552 }
553
554 SavedNoisePsk new_saved_psk{psk};
555 return this->update_noise_psk_(new_saved_psk, LOG_STR("Noise PSK saved"), LOG_STR("Failed to save Noise PSK"), psk,
556 make_active);
557#endif
558}
559bool APIServer::clear_noise_psk(bool make_active) {
560#ifdef USE_API_NOISE_PSK_FROM_YAML
561 // When PSK is set from YAML, this function should never be called
562 // but if it is, reject the change
563 ESP_LOGW(TAG, "Key set in YAML");
564 return false;
565#else
566 SavedNoisePsk empty_psk{};
567 psk_t empty{};
568 return this->update_noise_psk_(empty_psk, LOG_STR("Noise PSK cleared"), LOG_STR("Failed to clear Noise PSK"), empty,
569 make_active);
570#endif
571}
572#endif
573
574#ifdef USE_HOMEASSISTANT_TIME
576 for (auto &client : this->clients_) {
577 if (!client->flags_.remove && client->is_authenticated()) {
578 client->send_time_request();
579 return; // Only request from one client to avoid clock conflicts
580 }
581 }
582}
583#endif
584
585bool APIServer::is_connected(bool state_subscription_only) const {
586 if (!state_subscription_only) {
587 return !this->clients_.empty();
588 }
589
590 for (const auto &client : this->clients_) {
591 if (client->flags_.state_subscription) {
592 return true;
593 }
594 }
595 return false;
596}
597
598#ifdef USE_LOGGER
599void APIServer::on_log(uint8_t level, const char *tag, const char *message, size_t message_len) {
600 if (this->shutting_down_) {
601 // Don't try to send logs during shutdown
602 // as it could result in a recursion and
603 // we would be filling a buffer we are trying to clear
604 return;
605 }
606 for (auto &c : this->clients_) {
607 if (!c->flags_.remove && c->get_log_subscription_level() >= level)
608 c->try_send_log_message(level, tag, message, message_len);
609 }
610}
611#endif
612
613#ifdef USE_CAMERA
614void APIServer::on_camera_image(const std::shared_ptr<camera::CameraImage> &image) {
615 for (auto &c : this->clients_) {
616 if (!c->flags_.remove)
617 c->set_camera_state(image);
618 }
619}
620#endif
621
623 this->shutting_down_ = true;
624
625 // Close the listening socket to prevent new connections
626 if (this->socket_) {
627 this->socket_->close();
628 this->socket_ = nullptr;
629 }
630
631 // Change batch delay to 5ms for quick flushing during shutdown
632 this->batch_delay_ = 5;
633
634 // Send disconnect requests to all connected clients
635 for (auto &c : this->clients_) {
637 if (!c->send_message(req, DisconnectRequest::MESSAGE_TYPE)) {
638 // If we can't send the disconnect request directly (tx_buffer full),
639 // schedule it at the front of the batch so it will be sent with priority
640 c->schedule_message_front_(nullptr, DisconnectRequest::MESSAGE_TYPE, DisconnectRequest::ESTIMATED_SIZE);
641 }
642 }
643}
644
646 // If network is disconnected, no point trying to flush buffers
647 if (!network::is_connected()) {
648 return true;
649 }
650 this->loop();
651
652 // Return true only when all clients have been torn down
653 return this->clients_.empty();
654}
655
656#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
657// Timeout for action calls - matches aioesphomeapi client timeout (default 30s)
658// Can be overridden via USE_API_ACTION_CALL_TIMEOUT_MS define for testing
659#ifndef USE_API_ACTION_CALL_TIMEOUT_MS
660#define USE_API_ACTION_CALL_TIMEOUT_MS 30000 // NOLINT
661#endif
662
663uint32_t APIServer::register_active_action_call(uint32_t client_call_id, APIConnection *conn) {
664 uint32_t action_call_id = this->next_action_call_id_++;
665 // Handle wraparound (skip 0 as it means "no call")
666 if (this->next_action_call_id_ == 0) {
667 this->next_action_call_id_ = 1;
668 }
669 this->active_action_calls_.push_back({action_call_id, client_call_id, conn});
670
671 // Schedule automatic cleanup after timeout (client will have given up by then)
672 // Uses numeric ID overload to avoid heap allocation from str_sprintf
673 this->set_timeout(action_call_id, USE_API_ACTION_CALL_TIMEOUT_MS, [this, action_call_id]() {
674 ESP_LOGD(TAG, "Action call %u timed out", action_call_id);
675 this->unregister_active_action_call(action_call_id);
676 });
677
678 return action_call_id;
679}
680
681void APIServer::unregister_active_action_call(uint32_t action_call_id) {
682 // Cancel the timeout for this action call (uses numeric ID overload)
683 this->cancel_timeout(action_call_id);
684
685 // Swap-and-pop is more efficient than remove_if for unordered vectors
686 for (size_t i = 0; i < this->active_action_calls_.size(); i++) {
687 if (this->active_action_calls_[i].action_call_id == action_call_id) {
688 std::swap(this->active_action_calls_[i], this->active_action_calls_.back());
689 this->active_action_calls_.pop_back();
690 return;
691 }
692 }
693}
694
696 // Remove all active action calls for disconnected connection using swap-and-pop
697 for (size_t i = 0; i < this->active_action_calls_.size();) {
698 if (this->active_action_calls_[i].connection == conn) {
699 // Cancel the timeout for this action call (uses numeric ID overload)
700 this->cancel_timeout(this->active_action_calls_[i].action_call_id);
701
702 std::swap(this->active_action_calls_[i], this->active_action_calls_.back());
703 this->active_action_calls_.pop_back();
704 // Don't increment i - need to check the swapped element
705 } else {
706 i++;
707 }
708 }
709}
710
711void APIServer::send_action_response(uint32_t action_call_id, bool success, StringRef error_message) {
712 for (auto &call : this->active_action_calls_) {
713 if (call.action_call_id == action_call_id) {
714 call.connection->send_execute_service_response(call.client_call_id, success, error_message);
715 return;
716 }
717 }
718 ESP_LOGW(TAG, "Cannot send response: no active call found for action_call_id %u", action_call_id);
719}
720#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
721void APIServer::send_action_response(uint32_t action_call_id, bool success, StringRef error_message,
722 const uint8_t *response_data, size_t response_data_len) {
723 for (auto &call : this->active_action_calls_) {
724 if (call.action_call_id == action_call_id) {
725 call.connection->send_execute_service_response(call.client_call_id, success, error_message, response_data,
726 response_data_len);
727 return;
728 }
729 }
730 ESP_LOGW(TAG, "Cannot send response: no active call found for action_call_id %u", action_call_id);
731}
732#endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
733#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
734
735} // namespace esphome::api
736#endif
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
virtual void mark_failed()
Mark this component as failed.
void status_set_warning(const char *message=nullptr)
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.h:429
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") bool cancel_timeout(const std boo cancel_timeout)(const char *name)
Cancel a timeout function.
Definition component.h:451
ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.", "2026.2.0") void set_retry(const std uint32_t uint8_t std::function< RetryResult(uint8_t)> && f
Definition component.h:373
void status_clear_warning()
static void register_controller(Controller *controller)
Register a controller to receive entity state updates.
bool save(const T *src)
Definition preferences.h:21
virtual bool sync()=0
Commit pending writes to flash.
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
bool is_internal() const
Definition entity_base.h:77
StringRef is a reference to a string owned by something else.
Definition string_ref.h:26
void trigger(const Ts &...x)
Inform the parent automation that the event has triggered.
Definition automation.h:279
const psk_t & get_psk() const
void register_action_response_callback(uint32_t call_id, ActionResponseCallback callback)
std::vector< std::unique_ptr< APIConnection > > clients_
Definition api_server.h:270
void send_infrared_rf_receive_event(uint32_t device_id, uint32_t key, const std::vector< int32_t > *timings)
void on_camera_image(const std::shared_ptr< camera::CameraImage > &image) override
void set_port(uint16_t port)
void dump_config() override
void unregister_active_action_calls_for_connection(APIConnection *conn)
void handle_disconnect(APIConnection *conn)
void set_batch_delay(uint16_t batch_delay)
void set_reboot_timeout(uint32_t reboot_timeout)
void add_state_subscription_(const char *entity_id, const char *attribute, std::function< void(StringRef)> f, bool once)
void send_action_response(uint32_t action_call_id, bool success, StringRef error_message)
bool save_noise_psk(psk_t psk, bool make_active=true)
void setup() override
bool teardown() override
APINoiseContext noise_ctx_
Definition api_server.h:308
void unregister_active_action_call(uint32_t action_call_id)
void send_homeassistant_action(const HomeassistantActionRequest &call)
void on_event(event::Event *obj) override
void on_update(update::UpdateEntity *obj) override
std::vector< PendingActionResponse > action_response_callbacks_
Definition api_server.h:294
const std::vector< HomeAssistantStateSubscription > & get_state_subs() const
void subscribe_home_assistant_state(const char *entity_id, const char *attribute, std::function< void(StringRef)> f)
std::vector< uint8_t > shared_write_buffer_
Definition api_server.h:271
void handle_action_response(uint32_t call_id, bool success, StringRef error_message)
std::function< void(const class ActionResponse &)> ActionResponseCallback
Definition api_server.h:141
bool update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg, const LogString *fail_log_msg, const psk_t &active_psk, bool make_active)
bool is_connected(bool state_subscription_only=false) const
ESPPreferenceObject noise_pref_
Definition api_server.h:309
Trigger< std::string, std::string > client_disconnected_trigger_
Definition api_server.h:262
std::vector< HomeAssistantStateSubscription > state_subs_
Definition api_server.h:273
void on_zwave_proxy_request(const esphome::api::ProtoMessage &msg)
bool clear_noise_psk(bool make_active=true)
uint16_t get_port() const
std::vector< ActiveActionCall > active_action_calls_
Definition api_server.h:285
void set_noise_psk(psk_t psk)
Definition api_server.h:77
void get_home_assistant_state(const char *entity_id, const char *attribute, std::function< void(StringRef)> f)
float get_setup_priority() const override
std::unique_ptr< socket::Socket > socket_
Definition api_server.h:257
uint32_t register_active_action_call(uint32_t client_call_id, APIConnection *conn)
void on_shutdown() override
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) override
static constexpr uint8_t MESSAGE_TYPE
Definition api_pb2.h:395
static constexpr uint8_t ESTIMATED_SIZE
Definition api_pb2.h:396
static constexpr uint8_t MESSAGE_TYPE
Definition api_pb2.h:2944
Base class for all binary_sensor-type classes.
virtual void add_listener(CameraListener *listener)=0
Add a listener to receive camera events.
static Camera * instance()
The singleton instance of the camera implementation.
Definition camera.cpp:19
ClimateDevice - This is the base class for all climate integrations.
Definition climate.h:182
Base class for all cover devices.
Definition cover.h:110
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Definition light_state.h:91
Base class for all locks.
Definition lock.h:110
void add_log_listener(LogListener *listener)
Register a log listener to receive log messages.
Definition logger.h:191
Base-class for all numbers.
Definition number.h:29
bool has_value() const
Definition optional.h:92
value_type const & value() const
Definition optional.h:94
Base-class for all selects.
Definition select.h:29
Base-class for all sensors.
Definition sensor.h:43
Base class for all switches.
Definition switch.h:39
Base-class for all text inputs.
Definition text.h:22
Base class for all valve devices.
Definition valve.h:104
const char * message
Definition component.cpp:38
uint16_t addr_len
bool state
Definition fan.h:2
uint32_t socklen_t
Definition headers.h:97
APIServer * global_api_server
API_DISPATCH_UPDATE(binary_sensor::BinarySensor, binary_sensor) API_DISPATCH_UPDATE(cover
std::array< uint8_t, 32 > psk_t
Logger * global_logger
Definition logger.cpp:279
const char * get_use_address()
Get the active network hostname.
Definition util.cpp:88
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
Definition util.cpp:26
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition component.cpp:91
std::unique_ptr< Socket > socket_ip_loop_monitored(int type, int protocol)
Definition socket.cpp:106
socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port)
Set a sockaddr to the any address and specified port for the IP version used by socket_ip().
Definition socket.cpp:153
ESPPreferences * global_preferences
Application App
Global storage of Application pointer - only one Application can exist.
std::unique_ptr< std::string > entity_id_dynamic_storage
Definition api_server.h:203
std::unique_ptr< std::string > attribute_dynamic_storage
Definition api_server.h:204