18static const char *
const TAG =
"ble_device_base";
22static constexpr size_t BLE_ADV_MAX_LOG_BYTES = 62;
52 for (
int i = 0; i < 16; i++)
63 if (parsed.has_value()) {
70 if (parsed.has_value()) {
77 memcpy(ret.
uuid_.
uuid128,
reinterpret_cast<const uint8_t *
>(data), 16);
82 for (
size_t i = 0; i <
length; i += 2) {
85 uint8_t msb = data[i];
86 uint8_t lsb = data[i + 1];
91 ret.
uuid_.
uuid128[15 - n++] = ((msb & 0x0F) << 4) | (lsb & 0x0F);
94 ESP_LOGE(TAG,
"ERROR: UUID value not 4, 8, 16 or 36 bytes - %s", data);
101 if (uuid.len == ESP_UUID_LEN_16)
103 if (uuid.len == ESP_UUID_LEN_32)
110 switch (this->
type_) {
112 ret.len = ESP_UUID_LEN_16;
113 ret.uuid.uuid16 = this->
uuid_.uuid16;
116 ret.len = ESP_UUID_LEN_32;
117 ret.uuid.uuid32 = this->
uuid_.uuid32;
121 ret.len = ESP_UUID_LEN_128;
122 memcpy(ret.uuid.uuid128, this->uuid_.uuid128, ESP_UUID_LEN_128);
133 uint8_t mac_lsb_first[6];
134 for (uint8_t i = 0; i < 6; i++)
135 mac_lsb_first[i] = scan_result.bda[5 - i];
136 this->
from_scan_result(mac_lsb_first, scan_result.rssi, scan_result.ble_addr_type, scan_result.ble_adv,
137 scan_result.adv_data_len + scan_result.scan_rsp_len);
151 switch (this->
type_) {
153 return (this->
uuid_.uuid16 >> 8) == data2 && (this->
uuid_.uuid16 & 0xFF) == data1;
155 for (uint8_t i = 0; i < 3; i++) {
156 bool a = ((this->
uuid_.uuid32 >> i * 8) & 0xFF) == data1;
157 bool b = ((this->
uuid_.uuid32 >> (i + 1) * 8) & 0xFF) == data2;
163 for (uint8_t i = 0; i < 15; i++) {
164 if (this->
uuid_.uuid128[i] == data1 && this->uuid_.uuid128[i + 1] == data2)
175 switch (this->
type_) {
188 for (
int shift = 28; shift >= 0; shift -= 4)
195 for (int8_t i = 15; i >= 0; i--) {
196 uint8_t
byte = this->
uuid_.uuid128[i];
199 if (i == 12 || i == 10 || i == 8 || i == 6)
210 static const uint8_t BASE[16] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
211 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
213 memcpy(out, this->
uuid_.uuid128, 16);
216 memcpy(out, BASE, 16);
219 for (
size_t i = 0; i <
len; i++)
220 out[12 + i] = (value >> (i * 8)) & 0xFF;
225 switch (this->
type_) {
241 return memcmp(a, b, 16) == 0;
256 if (!data.uuid.contains(0x4C, 0x00))
258 if (data.data.size() != 23)
271 for (uint8_t i = 0; i < 6; i++)
284#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
285 ESP_LOGVV(TAG,
"Parse Result:");
286 const char *address_type;
288 case BLE_ADDR_TYPE_PUBLIC:
289 address_type =
"PUBLIC";
291 case BLE_ADDR_TYPE_RANDOM:
292 address_type =
"RANDOM";
294 case BLE_ADDR_TYPE_RPA_PUBLIC:
295 address_type =
"RPA_PUBLIC";
297 case BLE_ADDR_TYPE_RPA_RANDOM:
298 address_type =
"RPA_RANDOM";
301 address_type =
"UNKNOWN";
305 ESP_LOGVV(TAG,
" Address: %s (%s)", this->
address_str_to(addr_buf), address_type);
306 ESP_LOGVV(TAG,
" RSSI: %d", this->
rssi_);
307 ESP_LOGVV(TAG,
" Name: '%s'", this->
name_.c_str());
309 ESP_LOGVV(TAG,
" TX Power: %d", it);
312 ESP_LOGVV(TAG,
" Appearance: %u", *this->
appearance_);
315 ESP_LOGVV(TAG,
" Ad Flag: %u", *this->
ad_flag_);
317 char uuid_buf[UUID_STR_LEN];
319 ESP_LOGVV(TAG,
" Service UUID: %s", uuid.to_str(uuid_buf));
324 if (ibeacon.has_value()) {
325 ESP_LOGVV(TAG,
" Manufacturer iBeacon:");
326 ESP_LOGVV(TAG,
" UUID: %s", ibeacon.value().get_uuid().to_str(uuid_buf));
327 ESP_LOGVV(TAG,
" Major: %u", ibeacon.value().get_major());
328 ESP_LOGVV(TAG,
" Minor: %u", ibeacon.value().get_minor());
329 ESP_LOGVV(TAG,
" TXPower: %d", ibeacon.value().get_signal_power());
331 ESP_LOGVV(TAG,
" Manufacturer ID: %s, data: %s", mfg_data.uuid.to_str(uuid_buf),
336 ESP_LOGVV(TAG,
" Service data:");
337 ESP_LOGVV(TAG,
" UUID: %s", svc_data.uuid.to_str(uuid_buf));
338 ESP_LOGVV(TAG,
" Data: %s",
format_hex_pretty_to(hex_buf, svc_data.data.data(), svc_data.data.size()));
358 for (
int i = 0; i < 6; i++)
359 addr |=
static_cast<uint64_t
>(this->
address_[i]) << ((5 - i) * 8);
364#ifdef USE_BLE_DEVICE_IRK
370 uint8_t ecb_plaintext[16] = {0};
371 uint8_t ecb_ciphertext[16];
373 ecb_plaintext[13] = (addr64 >> 40) & 0xff;
374 ecb_plaintext[14] = (addr64 >> 32) & 0xff;
375 ecb_plaintext[15] = (addr64 >> 24) & 0xff;
377 return ecb_ciphertext[15] == (addr64 & 0xff) && ecb_ciphertext[14] == ((addr64 >> 8) & 0xff) &&
378 ecb_ciphertext[13] == ((addr64 >> 16) & 0xff);
390 while (offset <
len) {
391 uint8_t ad_len = payload[offset++];
394 if (offset + ad_len >
len)
396 uint8_t ad_type = payload[offset];
397 const uint8_t *ad_data = &payload[offset + 1];
398 uint8_t ad_data_len = ad_len - 1;
403 if (ad_data_len >= 1)
412 if (ad_data_len > this->
name_.length())
413 this->
name_.assign(
reinterpret_cast<const char *
>(ad_data), ad_data_len);
417 if (ad_data_len >= 1)
418 this->
tx_powers_.push_back(
static_cast<int8_t
>(ad_data[0]));
422 if (ad_data_len >= 2)
423 this->
appearance_ =
static_cast<uint16_t
>(ad_data[0]) | (
static_cast<uint16_t
>(ad_data[1]) << 8);
428 for (uint8_t i = 0; (i + 1) < ad_data_len; i += 2) {
429 uint16_t uuid = (
static_cast<uint16_t
>(ad_data[i + 1]) << 8) | ad_data[i];
436 for (uint8_t i = 0; (i + 3) < ad_data_len; i += 4) {
438 (
static_cast<uint32_t>(ad_data[i + 2]) << 16) | (
static_cast<uint32_t>(ad_data[i + 1]) << 8) |
446 for (uint8_t i = 0; (i + 15) < ad_data_len; i += 16)
451 if (ad_data_len >= 2) {
452 uint16_t company_id = (
static_cast<uint16_t
>(ad_data[1]) << 8) | ad_data[0];
455 sd.
data.assign(ad_data + 2, ad_data + ad_data_len);
461 if (ad_data_len >= 2) {
462 uint16_t uuid = (
static_cast<uint16_t
>(ad_data[1]) << 8) | ad_data[0];
465 sd.
data.assign(ad_data + 2, ad_data + ad_data_len);
471 if (ad_data_len >= 4) {
473 (
static_cast<uint32_t>(ad_data[1]) << 8) | ad_data[0];
476 sd.
data.assign(ad_data + 4, ad_data + ad_data_len);
482 if (ad_data_len >= 16) {
485 sd.
data.assign(ad_data + 16, ad_data + ad_data_len);
struct PACKED esphome::ble_device_base::ESPBLEiBeacon::BeaconData beacon_data_
static optional< ESPBLEiBeacon > from_manufacturer_data(const ServiceData &data)
const char * address_str_to(char *buf) const
Buffer overload: writes "XX:XX:XX:XX:XX:XX\0" into buf (>= 18 bytes), returns buf.
void parse_scan_rst(const esp32_ble::BLEScanResult &scan_result)
Historical esp32 ingest (esp32 builds only): parse an ESP-IDF scan result.
std::vector< ESPBTUUID > service_uuids_
std::vector< int8_t > tx_powers_
optional< uint16_t > appearance_
void from_scan_result(const uint8_t *mac, int rssi, uint8_t addr_type, const uint8_t *data, uint16_t data_len)
Populate from a raw scan result delivered by a BLE tracker backend.
static constexpr size_t MAC_ADDRESS_PRETTY_BUFFER_SIZE
void parse_adv_(const uint8_t *payload, uint16_t len)
std::vector< ServiceData > service_datas_
const esp32_ble::BLEScanResult * scan_result_
std::vector< ServiceData > manufacturer_datas_
std::string address_str() const
Return MAC as "XX:XX:XX:XX:XX:XX" string.
uint64_t address_uint64() const
Return MAC as packed uint64 (byte 0 in LSB — matches esp32's address_uint64).
bool resolve_irk(const uint8_t *irk) const
Resolve a Resolvable Private Address against a 16-byte IRK (Bluetooth "ah" function,...
optional< uint8_t > ad_flag_
static ESPBTUUID from_uuid(esp_bt_uuid_t uuid)
Source compatibility with the historical esp32_ble API (esp32 builds only).
static ESPBTUUID from_uint16(uint16_t uuid)
static ESPBTUUID from_raw(const uint8_t *data)
Construct from raw 16-byte little-endian UUID.
bool contains(uint8_t data1, uint8_t data2) const
True if the UUID value contains the adjacent byte pair (data1, data2).
void to_128bit_(uint8_t out[16]) const
esp_bt_uuid_t get_uuid() const
static ESPBTUUID from_raw_reversed(const uint8_t *data)
Construct from raw 16-byte big-endian UUID (reversed on store).
union esphome::ble_device_base::ESPBTUUID::@21 uuid_
static ESPBTUUID from_uint32(uint32_t uuid)
ESPBTUUID as_128bit() const
Expand to the 128-bit Bluetooth Base UUID form.
bool operator==(const ESPBTUUID &other) const
const char * to_str(char *buf) const
Write "0xABCD" / "0xABCDEF01" / the dashed 128-bit form into buf (>= UUID_STR_LEN bytes) and return b...
void aes128_encrypt_block(const uint8_t key[16], const uint8_t in[16], uint8_t out[16])
AES-128 single-block encrypt (the same software cipher CCM uses).
ESPHOME_ALWAYS_INLINE char format_hex_pretty_char(uint8_t v)
Convert a nibble (0-15) to uppercase hex char (used for pretty printing)
size_t parse_hex(const char *str, size_t length, uint8_t *data, size_t count)
Parse bytes from a hex-encoded string into a byte array.
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
char * format_mac_addr_upper(const uint8_t *mac, char *output)
Format MAC address as XX:XX:XX:XX:XX:XX (uppercase, colon separators)