diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index cdeabb5cac..ced0f489be 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -289,16 +289,26 @@ uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint8_t mess return 0; // Doesn't fit } - // Allocate buffer space - pass payload size, allocation functions add header/footer space - ProtoWriteBuffer buffer = is_single ? conn->allocate_single_message_buffer(calculated_size) - : conn->allocate_batch_message_buffer(calculated_size); - // Get buffer size after allocation (which includes header padding) std::vector &shared_buf = conn->parent_->get_shared_buffer_ref(); - size_t size_before_encode = shared_buf.size(); + + if (is_single || conn->flags_.batch_first_message) { + // Single message or first batch message + conn->prepare_first_message_buffer(shared_buf, header_padding, total_calculated_size); + if (conn->flags_.batch_first_message) { + conn->flags_.batch_first_message = false; + } + } else { + // Batch message second or later + // Add padding for previous message footer + this message header + size_t current_size = shared_buf.size(); + shared_buf.reserve(current_size + total_calculated_size); + shared_buf.resize(current_size + footer_size + header_padding); + } // Encode directly into buffer - msg.encode(buffer); + size_t size_before_encode = shared_buf.size(); + msg.encode({&shared_buf}); // Calculate actual encoded size (not including header that was already added) size_t actual_payload_size = shared_buf.size() - size_before_encode; @@ -1620,14 +1630,6 @@ bool APIConnection::schedule_batch_() { return true; } -ProtoWriteBuffer APIConnection::allocate_single_message_buffer(uint16_t size) { return this->create_buffer(size); } - -ProtoWriteBuffer APIConnection::allocate_batch_message_buffer(uint16_t size) { - ProtoWriteBuffer result = this->prepare_message_buffer(size, this->flags_.batch_first_message); - this->flags_.batch_first_message = false; - return result; -} - void APIConnection::process_batch_() { // Ensure PacketInfo remains trivially destructible for our placement new approach static_assert(std::is_trivially_destructible::value, @@ -1735,7 +1737,7 @@ void APIConnection::process_batch_() { } remaining_size -= payload_size; // Calculate where the next message's header padding will start - // Current buffer size + footer space (that prepare_message_buffer will add for this message) + // Current buffer size + footer space for this message current_offset = shared_buf.size() + footer_size; } diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index f0f308c248..076dccfad7 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -252,44 +252,21 @@ class APIConnection : public APIServerConnection { // Get header padding size - used for both reserve and insert uint8_t header_padding = this->helper_->frame_header_padding(); - // Get shared buffer from parent server std::vector &shared_buf = this->parent_->get_shared_buffer_ref(); + this->prepare_first_message_buffer(shared_buf, header_padding, + reserve_size + header_padding + this->helper_->frame_footer_size()); + return {&shared_buf}; + } + + void prepare_first_message_buffer(std::vector &shared_buf, size_t header_padding, size_t total_size) { shared_buf.clear(); // Reserve space for header padding + message + footer // - Header padding: space for protocol headers (7 bytes for Noise, 6 for Plaintext) // - Footer: space for MAC (16 bytes for Noise, 0 for Plaintext) - shared_buf.reserve(reserve_size + header_padding + this->helper_->frame_footer_size()); + shared_buf.reserve(total_size); // Resize to add header padding so message encoding starts at the correct position shared_buf.resize(header_padding); - return {&shared_buf}; - } - - // Prepare buffer for next message in batch - ProtoWriteBuffer prepare_message_buffer(uint16_t message_size, bool is_first_message) { - // Get reference to shared buffer (it maintains state between batch messages) - std::vector &shared_buf = this->parent_->get_shared_buffer_ref(); - - if (is_first_message) { - shared_buf.clear(); - } - - size_t current_size = shared_buf.size(); - - // Calculate padding to add: - // - First message: just header padding - // - Subsequent messages: footer for previous message + header padding for this message - size_t padding_to_add = is_first_message - ? this->helper_->frame_header_padding() - : this->helper_->frame_header_padding() + this->helper_->frame_footer_size(); - - // Reserve space for padding + message - shared_buf.reserve(current_size + padding_to_add + message_size); - - // Resize to add the padding bytes - shared_buf.resize(current_size + padding_to_add); - - return {&shared_buf}; } bool try_to_clear_buffer(bool log_out_of_space); @@ -297,10 +274,6 @@ class APIConnection : public APIServerConnection { std::string get_client_combined_info() const { return this->client_info_.get_combined_info(); } - // Buffer allocator methods for batch processing - ProtoWriteBuffer allocate_single_message_buffer(uint16_t size); - ProtoWriteBuffer allocate_batch_message_buffer(uint16_t size); - protected: // Helper function to handle authentication completion void complete_authentication_();