Skip to content

Commit

Permalink
Active BLE connection v3 (esphome#4113)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Cousens <[email protected]>
Co-authored-by: Maurice Makaay <[email protected]>
Co-authored-by: Jesse Hills <[email protected]>
  • Loading branch information
4 people authored Nov 29, 2022
1 parent ccef7c3 commit 8414bb9
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 1 deletion.
2 changes: 2 additions & 0 deletions esphome/components/api/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,8 @@ enum BluetoothDeviceRequestType {
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1;
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2;
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4;
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5;
}

message BluetoothDeviceRequest {
Expand Down
2 changes: 1 addition & 1 deletion esphome/components/api/api_connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
resp.webserver_port = USE_WEBSERVER_PORT;
#endif
#ifdef USE_BLUETOOTH_PROXY
resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 2 : 1;
resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 3 : 1;
#endif
return resp;
}
Expand Down
6 changes: 6 additions & 0 deletions esphome/components/api/api_pb2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
namespace esphome {
namespace api {

#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::EntityCategory value) {
switch (value) {
case enums::ENTITY_CATEGORY_NONE:
Expand Down Expand Up @@ -351,10 +352,15 @@ const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::Bluet
return "BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE";
default:
return "UNKNOWN";
}
}
#endif
bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 2: {
Expand Down
2 changes: 2 additions & 0 deletions esphome/components/api/api_pb2.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ enum BluetoothDeviceRequestType : uint32_t {
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2,
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3,
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4,
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5,
};

} // namespace enums
Expand Down
4 changes: 4 additions & 0 deletions esphome/components/bluetooth_proxy/bluetooth_connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
this->set_address(0);
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
this->proxy_->get_bluetooth_connections_limit());
} else if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE) {
api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
this->proxy_->get_bluetooth_connections_limit());
}
this->seen_mtu_or_services_ = false;
break;
Expand Down
38 changes: 38 additions & 0 deletions esphome/components/bluetooth_proxy/bluetooth_proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ void BluetoothProxy::loop() {
if (connection->send_service_ == connection->services_.size()) {
connection->send_service_ = -1;
api::global_api_server->send_bluetooth_gatt_services_done(connection->get_address());
if (connection->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
connection->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
connection->release_services();
}
} else if (connection->send_service_ >= 0) {
auto &service = connection->services_[connection->send_service_];
api::BluetoothGATTGetServicesResponse resp;
Expand Down Expand Up @@ -171,6 +175,8 @@ BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool rese

void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest &msg) {
switch (msg.request_type) {
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE:
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE:
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: {
auto *connection = this->get_connection_(msg.address, true);
if (connection == nullptr) {
Expand All @@ -186,11 +192,43 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
this->get_bluetooth_connections_limit());
return;
} else if (connection->state() == espbt::ClientState::SEARCHING) {
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already searching for device",
connection->get_connection_index(), connection->address_str().c_str());
return;
} else if (connection->state() == espbt::ClientState::DISCOVERED) {
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device already discovered",
connection->get_connection_index(), connection->address_str().c_str());
return;
} else if (connection->state() == espbt::ClientState::READY_TO_CONNECT) {
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, waiting in line to connect",
connection->get_connection_index(), connection->address_str().c_str());
return;
} else if (connection->state() == espbt::ClientState::CONNECTING) {
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already connecting", connection->get_connection_index(),
connection->address_str().c_str());
return;
} else if (connection->state() == espbt::ClientState::DISCONNECTING) {
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device is disconnecting",
connection->get_connection_index(), connection->address_str().c_str());
return;
} else if (connection->state() != espbt::ClientState::INIT) {
ESP_LOGW(TAG, "[%d] [%s] Connection already in progress", connection->get_connection_index(),
connection->address_str().c_str());
return;
}
if (msg.request_type == api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE) {
connection->set_connection_type(espbt::ConnectionType::V3_WITH_CACHE);
ESP_LOGI(TAG, "[%d] [%s] Connecting v3 with cache", connection->get_connection_index(),
connection->address_str().c_str());
} else if (msg.request_type == api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE) {
connection->set_connection_type(espbt::ConnectionType::V3_WITHOUT_CACHE);
ESP_LOGI(TAG, "[%d] [%s] Connecting v3 without cache", connection->get_connection_index(),
connection->address_str().c_str());
} else {
connection->set_connection_type(espbt::ConnectionType::V1);
ESP_LOGI(TAG, "[%d] [%s] Connecting v1", connection->get_connection_index(), connection->address_str().c_str());
}
if (msg.has_address_type) {
connection->remote_bda_[0] = (msg.address >> 40) & 0xFF;
connection->remote_bda_[1] = (msg.address >> 32) & 0xFF;
Expand Down
11 changes: 11 additions & 0 deletions esphome/components/esp32_ble_client/ble_client_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
this->set_state(espbt::ClientState::IDLE);
break;
}
if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE) {
this->set_state(espbt::ClientState::CONNECTED);
this->state_ = espbt::ClientState::ESTABLISHED;
break;
}
auto ret = esp_ble_gattc_send_mtu_req(this->gattc_if_, param->open.conn_id);
if (ret) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_send_mtu_req failed, status=%x", this->connection_index_,
Expand Down Expand Up @@ -180,6 +185,12 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
break;
}
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
// Client is responsible for flipping the descriptor value
// when using the cache
break;
}
esp_gattc_descr_elem_t desc_result;
uint16_t count = 1;
esp_gatt_status_t descr_status =
Expand Down
3 changes: 3 additions & 0 deletions esphome/components/esp32_ble_client/ble_client_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {

uint8_t get_connection_index() const { return this->connection_index_; }

virtual void set_connection_type(espbt::ConnectionType ct) { this->connection_type_ = ct; }

protected:
int gattc_if_;
esp_bd_addr_t remote_bda_;
Expand All @@ -83,6 +85,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
std::string address_str_{};
uint8_t connection_index_;
uint16_t mtu_{23};
espbt::ConnectionType connection_type_{espbt::ConnectionType::V1};

std::vector<BLEService *> services_;
};
Expand Down
12 changes: 12 additions & 0 deletions esphome/components/esp32_ble_tracker/esp32_ble_tracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,18 @@ enum class ClientState {
ESTABLISHED,
};

enum class ConnectionType {
// The default connection type, we hold all the services in ram
// for the duration of the connection.
V1,
// The client has a cache of the services and mtu so we should not
// fetch them again
V3_WITH_CACHE,
// The client does not need the services and mtu once we send them
// so we should wipe them from memory as soon as we send them
V3_WITHOUT_CACHE
};

class ESPBTClient : public ESPBTDeviceListener {
public:
virtual bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
Expand Down

0 comments on commit 8414bb9

Please sign in to comment.