mirror of
https://github.com/esphome/esphome.git
synced 2025-11-18 15:55:46 +00:00
Optimize API connection loop performance (#9184)
This commit is contained in:
@@ -33,9 +33,14 @@ namespace api {
|
||||
// Since each message could contain multiple protobuf messages when using packet batching,
|
||||
// this limits the number of messages processed, not the number of TCP packets.
|
||||
static constexpr uint8_t MAX_MESSAGES_PER_LOOP = 5;
|
||||
static constexpr uint8_t MAX_PING_RETRIES = 60;
|
||||
static constexpr uint16_t PING_RETRY_INTERVAL = 1000;
|
||||
static constexpr uint32_t KEEPALIVE_DISCONNECT_TIMEOUT = (KEEPALIVE_TIMEOUT_MS * 5) / 2;
|
||||
|
||||
static const char *const TAG = "api.connection";
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
static const int ESP32_CAMERA_STOP_STREAM = 5000;
|
||||
#endif
|
||||
|
||||
APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
|
||||
: parent_(parent), initial_state_iterator_(this), list_entities_iterator_(this) {
|
||||
@@ -90,16 +95,6 @@ APIConnection::~APIConnection() {
|
||||
}
|
||||
|
||||
void APIConnection::loop() {
|
||||
if (this->remove_)
|
||||
return;
|
||||
|
||||
if (!network::is_connected()) {
|
||||
// when network is disconnected force disconnect immediately
|
||||
// don't wait for timeout
|
||||
this->on_fatal_error();
|
||||
ESP_LOGW(TAG, "%s: Network unavailable; disconnecting", this->get_client_combined_info().c_str());
|
||||
return;
|
||||
}
|
||||
if (this->next_close_) {
|
||||
// requested a disconnect
|
||||
this->helper_->close();
|
||||
@@ -152,20 +147,19 @@ void APIConnection::loop() {
|
||||
|
||||
// Process deferred batch if scheduled
|
||||
if (this->deferred_batch_.batch_scheduled &&
|
||||
App.get_loop_component_start_time() - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) {
|
||||
now - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) {
|
||||
this->process_batch_();
|
||||
}
|
||||
|
||||
if (!this->list_entities_iterator_.completed())
|
||||
if (!this->list_entities_iterator_.completed()) {
|
||||
this->list_entities_iterator_.advance();
|
||||
if (!this->initial_state_iterator_.completed() && this->list_entities_iterator_.completed())
|
||||
} else if (!this->initial_state_iterator_.completed()) {
|
||||
this->initial_state_iterator_.advance();
|
||||
}
|
||||
|
||||
static uint8_t max_ping_retries = 60;
|
||||
static uint16_t ping_retry_interval = 1000;
|
||||
if (this->sent_ping_) {
|
||||
// Disconnect if not responded within 2.5*keepalive
|
||||
if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) {
|
||||
if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) {
|
||||
on_fatal_error();
|
||||
ESP_LOGW(TAG, "%s is unresponsive; disconnecting", this->get_client_combined_info().c_str());
|
||||
}
|
||||
@@ -173,17 +167,15 @@ void APIConnection::loop() {
|
||||
ESP_LOGVV(TAG, "Sending keepalive PING");
|
||||
this->sent_ping_ = this->send_message(PingRequest());
|
||||
if (!this->sent_ping_) {
|
||||
this->next_ping_retry_ = now + ping_retry_interval;
|
||||
this->next_ping_retry_ = now + PING_RETRY_INTERVAL;
|
||||
this->ping_retries_++;
|
||||
std::string warn_str = str_sprintf("%s: Sending keepalive failed %u time(s);",
|
||||
this->get_client_combined_info().c_str(), this->ping_retries_);
|
||||
if (this->ping_retries_ >= max_ping_retries) {
|
||||
if (this->ping_retries_ >= MAX_PING_RETRIES) {
|
||||
on_fatal_error();
|
||||
ESP_LOGE(TAG, "%s disconnecting", warn_str.c_str());
|
||||
ESP_LOGE(TAG, "%s: Ping failed %u times", this->get_client_combined_info().c_str(), this->ping_retries_);
|
||||
} else if (this->ping_retries_ >= 10) {
|
||||
ESP_LOGW(TAG, "%s retrying in %u ms", warn_str.c_str(), ping_retry_interval);
|
||||
ESP_LOGW(TAG, "%s: Ping retry %u", this->get_client_combined_info().c_str(), this->ping_retries_);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "%s retrying in %u ms", warn_str.c_str(), ping_retry_interval);
|
||||
ESP_LOGD(TAG, "%s: Ping retry %u", this->get_client_combined_info().c_str(), this->ping_retries_);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,22 +199,20 @@ void APIConnection::loop() {
|
||||
// bool done = 3;
|
||||
buffer.encode_bool(3, done);
|
||||
|
||||
bool success = this->send_buffer(buffer, 44);
|
||||
bool success = this->send_buffer(buffer, CameraImageResponse::MESSAGE_TYPE);
|
||||
|
||||
if (success) {
|
||||
this->image_reader_.consume_data(to_send);
|
||||
}
|
||||
if (success && done) {
|
||||
this->image_reader_.return_image();
|
||||
if (done) {
|
||||
this->image_reader_.return_image();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (state_subs_at_ != -1) {
|
||||
if (state_subs_at_ >= 0) {
|
||||
const auto &subs = this->parent_->get_state_subs();
|
||||
if (state_subs_at_ >= (int) subs.size()) {
|
||||
state_subs_at_ = -1;
|
||||
} else {
|
||||
if (state_subs_at_ < static_cast<int>(subs.size())) {
|
||||
auto &it = subs[state_subs_at_];
|
||||
SubscribeHomeAssistantStateResponse resp;
|
||||
resp.entity_id = it.entity_id;
|
||||
@@ -231,6 +221,8 @@ void APIConnection::loop() {
|
||||
if (this->send_message(resp)) {
|
||||
state_subs_at_++;
|
||||
}
|
||||
} else {
|
||||
state_subs_at_ = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user