13#ifdef USE_API_HOMEASSISTANT_SERVICES
26static const char *
const TAG =
"api";
34 ESP_LOGW(TAG,
"Socket %s: errno %d", LOG_STR_ARG(msg), errno);
47#ifndef USE_API_NOISE_PSK_FROM_YAML
50 ESP_LOGD(TAG,
"Loaded saved Noise PSK");
61 int err = this->
socket_->
setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable,
sizeof(
int));
63 ESP_LOGW(TAG,
"Socket reuseaddr: errno %d", errno);
95 this, [](
void *self, uint8_t level,
const char *
tag,
const char *
message,
size_t message_len) {
118 this->accept_new_connections_();
127 ESP_LOGE(TAG,
"No clients; rebooting");
138 for (
auto &client : this->
clients_) {
139 client->on_fatal_error();
140 client->log_client_(ESPHOME_LOG_LEVEL_WARN, LOG_STR(
"Network down; disconnect"));
145 size_t client_index = 0;
146 while (client_index < this->
clients_.size()) {
147 auto &client = this->
clients_[client_index];
150 if (!client->flags_.remove) {
155 if (client->flags_.remove) {
157 this->remove_client_(client_index);
164void APIServer::remove_client_(
size_t client_index) {
165 auto &client = this->
clients_[client_index];
167#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
170 ESP_LOGV(TAG,
"Remove connection %s", client->get_name());
172#ifdef USE_API_CLIENT_DISCONNECTED_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));
180 client->helper_->close();
183 if (client_index < this->
clients_.size() - 1) {
189 if (this->
clients_.empty() && this->reboot_timeout_ != 0) {
194#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
209 char peername[socket::SOCKADDR_STR_LEN];
210 sock->getpeername_to(peername);
213 if (this->
clients_.size() >= this->max_connections_) {
214 ESP_LOGW(TAG,
"Max connections (%d), rejecting %s", this->
max_connections_, peername);
220 ESP_LOGD(TAG,
"Accept %s", peername);
227 if (this->
clients_.size() == 1 && this->reboot_timeout_ != 0) {
238 " Listen backlog: %u\n"
239 " Max connections: %u",
244 ESP_LOGCONFIG(TAG,
" Supports encryption: YES");
247 ESP_LOGCONFIG(TAG,
" Noise encryption: NO");
254#define API_DISPATCH_UPDATE(entity_type, entity_name) \
255 void APIServer::on_##entity_name##_update(entity_type *obj) { \
256 if (obj->is_internal()) \
258 for (auto &c : this->clients_) { \
259 if (c->flags_.state_subscription) \
260 c->send_##entity_name##_state(obj); \
264#ifdef USE_BINARY_SENSOR
288#ifdef USE_TEXT_SENSOR
300#ifdef USE_DATETIME_DATE
304#ifdef USE_DATETIME_TIME
308#ifdef USE_DATETIME_DATETIME
328#ifdef USE_MEDIA_PLAYER
332#ifdef USE_WATER_HEATER
341 if (c->flags_.state_subscription)
353 if (c->flags_.state_subscription)
354 c->send_update_state(obj);
359#ifdef USE_ZWAVE_PROXY
364 c->send_message(msg);
370 const std::vector<int32_t> *timings) {
376 resp.timings = timings;
379 c->send_infrared_rf_receive_event(resp);
383#ifdef USE_ALARM_CONTROL_PANEL
393#ifdef USE_API_HOMEASSISTANT_SERVICES
395 for (
auto &client : this->
clients_) {
396 client->send_homeassistant_action(
call);
399#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
406 if (it->call_id == call_id) {
407 auto callback = std::move(it->callback);
415#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
417 const uint8_t *response_data,
size_t response_data_len) {
419 if (it->call_id == call_id) {
420 auto callback = std::move(it->callback);
422 ActionResponse response(success, error_message, response_data, response_data_len);
432#ifdef USE_API_HOMEASSISTANT_STATES
435 std::function<
void(
StringRef)> &&f,
bool once) {
437 .entity_id = entity_id, .attribute = attribute, .callback = std::move(
f), .once = once,
444 std::function<
void(
StringRef)> &&f,
bool once) {
450 if (attribute.has_value()) {
486 std::function<
void(
const std::string &)> &&f,
bool once) {
495 std::function<
void(
const std::string &)> &&f) {
500 std::function<
void(
const std::string &)> &&f) {
515 const LogString *fail_log_msg,
bool make_active) {
517 ESP_LOGW(TAG,
"%s", LOG_STR_ARG(fail_log_msg));
522 ESP_LOGW(TAG,
"Failed to sync preferences");
525 ESP_LOGD(TAG,
"%s", LOG_STR_ARG(save_log_msg));
531 ESP_LOGW(TAG,
"Failed to load saved PSK for activation");
534 ESP_LOGW(TAG,
"Disconnecting all clients to reset PSK");
537 c->send_message(req);
553#ifdef USE_API_NOISE_PSK_FROM_YAML
556 ESP_LOGW(TAG,
"Key set in YAML");
560 if (std::equal(old_psk.begin(), old_psk.end(), psk.begin())) {
561 ESP_LOGW(TAG,
"New PSK matches old");
566 return this->
update_noise_psk_(new_saved_psk, LOG_STR(
"Noise PSK saved"), LOG_STR(
"Failed to save Noise PSK"),
571#ifdef USE_API_NOISE_PSK_FROM_YAML
574 ESP_LOGW(TAG,
"Key set in YAML");
578 return this->
update_noise_psk_(empty_psk, LOG_STR(
"Noise PSK cleared"), LOG_STR(
"Failed to clear Noise PSK"),
584#ifdef USE_HOMEASSISTANT_TIME
586 for (
auto &client : this->
clients_) {
587 if (!client->flags_.remove && client->is_authenticated()) {
588 client->send_time_request();
596 for (
const auto &client : this->
clients_) {
597 if (client->flags_.state_subscription) {
613 if (!c->flags_.remove && c->get_log_subscription_level() >= level)
614 c->try_send_log_message(level,
tag,
message, message_len);
622 if (!c->flags_.remove)
623 c->set_camera_state(image);
640 if (!c->send_message(req)) {
659#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
662#ifndef USE_API_ACTION_CALL_TIMEOUT_MS
663#define USE_API_ACTION_CALL_TIMEOUT_MS 30000
676 this->
set_timeout(action_call_id, USE_API_ACTION_CALL_TIMEOUT_MS, [
this, action_call_id]() {
677 ESP_LOGD(TAG,
"Action call %u timed out", action_call_id);
681 return action_call_id;
716 if (
call.action_call_id == action_call_id) {
717 call.connection->send_execute_service_response(
call.client_call_id, success, error_message);
721 ESP_LOGW(TAG,
"Cannot send response: no active call found for action_call_id %u", action_call_id);
723#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
725 const uint8_t *response_data,
size_t response_data_len) {
727 if (
call.action_call_id == action_call_id) {
728 call.connection->send_execute_service_response(
call.client_call_id, success, error_message, response_data,
733 ESP_LOGW(TAG,
"Cannot send response: no active call found for action_call_id %u", action_call_id);
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.
void status_set_warning()
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.
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.
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
void status_clear_warning()
static void register_controller(Controller *controller)
Register a controller to receive entity state updates.
StringRef is a reference to a string owned by something else.
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Inform the parent automation that the event has triggered.
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
void register_action_response_callback(uint32_t call_id, ActionResponseCallback callback)
std::vector< std::unique_ptr< APIConnection > > clients_
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)
bool load_and_apply_noise_psk_()
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)
APINoiseContext noise_ctx_
void unregister_active_action_call(uint32_t action_call_id)
void send_homeassistant_action(const HomeassistantActionRequest &call)
socket::ListenSocket * socket_
void on_event(event::Event *obj) override
void on_update(update::UpdateEntity *obj) override
uint32_t next_action_call_id_
std::vector< PendingActionResponse > action_response_callbacks_
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
bool update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg, const LogString *fail_log_msg, bool make_active)
ESPPreferenceObject noise_pref_
Trigger< std::string, std::string > client_disconnected_trigger_
std::vector< HomeAssistantStateSubscription > state_subs_
bool clear_noise_psk(bool make_active=true)
uint16_t get_port() const
std::vector< ActiveActionCall > active_action_calls_
void set_noise_psk(psk_t psk)
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
static constexpr uint8_t ESTIMATED_SIZE
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.
ClimateDevice - This is the base class for all climate integrations.
Base class for all cover devices.
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Base class for all locks.
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.
Base-class for all numbers.
Base-class for all selects.
Base-class for all sensors.
int setblocking(bool blocking)
bool ready() const
Check if the socket has buffered data ready to read.
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.
Base-class for all text inputs.
Base class for all valve devices.
struct @65::@66 __attribute__
Wake the main loop task from an ISR. ISR-safe.
APIServer * global_api_server
API_DISPATCH_UPDATE(binary_sensor::BinarySensor, binary_sensor) API_DISPATCH_UPDATE(cover
std::array< uint8_t, 32 > psk_t
ESPHOME_ALWAYS_INLINE const char * get_use_address()
Get the active network hostname.
ESPHOME_ALWAYS_INLINE bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
constexpr float AFTER_WIFI
For components that should be initialized after WiFi is connected.
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().
std::unique_ptr< ListenSocket > socket_ip_loop_monitored(int type, int protocol)
ESPPreferences * global_preferences
Application App
Global storage of Application pointer - only one Application can exist.
ESPPreferenceObject make_preference(size_t, uint32_t, bool)
bool sync()
Commit pending writes to flash.
std::unique_ptr< std::string > entity_id_dynamic_storage
std::function< void(StringRef)> callback
std::unique_ptr< std::string > attribute_dynamic_storage