diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index ea1dacda32..af62b211bf 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -475,6 +475,11 @@ void BluetoothProxy::loop() { for (uint8_t i = 0; i < this->connection_count_; i++) { this->connections_[i]->process_pending_services(); } + if (this->connections_free_pending_ && this->api_connection_ != nullptr) { + // Resend a dropped slot-state update once the TCP buffer drains. + this->connections_free_pending_ = false; + this->send_connections_free(this->api_connection_); + } #endif // Run advertisement flush / scanner-state poll every 100ms @@ -629,7 +634,10 @@ void BluetoothProxy::send_connections_free() { } void BluetoothProxy::send_connections_free(api::APIConnection *api_connection) { - api_connection->send_message(this->connections_free_response_); + if (!api_connection->send_message(this->connections_free_response_)) { + ESP_LOGD(TAG, "Connections-free update deferred, TCP buffer full"); + this->connections_free_pending_ = true; + } } void BluetoothProxy::send_gatt_services_done(uint64_t address) { diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.h b/esphome/components/bluetooth_proxy/bluetooth_proxy.h index 17e480b671..26f99fcca2 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.h +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.h @@ -254,6 +254,10 @@ class BluetoothProxy final : public Component { // Group 4: 1-byte types grouped together bool active_; + // A dropped send (full TCP buffer) would leave the API client with a stale + // slot state forever; the cached response is current by construction, so + // retrying it from loop() is an idempotent resync. + bool connections_free_pending_{false}; uint8_t connection_count_{0}; bool configured_scan_active_{false}; // Configured scan mode from YAML #ifndef USE_BLE_SCANNER_STATE_CALLBACK