mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	[bluetooth_proxy] Optimize UUID transmission with efficient short_uuid field (#9995)
This commit is contained in:
		| @@ -1482,21 +1482,39 @@ message BluetoothGATTGetServicesRequest { | ||||
| } | ||||
|  | ||||
| message BluetoothGATTDescriptor { | ||||
|   repeated uint64 uuid = 1 [(fixed_array_size) = 2]; | ||||
|   repeated uint64 uuid = 1 [(fixed_array_size) = 2, (fixed_array_skip_zero) = true]; | ||||
|   uint32 handle = 2; | ||||
|  | ||||
|   // New field for efficient UUID (v1.12+) | ||||
|   // Only one of uuid or short_uuid will be set. | ||||
|   // short_uuid is used for both 16-bit and 32-bit UUIDs with v1.12+ clients. | ||||
|   // 128-bit UUIDs always use the uuid field for backwards compatibility. | ||||
|   uint32 short_uuid = 3;  // 16-bit or 32-bit UUID | ||||
| } | ||||
|  | ||||
| message BluetoothGATTCharacteristic { | ||||
|   repeated uint64 uuid = 1 [(fixed_array_size) = 2]; | ||||
|   repeated uint64 uuid = 1 [(fixed_array_size) = 2, (fixed_array_skip_zero) = true]; | ||||
|   uint32 handle = 2; | ||||
|   uint32 properties = 3; | ||||
|   repeated BluetoothGATTDescriptor descriptors = 4; | ||||
|  | ||||
|   // New field for efficient UUID (v1.12+) | ||||
|   // Only one of uuid or short_uuid will be set. | ||||
|   // short_uuid is used for both 16-bit and 32-bit UUIDs with v1.12+ clients. | ||||
|   // 128-bit UUIDs always use the uuid field for backwards compatibility. | ||||
|   uint32 short_uuid = 5;  // 16-bit or 32-bit UUID | ||||
| } | ||||
|  | ||||
| message BluetoothGATTService { | ||||
|   repeated uint64 uuid = 1 [(fixed_array_size) = 2]; | ||||
|   repeated uint64 uuid = 1 [(fixed_array_size) = 2, (fixed_array_skip_zero) = true]; | ||||
|   uint32 handle = 2; | ||||
|   repeated BluetoothGATTCharacteristic characteristics = 3; | ||||
|  | ||||
|   // New field for efficient UUID (v1.12+) | ||||
|   // Only one of uuid or short_uuid will be set. | ||||
|   // short_uuid is used for both 16-bit and 32-bit UUIDs with v1.12+ clients. | ||||
|   // 128-bit UUIDs always use the uuid field for backwards compatibility. | ||||
|   uint32 short_uuid = 4;  // 16-bit or 32-bit UUID | ||||
| } | ||||
|  | ||||
| message BluetoothGATTGetServicesResponse { | ||||
|   | ||||
| @@ -1363,7 +1363,7 @@ bool APIConnection::send_hello_response(const HelloRequest &msg) { | ||||
|  | ||||
|   HelloResponse resp; | ||||
|   resp.api_version_major = 1; | ||||
|   resp.api_version_minor = 11; | ||||
|   resp.api_version_minor = 12; | ||||
|   // Temporary string for concatenation - will be valid during send_message call | ||||
|   std::string server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")"; | ||||
|   resp.set_server_info(StringRef(server_info)); | ||||
|   | ||||
| @@ -235,6 +235,13 @@ class APIConnection : public APIServerConnection { | ||||
|            this->is_authenticated(); | ||||
|   } | ||||
|   uint8_t get_log_subscription_level() const { return this->flags_.log_subscription; } | ||||
|  | ||||
|   // Get client API version for feature detection | ||||
|   bool client_supports_api_version(uint16_t major, uint16_t minor) const { | ||||
|     return this->client_api_version_major_ > major || | ||||
|            (this->client_api_version_major_ == major && this->client_api_version_minor_ >= minor); | ||||
|   } | ||||
|  | ||||
|   void on_fatal_error() override; | ||||
| #ifdef USE_API_PASSWORD | ||||
|   void on_unauthenticated_access() override; | ||||
|   | ||||
| @@ -28,6 +28,7 @@ extend google.protobuf.FieldOptions { | ||||
|     optional string field_ifdef = 1042; | ||||
|     optional uint32 fixed_array_size = 50007; | ||||
|     optional bool no_zero_copy = 50008 [default=false]; | ||||
|     optional bool fixed_array_skip_zero = 50009 [default=false]; | ||||
|  | ||||
|     // container_pointer: Zero-copy optimization for repeated fields. | ||||
|     // | ||||
|   | ||||
| @@ -1888,44 +1888,62 @@ bool BluetoothGATTGetServicesRequest::decode_varint(uint32_t field_id, ProtoVarI | ||||
|   return true; | ||||
| } | ||||
| void BluetoothGATTDescriptor::encode(ProtoWriteBuffer buffer) const { | ||||
|   buffer.encode_uint64(1, this->uuid[0], true); | ||||
|   buffer.encode_uint64(1, this->uuid[1], true); | ||||
|   if (this->uuid[0] != 0 || this->uuid[1] != 0) { | ||||
|     buffer.encode_uint64(1, this->uuid[0], true); | ||||
|     buffer.encode_uint64(1, this->uuid[1], true); | ||||
|   } | ||||
|   buffer.encode_uint32(2, this->handle); | ||||
|   buffer.encode_uint32(3, this->short_uuid); | ||||
| } | ||||
| void BluetoothGATTDescriptor::calculate_size(ProtoSize &size) const { | ||||
|   size.add_uint64_force(1, this->uuid[0]); | ||||
|   size.add_uint64_force(1, this->uuid[1]); | ||||
|   if (this->uuid[0] != 0 || this->uuid[1] != 0) { | ||||
|     size.add_uint64_force(1, this->uuid[0]); | ||||
|     size.add_uint64_force(1, this->uuid[1]); | ||||
|   } | ||||
|   size.add_uint32(1, this->handle); | ||||
|   size.add_uint32(1, this->short_uuid); | ||||
| } | ||||
| void BluetoothGATTCharacteristic::encode(ProtoWriteBuffer buffer) const { | ||||
|   buffer.encode_uint64(1, this->uuid[0], true); | ||||
|   buffer.encode_uint64(1, this->uuid[1], true); | ||||
|   if (this->uuid[0] != 0 || this->uuid[1] != 0) { | ||||
|     buffer.encode_uint64(1, this->uuid[0], true); | ||||
|     buffer.encode_uint64(1, this->uuid[1], true); | ||||
|   } | ||||
|   buffer.encode_uint32(2, this->handle); | ||||
|   buffer.encode_uint32(3, this->properties); | ||||
|   for (auto &it : this->descriptors) { | ||||
|     buffer.encode_message(4, it, true); | ||||
|   } | ||||
|   buffer.encode_uint32(5, this->short_uuid); | ||||
| } | ||||
| void BluetoothGATTCharacteristic::calculate_size(ProtoSize &size) const { | ||||
|   size.add_uint64_force(1, this->uuid[0]); | ||||
|   size.add_uint64_force(1, this->uuid[1]); | ||||
|   if (this->uuid[0] != 0 || this->uuid[1] != 0) { | ||||
|     size.add_uint64_force(1, this->uuid[0]); | ||||
|     size.add_uint64_force(1, this->uuid[1]); | ||||
|   } | ||||
|   size.add_uint32(1, this->handle); | ||||
|   size.add_uint32(1, this->properties); | ||||
|   size.add_repeated_message(1, this->descriptors); | ||||
|   size.add_uint32(1, this->short_uuid); | ||||
| } | ||||
| void BluetoothGATTService::encode(ProtoWriteBuffer buffer) const { | ||||
|   buffer.encode_uint64(1, this->uuid[0], true); | ||||
|   buffer.encode_uint64(1, this->uuid[1], true); | ||||
|   if (this->uuid[0] != 0 || this->uuid[1] != 0) { | ||||
|     buffer.encode_uint64(1, this->uuid[0], true); | ||||
|     buffer.encode_uint64(1, this->uuid[1], true); | ||||
|   } | ||||
|   buffer.encode_uint32(2, this->handle); | ||||
|   for (auto &it : this->characteristics) { | ||||
|     buffer.encode_message(3, it, true); | ||||
|   } | ||||
|   buffer.encode_uint32(4, this->short_uuid); | ||||
| } | ||||
| void BluetoothGATTService::calculate_size(ProtoSize &size) const { | ||||
|   size.add_uint64_force(1, this->uuid[0]); | ||||
|   size.add_uint64_force(1, this->uuid[1]); | ||||
|   if (this->uuid[0] != 0 || this->uuid[1] != 0) { | ||||
|     size.add_uint64_force(1, this->uuid[0]); | ||||
|     size.add_uint64_force(1, this->uuid[1]); | ||||
|   } | ||||
|   size.add_uint32(1, this->handle); | ||||
|   size.add_repeated_message(1, this->characteristics); | ||||
|   size.add_uint32(1, this->short_uuid); | ||||
| } | ||||
| void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer buffer) const { | ||||
|   buffer.encode_uint64(1, this->address); | ||||
|   | ||||
| @@ -1857,6 +1857,7 @@ class BluetoothGATTDescriptor : public ProtoMessage { | ||||
|  public: | ||||
|   std::array<uint64_t, 2> uuid{}; | ||||
|   uint32_t handle{0}; | ||||
|   uint32_t short_uuid{0}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
|   void calculate_size(ProtoSize &size) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
| @@ -1871,6 +1872,7 @@ class BluetoothGATTCharacteristic : public ProtoMessage { | ||||
|   uint32_t handle{0}; | ||||
|   uint32_t properties{0}; | ||||
|   std::vector<BluetoothGATTDescriptor> descriptors{}; | ||||
|   uint32_t short_uuid{0}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
|   void calculate_size(ProtoSize &size) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
| @@ -1884,6 +1886,7 @@ class BluetoothGATTService : public ProtoMessage { | ||||
|   std::array<uint64_t, 2> uuid{}; | ||||
|   uint32_t handle{0}; | ||||
|   std::vector<BluetoothGATTCharacteristic> characteristics{}; | ||||
|   uint32_t short_uuid{0}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
|   void calculate_size(ProtoSize &size) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   | ||||
| @@ -1561,6 +1561,7 @@ void BluetoothGATTDescriptor::dump_to(std::string &out) const { | ||||
|     dump_field(out, "uuid", it, 4); | ||||
|   } | ||||
|   dump_field(out, "handle", this->handle); | ||||
|   dump_field(out, "short_uuid", this->short_uuid); | ||||
| } | ||||
| void BluetoothGATTCharacteristic::dump_to(std::string &out) const { | ||||
|   MessageDumpHelper helper(out, "BluetoothGATTCharacteristic"); | ||||
| @@ -1574,6 +1575,7 @@ void BluetoothGATTCharacteristic::dump_to(std::string &out) const { | ||||
|     it.dump_to(out); | ||||
|     out.append("\n"); | ||||
|   } | ||||
|   dump_field(out, "short_uuid", this->short_uuid); | ||||
| } | ||||
| void BluetoothGATTService::dump_to(std::string &out) const { | ||||
|   MessageDumpHelper helper(out, "BluetoothGATTService"); | ||||
| @@ -1586,6 +1588,7 @@ void BluetoothGATTService::dump_to(std::string &out) const { | ||||
|     it.dump_to(out); | ||||
|     out.append("\n"); | ||||
|   } | ||||
|   dump_field(out, "short_uuid", this->short_uuid); | ||||
| } | ||||
| void BluetoothGATTGetServicesResponse::dump_to(std::string &out) const { | ||||
|   MessageDumpHelper helper(out, "BluetoothGATTGetServicesResponse"); | ||||
|   | ||||
| @@ -24,6 +24,24 @@ static void fill_128bit_uuid_array(std::array<uint64_t, 2> &out, esp_bt_uuid_t u | ||||
|            ((uint64_t) uuid.uuid.uuid128[1] << 8) | ((uint64_t) uuid.uuid.uuid128[0]); | ||||
| } | ||||
|  | ||||
| // Helper to fill UUID in the appropriate format based on client support and UUID type | ||||
| static void fill_gatt_uuid(std::array<uint64_t, 2> &uuid_128, uint32_t &short_uuid, const esp_bt_uuid_t &uuid, | ||||
|                            bool use_efficient_uuids) { | ||||
|   if (!use_efficient_uuids || uuid.len == ESP_UUID_LEN_128) { | ||||
|     // Use 128-bit format for old clients or when UUID is already 128-bit | ||||
|     fill_128bit_uuid_array(uuid_128, uuid); | ||||
|   } else if (uuid.len == ESP_UUID_LEN_16) { | ||||
|     short_uuid = uuid.uuid.uuid16; | ||||
|   } else if (uuid.len == ESP_UUID_LEN_32) { | ||||
|     short_uuid = uuid.uuid.uuid32; | ||||
|   } | ||||
| } | ||||
|  | ||||
| bool BluetoothConnection::supports_efficient_uuids_() const { | ||||
|   auto *api_conn = this->proxy_->get_api_connection(); | ||||
|   return api_conn && api_conn->client_supports_api_version(1, 12); | ||||
| } | ||||
|  | ||||
| void BluetoothConnection::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "BLE Connection:"); | ||||
|   BLEClientBase::dump_config(); | ||||
| @@ -74,6 +92,9 @@ void BluetoothConnection::send_service_for_discovery_() { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // Check if client supports efficient UUIDs | ||||
|   bool use_efficient_uuids = this->supports_efficient_uuids_(); | ||||
|  | ||||
|   // Prepare response for up to 3 services | ||||
|   api::BluetoothGATTGetServicesResponse resp; | ||||
|   resp.address = this->address_; | ||||
| @@ -100,7 +121,9 @@ void BluetoothConnection::send_service_for_discovery_() { | ||||
|     this->send_service_++; | ||||
|     resp.services.emplace_back(); | ||||
|     auto &service_resp = resp.services.back(); | ||||
|     fill_128bit_uuid_array(service_resp.uuid, service_result.uuid); | ||||
|  | ||||
|     fill_gatt_uuid(service_resp.uuid, service_resp.short_uuid, service_result.uuid, use_efficient_uuids); | ||||
|  | ||||
|     service_resp.handle = service_result.start_handle; | ||||
|  | ||||
|     // Get the number of characteristics directly with one call | ||||
| @@ -145,7 +168,9 @@ void BluetoothConnection::send_service_for_discovery_() { | ||||
|  | ||||
|       service_resp.characteristics.emplace_back(); | ||||
|       auto &characteristic_resp = service_resp.characteristics.back(); | ||||
|       fill_128bit_uuid_array(characteristic_resp.uuid, char_result.uuid); | ||||
|  | ||||
|       fill_gatt_uuid(characteristic_resp.uuid, characteristic_resp.short_uuid, char_result.uuid, use_efficient_uuids); | ||||
|  | ||||
|       characteristic_resp.handle = char_result.char_handle; | ||||
|       characteristic_resp.properties = char_result.properties; | ||||
|       char_offset++; | ||||
| @@ -189,7 +214,9 @@ void BluetoothConnection::send_service_for_discovery_() { | ||||
|  | ||||
|         characteristic_resp.descriptors.emplace_back(); | ||||
|         auto &descriptor_resp = characteristic_resp.descriptors.back(); | ||||
|         fill_128bit_uuid_array(descriptor_resp.uuid, desc_result.uuid); | ||||
|  | ||||
|         fill_gatt_uuid(descriptor_resp.uuid, descriptor_resp.short_uuid, desc_result.uuid, use_efficient_uuids); | ||||
|  | ||||
|         descriptor_resp.handle = desc_result.handle; | ||||
|         desc_offset++; | ||||
|       } | ||||
|   | ||||
| @@ -27,6 +27,7 @@ class BluetoothConnection : public esp32_ble_client::BLEClientBase { | ||||
|  protected: | ||||
|   friend class BluetoothProxy; | ||||
|  | ||||
|   bool supports_efficient_uuids_() const; | ||||
|   void send_service_for_discovery_(); | ||||
|   void reset_connection_(esp_err_t reason); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user