1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-28 21:53:48 +00:00

Bluetooth Proxy: Raw bundled advertisements (#4924)

This commit is contained in:
Jesse Hills
2023-06-09 07:41:09 +12:00
committed by GitHub
parent 1cf210fa25
commit ce13979690
16 changed files with 450 additions and 235 deletions

View File

@@ -206,7 +206,8 @@ message DeviceInfoResponse {
uint32 webserver_port = 10;
uint32 bluetooth_proxy_version = 11;
uint32 legacy_bluetooth_proxy_version = 11;
uint32 bluetooth_proxy_feature_flags = 15;
string manufacturer = 12;
@@ -1130,6 +1131,8 @@ message SubscribeBluetoothLEAdvertisementsRequest {
option (id) = 66;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint32 flags = 1;
}
message BluetoothServiceData {
@@ -1154,6 +1157,23 @@ message BluetoothLEAdvertisementResponse {
uint32 address_type = 7;
}
message BluetoothLERawAdvertisement {
uint64 address = 1;
sint32 rssi = 2;
uint32 address_type = 3;
bytes data = 4;
}
message BluetoothLERawAdvertisementsResponse {
option (id) = 93;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
option (no_delay) = true;
repeated BluetoothLERawAdvertisement advertisements = 1;
}
enum BluetoothDeviceRequestType {
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0;
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1;

View File

@@ -51,6 +51,14 @@ void APIConnection::start() {
helper_->set_log_info(client_info_);
}
APIConnection::~APIConnection() {
#ifdef USE_BLUETOOTH_PROXY
if (bluetooth_proxy::global_bluetooth_proxy->get_api_connection() == this) {
bluetooth_proxy::global_bluetooth_proxy->unsubscribe_api_connection(this);
}
#endif
}
void APIConnection::loop() {
if (this->remove_)
return;
@@ -845,9 +853,13 @@ void APIConnection::on_get_time_response(const GetTimeResponse &value) {
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIConnection::subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) {
bluetooth_proxy::global_bluetooth_proxy->subscribe_api_connection(this, msg.flags);
}
void APIConnection::unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) {
bluetooth_proxy::global_bluetooth_proxy->unsubscribe_api_connection(this);
}
bool APIConnection::send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg) {
if (!this->bluetooth_le_advertisement_subscription_)
return false;
if (this->client_api_version_major_ < 1 || this->client_api_version_minor_ < 7) {
BluetoothLEAdvertisementResponse resp = msg;
for (auto &service : resp.service_data) {
@@ -943,7 +955,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) {
HelloResponse resp;
resp.api_version_major = 1;
resp.api_version_minor = 8;
resp.api_version_minor = 9;
resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
resp.name = App.get_name();
@@ -995,9 +1007,8 @@ 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()
? bluetooth_proxy::ACTIVE_CONNECTIONS_VERSION
: bluetooth_proxy::PASSIVE_ONLY_VERSION;
resp.legacy_bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->get_legacy_version();
resp.bluetooth_proxy_feature_flags = bluetooth_proxy::global_bluetooth_proxy->get_feature_flags();
#endif
#ifdef USE_VOICE_ASSISTANT
resp.voice_assistant_version = voice_assistant::global_voice_assistant->get_version();

View File

@@ -16,7 +16,7 @@ namespace api {
class APIConnection : public APIServerConnection {
public:
APIConnection(std::unique_ptr<socket::Socket> socket, APIServer *parent);
virtual ~APIConnection() = default;
virtual ~APIConnection();
void start();
void loop();
@@ -98,12 +98,8 @@ class APIConnection : public APIServerConnection {
this->send_homeassistant_service_response(call);
}
#ifdef USE_BLUETOOTH_PROXY
void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override {
this->bluetooth_le_advertisement_subscription_ = true;
}
void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override {
this->bluetooth_le_advertisement_subscription_ = false;
}
void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override;
void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override;
bool send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg);
void bluetooth_device_request(const BluetoothDeviceRequest &msg) override;
@@ -211,9 +207,6 @@ class APIConnection : public APIServerConnection {
uint32_t last_traffic_;
bool sent_ping_{false};
bool service_call_subscription_{false};
#ifdef USE_BLUETOOTH_PROXY
bool bluetooth_le_advertisement_subscription_{false};
#endif
#ifdef USE_VOICE_ASSISTANT
bool voice_assistant_subscription_{false};
#endif

View File

@@ -617,7 +617,11 @@ bool DeviceInfoResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
return true;
}
case 11: {
this->bluetooth_proxy_version = value.as_uint32();
this->legacy_bluetooth_proxy_version = value.as_uint32();
return true;
}
case 15: {
this->bluetooth_proxy_feature_flags = value.as_uint32();
return true;
}
case 14: {
@@ -681,7 +685,8 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(8, this->project_name);
buffer.encode_string(9, this->project_version);
buffer.encode_uint32(10, this->webserver_port);
buffer.encode_uint32(11, this->bluetooth_proxy_version);
buffer.encode_uint32(11, this->legacy_bluetooth_proxy_version);
buffer.encode_uint32(15, this->bluetooth_proxy_feature_flags);
buffer.encode_string(12, this->manufacturer);
buffer.encode_string(13, this->friendly_name);
buffer.encode_uint32(14, this->voice_assistant_version);
@@ -731,8 +736,13 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
out.append(buffer);
out.append("\n");
out.append(" bluetooth_proxy_version: ");
sprintf(buffer, "%u", this->bluetooth_proxy_version);
out.append(" legacy_bluetooth_proxy_version: ");
sprintf(buffer, "%u", this->legacy_bluetooth_proxy_version);
out.append(buffer);
out.append("\n");
out.append(" bluetooth_proxy_feature_flags: ");
sprintf(buffer, "%u", this->bluetooth_proxy_feature_flags);
out.append(buffer);
out.append("\n");
@@ -5041,10 +5051,28 @@ void MediaPlayerCommandRequest::dump_to(std::string &out) const {
out.append("}");
}
#endif
void SubscribeBluetoothLEAdvertisementsRequest::encode(ProtoWriteBuffer buffer) const {}
bool SubscribeBluetoothLEAdvertisementsRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->flags = value.as_uint32();
return true;
}
default:
return false;
}
}
void SubscribeBluetoothLEAdvertisementsRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(1, this->flags);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void SubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const {
out.append("SubscribeBluetoothLEAdvertisementsRequest {}");
__attribute__((unused)) char buffer[64];
out.append("SubscribeBluetoothLEAdvertisementsRequest {\n");
out.append(" flags: ");
sprintf(buffer, "%u", this->flags);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool BluetoothServiceData::decode_varint(uint32_t field_id, ProtoVarInt value) {
@@ -5197,6 +5225,92 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const {
out.append("}");
}
#endif
bool BluetoothLERawAdvertisement::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->rssi = value.as_sint32();
return true;
}
case 3: {
this->address_type = value.as_uint32();
return true;
}
default:
return false;
}
}
bool BluetoothLERawAdvertisement::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 4: {
this->data = value.as_string();
return true;
}
default:
return false;
}
}
void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_sint32(2, this->rssi);
buffer.encode_uint32(3, this->address_type);
buffer.encode_string(4, this->data);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothLERawAdvertisement::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothLERawAdvertisement {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" rssi: ");
sprintf(buffer, "%d", this->rssi);
out.append(buffer);
out.append("\n");
out.append(" address_type: ");
sprintf(buffer, "%u", this->address_type);
out.append(buffer);
out.append("\n");
out.append(" data: ");
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
#endif
bool BluetoothLERawAdvertisementsResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
this->advertisements.push_back(value.as_message<BluetoothLERawAdvertisement>());
return true;
}
default:
return false;
}
}
void BluetoothLERawAdvertisementsResponse::encode(ProtoWriteBuffer buffer) const {
for (auto &it : this->advertisements) {
buffer.encode_message<BluetoothLERawAdvertisement>(1, it, true);
}
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothLERawAdvertisementsResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothLERawAdvertisementsResponse {\n");
for (const auto &it : this->advertisements) {
out.append(" advertisements: ");
it.dump_to(out);
out.append("\n");
}
out.append("}");
}
#endif
bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {

View File

@@ -287,7 +287,8 @@ class DeviceInfoResponse : public ProtoMessage {
std::string project_name{};
std::string project_version{};
uint32_t webserver_port{0};
uint32_t bluetooth_proxy_version{0};
uint32_t legacy_bluetooth_proxy_version{0};
uint32_t bluetooth_proxy_feature_flags{0};
std::string manufacturer{};
std::string friendly_name{};
uint32_t voice_assistant_version{0};
@@ -1247,12 +1248,14 @@ class MediaPlayerCommandRequest : public ProtoMessage {
};
class SubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage {
public:
uint32_t flags{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothServiceData : public ProtoMessage {
public:
@@ -1286,6 +1289,32 @@ class BluetoothLEAdvertisementResponse : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothLERawAdvertisement : public ProtoMessage {
public:
uint64_t address{0};
int32_t rssi{0};
uint32_t address_type{0};
std::string data{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothLERawAdvertisementsResponse : public ProtoMessage {
public:
std::vector<BluetoothLERawAdvertisement> advertisements{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
};
class BluetoothDeviceRequest : public ProtoMessage {
public:
uint64_t address{0};

View File

@@ -339,6 +339,15 @@ bool APIServerConnectionBase::send_bluetooth_le_advertisement_response(const Blu
}
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_le_raw_advertisements_response(
const BluetoothLERawAdvertisementsResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_le_raw_advertisements_response: %s", msg.dump().c_str());
#endif
return this->send_message_<BluetoothLERawAdvertisementsResponse>(msg, 93);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_device_connection_response(const BluetoothDeviceConnectionResponse &msg) {

View File

@@ -161,6 +161,9 @@ class APIServerConnectionBase : public ProtoService {
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_le_raw_advertisements_response(const BluetoothLERawAdvertisementsResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_bluetooth_device_request(const BluetoothDeviceRequest &value){};
#endif

View File

@@ -291,112 +291,7 @@ void APIServer::send_homeassistant_service_call(const HomeassistantServiceRespon
client->send_homeassistant_service_call(call);
}
}
#ifdef USE_BLUETOOTH_PROXY
void APIServer::send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &call) {
for (auto &client : this->clients_) {
client->send_bluetooth_le_advertisement(call);
}
}
void APIServer::send_bluetooth_device_connection(uint64_t address, bool connected, uint16_t mtu, esp_err_t error) {
BluetoothDeviceConnectionResponse call;
call.address = address;
call.connected = connected;
call.mtu = mtu;
call.error = error;
for (auto &client : this->clients_) {
client->send_bluetooth_device_connection_response(call);
}
}
void APIServer::send_bluetooth_device_pairing(uint64_t address, bool paired, esp_err_t error) {
BluetoothDevicePairingResponse call;
call.address = address;
call.paired = paired;
call.error = error;
for (auto &client : this->clients_) {
client->send_bluetooth_device_pairing_response(call);
}
}
void APIServer::send_bluetooth_device_unpairing(uint64_t address, bool success, esp_err_t error) {
BluetoothDeviceUnpairingResponse call;
call.address = address;
call.success = success;
call.error = error;
for (auto &client : this->clients_) {
client->send_bluetooth_device_unpairing_response(call);
}
}
void APIServer::send_bluetooth_device_clear_cache(uint64_t address, bool success, esp_err_t error) {
BluetoothDeviceClearCacheResponse call;
call.address = address;
call.success = success;
call.error = error;
for (auto &client : this->clients_) {
client->send_bluetooth_device_clear_cache_response(call);
}
}
void APIServer::send_bluetooth_connections_free(uint8_t free, uint8_t limit) {
BluetoothConnectionsFreeResponse call;
call.free = free;
call.limit = limit;
for (auto &client : this->clients_) {
client->send_bluetooth_connections_free_response(call);
}
}
void APIServer::send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &call) {
for (auto &client : this->clients_) {
client->send_bluetooth_gatt_read_response(call);
}
}
void APIServer::send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &call) {
for (auto &client : this->clients_) {
client->send_bluetooth_gatt_write_response(call);
}
}
void APIServer::send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &call) {
for (auto &client : this->clients_) {
client->send_bluetooth_gatt_notify_data_response(call);
}
}
void APIServer::send_bluetooth_gatt_notify_response(const BluetoothGATTNotifyResponse &call) {
for (auto &client : this->clients_) {
client->send_bluetooth_gatt_notify_response(call);
}
}
void APIServer::send_bluetooth_gatt_services(const BluetoothGATTGetServicesResponse &call) {
for (auto &client : this->clients_) {
client->send_bluetooth_gatt_get_services_response(call);
}
}
void APIServer::send_bluetooth_gatt_services_done(uint64_t address) {
BluetoothGATTGetServicesDoneResponse call;
call.address = address;
for (auto &client : this->clients_) {
client->send_bluetooth_gatt_get_services_done_response(call);
}
}
void APIServer::send_bluetooth_gatt_error(uint64_t address, uint16_t handle, esp_err_t error) {
BluetoothGATTErrorResponse call;
call.address = address;
call.handle = handle;
call.error = error;
for (auto &client : this->clients_) {
client->send_bluetooth_gatt_error_response(call);
}
}
#endif
APIServer::APIServer() { global_api_server = this; }
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f) {

View File

@@ -75,21 +75,6 @@ class APIServer : public Component, public Controller {
void on_media_player_update(media_player::MediaPlayer *obj) override;
#endif
void send_homeassistant_service_call(const HomeassistantServiceResponse &call);
#ifdef USE_BLUETOOTH_PROXY
void send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &call);
void send_bluetooth_device_connection(uint64_t address, bool connected, uint16_t mtu = 0, esp_err_t error = ESP_OK);
void send_bluetooth_device_pairing(uint64_t address, bool paired, esp_err_t error = ESP_OK);
void send_bluetooth_device_unpairing(uint64_t address, bool success, esp_err_t error = ESP_OK);
void send_bluetooth_device_clear_cache(uint64_t address, bool success, esp_err_t error = ESP_OK);
void send_bluetooth_connections_free(uint8_t free, uint8_t limit);
void send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &call);
void send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &call);
void send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &call);
void send_bluetooth_gatt_notify_response(const BluetoothGATTNotifyResponse &call);
void send_bluetooth_gatt_services(const BluetoothGATTGetServicesResponse &call);
void send_bluetooth_gatt_services_done(uint64_t address);
void send_bluetooth_gatt_error(uint64_t address, uint16_t handle, esp_err_t error);
#endif
void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
#ifdef USE_HOMEASSISTANT_TIME
void request_time();