ESPHome 2026.7.2
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#include "api_noise_context.h"
9#include "api_pb2.h"
10#include "api_pb2_service.h"
15#include "esphome/core/log.h"
17#ifdef USE_PROVISIONING
19#endif
20#ifdef USE_LOGGER
22#endif
23#ifdef USE_CAMERA
25#endif
26
27#include <array>
28#include <memory>
29#include <vector>
30
31namespace esphome::api {
32
33#ifdef USE_API_USER_DEFINED_ACTIONS
34// Forward declaration - full definition in user_services.h
35class UserServiceDescriptor;
36#endif
37
38#ifdef USE_API_NOISE
41} PACKED; // NOLINT
42#endif
43
44class APIServer final : public Component,
45 public Controller
46#ifdef USE_CAMERA
47 ,
49#endif
50{
51 public:
52 APIServer();
53 void setup() override;
54 uint16_t get_port() const;
55 float get_setup_priority() const override;
56 void loop() override;
57 void dump_config() override;
58 void on_shutdown() override;
59 bool teardown() override;
60#ifdef USE_LOGGER
61 void on_log(uint8_t level, const char *tag, const char *message, size_t message_len);
62#endif
63#ifdef USE_CAMERA
64 void on_camera_image(const std::shared_ptr<camera::CameraImage> &image) override;
65#endif
66 void set_port(uint16_t port);
67 void set_reboot_timeout(uint32_t reboot_timeout);
68 void set_batch_delay(uint16_t batch_delay);
69 uint16_t get_batch_delay() const { return batch_delay_; }
70 void set_listen_backlog(uint8_t listen_backlog) { this->listen_backlog_ = listen_backlog; }
71
72 // Get reference to shared buffer for API connections
74
75#ifdef USE_API_NOISE
76 bool save_noise_psk(psk_t psk, bool make_active = true);
77 bool clear_noise_psk(bool make_active = true);
78 void set_noise_psk(psk_t psk) { this->noise_ctx_.set_psk(psk); }
80#endif // USE_API_NOISE
81
83#ifdef USE_BINARY_SENSOR
85#endif
86#ifdef USE_COVER
87 void on_cover_update(cover::Cover *obj) override;
88#endif
89#ifdef USE_FAN
90 void on_fan_update(fan::Fan *obj) override;
91#endif
92#ifdef USE_LIGHT
94#endif
95#ifdef USE_SENSOR
96 void on_sensor_update(sensor::Sensor *obj) override;
97#endif
98#ifdef USE_SWITCH
99 void on_switch_update(switch_::Switch *obj) override;
100#endif
101#ifdef USE_TEXT_SENSOR
103#endif
104#ifdef USE_CLIMATE
106#endif
107#ifdef USE_NUMBER
108 void on_number_update(number::Number *obj) override;
109#endif
110#ifdef USE_DATETIME_DATE
112#endif
113#ifdef USE_DATETIME_TIME
115#endif
116#ifdef USE_DATETIME_DATETIME
118#endif
119#ifdef USE_TEXT
120 void on_text_update(text::Text *obj) override;
121#endif
122#ifdef USE_SELECT
123 void on_select_update(select::Select *obj) override;
124#endif
125#ifdef USE_LOCK
126 void on_lock_update(lock::Lock *obj) override;
127#endif
128#ifdef USE_VALVE
129 void on_valve_update(valve::Valve *obj) override;
130#endif
131#ifdef USE_MEDIA_PLAYER
133#endif
134#ifdef USE_WATER_HEATER
136#endif
137#ifdef USE_API_HOMEASSISTANT_SERVICES
139
140#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
141 // Action response handling
142 using ActionResponseCallback = std::function<void(const class ActionResponse &)>;
144 void handle_action_response(uint32_t call_id, bool success, StringRef error_message);
145#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
146 void handle_action_response(uint32_t call_id, bool success, StringRef error_message, const uint8_t *response_data,
147 size_t response_data_len);
148#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
149#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES
150#endif // USE_API_HOMEASSISTANT_SERVICES
151#ifdef USE_API_USER_DEFINED_ACTIONS
152 void initialize_user_services(std::initializer_list<UserServiceDescriptor *> services) {
153 this->user_services_.assign(services);
154 }
155#ifdef USE_API_CUSTOM_SERVICES
156 // Only compile push_back method when custom_services: true (external components)
157 void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
158#endif
159#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
160 // Action call context management - supports concurrent calls from multiple clients
161 // Returns server-generated action_call_id to avoid collisions when clients use same call_id
163 void unregister_active_action_call(uint32_t action_call_id);
165 // Send response for a specific action call (uses action_call_id, sends client_call_id in response)
166 void send_action_response(uint32_t action_call_id, bool success, StringRef error_message);
167#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
168 void send_action_response(uint32_t action_call_id, bool success, StringRef error_message,
169 const uint8_t *response_data, size_t response_data_len);
170#endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
171#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
172#endif
173#ifdef USE_HOMEASSISTANT_TIME
174 void request_time();
175#endif
176
177#ifdef USE_ALARM_CONTROL_PANEL
179#endif
180#ifdef USE_EVENT
181 void on_event(event::Event *obj) override;
182#endif
183#ifdef USE_UPDATE
184 void on_update(update::UpdateEntity *obj) override;
185#endif
186#ifdef USE_ZWAVE_PROXY
188#endif
189#if defined(USE_IR_RF) || defined(USE_RADIO_FREQUENCY)
190 void send_infrared_rf_receive_event(uint32_t device_id, uint32_t key, const std::vector<int32_t> *timings);
191#endif
192
193 bool is_connected() const { return this->api_connection_count_ != 0; }
195
196 // Range-for view over the populated slice [0, api_connection_count_). Read-only with respect
197 // to ownership; callers get `const unique_ptr&` so they can invoke non-const methods on the
198 // APIConnection but cannot reset/move the slot and break the count invariant.
199 using APIConnectionPtr = std::unique_ptr<APIConnection>;
201 const APIConnectionPtr *begin_;
202 const APIConnectionPtr *end_;
203
204 public:
205 ActiveClientsView(const APIConnectionPtr *b, const APIConnectionPtr *e) : begin_(b), end_(e) {}
206 const APIConnectionPtr *begin() const { return this->begin_; }
207 const APIConnectionPtr *end() const { return this->end_; }
208 };
210 return {this->clients_.data(), this->clients_.data() + this->api_connection_count_};
211 }
212
213#ifdef USE_API_HOMEASSISTANT_STATES
215 const char *entity_id; // Pointer to flash (internal) or heap (external)
216 const char *attribute; // Pointer to flash or nullptr (nullptr means no attribute)
217 std::function<void(StringRef)> callback;
218 bool once;
219
220 // Dynamic storage for external components using std::string API (custom_api_device.h)
221 // These are only allocated when using the std::string overload (nullptr for const char* overload)
222 std::unique_ptr<std::string> entity_id_dynamic_storage;
223 std::unique_ptr<std::string> attribute_dynamic_storage;
224 };
225
226 // New const char* overload (for internal components - zero allocation)
227 void subscribe_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(StringRef)> &&f);
228 void get_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(StringRef)> &&f);
229
230 // std::string overload with StringRef callback (for custom_api_device.h with zero-allocation callback)
231 void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
232 std::function<void(StringRef)> &&f);
233 void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
234 std::function<void(StringRef)> &&f);
235
236 // Legacy std::string overload (for custom_api_device.h - converts StringRef to std::string for callback)
237 void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
238 std::function<void(const std::string &)> &&f);
239 void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
240 std::function<void(const std::string &)> &&f);
241
242 const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
243#endif
244#ifdef USE_API_USER_DEFINED_ACTIONS
245 const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
246#endif
247
248#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
250#endif
251#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
253#endif
254
255 protected:
256 // Accept incoming socket connections. Only called when socket has pending connections.
257 void __attribute__((noinline)) accept_new_connections_();
258 // Remove a disconnected client by index. Swaps with the last populated slot and resets it.
259 void __attribute__((noinline)) remove_client_(uint8_t client_index);
260
261#ifdef USE_PROVISIONING
262 // True while a configured provisioning window is still pending (the device is
263 // unprovisioned). Suppresses the reboot timeout and its warning so the device is
264 // not auto-rebooted while waiting to be provisioned. False when no provisioning
265 // window is configured.
270#else
271 bool provisioning_pending_() const { return false; }
272#endif
273
274#ifdef USE_API_NOISE
275 bool update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg, const LogString *fail_log_msg,
276 bool make_active);
277 // Load saved PSK from preferences and apply it. Returns true on success.
279#endif // USE_API_NOISE
280#ifdef USE_API_HOMEASSISTANT_STATES
281 // Helper methods to reduce code duplication
282 void add_state_subscription_(const char *entity_id, const char *attribute, std::function<void(StringRef)> &&f,
283 bool once);
284 void add_state_subscription_(std::string entity_id, optional<std::string> attribute,
285 std::function<void(StringRef)> &&f, bool once);
286 // Legacy helper: wraps std::string callback and delegates to StringRef version
287 void add_state_subscription_(std::string entity_id, optional<std::string> attribute,
288 std::function<void(const std::string &)> &&f, bool once);
289#endif // USE_API_HOMEASSISTANT_STATES
290 // No explicit close() needed — listen sockets have no active connections on
291 // failure/shutdown. Destructor handles fd cleanup (close or abort per platform).
292 inline void destroy_socket_() {
293 delete this->socket_;
294 this->socket_ = nullptr;
295 }
296 void socket_failed_(const LogString *msg);
297 // Pointers and pointer-like types first (4 bytes each)
299#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
301#endif
302#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
304#endif
305
306 // 4-byte aligned types
309
310 // Slots [0, api_connection_count_) are populated; trailing slots are always nullptr.
311 std::array<APIConnectionPtr, MAX_API_CONNECTIONS> clients_{};
312 // Vectors and strings (12 bytes each on 32-bit)
313 // Shared proto write buffer for all connections.
314 // Not pre-allocated: all send paths call prepare_first_message_buffer() which
315 // reserves the exact needed size. Pre-allocating here would cause heap fragmentation
316 // since the buffer would almost always reallocate on first use.
318#ifdef USE_API_HOMEASSISTANT_STATES
319 std::vector<HomeAssistantStateSubscription> state_subs_;
320#endif
321#ifdef USE_API_USER_DEFINED_ACTIONS
322 std::vector<UserServiceDescriptor *> user_services_;
323#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
324 // Active action calls - supports concurrent calls from multiple clients
325 // Uses server-generated action_call_id to avoid collisions when multiple clients use same call_id
327 uint32_t action_call_id; // Server-generated unique ID (passed to actions)
328 uint32_t client_call_id; // Client's original call_id (used in response)
330 };
331 std::vector<ActiveActionCall> active_action_calls_;
332 uint32_t next_action_call_id_{1}; // Counter for generating unique action_call_ids
333#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
334#endif
335#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
340 std::vector<PendingActionResponse> action_response_callbacks_;
341#endif
342
343 // Group smaller types together
344 uint16_t port_{6053};
345 uint16_t batch_delay_{100};
346 // Connection limits - these defaults will be overridden by config values
347 // from cv.SplitDefault in __init__.py which sets platform-specific defaults.
348 uint8_t listen_backlog_{4};
349 bool shutting_down_ = false;
351#if defined(USE_PROVISIONING) && defined(USE_API_NOISE)
352 // Index assigned by the provisioning manager for reporting this transport's state.
354#endif
355
356#ifdef USE_API_NOISE
359#endif // USE_API_NOISE
360};
361
362extern APIServer *global_api_server; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
363
364template<typename... Ts> class APIConnectedCondition final : public Condition<Ts...> {
365 TEMPLATABLE_VALUE(bool, state_subscription_only)
366 public:
367 bool check(const Ts &...x) override {
368 if (this->state_subscription_only_.value(x...)) {
370 }
372 }
373};
374
375} // namespace esphome::api
376#endif
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:424
Base class for all automation conditions.
Definition automation.h:438
virtual bool check(const Ts &...x)=0
StringRef is a reference to a string owned by something else.
Definition string_ref.h:26
Byte buffer that skips zero-initialization on resize().
Definition api_buffer.h:36
const APIConnectionPtr * end() const
Definition api_server.h:207
ActiveClientsView(const APIConnectionPtr *b, const APIConnectionPtr *e)
Definition api_server.h:205
const APIConnectionPtr * begin() const
Definition api_server.h:206
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len)
bool is_connected_with_state_subscription() const
Trigger< std::string, std::string > * get_client_connected_trigger()
Definition api_server.h:249
std::array< APIConnectionPtr, MAX_API_CONNECTIONS > clients_
Definition api_server.h:311
void on_valve_update(valve::Valve *obj) override
uint16_t get_batch_delay() const
Definition api_server.h:69
std::unique_ptr< APIConnection > APIConnectionPtr
Definition api_server.h:199
void on_switch_update(switch_::Switch *obj) override
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)
APIBuffer & get_shared_buffer_ref()
Definition api_server.h:73
void on_time_update(datetime::TimeEntity *obj) override
void on_cover_update(cover::Cover *obj) override
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:252
void on_camera_image(const std::shared_ptr< camera::CameraImage > &image) override
std::vector< UserServiceDescriptor * > user_services_
Definition api_server.h:322
void on_light_update(light::LightState *obj) override
void socket_failed_(const LogString *msg)
void on_media_player_update(media_player::MediaPlayer *obj) override
const std::vector< UserServiceDescriptor * > & get_user_services() const
Definition api_server.h:245
void initialize_user_services(std::initializer_list< UserServiceDescriptor * > services)
Definition api_server.h:152
void on_water_heater_update(water_heater::WaterHeater *obj) 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)
Trigger< std::string, std::string > client_connected_trigger_
Definition api_server.h:300
void set_listen_backlog(uint8_t listen_backlog)
Definition api_server.h:70
void send_action_response(uint32_t action_call_id, bool success, StringRef error_message)
APINoiseContext & get_noise_ctx()
Definition api_server.h:79
void register_user_service(UserServiceDescriptor *descriptor)
Definition api_server.h:157
bool save_noise_psk(psk_t psk, bool make_active=true)
void on_lock_update(lock::Lock *obj) override
void setup() override
void on_date_update(datetime::DateEntity *obj) override
bool teardown() override
bool is_connected() const
Definition api_server.h:193
APINoiseContext noise_ctx_
Definition api_server.h:357
void unregister_active_action_call(uint32_t action_call_id)
void on_number_update(number::Number *obj) override
void send_homeassistant_action(const HomeassistantActionRequest &call)
socket::ListenSocket * socket_
Definition api_server.h:298
void on_event(event::Event *obj) override
void on_update(update::UpdateEntity *obj) override
std::vector< PendingActionResponse > action_response_callbacks_
Definition api_server.h:340
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 on_climate_update(climate::Climate *obj) override
void handle_action_response(uint32_t call_id, bool success, StringRef error_message)
std::function< void(const class ActionResponse &)> ActionResponseCallback
Definition api_server.h:142
bool provisioning_pending_() const
Definition api_server.h:266
void on_binary_sensor_update(binary_sensor::BinarySensor *obj) override
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:358
void on_fan_update(fan::Fan *obj) override
Trigger< std::string, std::string > client_disconnected_trigger_
Definition api_server.h:303
std::vector< HomeAssistantStateSubscription > state_subs_
Definition api_server.h:319
bool clear_noise_psk(bool make_active=true)
ActiveClientsView active_clients() const
Definition api_server.h:209
void on_select_update(select::Select *obj) override
uint16_t get_port() const
void __attribute__((noinline)) accept_new_connections_()
void on_text_update(text::Text *obj) override
void on_text_sensor_update(text_sensor::TextSensor *obj) override
std::vector< ActiveActionCall > active_action_calls_
Definition api_server.h:331
void set_noise_psk(psk_t psk)
Definition api_server.h:78
void on_datetime_update(datetime::DateTimeEntity *obj) override
APIBuffer shared_write_buffer_
Definition api_server.h:317
void on_sensor_update(sensor::Sensor *obj) override
void __attribute__((noinline)) remove_client_(uint8_t client_index)
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)
void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) override
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: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
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
APIServer * global_api_server
struct esphome::api::SavedNoisePsk PACKED
std::array< uint8_t, 32 > psk_t
ProvisioningManager * global_provisioning_manager
const char * tag
Definition log.h:74
static void uint32_t
std::unique_ptr< std::string > entity_id_dynamic_storage
Definition api_server.h:222
std::unique_ptr< std::string > attribute_dynamic_storage
Definition api_server.h:223
uint16_t x
Definition tt21100.cpp:5