mirror of
https://github.com/esphome/esphome.git
synced 2024-12-27 17:28:01 +01:00
Active BLE connection v3 (#4113)
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
ccef7c322f
commit
8414bb9a7a
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
@ -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: {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
@ -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) {
|
||||
@ -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;
|
||||
|
@ -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_,
|
||||
@ -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 =
|
||||
|
@ -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_;
|
||||
@ -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_;
|
||||
};
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user