mirror of
https://github.com/esphome/esphome.git
synced 2024-11-29 12:55:46 +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_DISCONNECT = 1;
|
||||||
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2;
|
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2;
|
||||||
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
|
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 {
|
message BluetoothDeviceRequest {
|
||||||
|
@ -950,7 +950,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
|
|||||||
resp.webserver_port = USE_WEBSERVER_PORT;
|
resp.webserver_port = USE_WEBSERVER_PORT;
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_BLUETOOTH_PROXY
|
#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
|
#endif
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::EntityCategory value) {
|
template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::EntityCategory value) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case enums::ENTITY_CATEGORY_NONE:
|
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";
|
return "BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR";
|
||||||
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR:
|
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR:
|
||||||
return "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:
|
default:
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||||
switch (field_id) {
|
switch (field_id) {
|
||||||
case 2: {
|
case 2: {
|
||||||
|
@ -160,6 +160,8 @@ enum BluetoothDeviceRequestType : uint32_t {
|
|||||||
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
|
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
|
||||||
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2,
|
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2,
|
||||||
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3,
|
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
|
} // namespace enums
|
||||||
|
@ -34,6 +34,10 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
|
|||||||
this->set_address(0);
|
this->set_address(0);
|
||||||
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
|
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
|
||||||
this->proxy_->get_bluetooth_connections_limit());
|
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;
|
this->seen_mtu_or_services_ = false;
|
||||||
break;
|
break;
|
||||||
|
@ -80,6 +80,10 @@ void BluetoothProxy::loop() {
|
|||||||
if (connection->send_service_ == connection->services_.size()) {
|
if (connection->send_service_ == connection->services_.size()) {
|
||||||
connection->send_service_ = -1;
|
connection->send_service_ = -1;
|
||||||
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 ||
|
||||||
|
connection->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
|
||||||
|
connection->release_services();
|
||||||
|
}
|
||||||
} else if (connection->send_service_ >= 0) {
|
} else if (connection->send_service_ >= 0) {
|
||||||
auto &service = connection->services_[connection->send_service_];
|
auto &service = connection->services_[connection->send_service_];
|
||||||
api::BluetoothGATTGetServicesResponse resp;
|
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) {
|
void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest &msg) {
|
||||||
switch (msg.request_type) {
|
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: {
|
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: {
|
||||||
auto *connection = this->get_connection_(msg.address, true);
|
auto *connection = this->get_connection_(msg.address, true);
|
||||||
if (connection == nullptr) {
|
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(),
|
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
|
||||||
this->get_bluetooth_connections_limit());
|
this->get_bluetooth_connections_limit());
|
||||||
return;
|
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) {
|
} else if (connection->state() != espbt::ClientState::INIT) {
|
||||||
ESP_LOGW(TAG, "[%d] [%s] Connection already in progress", connection->get_connection_index(),
|
ESP_LOGW(TAG, "[%d] [%s] Connection already in progress", connection->get_connection_index(),
|
||||||
connection->address_str().c_str());
|
connection->address_str().c_str());
|
||||||
return;
|
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) {
|
if (msg.has_address_type) {
|
||||||
connection->remote_bda_[0] = (msg.address >> 40) & 0xFF;
|
connection->remote_bda_[0] = (msg.address >> 40) & 0xFF;
|
||||||
connection->remote_bda_[1] = (msg.address >> 32) & 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);
|
this->set_state(espbt::ClientState::IDLE);
|
||||||
break;
|
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);
|
auto ret = esp_ble_gattc_send_mtu_req(this->gattc_if_, param->open.conn_id);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_send_mtu_req failed, status=%x", this->connection_index_,
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
|
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;
|
esp_gattc_descr_elem_t desc_result;
|
||||||
uint16_t count = 1;
|
uint16_t count = 1;
|
||||||
esp_gatt_status_t descr_status =
|
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_; }
|
uint8_t get_connection_index() const { return this->connection_index_; }
|
||||||
|
|
||||||
|
virtual void set_connection_type(espbt::ConnectionType ct) { this->connection_type_ = ct; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int gattc_if_;
|
int gattc_if_;
|
||||||
esp_bd_addr_t remote_bda_;
|
esp_bd_addr_t remote_bda_;
|
||||||
@ -83,6 +85,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
|
|||||||
std::string address_str_{};
|
std::string address_str_{};
|
||||||
uint8_t connection_index_;
|
uint8_t connection_index_;
|
||||||
uint16_t mtu_{23};
|
uint16_t mtu_{23};
|
||||||
|
espbt::ConnectionType connection_type_{espbt::ConnectionType::V1};
|
||||||
|
|
||||||
std::vector<BLEService *> services_;
|
std::vector<BLEService *> services_;
|
||||||
};
|
};
|
||||||
|
@ -165,6 +165,18 @@ enum class ClientState {
|
|||||||
ESTABLISHED,
|
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 {
|
class ESPBTClient : public ESPBTDeviceListener {
|
||||||
public:
|
public:
|
||||||
virtual bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
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