mirror of
https://github.com/esphome/esphome.git
synced 2025-08-02 08:27:47 +00:00
[api] Reduce flash usage through targeted optimizations (#9979)
This commit is contained in:
parent
853dca6c5c
commit
1d0a38446f
@ -112,8 +112,7 @@ void APIConnection::start() {
|
|||||||
APIError err = this->helper_->init();
|
APIError err = this->helper_->init();
|
||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Helper init failed %s errno=%d", this->get_client_combined_info().c_str(), api_error_to_str(err),
|
this->log_warning_("Helper init failed", err);
|
||||||
errno);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->client_info_.peername = helper_->getpeername();
|
this->client_info_.peername = helper_->getpeername();
|
||||||
@ -144,8 +143,7 @@ void APIConnection::loop() {
|
|||||||
APIError err = this->helper_->loop();
|
APIError err = this->helper_->loop();
|
||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Socket operation failed %s errno=%d", this->get_client_combined_info().c_str(),
|
this->log_socket_operation_failed_(err);
|
||||||
api_error_to_str(err), errno);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,8 +159,7 @@ void APIConnection::loop() {
|
|||||||
break;
|
break;
|
||||||
} else if (err != APIError::OK) {
|
} else if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Reading failed %s errno=%d", this->get_client_combined_info().c_str(), api_error_to_str(err),
|
this->log_warning_("Reading failed", err);
|
||||||
errno);
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
this->last_traffic_ = now;
|
this->last_traffic_ = now;
|
||||||
@ -1540,8 +1537,7 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) {
|
|||||||
APIError err = this->helper_->loop();
|
APIError err = this->helper_->loop();
|
||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Socket operation failed %s errno=%d", this->get_client_combined_info().c_str(),
|
this->log_socket_operation_failed_(err);
|
||||||
api_error_to_str(err), errno);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this->helper_->can_write_without_blocking())
|
if (this->helper_->can_write_without_blocking())
|
||||||
@ -1561,8 +1557,7 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) {
|
|||||||
return false;
|
return false;
|
||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Packet write failed %s errno=%d", this->get_client_combined_info().c_str(),
|
this->log_warning_("Packet write failed", err);
|
||||||
api_error_to_str(err), errno);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Do not set last_traffic_ on send
|
// Do not set last_traffic_ on send
|
||||||
@ -1647,6 +1642,8 @@ void APIConnection::process_batch_() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get shared buffer reference once to avoid multiple calls
|
||||||
|
auto &shared_buf = this->parent_->get_shared_buffer_ref();
|
||||||
size_t num_items = this->deferred_batch_.size();
|
size_t num_items = this->deferred_batch_.size();
|
||||||
|
|
||||||
// Fast path for single message - allocate exact size needed
|
// Fast path for single message - allocate exact size needed
|
||||||
@ -1657,8 +1654,7 @@ void APIConnection::process_batch_() {
|
|||||||
uint16_t payload_size =
|
uint16_t payload_size =
|
||||||
item.creator(item.entity, this, std::numeric_limits<uint16_t>::max(), true, item.message_type);
|
item.creator(item.entity, this, std::numeric_limits<uint16_t>::max(), true, item.message_type);
|
||||||
|
|
||||||
if (payload_size > 0 &&
|
if (payload_size > 0 && this->send_buffer(ProtoWriteBuffer{&shared_buf}, item.message_type)) {
|
||||||
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, item.message_type)) {
|
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
// Log messages after send attempt for VV debugging
|
// Log messages after send attempt for VV debugging
|
||||||
// It's safe to use the buffer for logging at this point regardless of send result
|
// It's safe to use the buffer for logging at this point regardless of send result
|
||||||
@ -1685,20 +1681,18 @@ void APIConnection::process_batch_() {
|
|||||||
const uint8_t footer_size = this->helper_->frame_footer_size();
|
const uint8_t footer_size = this->helper_->frame_footer_size();
|
||||||
|
|
||||||
// Initialize buffer and tracking variables
|
// Initialize buffer and tracking variables
|
||||||
this->parent_->get_shared_buffer_ref().clear();
|
shared_buf.clear();
|
||||||
|
|
||||||
// Pre-calculate exact buffer size needed based on message types
|
// Pre-calculate exact buffer size needed based on message types
|
||||||
uint32_t total_estimated_size = 0;
|
uint32_t total_estimated_size = num_items * (header_padding + footer_size);
|
||||||
for (size_t i = 0; i < this->deferred_batch_.size(); i++) {
|
for (size_t i = 0; i < this->deferred_batch_.size(); i++) {
|
||||||
const auto &item = this->deferred_batch_[i];
|
const auto &item = this->deferred_batch_[i];
|
||||||
total_estimated_size += item.estimated_size;
|
total_estimated_size += item.estimated_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate total overhead for all messages
|
// Calculate total overhead for all messages
|
||||||
uint32_t total_overhead = (header_padding + footer_size) * num_items;
|
|
||||||
|
|
||||||
// Reserve based on estimated size (much more accurate than 24-byte worst-case)
|
// Reserve based on estimated size (much more accurate than 24-byte worst-case)
|
||||||
this->parent_->get_shared_buffer_ref().reserve(total_estimated_size + total_overhead);
|
shared_buf.reserve(total_estimated_size);
|
||||||
this->flags_.batch_first_message = true;
|
this->flags_.batch_first_message = true;
|
||||||
|
|
||||||
size_t items_processed = 0;
|
size_t items_processed = 0;
|
||||||
@ -1740,7 +1734,7 @@ void APIConnection::process_batch_() {
|
|||||||
remaining_size -= payload_size;
|
remaining_size -= payload_size;
|
||||||
// Calculate where the next message's header padding will start
|
// 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 (that prepare_message_buffer will add for this message)
|
||||||
current_offset = this->parent_->get_shared_buffer_ref().size() + footer_size;
|
current_offset = shared_buf.size() + footer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (items_processed == 0) {
|
if (items_processed == 0) {
|
||||||
@ -1750,17 +1744,15 @@ void APIConnection::process_batch_() {
|
|||||||
|
|
||||||
// Add footer space for the last message (for Noise protocol MAC)
|
// Add footer space for the last message (for Noise protocol MAC)
|
||||||
if (footer_size > 0) {
|
if (footer_size > 0) {
|
||||||
auto &shared_buf = this->parent_->get_shared_buffer_ref();
|
|
||||||
shared_buf.resize(shared_buf.size() + footer_size);
|
shared_buf.resize(shared_buf.size() + footer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send all collected packets
|
// Send all collected packets
|
||||||
APIError err = this->helper_->write_protobuf_packets(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()},
|
APIError err = this->helper_->write_protobuf_packets(ProtoWriteBuffer{&shared_buf},
|
||||||
std::span<const PacketInfo>(packet_info, packet_count));
|
std::span<const PacketInfo>(packet_info, packet_count));
|
||||||
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
|
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Batch write failed %s errno=%d", this->get_client_combined_info().c_str(), api_error_to_str(err),
|
this->log_warning_("Batch write failed", err);
|
||||||
errno);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
@ -1838,5 +1830,11 @@ void APIConnection::process_state_subscriptions_() {
|
|||||||
}
|
}
|
||||||
#endif // USE_API_HOMEASSISTANT_STATES
|
#endif // USE_API_HOMEASSISTANT_STATES
|
||||||
|
|
||||||
|
void APIConnection::log_warning_(const char *message, APIError err) {
|
||||||
|
ESP_LOGW(TAG, "%s: %s %s errno=%d", this->get_client_combined_info().c_str(), message, api_error_to_str(err), errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIConnection::log_socket_operation_failed_(APIError err) { this->log_warning_("Socket operation failed", err); }
|
||||||
|
|
||||||
} // namespace esphome::api
|
} // namespace esphome::api
|
||||||
#endif
|
#endif
|
||||||
|
@ -736,6 +736,11 @@ class APIConnection : public APIServerConnection {
|
|||||||
this->deferred_batch_.add_item_front(entity, MessageCreator(function_ptr), message_type, estimated_size);
|
this->deferred_batch_.add_item_front(entity, MessageCreator(function_ptr), message_type, estimated_size);
|
||||||
return this->schedule_batch_();
|
return this->schedule_batch_();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to log API errors with errno
|
||||||
|
void log_warning_(const char *message, APIError err);
|
||||||
|
// Specific helper for duplicated error message
|
||||||
|
void log_socket_operation_failed_(APIError err);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace esphome::api
|
} // namespace esphome::api
|
||||||
|
Loading…
x
Reference in New Issue
Block a user