ESPHome 2026.10.1
Loading...
Searching...
No Matches
api_server.h
Go to the documentation of this file.
1#pragma once
2
4#ifdef USE_API
5#include "api_buffer.h"
6// Must precede clients_ so APIConnection is complete for default_delete (libc++).
7#include "api_connection.h"
8#if defined(USE_API_NOISE) || defined(USE_NOISE_SPARE_EPHEMERAL)
9// Only present in the build when the noise component is loaded
11#endif
12#include "api_pb2.h"
13#include "api_pb2_service.h"
19#include "esphome/core/log.h"
21#ifdef USE_PROVISIONING
23#endif
24#ifdef USE_LOGGER
26#endif
27#ifdef USE_CAMERA
29#endif
30
31#include <array>
32#include <memory>
33#include <vector>
34
35namespace esphome::api {
36
37#ifdef USE_API_USER_DEFINED_ACTIONS
38// Forward declaration - full definition in user_services.h
39class UserServiceDescriptor;
40#endif
41
42#ifdef USE_API_NOISE
45} PACKED; // NOLINT
46#endif
47#if defined(USE_API_NOISE) && defined(USE_OTA_ENCRYPTION_PROVISIONED)
51#endif
52
53class APIServer final : public Component
54#ifdef USE_CAMERA
55 ,
57#endif
58{
59 public:
60 APIServer();
61 void setup() override;
62 uint16_t get_port() const { return this->port_; }
63 float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
64 void loop() override;
65 void dump_config() override;
66 void on_shutdown() override;
67 bool teardown() override;
68#ifdef USE_LOGGER
69 void on_log(uint8_t level, const char *tag, const char *message, size_t message_len);
70#endif
71#ifdef USE_CAMERA
72 void on_camera_image(const std::shared_ptr<camera::CameraImage> &image) override;
73#endif
74 void set_port(uint16_t port) { this->port_ = port; }
75 void set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
76 void set_batch_delay(uint16_t batch_delay) { this->batch_delay_ = batch_delay; }
77 uint16_t get_batch_delay() const { return batch_delay_; }
78 void set_listen_backlog(uint8_t listen_backlog) { this->listen_backlog_ = listen_backlog; }
79
80 // Get reference to shared buffer for API connections
82
83#ifdef USE_API_NOISE
84#ifndef USE_API_NOISE_PSK_FROM_YAML
85 // Runtime key changes exist for the provisioning path only (not lambdas);
86 // with a yaml key they compile out
87 bool save_noise_psk(noise::psk_t psk, bool make_active = true);
88 bool clear_noise_psk(bool make_active = true);
89#endif
91 void set_noise_psk(const uint8_t *psk) { this->noise_ctx_.set_psk(psk); }
93#endif // USE_API_NOISE
94#ifdef USE_API_OUTGOING_CONNECTION
95 // Called by APIConnection when a client declares itself a dial-back target in its hello
97#endif
98
100#ifdef USE_BINARY_SENSOR
102#endif
103#ifdef USE_COVER
105#endif
106#ifdef USE_FAN
108#endif
109#ifdef USE_LIGHT
111#endif
112#ifdef USE_SENSOR
114#endif
115#ifdef USE_SWITCH
117#endif
118#ifdef USE_TEXT_SENSOR
120#endif
121#ifdef USE_CLIMATE
123#endif
124#ifdef USE_NUMBER
126#endif
127#ifdef USE_DATETIME_DATE
129#endif
130#ifdef USE_DATETIME_TIME
132#endif
133#ifdef USE_DATETIME_DATETIME
135#endif
136#ifdef USE_TEXT
138#endif
139#ifdef USE_SELECT
141#endif
142#ifdef USE_LOCK
144#endif
145#ifdef USE_VALVE
147#endif
148#ifdef USE_MEDIA_PLAYER
150#endif
151#ifdef USE_WATER_HEATER
153#endif
154#ifdef USE_API_HOMEASSISTANT_SERVICES
156
157#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
158 // Action response handling
159 using ActionResponseCallback = std::function<void(const class ActionResponse &)>;
161 void handle_action_response(uint32_t call_id, bool success, StringRef error_message);
162#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
163 void handle_action_response(uint32_t call_id, bool success, StringRef error_message, const uint8_t *response_data,
164 size_t response_data_len);
165#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
166#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES
167#endif // USE_API_HOMEASSISTANT_SERVICES
168#ifdef USE_API_USER_DEFINED_ACTIONS
169 void initialize_user_services(std::initializer_list<UserServiceDescriptor *> services) {
170 this->user_services_.assign(services);
171 }
172#ifdef USE_API_CUSTOM_SERVICES
173 // Only compile push_back method when custom_services: true (external components)
174 void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
175#endif
176#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
177 // Action call context management - supports concurrent calls from multiple clients
178 // Returns server-generated action_call_id to avoid collisions when clients use same call_id
180 void unregister_active_action_call(uint32_t action_call_id);
182 // Send response for a specific action call (uses action_call_id, sends client_call_id in response)
183 void send_action_response(uint32_t action_call_id, bool success, StringRef error_message);
184#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
185 void send_action_response(uint32_t action_call_id, bool success, StringRef error_message,
186 const uint8_t *response_data, size_t response_data_len);
187#endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
188#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
189#endif
190#ifdef USE_HOMEASSISTANT_TIME
191 void request_time();
192#endif
193
194#ifdef USE_ALARM_CONTROL_PANEL
196#endif
197#ifdef USE_EVENT
199#endif
200#ifdef USE_UPDATE
202#endif
203#ifdef USE_ZWAVE_PROXY
205#endif
206#ifdef USE_SERIAL_PROXY_USB_IDENTITY
209#endif
210#ifdef USE_IR_RF
211 void send_infrared_rf_receive_event(uint32_t device_id, uint32_t key, const std::vector<int32_t> *timings);
212#endif
213
214 bool is_connected() const { return this->api_connection_count_ != 0; }
216
217 // Range-for view over the populated slice [0, api_connection_count_). Read-only with respect
218 // to ownership; callers get `const unique_ptr&` so they can invoke non-const methods on the
219 // APIConnection but cannot reset/move the slot and break the count invariant.
220 using APIConnectionPtr = std::unique_ptr<APIConnection>;
222 const APIConnectionPtr *begin_;
223 const APIConnectionPtr *end_;
224
225 public:
226 ActiveClientsView(const APIConnectionPtr *b, const APIConnectionPtr *e) : begin_(b), end_(e) {}
227 const APIConnectionPtr *begin() const { return this->begin_; }
228 const APIConnectionPtr *end() const { return this->end_; }
229 };
231 return {this->clients_.data(), this->clients_.data() + this->api_connection_count_};
232 }
233
234#ifdef USE_API_HOMEASSISTANT_STATES
236 const char *entity_id; // Pointer to flash (internal) or heap (external)
237 const char *attribute; // Pointer to flash or nullptr (nullptr means no attribute)
238 std::function<void(StringRef)> callback;
239 bool once;
240
241 // Dynamic storage for external components using std::string API (custom_api_device.h)
242 // These are only allocated when using the std::string overload (nullptr for const char* overload)
243 std::unique_ptr<std::string> entity_id_dynamic_storage;
244 std::unique_ptr<std::string> attribute_dynamic_storage;
245 };
246
247 // New const char* overload (for internal components - zero allocation)
248 void subscribe_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(StringRef)> &&f);
249 void get_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(StringRef)> &&f);
250
251 // std::string overload with StringRef callback (for custom_api_device.h with zero-allocation callback)
252 void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
253 std::function<void(StringRef)> &&f);
254 void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
255 std::function<void(StringRef)> &&f);
256
257 // Legacy std::string overload (for custom_api_device.h - converts StringRef to std::string for callback)
258 void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
259 std::function<void(const std::string &)> &&f);
260 void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
261 std::function<void(const std::string &)> &&f);
262
263 const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
264#endif
265#ifdef USE_API_USER_DEFINED_ACTIONS
266 const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
267#endif
268
269#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
271#endif
272#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
274#endif
275
276 protected:
277 // Accept incoming socket connections. Only called when socket has pending connections.
278 void __attribute__((noinline)) accept_new_connections_();
281 APIConnection *add_client_(std::unique_ptr<socket::Socket> sock);
282 bool at_client_limit_() const { return this->api_connection_count_ >= MAX_API_CONNECTIONS; }
283#ifdef USE_API_OUTGOING_CONNECTION
284 // Returns the new connection, or nullptr (socket dropped) when at the limit
285 APIConnection *add_outgoing_client_(std::unique_ptr<socket::Socket> sock);
286 bool has_outgoing_target_client_() const { return this->outgoing_target_count_ != 0; }
288#endif
289 // Remove a disconnected client by index. Swaps with the last populated slot and resets it.
290 void __attribute__((noinline)) remove_client_(uint8_t client_index);
291
292#ifdef USE_PROVISIONING
293 // True while a configured provisioning window is still pending (the device is
294 // unprovisioned). Suppresses the reboot timeout and its warning so the device is
295 // not auto-rebooted while waiting to be provisioned. False when no provisioning
296 // window is configured.
301#else
302 bool provisioning_pending_() const { return false; }
303#endif
304
305#ifdef USE_API_NOISE
306#ifndef USE_API_NOISE_PSK_FROM_YAML
307 bool update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg, const LogString *fail_log_msg,
308 bool make_active);
309 // Load saved PSK from preferences and apply it. Returns true on success.
311#endif // USE_API_NOISE_PSK_FROM_YAML
312#endif // USE_API_NOISE
313#ifdef USE_API_HOMEASSISTANT_STATES
314 // Helper methods to reduce code duplication
315 void add_state_subscription_(const char *entity_id, const char *attribute, std::function<void(StringRef)> &&f,
316 bool once);
317 void add_state_subscription_(std::string entity_id, optional<std::string> attribute,
318 std::function<void(StringRef)> &&f, bool once);
319 // Legacy helper: wraps std::string callback and delegates to StringRef version
320 void add_state_subscription_(std::string entity_id, optional<std::string> attribute,
321 std::function<void(const std::string &)> &&f, bool once);
322#endif // USE_API_HOMEASSISTANT_STATES
323 // No explicit close() needed — listen sockets have no active connections on
324 // failure/shutdown. Destructor handles fd cleanup (close or abort per platform).
325 inline void destroy_socket_() {
326 delete this->socket_;
327 this->socket_ = nullptr;
328 }
331 void socket_failed_(const LogString *msg);
332 // Pointers and pointer-like types first (4 bytes each)
334#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
336#endif
337#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
339#endif
340
341 // 4-byte aligned types
342 uint32_t reboot_timeout_{900000}; // Keep in sync with DEFAULT_REBOOT_TIMEOUT in __init__.py
344
345 // Slots [0, api_connection_count_) are populated; trailing slots are always nullptr.
346 std::array<APIConnectionPtr, MAX_API_CONNECTIONS> clients_{};
347 // Vectors and strings (12 bytes each on 32-bit)
348 // Shared proto write buffer for all connections.
349 // Not pre-allocated: all send paths call prepare_first_message_buffer() which
350 // reserves the exact needed size. Pre-allocating here would cause heap fragmentation
351 // since the buffer would almost always reallocate on first use.
353#ifdef USE_API_HOMEASSISTANT_STATES
354 std::vector<HomeAssistantStateSubscription> state_subs_;
355#endif
356#ifdef USE_API_USER_DEFINED_ACTIONS
357 std::vector<UserServiceDescriptor *> user_services_;
358#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
359 // Active action calls - supports concurrent calls from multiple clients
360 // Uses server-generated action_call_id to avoid collisions when multiple clients use same call_id
362 uint32_t action_call_id; // Server-generated unique ID (passed to actions)
363 uint32_t client_call_id; // Client's original call_id (used in response)
365 };
366 std::vector<ActiveActionCall> active_action_calls_;
367 uint32_t next_action_call_id_{1}; // Counter for generating unique action_call_ids
368#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
369#endif
370#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
375 std::vector<PendingActionResponse> action_response_callbacks_;
376#endif
377
378 // Group smaller types together
379 uint16_t port_{6053}; // Keep in sync with DEFAULT_PORT in __init__.py
380 uint16_t batch_delay_{100}; // Keep in sync with DEFAULT_BATCH_DELAY in __init__.py
381 uint8_t listen_backlog_{4}; // Keep in sync with DEFAULT_LISTEN_BACKLOG in __init__.py
382 bool shutting_down_ = false;
384#ifdef USE_API_OUTGOING_CONNECTION
385 // Connected clients whose hello declared them a dial-back target
387#endif
388#if defined(USE_PROVISIONING) && defined(USE_API_NOISE)
389 // Index assigned by the provisioning manager for reporting this transport's state.
391#endif
392
393#ifdef USE_NOISE_SPARE_EPHEMERAL
395#endif
396#ifdef USE_API_NOISE
398#ifndef USE_API_NOISE_PSK_FROM_YAML
399 SavedNoisePsk saved_psk_{}; // backs noise_ctx_ for a runtime provisioned key
400#endif
402#endif // USE_API_NOISE
403#ifdef USE_API_OUTGOING_CONNECTION
405#endif
406};
407
408extern APIServer *global_api_server; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
409
410template<typename... Ts> class APIConnectedCondition final : public Condition<Ts...> {
411 TEMPLATABLE_VALUE(bool, state_subscription_only)
412 public:
413 bool check(const Ts &...x) override {
414 if (this->state_subscription_only_.value(x...)) {
416 }
418 }
419};
420
421} // namespace esphome::api
422#endif
Base class for all automation conditions.
Definition automation.h:505
virtual bool check(const Ts &...x)=0
StringRef is a reference to a string owned by something else.
Definition string_ref.h:30
Byte buffer that skips zero-initialization on resize().
Definition api_buffer.h:26
const APIConnectionPtr * end() const
Definition api_server.h:228
ActiveClientsView(const APIConnectionPtr *b, const APIConnectionPtr *e)
Definition api_server.h:226
const APIConnectionPtr * begin() const
Definition api_server.h:227
void on_media_player_update(media_player::MediaPlayer *obj)
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len)
bool is_connected_with_state_subscription() const
OutgoingConnectionManager outgoing_conn_
Definition api_server.h:404
Trigger< std::string, std::string > * get_client_connected_trigger()
Definition api_server.h:270
void on_valve_update(valve::Valve *obj)
std::array< APIConnectionPtr, MAX_API_CONNECTIONS > clients_
Definition api_server.h:346
uint16_t get_batch_delay() const
Definition api_server.h:77
std::unique_ptr< APIConnection > APIConnectionPtr
Definition api_server.h:220
void register_action_response_callback(uint32_t call_id, ActionResponseCallback callback)
void on_lock_update(lock::Lock *obj)
void send_infrared_rf_receive_event(uint32_t device_id, uint32_t key, const std::vector< int32_t > *timings)
void on_update(update::UpdateEntity *obj)
APIBuffer & get_shared_buffer_ref()
Definition api_server.h:81
void on_binary_sensor_update(binary_sensor::BinarySensor *obj)
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)
Trigger< std::string, std::string > * get_client_disconnected_trigger()
Definition api_server.h:273
void on_sensor_update(sensor::Sensor *obj)
bool at_client_limit_() const
Definition api_server.h:282
void on_switch_update(switch_::Switch *obj)
void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj)
void on_camera_image(const std::shared_ptr< camera::CameraImage > &image) override
std::vector< UserServiceDescriptor * > user_services_
Definition api_server.h:357
void set_noise_psk(const uint8_t *psk)
psk points at 32 bytes that live in flash for the life of the program
Definition api_server.h:91
void socket_failed_(const LogString *msg)
Log the failure, drop the listen socket, and mark the component failed unless this build can still di...
const std::vector< UserServiceDescriptor * > & get_user_services() const
Definition api_server.h:266
void initialize_user_services(std::initializer_list< UserServiceDescriptor * > services)
Definition api_server.h:169
void set_port(uint16_t port)
Definition api_server.h:74
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)
Definition api_server.h:76
void set_reboot_timeout(uint32_t reboot_timeout)
Definition api_server.h:75
Trigger< std::string, std::string > client_connected_trigger_
Definition api_server.h:335
void set_listen_backlog(uint8_t listen_backlog)
Definition api_server.h:78
void send_action_response(uint32_t action_call_id, bool success, StringRef error_message)
void on_fan_update(fan::Fan *obj)
void on_number_update(number::Number *obj)
void register_user_service(UserServiceDescriptor *descriptor)
Definition api_server.h:174
void setup() override
void on_climate_update(climate::Climate *obj)
bool teardown() override
bool is_connected() const
Definition api_server.h:214
void unregister_active_action_call(uint32_t action_call_id)
void send_homeassistant_action(const HomeassistantActionRequest &call)
socket::ListenSocket * socket_
Definition api_server.h:333
void on_select_update(select::Select *obj)
std::vector< PendingActionResponse > action_response_callbacks_
Definition api_server.h:375
void on_text_sensor_update(text_sensor::TextSensor *obj)
const std::vector< HomeAssistantStateSubscription > & get_state_subs() const
void on_cover_update(cover::Cover *obj)
void send_serial_proxy_identity(const SerialProxyIdentity &msg)
Tell every subscribed client that a serial proxy port's identity changed.
void subscribe_home_assistant_state(const char *entity_id, const char *attribute, std::function< void(StringRef)> &&f)
void on_date_update(datetime::DateEntity *obj)
void handle_action_response(uint32_t call_id, bool success, StringRef error_message)
std::function< void(const class ActionResponse &)> ActionResponseCallback
Definition api_server.h:159
void on_light_update(light::LightState *obj)
void on_event(event::Event *obj)
bool provisioning_pending_() const
Definition api_server.h:297
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:401
SavedNoisePsk saved_psk_
Definition api_server.h:399
Trigger< std::string, std::string > client_disconnected_trigger_
Definition api_server.h:338
std::vector< HomeAssistantStateSubscription > state_subs_
Definition api_server.h:354
bool clear_noise_psk(bool make_active=true)
ActiveClientsView active_clients() const
Definition api_server.h:230
uint16_t get_port() const
Definition api_server.h:62
void on_outgoing_target_client(APIConnection *conn)
void __attribute__((noinline)) accept_new_connections_()
bool has_outgoing_target_client_() const
Definition api_server.h:286
bool save_noise_psk(noise::psk_t psk, bool make_active=true)
void on_water_heater_update(water_heater::WaterHeater *obj)
void on_time_update(datetime::TimeEntity *obj)
APIConnection * add_client_(std::unique_ptr< socket::Socket > sock)
Takes the socket into a new connection and starts it; callers must have checked at_client_limit_() fi...
std::vector< ActiveActionCall > active_action_calls_
Definition api_server.h:366
APIConnection * add_outgoing_client_(std::unique_ptr< socket::Socket > sock)
APIBuffer shared_write_buffer_
Definition api_server.h:352
void __attribute__((noinline)) remove_client_(uint8_t client_index)
float get_setup_priority() const override
Definition api_server.h:63
void on_text_update(text::Text *obj)
uint32_t register_active_action_call(uint32_t client_call_id, APIConnection *conn)
void on_datetime_update(datetime::DateTimeEntity *obj)
noise::NoiseContext noise_ctx_
Definition api_server.h:397
void on_shutdown() override
void on_zwave_proxy_request(const ZWaveProxyRequest &msg)
noise::NoiseContext & get_noise_ctx()
Definition api_server.h:92
Dials out when no dial-back target client is connected.
Base class for all binary_sensor-type classes.
Listener interface for camera events.
Definition camera.h:45
ClimateDevice - This is the base class for all climate integrations.
Definition climate.h:195
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:68
Base class for all locks.
Definition lock.h:109
void set_psk(const uint8_t *psk)
psk points at 32 bytes that outlive the context (PROGMEM or caller owned RAM); nullptr means no key.
Definition noise.h:32
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
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
const LogString * message
Definition component.cpp:35
std::vector< uint8_t > & out
Definition gif.cpp:49
APIServer * global_api_server
struct esphome::api::SavedOutgoingTarget PACKED
bool load_saved_noise_psk(noise::psk_t &out)
One-shot read of the provisioned key for a boot without an api server (safe mode); false when there i...
std::array< uint8_t, 32 > psk_t
Definition noise.h:14
ProvisioningManager * global_provisioning_manager
constexpr float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition component.h:55
static void uint32_t
std::unique_ptr< std::string > entity_id_dynamic_storage
Definition api_server.h:243
std::unique_ptr< std::string > attribute_dynamic_storage
Definition api_server.h:244
uint16_t x
Definition tt21100.cpp:5