13#ifdef USE_API_HOMEASSISTANT_SERVICES
32static constexpr uint32_t NOISE_PSK_PREF_HASH = 88491486UL;
35#if defined(USE_API_NOISE) && defined(USE_OTA_ENCRYPTION_PROVISIONED)
38#ifdef USE_PREFERENCE_KEY_LOOKUP
57 ESP_LOGW(TAG,
"Socket %s: errno %d", LOG_STR_ARG(msg), errno);
59#ifdef USE_API_OUTGOING_CONNECTION
68#if defined(USE_API_HOMEASSISTANT_STATES) && defined(HOMEASSISTANT_STATE_SUBSCRIPTION_COUNT)
69 this->
state_subs_.reserve(HOMEASSISTANT_STATE_SUBSCRIPTION_COUNT);
75#ifndef USE_API_NOISE_PSK_FROM_YAML
78 ESP_LOGD(TAG,
"Loaded saved Noise PSK");
86 this, [](
void *self, uint8_t level,
const char *tag,
const char *
message,
size_t message_len) {
100#if defined(USE_PROVISIONING) && defined(USE_API_NOISE)
116 if (!c->send_message(req)) {
117 API_LOG_MSG_DROPPED(TAG,
"Disconnect request");
128#ifdef USE_API_OUTGOING_CONNECTION
135 if (this->
socket_ ==
nullptr) {
140 int err = this->
socket_->
setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable,
sizeof(
int));
142 ESP_LOGW(TAG,
"Socket reuseaddr: errno %d", errno);
174 this->accept_new_connections_();
178#ifdef USE_NOISE_SPARE_EPHEMERAL
184#ifdef USE_API_OUTGOING_CONNECTION
198 ESP_LOGE(TAG,
"No clients; rebooting");
209 client->on_fatal_error();
210 client->log_client_(ESPHOME_LOG_LEVEL_WARN, LOG_STR(
"Network down; disconnect"));
215 uint8_t client_index = 0;
217 auto &client = this->
clients_[client_index];
220 if (!client->flags_.remove) {
225 if (client->flags_.remove) {
227 this->remove_client_(client_index);
234#ifdef USE_NOISE_SPARE_EPHEMERAL
239 if (client->is_still_connecting(now)) {
249void APIServer::remove_client_(uint8_t client_index) {
250 auto &client = this->
clients_[client_index];
252#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
255 ESP_LOGV(TAG,
"Remove connection %s", client->get_name());
257#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
259 char peername_buf[socket::SOCKADDR_STR_LEN];
260 std::string client_name(client->get_name());
261 std::string client_peername(client->get_peername_to(peername_buf));
265 const bool was_authenticated = client->is_authenticated();
266#ifdef USE_API_OUTGOING_CONNECTION
267 if (client->flags_.outgoing_connection_target) {
274 client->helper_->close();
279 if (client_index < last_index) {
295 if (was_authenticated) {
302#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
317 char peername[socket::SOCKADDR_STR_LEN];
318 sock->getpeername_to(peername);
322 ESP_LOGW(TAG,
"Max connections (%d), rejecting %s", MAX_API_CONNECTIONS, peername);
328 ESP_LOGD(TAG,
"Accept %s", peername);
348#ifdef USE_API_OUTGOING_CONNECTION
355 ESP_LOGW(TAG,
"Dropping outgoing connection (%s)",
356 at_limit ? LOG_STR_LITERAL(
"max connections") : LOG_STR_LITERAL(
"no key"));
361 conn->mark_outgoing();
372 char addr_buf[network::USE_ADDRESS_BUFFER_SIZE];
376 " Listen backlog: %u\n"
377 " Max connections: %u",
382 ESP_LOGCONFIG(TAG,
" Supports encryption: YES");
385 ESP_LOGCONFIG(TAG,
" Noise encryption: NO");
387#ifdef USE_API_OUTGOING_CONNECTION
395#define API_DISPATCH_UPDATE(entity_type, entity_name) \
396 void APIServer::on_##entity_name##_update(entity_type *obj) { \
397 if (obj->is_internal()) \
399 for (auto &c : this->active_clients()) { \
400 if (c->flags_.state_subscription) \
401 c->send_##entity_name##_state(obj); \
405#ifdef USE_BINARY_SENSOR
429#ifdef USE_TEXT_SENSOR
441#ifdef USE_DATETIME_DATE
445#ifdef USE_DATETIME_TIME
449#ifdef USE_DATETIME_DATETIME
469#ifdef USE_MEDIA_PLAYER
473#ifdef USE_WATER_HEATER
482 if (c->flags_.state_subscription)
494 if (c->flags_.state_subscription)
495 c->send_update_state(obj);
500#ifdef USE_ZWAVE_PROXY
505 if (!c->send_message(msg)) {
506 API_LOG_MSG_DROPPED(TAG,
"Home ID notification");
512#ifdef USE_SERIAL_PROXY_USB_IDENTITY
515 if (c->flags_.serial_proxy_identity_subscription)
516 c->send_serial_proxy_identity(msg);
523 const std::vector<int32_t> *timings) {
529 resp.timings = timings;
532 c->send_infrared_rf_receive_event(resp);
537#ifdef USE_ALARM_CONTROL_PANEL
541#ifdef USE_API_HOMEASSISTANT_SERVICES
543 bool has_subscriber =
false;
545 has_subscriber |= client->send_homeassistant_action(
call);
547 if (!has_subscriber) {
551 ESP_LOGW(TAG,
"Home Assistant %s '%.*s' dropped; %s",
552 call.is_event ? LOG_STR_LITERAL(
"event") : LOG_STR_LITERAL(
"action"),
553 static_cast<int>(
call.service.size()),
call.service.empty() ?
"" :
call.service.progmem_ptr(),
554 this->is_connected() ? LOG_STR_LITERAL(
"client has not subscribed to actions (yet)")
555 : LOG_STR_LITERAL(
"no client connected"));
558#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
565 if (it->call_id == call_id) {
566 auto callback = std::move(it->callback);
574#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
576 const uint8_t *response_data,
size_t response_data_len) {
578 if (it->call_id == call_id) {
579 auto callback = std::move(it->callback);
581 ActionResponse response(success, error_message, response_data, response_data_len);
591#ifdef USE_API_HOMEASSISTANT_STATES
594 std::function<
void(
StringRef)> &&f,
bool once) {
596 .entity_id = entity_id,
597 .attribute = attribute,
598 .callback = std::move(f),
606 std::function<
void(
StringRef)> &&f,
bool once) {
612 if (attribute.has_value()) {
648 std::function<
void(
const std::string &)> &&f,
bool once) {
657 std::function<
void(
const std::string &)> &&f) {
662 std::function<
void(
const std::string &)> &&f) {
672#ifndef USE_API_NOISE_PSK_FROM_YAML
674 const LogString *fail_log_msg,
bool make_active) {
676 ESP_LOGW(TAG,
"%s", LOG_STR_ARG(fail_log_msg));
681 ESP_LOGW(TAG,
"Failed to sync preferences");
684 ESP_LOGD(TAG,
"%s", LOG_STR_ARG(save_log_msg));
690 ESP_LOGW(TAG,
"Failed to load saved PSK for activation");
693 ESP_LOGW(TAG,
"Disconnecting all clients to reset PSK");
696 if (!c->send_message(req)) {
697 API_LOG_MSG_DROPPED(TAG,
"Disconnect request");
700 c->flags_.next_close =
true;
721 ESP_LOGW(TAG,
"New PSK matches old");
726 bool result = this->
update_noise_psk_(new_saved_psk, LOG_STR(
"Noise PSK saved"), LOG_STR(
"Failed to save Noise PSK"),
728#ifdef USE_PROVISIONING
739 bool result = this->
update_noise_psk_(empty_psk, LOG_STR(
"Noise PSK cleared"), LOG_STR(
"Failed to clear Noise PSK"),
741#ifdef USE_PROVISIONING
753#ifdef USE_HOMEASSISTANT_TIME
756 if (!client->flags_.remove && client->is_authenticated()) {
757 client->send_time_request();
766 if (this->
clients_[i]->flags_.state_subscription) {
782 if (!c->flags_.remove && c->get_log_subscription_level() >= level)
783 c->try_send_log_message(level, tag,
message, message_len);
791 if (!c->flags_.remove)
792 c->set_camera_state(image);
802#ifdef USE_API_OUTGOING_CONNECTION
812 if (!c->send_message(req)) {
831#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
834#ifndef USE_API_ACTION_CALL_TIMEOUT_MS
835#define USE_API_ACTION_CALL_TIMEOUT_MS 30000
848 this->
set_timeout(action_call_id, USE_API_ACTION_CALL_TIMEOUT_MS, [
this, action_call_id]() {
849 ESP_LOGD(TAG,
"Action call %" PRIu32
" timed out", action_call_id);
853 return action_call_id;
888 if (
call.action_call_id == action_call_id) {
889 call.connection->send_execute_service_response(
call.client_call_id, success, error_message);
893 ESP_LOGW(TAG,
"Cannot send response: no active call found for action_call_id %" PRIu32, action_call_id);
895#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
897 const uint8_t *response_data,
size_t response_data_len) {
899 if (
call.action_call_id == action_call_id) {
900 call.connection->send_execute_service_response(
call.client_call_id, success, error_message, response_data,
905 ESP_LOGW(TAG,
"Cannot send response: no active call found for action_call_id %" PRIu32, 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()
bool cancel_timeout(const char *name)
Cancel a timeout function.
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
void status_clear_warning()
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.
Leaves a stretch of the current loop pass out of the blocking warning.
void refill_spare_ephemeral_()
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_
std::array< APIConnectionPtr, MAX_API_CONNECTIONS > clients_
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 on_update(update::UpdateEntity *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)
bool at_client_limit_() const
void on_camera_image(const std::shared_ptr< camera::CameraImage > &image) override
void socket_failed_(const LogString *msg)
Log the failure, drop the listen socket, and mark the component failed unless this build can still di...
bool load_and_apply_noise_psk_()
void dump_config() override
void unregister_active_action_calls_for_connection(APIConnection *conn)
void handle_disconnect(APIConnection *conn)
void send_action_response(uint32_t action_call_id, bool success, StringRef error_message)
uint8_t api_connection_count_
void unregister_active_action_call(uint32_t action_call_id)
void send_homeassistant_action(const HomeassistantActionRequest &call)
socket::ListenSocket * socket_
uint32_t next_action_call_id_
std::vector< PendingActionResponse > action_response_callbacks_
const std::vector< HomeAssistantStateSubscription > & get_state_subs() const
void send_serial_proxy_identity(const SerialProxyIdentity &msg)
Tell every subscribed client that a serial proxy port's identity changed.
uint8_t provisioning_source_
uint8_t outgoing_target_count_
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
void on_event(event::Event *obj)
bool provisioning_pending_() const
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)
ActiveClientsView active_clients() const
void on_outgoing_target_client(APIConnection *conn)
bool save_noise_psk(noise::psk_t psk, bool make_active=true)
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_
APIConnection * add_outgoing_client_(std::unique_ptr< socket::Socket > sock)
uint32_t register_active_action_call(uint32_t client_call_id, APIConnection *conn)
noise::NoiseContext noise_ctx_
void on_shutdown() override
void on_zwave_proxy_request(const ZWaveProxyRequest &msg)
static constexpr uint16_t MESSAGE_TYPE
static constexpr uint8_t ESTIMATED_SIZE
enums::DisconnectReason reason
void on_client_removed(APIConnection *conn, bool was_authenticated)
Clears the dialed-connection gate; dying unauthenticated escalates the backoff.
void loop(APIServer *server)
void on_target_client(APIConnection *conn)
A key-verified client declared itself a dial-back target; last one wins.
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.
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.
static bool is_all_zeros(const psk_t &psk)
Base-class for all numbers.
void add_on_closed_callback(F &&callback)
uint8_t register_source()
void set_source_provisioned(uint8_t source, bool provisioned)
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 @66::@67 __attribute__
Wake the main loop task from an ISR. ISR-safe.
const LogString * message
std::vector< uint8_t > & out
@ DISCONNECT_REASON_PROVISIONING_CLOSED
APIServer * global_api_server
ESPHOME_LOG_TAG(TAG, "api.connection")
API_DISPATCH_UPDATE(binary_sensor::BinarySensor, binary_sensor) API_DISPATCH_UPDATE(cover
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...
ESPHOME_ALWAYS_INLINE bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
const char * get_use_address_to(std::span< char, USE_ADDRESS_BUFFER_SIZE > buf)
Get the active network address for logging.
std::array< uint8_t, 32 > psk_t
bool has_spare_ephemeral()
void prepare_spare_ephemeral()
Fill the slot; blocks for the base point multiply.
ProvisioningManager * global_provisioning_manager
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 load_from_key(uint32_t, uint8_t *, size_t)
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