diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 27344a53ec..b624cace2c 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1820,10 +1820,17 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) { return false; } bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) { - if (!this->try_to_clear_buffer(message_type != SubscribeLogsResponse::MESSAGE_TYPE)) { // SubscribeLogsResponse + const bool is_log_message = (message_type == SubscribeLogsResponse::MESSAGE_TYPE); + + if (!this->try_to_clear_buffer(!is_log_message)) { return false; } + // Toggle NODELAY based on message type: + // - Log messages: Enable Nagle (NODELAY=false) so they coalesce into fewer packets + // - All other messages: Disable Nagle (NODELAY=true) for immediate delivery + this->helper_->set_nodelay(!is_log_message); + APIError err = this->helper_->write_protobuf_packet(message_type, buffer); if (err == APIError::WOULD_BLOCK) return false; diff --git a/esphome/components/api/api_frame_helper.h b/esphome/components/api/api_frame_helper.h index 383e763e6d..6fdda64c3e 100644 --- a/esphome/components/api/api_frame_helper.h +++ b/esphome/components/api/api_frame_helper.h @@ -111,6 +111,19 @@ class APIFrameHelper { } return APIError::OK; } + /// Set TCP_NODELAY option. Only calls setsockopt when state changes. + /// @param enable true to enable NODELAY (disable Nagle), false to enable Nagle + /// @return true if successful or already in desired state + bool set_nodelay(bool enable) { + if (this->nodelay_enabled_ == enable) + return true; + int val = enable ? 1 : 0; + int err = this->socket_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int)); + if (err == 0) { + this->nodelay_enabled_ = enable; + } + return err == 0; + } virtual APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) = 0; // Write multiple protobuf messages in a single operation // messages contains (message_type, offset, length) for each message in the buffer @@ -198,7 +211,7 @@ class APIFrameHelper { uint8_t tx_buf_head_{0}; uint8_t tx_buf_tail_{0}; uint8_t tx_buf_count_{0}; - // 8 bytes total, 0 bytes padding + bool nodelay_enabled_{true}; // Tracks current TCP_NODELAY state // Common initialization for both plaintext and noise protocols APIError init_common_();