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