mirror of
https://github.com/esphome/esphome.git
synced 2024-12-01 19:24:14 +01:00
Avoid parsing services with v3 connections without cache (#4117)
Co-authored-by: Daniel Cousens <413395+dcousens@users.noreply.github.com> Co-authored-by: Maurice Makaay <account+github@makaay.nl> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
a6196267c9
commit
a59ce7bfa2
5 changed files with 41 additions and 15 deletions
|
@ -25,7 +25,7 @@ class BluetoothConnection : public esp32_ble_client::BLEClientBase {
|
||||||
friend class BluetoothProxy;
|
friend class BluetoothProxy;
|
||||||
bool seen_mtu_or_services_{false};
|
bool seen_mtu_or_services_{false};
|
||||||
|
|
||||||
int16_t send_service_{-1};
|
int16_t send_service_{-2};
|
||||||
BluetoothProxy *proxy_;
|
BluetoothProxy *proxy_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace esphome {
|
||||||
namespace bluetooth_proxy {
|
namespace bluetooth_proxy {
|
||||||
|
|
||||||
static const char *const TAG = "bluetooth_proxy";
|
static const char *const TAG = "bluetooth_proxy";
|
||||||
|
static const int DONE_SENDING_SERVICES = -2;
|
||||||
|
|
||||||
BluetoothProxy::BluetoothProxy() { global_bluetooth_proxy = this; }
|
BluetoothProxy::BluetoothProxy() { global_bluetooth_proxy = this; }
|
||||||
|
|
||||||
|
@ -77,32 +78,49 @@ void BluetoothProxy::loop() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (auto *connection : this->connections_) {
|
for (auto *connection : this->connections_) {
|
||||||
if (connection->send_service_ == connection->services_.size()) {
|
if (connection->send_service_ == connection->service_count_) {
|
||||||
connection->send_service_ = -1;
|
connection->send_service_ = DONE_SENDING_SERVICES;
|
||||||
api::global_api_server->send_bluetooth_gatt_services_done(connection->get_address());
|
api::global_api_server->send_bluetooth_gatt_services_done(connection->get_address());
|
||||||
if (connection->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
|
if (connection->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
|
||||||
connection->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
|
connection->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
|
||||||
connection->release_services();
|
connection->release_services();
|
||||||
}
|
}
|
||||||
} else if (connection->send_service_ >= 0) {
|
} else if (connection->send_service_ >= 0) {
|
||||||
auto &service = connection->services_[connection->send_service_];
|
esp_gattc_service_elem_t service_result;
|
||||||
|
uint16_t service_count = 1;
|
||||||
|
esp_gatt_status_t service_status =
|
||||||
|
esp_ble_gattc_get_service(connection->get_gattc_if(), connection->get_conn_id(), nullptr, &service_result,
|
||||||
|
&service_count, connection->send_service_);
|
||||||
|
connection->send_service_++;
|
||||||
|
if (service_status != ESP_GATT_OK) {
|
||||||
|
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service error at offset=%d, status=%d",
|
||||||
|
connection->get_connection_index(), connection->address_str().c_str(), connection->send_service_ - 1,
|
||||||
|
service_status);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (service_count == 0) {
|
||||||
|
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service missing, service_count=%d",
|
||||||
|
connection->get_connection_index(), connection->address_str().c_str(), service_count);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
api::BluetoothGATTGetServicesResponse resp;
|
api::BluetoothGATTGetServicesResponse resp;
|
||||||
resp.address = connection->get_address();
|
resp.address = connection->get_address();
|
||||||
api::BluetoothGATTService service_resp;
|
api::BluetoothGATTService service_resp;
|
||||||
service_resp.uuid = {service->uuid.get_128bit_high(), service->uuid.get_128bit_low()};
|
auto service_uuid = espbt::ESPBTUUID::from_uuid(service_result.uuid);
|
||||||
service_resp.handle = service->start_handle;
|
service_resp.uuid = {service_uuid.get_128bit_high(), service_uuid.get_128bit_low()};
|
||||||
|
service_resp.handle = service_result.start_handle;
|
||||||
uint16_t char_offset = 0;
|
uint16_t char_offset = 0;
|
||||||
esp_gattc_char_elem_t char_result;
|
esp_gattc_char_elem_t char_result;
|
||||||
while (true) { // characteristics
|
while (true) { // characteristics
|
||||||
uint16_t char_count = 1;
|
uint16_t char_count = 1;
|
||||||
esp_gatt_status_t char_status =
|
esp_gatt_status_t char_status = esp_ble_gattc_get_all_char(
|
||||||
esp_ble_gattc_get_all_char(connection->get_gattc_if(), connection->get_conn_id(), service->start_handle,
|
connection->get_gattc_if(), connection->get_conn_id(), service_result.start_handle,
|
||||||
service->end_handle, &char_result, &char_count, char_offset);
|
service_result.end_handle, &char_result, &char_count, char_offset);
|
||||||
if (char_status == ESP_GATT_INVALID_OFFSET || char_status == ESP_GATT_NOT_FOUND) {
|
if (char_status == ESP_GATT_INVALID_OFFSET || char_status == ESP_GATT_NOT_FOUND) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (char_status != ESP_GATT_OK) {
|
if (char_status != ESP_GATT_OK) {
|
||||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_get_all_char error, status=%d", connection->get_connection_index(),
|
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_char error, status=%d", connection->get_connection_index(),
|
||||||
connection->address_str().c_str(), char_status);
|
connection->address_str().c_str(), char_status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +144,7 @@ void BluetoothProxy::loop() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (desc_status != ESP_GATT_OK) {
|
if (desc_status != ESP_GATT_OK) {
|
||||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_get_all_descr error, status=%d", connection->get_connection_index(),
|
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_descr error, status=%d", connection->get_connection_index(),
|
||||||
connection->address_str().c_str(), desc_status);
|
connection->address_str().c_str(), desc_status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -144,7 +162,6 @@ void BluetoothProxy::loop() {
|
||||||
}
|
}
|
||||||
resp.services.push_back(std::move(service_resp));
|
resp.services.push_back(std::move(service_resp));
|
||||||
api::global_api_server->send_bluetooth_gatt_services(resp);
|
api::global_api_server->send_bluetooth_gatt_services(resp);
|
||||||
connection->send_service_++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,6 +177,7 @@ BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool rese
|
||||||
|
|
||||||
for (auto *connection : this->connections_) {
|
for (auto *connection : this->connections_) {
|
||||||
if (connection->get_address() == 0) {
|
if (connection->get_address() == 0) {
|
||||||
|
connection->send_service_ = DONE_SENDING_SERVICES;
|
||||||
connection->set_address(address);
|
connection->set_address(address);
|
||||||
// All connections must start at INIT
|
// All connections must start at INIT
|
||||||
// We only set the state if we allocate the connection
|
// We only set the state if we allocate the connection
|
||||||
|
@ -332,12 +350,13 @@ void BluetoothProxy::bluetooth_gatt_send_services(const api::BluetoothGATTGetSer
|
||||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, 0, ESP_GATT_NOT_CONNECTED);
|
api::global_api_server->send_bluetooth_gatt_error(msg.address, 0, ESP_GATT_NOT_CONNECTED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (connection->services_.empty()) {
|
if (!connection->service_count_) {
|
||||||
ESP_LOGW(TAG, "[%d] [%s] No GATT services found", connection->connection_index_, connection->address_str().c_str());
|
ESP_LOGW(TAG, "[%d] [%s] No GATT services found", connection->connection_index_, connection->address_str().c_str());
|
||||||
api::global_api_server->send_bluetooth_gatt_services_done(msg.address);
|
api::global_api_server->send_bluetooth_gatt_services_done(msg.address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (connection->send_service_ == -1) // Don't start sending services again if we're already sending them
|
if (connection->send_service_ ==
|
||||||
|
DONE_SENDING_SERVICES) // Only start sending services if we're not already sending them
|
||||||
connection->send_service_ = 0;
|
connection->send_service_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,6 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
|
||||||
|
|
||||||
BluetoothConnection *get_connection_(uint64_t address, bool reserve);
|
BluetoothConnection *get_connection_(uint64_t address, bool reserve);
|
||||||
|
|
||||||
int16_t send_service_{-1};
|
|
||||||
bool active_;
|
bool active_;
|
||||||
|
|
||||||
std::vector<BluetoothConnection *> connections_{};
|
std::vector<BluetoothConnection *> connections_{};
|
||||||
|
|
|
@ -123,6 +123,7 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||||
case ESP_GATTC_OPEN_EVT: {
|
case ESP_GATTC_OPEN_EVT: {
|
||||||
ESP_LOGV(TAG, "[%d] [%s] ESP_GATTC_OPEN_EVT", this->connection_index_, this->address_str_.c_str());
|
ESP_LOGV(TAG, "[%d] [%s] ESP_GATTC_OPEN_EVT", this->connection_index_, this->address_str_.c_str());
|
||||||
this->conn_id_ = param->open.conn_id;
|
this->conn_id_ = param->open.conn_id;
|
||||||
|
this->service_count_ = 0;
|
||||||
if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) {
|
if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) {
|
||||||
ESP_LOGW(TAG, "[%d] [%s] Connection failed, status=%d", this->connection_index_, this->address_str_.c_str(),
|
ESP_LOGW(TAG, "[%d] [%s] Connection failed, status=%d", this->connection_index_, this->address_str_.c_str(),
|
||||||
param->open.status);
|
param->open.status);
|
||||||
|
@ -164,6 +165,12 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ESP_GATTC_SEARCH_RES_EVT: {
|
case ESP_GATTC_SEARCH_RES_EVT: {
|
||||||
|
this->service_count_++;
|
||||||
|
if (this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
|
||||||
|
// V3 clients don't need services initialized since
|
||||||
|
// they only request by handle after receiving the services.
|
||||||
|
break;
|
||||||
|
}
|
||||||
BLEService *ble_service = new BLEService(); // NOLINT(cppcoreguidelines-owning-memory)
|
BLEService *ble_service = new BLEService(); // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
ble_service->uuid = espbt::ESPBTUUID::from_uuid(param->search_res.srvc_id.uuid);
|
ble_service->uuid = espbt::ESPBTUUID::from_uuid(param->search_res.srvc_id.uuid);
|
||||||
ble_service->start_handle = param->search_res.start_handle;
|
ble_service->start_handle = param->search_res.start_handle;
|
||||||
|
|
|
@ -84,6 +84,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
|
||||||
uint64_t address_{0};
|
uint64_t address_{0};
|
||||||
std::string address_str_{};
|
std::string address_str_{};
|
||||||
uint8_t connection_index_;
|
uint8_t connection_index_;
|
||||||
|
int16_t service_count_{0};
|
||||||
uint16_t mtu_{23};
|
uint16_t mtu_{23};
|
||||||
espbt::ConnectionType connection_type_{espbt::ConnectionType::V1};
|
espbt::ConnectionType connection_type_{espbt::ConnectionType::V1};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue