diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 8721072e499..bd3de028951 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1188,6 +1188,9 @@ void APIConnection::on_bluetooth_scanner_set_mode_request(const BluetoothScanner bluetooth_proxy::global_bluetooth_proxy->bluetooth_scanner_set_mode( msg.mode == enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE); } +void APIConnection::on_bluetooth_set_connection_params_request(const BluetoothSetConnectionParamsRequest &msg) { + bluetooth_proxy::global_bluetooth_proxy->bluetooth_set_connection_params(msg); +} #endif #ifdef USE_VOICE_ASSISTANT diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 54b6db68000..b075bc83ab2 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -148,6 +148,7 @@ class APIConnection final : public APIServerConnectionBase { void on_bluetooth_gatt_notify_request(const BluetoothGATTNotifyRequest &msg) override; void on_subscribe_bluetooth_connections_free_request() override; void on_bluetooth_scanner_set_mode_request(const BluetoothScannerSetModeRequest &msg) override; + void on_bluetooth_set_connection_params_request(const BluetoothSetConnectionParamsRequest &msg) override; #endif #ifdef USE_HOMEASSISTANT_TIME diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.h b/esphome/components/bluetooth_proxy/bluetooth_connection.h index 60bbc93e8b4..b50ea2d6a22 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.h +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.h @@ -24,6 +24,10 @@ class BluetoothConnection final : public esp32_ble_client::BLEClientBase { esp_err_t notify_characteristic(uint16_t handle, bool enable); + esp_err_t update_connection_params(uint16_t min_interval, uint16_t max_interval, uint16_t latency, uint16_t timeout) { + return this->update_conn_params_(min_interval, max_interval, latency, timeout, "custom"); + } + void set_address(uint64_t address) override; protected: diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index 21da4ead144..87206996b27 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -3,7 +3,9 @@ #include "esphome/core/log.h" #include "esphome/core/macros.h" #include "esphome/core/application.h" +#include #include +#include #ifdef USE_ESP32 @@ -361,6 +363,33 @@ void BluetoothProxy::bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest } } +void BluetoothProxy::bluetooth_set_connection_params(const api::BluetoothSetConnectionParamsRequest &msg) { + if (this->api_connection_ == nullptr) + return; + + auto *connection = this->get_connection_(msg.address, false); + api::BluetoothSetConnectionParamsResponse resp; + resp.address = msg.address; + + if (connection == nullptr || !connection->connected()) { + ESP_LOGW(TAG, "[%d] [%s] Cannot set connection params, not connected", + connection ? static_cast(connection->connection_index_) : -1, + connection ? connection->address_str() : "unknown"); + resp.error = ESP_GATT_NOT_CONNECTED; + this->api_connection_->send_message(resp); + return; + } + + // Protobuf fields are uint32_t to future-proof the API if BLE ever supports wider values; + // clamp to uint16_t since the current BLE spec defines these as 16-bit. + constexpr uint32_t max_val = std::numeric_limits::max(); + resp.error = connection->update_connection_params(static_cast(std::min(msg.min_interval, max_val)), + static_cast(std::min(msg.max_interval, max_val)), + static_cast(std::min(msg.latency, max_val)), + static_cast(std::min(msg.timeout, max_val))); + this->api_connection_->send_message(resp); +} + void BluetoothProxy::subscribe_api_connection(api::APIConnection *api_connection, uint32_t flags) { if (this->api_connection_ != nullptr) { ESP_LOGE(TAG, "Only one API subscription is allowed at a time"); diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.h b/esphome/components/bluetooth_proxy/bluetooth_proxy.h index 85461755aac..f1b723e7192 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.h +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.h @@ -46,6 +46,7 @@ enum BluetoothProxyFeature : uint32_t { FEATURE_CACHE_CLEARING = 1 << 4, FEATURE_RAW_ADVERTISEMENTS = 1 << 5, FEATURE_STATE_AND_MODE = 1 << 6, + FEATURE_CONNECTION_PARAMS_SETTING = 1 << 7, }; enum BluetoothProxySubscriptionFlag : uint32_t { @@ -82,6 +83,7 @@ class BluetoothProxy final : public esp32_ble_tracker::ESPBTDeviceListener, void bluetooth_gatt_write_descriptor(const api::BluetoothGATTWriteDescriptorRequest &msg); void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg); void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg); + void bluetooth_set_connection_params(const api::BluetoothSetConnectionParamsRequest &msg); void subscribe_api_connection(api::APIConnection *api_connection, uint32_t flags); void unsubscribe_api_connection(api::APIConnection *api_connection); @@ -130,6 +132,7 @@ class BluetoothProxy final : public esp32_ble_tracker::ESPBTDeviceListener, flags |= BluetoothProxyFeature::FEATURE_REMOTE_CACHING; flags |= BluetoothProxyFeature::FEATURE_PAIRING; flags |= BluetoothProxyFeature::FEATURE_CACHE_CLEARING; + flags |= BluetoothProxyFeature::FEATURE_CONNECTION_PARAMS_SETTING; } return flags; diff --git a/esphome/components/esp32_ble_client/ble_client_base.cpp b/esphome/components/esp32_ble_client/ble_client_base.cpp index e6a85c784a9..2f17334c77c 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.cpp +++ b/esphome/components/esp32_ble_client/ble_client_base.cpp @@ -236,8 +236,8 @@ void BLEClientBase::log_warning_(const char *message) { ESP_LOGW(TAG, "[%d] [%s] %s", this->connection_index_, this->address_str_, message); } -void BLEClientBase::update_conn_params_(uint16_t min_interval, uint16_t max_interval, uint16_t latency, - uint16_t timeout, const char *param_type) { +esp_err_t BLEClientBase::update_conn_params_(uint16_t min_interval, uint16_t max_interval, uint16_t latency, + uint16_t timeout, const char *param_type) { esp_ble_conn_update_params_t conn_params = {{0}}; memcpy(conn_params.bda, this->remote_bda_, sizeof(esp_bd_addr_t)); conn_params.min_int = min_interval; @@ -249,6 +249,7 @@ void BLEClientBase::update_conn_params_(uint16_t min_interval, uint16_t max_inte if (err != ESP_OK) { this->log_gattc_warning_("esp_ble_gap_update_conn_params", err); } + return err; } void BLEClientBase::set_conn_params_(uint16_t min_interval, uint16_t max_interval, uint16_t latency, uint16_t timeout, diff --git a/esphome/components/esp32_ble_client/ble_client_base.h b/esphome/components/esp32_ble_client/ble_client_base.h index c2336b23498..af4f1b30290 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.h +++ b/esphome/components/esp32_ble_client/ble_client_base.h @@ -129,8 +129,8 @@ class BLEClientBase : public espbt::ESPBTClient, public Component { void log_event_(const char *name); void log_gattc_lifecycle_event_(const char *name); void log_gattc_data_event_(const char *name); - void update_conn_params_(uint16_t min_interval, uint16_t max_interval, uint16_t latency, uint16_t timeout, - const char *param_type); + esp_err_t update_conn_params_(uint16_t min_interval, uint16_t max_interval, uint16_t latency, uint16_t timeout, + const char *param_type); void set_conn_params_(uint16_t min_interval, uint16_t max_interval, uint16_t latency, uint16_t timeout, const char *param_type); void log_gattc_warning_(const char *operation, esp_gatt_status_t status);