Retry a dropped connections-free update

Field bug on a Pico W: the slot freed device-side but the API client
kept free=0 with the address still allocated. send_message drops the
response when the TCP buffer is full (a boot storm makes that likely
right when HA reconnects), and nothing ever resent it - the client's
slot state is verbatim the last response received, so it stayed stale
until reboot. The cached response is current by construction, so a
pending bit retried from loop() is an idempotent resync; the
subscribe-time send heals through the same bit.
This commit is contained in:
J. Nick Koston
2026-08-09 14:13:50 -05:00
parent 4276815734
commit aceff27948
2 changed files with 13 additions and 1 deletions
@@ -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) {
@@ -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