mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	[esp32_ble_client] Fix BLE connection stability for WiFi-based proxies (#9993)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
		| @@ -13,10 +13,15 @@ namespace esp32_ble_client { | |||||||
|  |  | ||||||
| static const char *const TAG = "esp32_ble_client"; | static const char *const TAG = "esp32_ble_client"; | ||||||
|  |  | ||||||
| // Connection interval defaults matching ESP-IDF's BTM_BLE_CONN_INT_*_DEF | // Intermediate connection parameters for standard operation | ||||||
| static const uint16_t DEFAULT_MIN_CONN_INTERVAL = 0x0A;  // 10 * 1.25ms = 12.5ms | // ESP-IDF defaults (12.5-15ms) are too slow for stable connections through WiFi-based BLE proxies, | ||||||
| static const uint16_t DEFAULT_MAX_CONN_INTERVAL = 0x0C;  // 12 * 1.25ms = 15ms | // causing disconnections. These medium parameters balance responsiveness with bandwidth usage. | ||||||
| static const uint16_t DEFAULT_CONN_TIMEOUT = 600;        // 600 * 10ms = 6s | static const uint16_t MEDIUM_MIN_CONN_INTERVAL = 0x08;  // 8 * 1.25ms = 10ms | ||||||
|  | static const uint16_t MEDIUM_MAX_CONN_INTERVAL = 0x0A;  // 10 * 1.25ms = 12.5ms | ||||||
|  | // The timeout value was increased from 6s to 8s to address stability issues observed | ||||||
|  | // in certain BLE devices when operating through WiFi-based BLE proxies. The longer | ||||||
|  | // timeout reduces the likelihood of disconnections during periods of high latency. | ||||||
|  | static const uint16_t MEDIUM_CONN_TIMEOUT = 800;  // 800 * 10ms = 8s | ||||||
|  |  | ||||||
| // Fastest connection parameters for devices with short discovery timeouts | // Fastest connection parameters for devices with short discovery timeouts | ||||||
| static const uint16_t FAST_MIN_CONN_INTERVAL = 0x06;  // 6 * 1.25ms = 7.5ms (BLE minimum) | static const uint16_t FAST_MIN_CONN_INTERVAL = 0x06;  // 6 * 1.25ms = 7.5ms (BLE minimum) | ||||||
| @@ -151,20 +156,32 @@ void BLEClientBase::connect() { | |||||||
|   } else { |   } else { | ||||||
|     this->set_state(espbt::ClientState::CONNECTING); |     this->set_state(espbt::ClientState::CONNECTING); | ||||||
|  |  | ||||||
|     // For connections without cache, set fast connection parameters after initiating connection |     // Always set connection parameters to ensure stable operation | ||||||
|     // This ensures service discovery completes within the 10-second timeout that |     // Use FAST for V3_WITHOUT_CACHE (devices that need lowest latency) | ||||||
|     // some devices like HomeKit BLE sensors enforce |     // Use MEDIUM for all other connections (balanced performance) | ||||||
|  |     uint16_t min_interval, max_interval, timeout; | ||||||
|  |     const char *param_type; | ||||||
|  |  | ||||||
|     if (this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) { |     if (this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) { | ||||||
|       auto param_ret = |       min_interval = FAST_MIN_CONN_INTERVAL; | ||||||
|           esp_ble_gap_set_prefer_conn_params(this->remote_bda_, FAST_MIN_CONN_INTERVAL, FAST_MAX_CONN_INTERVAL, |       max_interval = FAST_MAX_CONN_INTERVAL; | ||||||
|  |       timeout = FAST_CONN_TIMEOUT; | ||||||
|  |       param_type = "fast"; | ||||||
|  |     } else { | ||||||
|  |       min_interval = MEDIUM_MIN_CONN_INTERVAL; | ||||||
|  |       max_interval = MEDIUM_MAX_CONN_INTERVAL; | ||||||
|  |       timeout = MEDIUM_CONN_TIMEOUT; | ||||||
|  |       param_type = "medium"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     auto param_ret = esp_ble_gap_set_prefer_conn_params(this->remote_bda_, min_interval, max_interval, | ||||||
|                                                         0,  // latency: 0 |                                                         0,  // latency: 0 | ||||||
|                                              FAST_CONN_TIMEOUT); |                                                         timeout); | ||||||
|     if (param_ret != ESP_OK) { |     if (param_ret != ESP_OK) { | ||||||
|       ESP_LOGW(TAG, "[%d] [%s] esp_ble_gap_set_prefer_conn_params failed: %d", this->connection_index_, |       ESP_LOGW(TAG, "[%d] [%s] esp_ble_gap_set_prefer_conn_params failed: %d", this->connection_index_, | ||||||
|                this->address_str_.c_str(), param_ret); |                this->address_str_.c_str(), param_ret); | ||||||
|     } else { |     } else { | ||||||
|         ESP_LOGD(TAG, "[%d] [%s] Set fast conn params", this->connection_index_, this->address_str_.c_str()); |       ESP_LOGD(TAG, "[%d] [%s] Set %s conn params", this->connection_index_, this->address_str_.c_str(), param_type); | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -394,17 +411,17 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_ | |||||||
|       } |       } | ||||||
|       ESP_LOGI(TAG, "[%d] [%s] Service discovery complete", this->connection_index_, this->address_str_.c_str()); |       ESP_LOGI(TAG, "[%d] [%s] Service discovery complete", this->connection_index_, this->address_str_.c_str()); | ||||||
|  |  | ||||||
|       // For non-cached connections, restore default connection parameters after service discovery |       // For non-cached connections, restore to medium connection parameters after service discovery | ||||||
|       // Now that we've discovered all services, we can use more balanced parameters |       // This balances performance with bandwidth usage after the critical discovery phase | ||||||
|       // that save power and reduce interference |  | ||||||
|       if (this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) { |       if (this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) { | ||||||
|         esp_ble_conn_update_params_t conn_params = {{0}}; |         esp_ble_conn_update_params_t conn_params = {{0}}; | ||||||
|         memcpy(conn_params.bda, this->remote_bda_, sizeof(esp_bd_addr_t)); |         memcpy(conn_params.bda, this->remote_bda_, sizeof(esp_bd_addr_t)); | ||||||
|         conn_params.min_int = DEFAULT_MIN_CONN_INTERVAL; |         conn_params.min_int = MEDIUM_MIN_CONN_INTERVAL; | ||||||
|         conn_params.max_int = DEFAULT_MAX_CONN_INTERVAL; |         conn_params.max_int = MEDIUM_MAX_CONN_INTERVAL; | ||||||
|         conn_params.latency = 0; |         conn_params.latency = 0; | ||||||
|         conn_params.timeout = DEFAULT_CONN_TIMEOUT; |         conn_params.timeout = MEDIUM_CONN_TIMEOUT; | ||||||
|         ESP_LOGD(TAG, "[%d] [%s] Restored default conn params", this->connection_index_, this->address_str_.c_str()); |         ESP_LOGD(TAG, "[%d] [%s] Restored medium conn params after service discovery", this->connection_index_, | ||||||
|  |                  this->address_str_.c_str()); | ||||||
|         esp_ble_gap_update_conn_params(&conn_params); |         esp_ble_gap_update_conn_params(&conn_params); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user