1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-02 19:32:19 +01:00
This commit is contained in:
J. Nick Koston
2025-08-21 21:44:59 -05:00
parent 9d16eeeb77
commit 65eb57ca1b
3 changed files with 34 additions and 49 deletions

View File

@@ -4,6 +4,7 @@ import re
from esphome import automation from esphome import automation
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant
from esphome.components.esp32.const import VARIANT_ESP32C3, VARIANT_ESP32S3
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ESPHOME, CONF_ID, CONF_NAME from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ESPHOME, CONF_ID, CONF_NAME
from esphome.core import CORE, TimePeriod from esphome.core import CORE, TimePeriod
@@ -259,6 +260,12 @@ async def to_code(config):
if CORE.using_esp_idf: if CORE.using_esp_idf:
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True) add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True)
# Enable BLE 5.0 features on ESP32-S3/C3
# Note: Despite ESP-IDF docs stating BLE 4.2 and 5.0 can't be used simultaneously,
# both were already enabled by default and this configuration works in practice.
# We're making it explicit here for clarity and to ensure both APIs are available.
if get_esp32_variant() in (VARIANT_ESP32S3, VARIANT_ESP32C3):
add_idf_sdkconfig_option("CONFIG_BT_BLE_50_FEATURES_SUPPORTED", True)
# Register the core BLE loggers that are always needed # Register the core BLE loggers that are always needed
register_bt_logger(BTLoggers.GAP, BTLoggers.BTM, BTLoggers.HCI) register_bt_logger(BTLoggers.GAP, BTLoggers.BTM, BTLoggers.HCI)

View File

@@ -7,17 +7,12 @@
#include <esp_gap_ble_api.h> #include <esp_gap_ble_api.h>
#include <esp_gatt_defs.h> #include <esp_gatt_defs.h>
#include <esp_gattc_api.h>
namespace esphome::esp32_ble_client { namespace esphome::esp32_ble_client {
static const char *const TAG = "esp32_ble_client"; static const char *const TAG = "esp32_ble_client";
// Default connection parameters matching ESP-IDF's BTM_BLE_CONN_INT_*_DEF
// These are conservative values that work well with most devices
static const uint16_t DEFAULT_MIN_CONN_INTERVAL = 0x0A; // 10 * 1.25ms = 12.5ms
static const uint16_t DEFAULT_MAX_CONN_INTERVAL = 0x0C; // 12 * 1.25ms = 15ms
static const uint16_t DEFAULT_CONN_TIMEOUT = 600; // 600 * 10ms = 6s
// Intermediate connection parameters for standard operation // Intermediate connection parameters for standard operation
// ESP-IDF defaults (12.5-15ms) are too slow for stable connections through WiFi-based BLE proxies, // ESP-IDF defaults (12.5-15ms) are too slow for stable connections through WiFi-based BLE proxies,
// causing disconnections. These medium parameters balance responsiveness with bandwidth usage. // causing disconnections. These medium parameters balance responsiveness with bandwidth usage.
@@ -117,19 +112,19 @@ void BLEClientBase::connect() {
this->remote_addr_type_); this->remote_addr_type_);
this->paired_ = false; this->paired_ = false;
// Set default connection parameters before connecting // Determine connection parameters based on connection type
// This ensures we use conservative parameters that work well with weak signal devices if (this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
// rather than potentially aggressive parameters from a previous connection // V3 without cache needs fast params for service discovery
this->set_default_conn_params_(); this->set_conn_params_(FAST_MIN_CONN_INTERVAL, FAST_MAX_CONN_INTERVAL, 0, FAST_CONN_TIMEOUT, "fast");
} else if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE) {
// Open the connection with default parameters // V3 with cache can use medium params
auto ret = esp_ble_gattc_open(this->gattc_if_, this->remote_bda_, this->remote_addr_type_, true); this->set_conn_params_(MEDIUM_MIN_CONN_INTERVAL, MEDIUM_MAX_CONN_INTERVAL, 0, MEDIUM_CONN_TIMEOUT, "medium");
if (ret) {
this->log_gattc_warning_("esp_ble_gattc_open", ret);
this->set_state(espbt::ClientState::IDLE);
} else {
this->set_state(espbt::ClientState::CONNECTING);
} }
// For V1/Legacy, don't set params - use ESP-IDF defaults
// Open the connection
auto ret = esp_ble_gattc_open(this->gattc_if_, this->remote_bda_, this->remote_addr_type_, true);
this->handle_connection_result_(ret);
} }
esp_err_t BLEClientBase::pair() { return esp_ble_set_encryption(this->remote_bda_, ESP_BLE_SEC_ENCRYPT); } esp_err_t BLEClientBase::pair() { return esp_ble_set_encryption(this->remote_bda_, ESP_BLE_SEC_ENCRYPT); }
@@ -213,6 +208,15 @@ void BLEClientBase::log_connection_params_(const char *param_type) {
ESP_LOGD(TAG, "[%d] [%s] %s conn params", this->connection_index_, this->address_str_.c_str(), param_type); ESP_LOGD(TAG, "[%d] [%s] %s conn params", this->connection_index_, this->address_str_.c_str(), param_type);
} }
void BLEClientBase::handle_connection_result_(esp_err_t ret) {
if (ret) {
this->log_gattc_warning_("esp_ble_gattc_open", ret);
this->set_state(espbt::ClientState::IDLE);
} else {
this->set_state(espbt::ClientState::CONNECTING);
}
}
void BLEClientBase::log_error_(const char *message) { void BLEClientBase::log_error_(const char *message) {
ESP_LOGE(TAG, "[%d] [%s] %s", this->connection_index_, this->address_str_.c_str(), message); ESP_LOGE(TAG, "[%d] [%s] %s", this->connection_index_, this->address_str_.c_str(), message);
} }
@@ -251,24 +255,6 @@ void BLEClientBase::set_conn_params_(uint16_t min_interval, uint16_t max_interva
} }
} }
void BLEClientBase::set_fast_conn_params_() {
// Switch to fast connection parameters for service discovery
// This improves discovery speed for devices with short timeouts
this->update_conn_params_(FAST_MIN_CONN_INTERVAL, FAST_MAX_CONN_INTERVAL, 0, FAST_CONN_TIMEOUT, "fast");
}
void BLEClientBase::set_medium_conn_params_() {
// Set medium connection parameters for balanced performance
// This balances performance with bandwidth usage for normal operation
this->update_conn_params_(MEDIUM_MIN_CONN_INTERVAL, MEDIUM_MAX_CONN_INTERVAL, 0, MEDIUM_CONN_TIMEOUT, "medium");
}
void BLEClientBase::set_default_conn_params_() {
// Set default connection parameters before connecting
// These conservative values work well with most devices including weak signal ones
this->set_conn_params_(DEFAULT_MIN_CONN_INTERVAL, DEFAULT_MAX_CONN_INTERVAL, 0, DEFAULT_CONN_TIMEOUT, "default");
}
bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t esp_gattc_if, bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t esp_gattc_if,
esp_ble_gattc_cb_param_t *param) { esp_ble_gattc_cb_param_t *param) {
if (event == ESP_GATTC_REG_EVT && this->app_id != param->reg.app_id) if (event == ESP_GATTC_REG_EVT && this->app_id != param->reg.app_id)
@@ -321,19 +307,13 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
this->set_state(espbt::ClientState::CONNECTED); this->set_state(espbt::ClientState::CONNECTED);
ESP_LOGI(TAG, "[%d] [%s] Connection open", this->connection_index_, this->address_str_.c_str()); ESP_LOGI(TAG, "[%d] [%s] Connection open", this->connection_index_, this->address_str_.c_str());
if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE) { if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE) {
// Cached connections use medium connection parameters // Cached connections already connected with medium parameters, no update needed
this->set_medium_conn_params_();
// only set our state, subclients might have more stuff to do yet. // only set our state, subclients might have more stuff to do yet.
this->state_ = espbt::ClientState::ESTABLISHED; this->state_ = espbt::ClientState::ESTABLISHED;
break; break;
} }
// For V3_WITHOUT_CACHE, switch to fast params for service discovery // For V3_WITHOUT_CACHE, we already set fast params before connecting
// Service discovery period is critical - we typically have only 10s to complete // No need to update them again here
// discovery before the device disconnects us. Fast connection parameters are
// essential to finish service resolution in time and avoid retry loops.
else if (this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
this->set_fast_conn_params_();
}
this->log_event_("Searching for services"); this->log_event_("Searching for services");
esp_ble_gattc_search_service(esp_gattc_if, param->cfg_mtu.conn_id, nullptr); esp_ble_gattc_search_service(esp_gattc_if, param->cfg_mtu.conn_id, nullptr);
break; break;
@@ -418,7 +398,7 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
// For V3_WITHOUT_CACHE, switch back to medium connection parameters after service discovery // For V3_WITHOUT_CACHE, switch back to medium connection parameters after service discovery
// This balances performance with bandwidth usage after the critical discovery phase // This balances performance with bandwidth usage after the critical discovery phase
if (this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) { if (this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
this->set_medium_conn_params_(); this->update_conn_params_(MEDIUM_MIN_CONN_INTERVAL, MEDIUM_MAX_CONN_INTERVAL, 0, MEDIUM_CONN_TIMEOUT, "medium");
} else if (this->connection_type_ != espbt::ConnectionType::V3_WITH_CACHE) { } else if (this->connection_type_ != espbt::ConnectionType::V3_WITH_CACHE) {
#ifdef USE_ESP32_BLE_DEVICE #ifdef USE_ESP32_BLE_DEVICE
for (auto &svc : this->services_) { for (auto &svc : this->services_) {

View File

@@ -137,12 +137,10 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
const char *param_type); const char *param_type);
void set_conn_params_(uint16_t min_interval, uint16_t max_interval, uint16_t latency, uint16_t timeout, void set_conn_params_(uint16_t min_interval, uint16_t max_interval, uint16_t latency, uint16_t timeout,
const char *param_type); const char *param_type);
void set_fast_conn_params_();
void set_medium_conn_params_();
void set_default_conn_params_();
void log_gattc_warning_(const char *operation, esp_gatt_status_t status); void log_gattc_warning_(const char *operation, esp_gatt_status_t status);
void log_gattc_warning_(const char *operation, esp_err_t err); void log_gattc_warning_(const char *operation, esp_err_t err);
void log_connection_params_(const char *param_type); void log_connection_params_(const char *param_type);
void handle_connection_result_(esp_err_t ret);
// Compact error logging helpers to reduce flash usage // Compact error logging helpers to reduce flash usage
void log_error_(const char *message); void log_error_(const char *message);
void log_error_(const char *message, int code); void log_error_(const char *message, int code);