ESPHome 2026.8.0b4
Loading...
Searching...
No Matches
ble_device.h
Go to the documentation of this file.
1// ble_device.h
2//
3// Platform-neutral BLE advertisement types — the generic base every BLE consumer
4// (sensor components, bluetooth_proxy, automation triggers) builds against:
5// ESPBTUUID / ServiceData / ESPBLEiBeacon / ESPBTDevice / ESPBTDeviceListener
6//
7// These types are owned here on EVERY platform, with no chip-SDK types in their
8// public surface. Platform trackers produce them:
9// - esp32_ble_tracker adapts ESP-IDF scan results into ESPBTDevice and
10// re-exports these names (esp32 only) for backward compatibility;
11// - the LibreTiny trackers (bk72xx / ln882h) feed from_scan_result() directly.
12
13#pragma once
14
18
19#include <cstdint>
20#include <cstring>
21#include <initializer_list>
22#include <string>
23#include <vector>
24
25#if defined(__cpp_lib_span)
26#include <span>
27#endif
28
29#ifdef USE_ESP32
30// Historical esp32_ble API surface (below, under the same define) uses the
31// ESP-IDF UUID/address/scan-result types directly; never referenced off-esp32.
33#include <esp_bt_defs.h>
34#endif
35
37
38using adv_data_t = std::vector<uint8_t>;
39
40// Bluetooth Core address types (spec values; matches ESP-IDF's esp_ble_addr_type_t).
41static constexpr uint8_t BLE_ADDR_TYPE_PUBLIC = 0;
42static constexpr uint8_t BLE_ADDR_TYPE_RANDOM = 1;
43static constexpr uint8_t BLE_ADDR_TYPE_RPA_PUBLIC = 2;
44static constexpr uint8_t BLE_ADDR_TYPE_RPA_RANDOM = 3;
45
47static constexpr size_t UUID_STR_LEN = 37;
48
49// ---------------------------------------------------------------------------
50// ESPBTUUID — 16/32/128-bit Bluetooth UUID value type.
51// API-compatible with the historical esp32_ble::ESPBTUUID; the esp_bt_uuid_t
52// conversions live in esp32_ble (esp32-only adapters), not here.
53// ---------------------------------------------------------------------------
54
55class ESPBTUUID {
56 public:
57 ESPBTUUID() = default;
58
59 static ESPBTUUID from_uint16(uint16_t uuid);
60 static ESPBTUUID from_uint32(uint32_t uuid);
62 static ESPBTUUID from_raw(const uint8_t *data);
64 static ESPBTUUID from_raw_reversed(const uint8_t *data);
67 static ESPBTUUID from_raw(const char *data, size_t length);
68 static ESPBTUUID from_raw(const char *data) { return from_raw(data, strlen(data)); }
69 static ESPBTUUID from_raw(const std::string &data) { return from_raw(data.c_str(), data.length()); }
70 static ESPBTUUID from_raw(std::initializer_list<uint8_t> data) {
71 return from_raw(reinterpret_cast<const char *>(data.begin()), data.size());
72 }
73
74#ifdef USE_ESP32
76 static ESPBTUUID from_uuid(esp_bt_uuid_t uuid);
77 esp_bt_uuid_t get_uuid() const;
78#endif
79
81 ESPBTUUID as_128bit() const;
82
84 bool contains(uint8_t data1, uint8_t data2) const;
85
86 bool operator==(const ESPBTUUID &other) const;
87 bool operator!=(const ESPBTUUID &other) const { return !(*this == other); }
88
91 const char *to_str(char *buf) const;
92#if defined(__cpp_lib_span)
93 const char *to_str(std::span<char, UUID_STR_LEN> output) const { return this->to_str(output.data()); }
94#endif
95 // UNSET is the default-constructed state; get_uuid() reports it as len 0 (the historical sentinel).
96 enum class Type : uint8_t { UNSET, UUID16, UUID32, UUID128 };
97 Type type() const { return this->type_; }
99 bool is_set() const { return this->type_ != Type::UNSET; }
100 uint16_t uuid16() const { return this->uuid_.uuid16; }
101 uint32_t uuid32() const { return this->uuid_.uuid32; }
102 const uint8_t *uuid128() const { return this->uuid_.uuid128; }
103
104 protected:
105 // Expand to the 128-bit Bluetooth Base UUID byte form (out is 16 bytes, little-endian).
106 void to_128bit_(uint8_t out[16]) const;
107
109 union {
110 uint16_t uuid16;
112 uint8_t uuid128[16];
113 } uuid_{};
114};
115
116// ---------------------------------------------------------------------------
117// ServiceData — UUID-tagged advertisement payload (0x16 / 0xFF AD types)
118// ---------------------------------------------------------------------------
119
124
125// ---------------------------------------------------------------------------
126// ESPBLEiBeacon
127// ---------------------------------------------------------------------------
128
130 public:
131 ESPBLEiBeacon() { memset(&this->beacon_data_, 0, sizeof(this->beacon_data_)); }
132 explicit ESPBLEiBeacon(const uint8_t *data);
138 static optional<ESPBLEiBeacon> from_manufacturer_data(const ServiceData &data, bool *prefix_rejected = nullptr);
139
140 uint16_t get_major() const { return byteswap(this->beacon_data_.major); }
141 uint16_t get_minor() const { return byteswap(this->beacon_data_.minor); }
142 int8_t get_signal_power() const { return this->beacon_data_.signal_power; }
144
145 protected:
146 struct PACKED BeaconData {
147 uint8_t sub_type;
148 uint8_t length;
149 uint8_t proximity_uuid[16];
150 uint16_t major;
151 uint16_t minor;
154};
155
160inline uint64_t mac_lsb_first_to_uint64(const uint8_t *mac) {
161 uint64_t addr = 0;
162 for (int i = 0; i < 6; i++)
163 addr |= static_cast<uint64_t>(mac[i]) << (i * 8);
164 return addr;
165}
166
169inline void uint64_to_mac_msb_first(uint64_t address, uint8_t out[6]) {
170 for (int i = 0; i < 6; i++)
171 out[i] = (address >> ((5 - i) * 8)) & 0xFF;
172}
173
174// ---------------------------------------------------------------------------
175// ESPBTDevice — parsed BLE advertisement
176// ---------------------------------------------------------------------------
177
179 public:
182 void from_scan_result(const uint8_t *mac, int rssi, uint8_t addr_type, const uint8_t *data, uint16_t data_len);
183
184 // Alias the core constant so the two cannot drift apart.
185 static constexpr size_t MAC_ADDRESS_PRETTY_BUFFER_SIZE = esphome::MAC_ADDRESS_PRETTY_BUFFER_SIZE;
186
188 ESPDEPRECATED("Use address_str_to() instead. Removed in 2027.2.0.", "2026.8.0")
189 std::string address_str() const;
191 const char *address_str_to(char *buf) const;
192#if defined(__cpp_lib_span)
193 const char *address_str_to(std::span<char, MAC_ADDRESS_PRETTY_BUFFER_SIZE> buf) const {
194 return this->address_str_to(buf.data());
195 }
196#endif
198 uint64_t address_uint64() const;
201 const uint8_t *address() const { return address_; }
202#ifdef USE_ESP32
203 // Historical esp32 signature: consumers assign the result to esp_ble_addr_type_t.
204 esp_ble_addr_type_t get_address_type() const { return static_cast<esp_ble_addr_type_t>(this->address_type_); }
208 void parse_scan_rst(const esp32_ble::BLEScanResult &scan_result);
209 // Exposed through a function for use in lambdas
210 const esp32_ble::BLEScanResult &get_scan_result() const { return *scan_result_; }
211#else
212 uint8_t get_address_type() const { return this->address_type_; }
213#endif
216 const char *address_type_str() const;
217
218 int get_rssi() const { return rssi_; }
221 StringRef get_name() const { return StringRef(this->name_, this->name_len_); }
222
223 const std::vector<ESPBTUUID> &get_service_uuids() const { return service_uuids_; }
224 const std::vector<ServiceData> &get_manufacturer_datas() const { return manufacturer_datas_; }
225 const std::vector<ServiceData> &get_service_datas() const { return service_datas_; }
226 const std::vector<int8_t> &get_tx_powers() const { return tx_powers_; }
227 const optional<uint16_t> &get_appearance() const { return appearance_; }
228 const optional<uint8_t> &get_ad_flag() const { return ad_flag_; }
229
233 bool resolve_irk(const uint8_t *irk) const;
234
235 optional<ESPBLEiBeacon> get_ibeacon() const;
236
237 protected:
238 void parse_adv_(const uint8_t *payload, uint16_t len);
239
240 // Max name bytes in a legacy advertisement AD element (31-byte PDU minus
241 // the 2-byte element header); every in-tree tracker scans legacy PDUs only.
242 static constexpr uint8_t MAX_ADV_NAME_LEN = 29;
243
244 uint8_t address_[MAC_ADDRESS_SIZE]{0};
245 uint8_t address_type_{0};
246 int rssi_{0};
247 // Fixed buffer instead of std::string: no per-advertisement heap churn on
248 // the scan path, and no libstdc++ string/exception machinery in the image.
250 uint8_t name_len_{0};
251 std::vector<ESPBTUUID> service_uuids_{};
252 std::vector<ServiceData> manufacturer_datas_{};
253 std::vector<ServiceData> service_datas_{};
254#ifdef USE_ESP32
255 const esp32_ble::BLEScanResult *scan_result_{nullptr};
256#endif
257 std::vector<int8_t> tx_powers_{};
258 optional<uint16_t> appearance_{};
259 optional<uint8_t> ad_flag_{};
260};
261
262// ---------------------------------------------------------------------------
263// DiscoveredDeviceLog — shared per-scan-period "Found device" DEBUG logger
264// ---------------------------------------------------------------------------
265
270 public:
272 void log_device(const char *tag, const ESPBTDevice &device);
274 void clear() { this->already_discovered_.clear(); }
275
276 protected:
277 std::vector<uint64_t> already_discovered_;
278};
279
280// ---------------------------------------------------------------------------
281// ESPBTDeviceListener — base class for BLE consumers (sensors, proxy, triggers)
282// ---------------------------------------------------------------------------
283
285 public:
286 virtual ~ESPBTDeviceListener() = default;
288 virtual void on_scan_end() {}
289 virtual bool parse_device(const ESPBTDevice &device) = 0;
290};
291
292} // namespace esphome::ble_device_base
uint8_t address
Definition bl0906.h:4
StringRef is a reference to a string owned by something else.
Definition string_ref.h:26
Per-scan-period "Found device" DEBUG logger, deduplicated by MAC address.
Definition ble_device.h:269
void clear()
Reset the per-period dedup list (call when a scan period ends).
Definition ble_device.h:274
void log_device(const char *tag, const ESPBTDevice &device)
Log the device at DEBUG the first time its MAC is seen this scan period.
static optional< ESPBLEiBeacon > from_manufacturer_data(const ServiceData &data, bool *prefix_rejected=nullptr)
prefix_rejected: caller must initialise to false; set to true ONLY when a 23-byte Apple frame was ref...
struct PACKED esphome::ble_device_base::ESPBLEiBeacon::BeaconData beacon_data_
ESPDEPRECATED("Use address_str_to() instead. Removed in 2027.2.0.", "2026.8.0") std const char * address_str_to(char *buf) const
Return MAC as "XX:XX:XX:XX:XX:XX" string.
void parse_scan_rst(const esp32_ble::BLEScanResult &scan_result)
Historical esp32 ingest (esp32 builds only): parse an ESP-IDF scan result.
const optional< uint8_t > & get_ad_flag() const
Definition ble_device.h:228
const std::vector< ESPBTUUID > & get_service_uuids() const
Definition ble_device.h:223
const uint8_t * address() const
Raw MAC bytes in printable (MSB-first) order — matches the historical esp32 layout (ESP-IDF bda order...
Definition ble_device.h:201
std::vector< ESPBTUUID > service_uuids_
Definition ble_device.h:251
const optional< uint16_t > & get_appearance() const
Definition ble_device.h:227
const std::vector< int8_t > & get_tx_powers() const
Definition ble_device.h:226
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
Definition ble_device.h:185
esp_ble_addr_type_t get_address_type() const
Definition ble_device.h:204
char name_[MAX_ADV_NAME_LEN+1]
Definition ble_device.h:249
void parse_adv_(const uint8_t *payload, uint16_t len)
std::vector< ServiceData > service_datas_
Definition ble_device.h:253
const esp32_ble::BLEScanResult * scan_result_
Definition ble_device.h:255
std::vector< ServiceData > manufacturer_datas_
Definition ble_device.h:252
const char * address_str_to(std::span< char, MAC_ADDRESS_PRETTY_BUFFER_SIZE > buf) const
Definition ble_device.h:193
optional< ESPBLEiBeacon > get_ibeacon() const
uint64_t address_uint64() const
Return MAC as packed uint64 (byte 0 in LSB — matches esp32's address_uint64).
const char * address_type_str() const
Human-readable address type ("PUBLIC", "RANDOM", "RPA_PUBLIC", "RPA_RANDOM" or "UNKNOWN"),...
const std::vector< ServiceData > & get_service_datas() const
Definition ble_device.h:225
const std::vector< ServiceData > & get_manufacturer_datas() const
Definition ble_device.h:224
uint8_t address_[MAC_ADDRESS_SIZE]
Definition ble_device.h:244
const esp32_ble::BLEScanResult & get_scan_result() const
Definition ble_device.h:210
static constexpr uint8_t MAX_ADV_NAME_LEN
Definition ble_device.h:242
StringRef get_name() const
Advertised name as a view into the fixed buffer (always NUL-terminated, so c_str() is safe); converts...
Definition ble_device.h:221
bool resolve_irk(const uint8_t *irk) const
Resolve a Resolvable Private Address against a 16-byte IRK (Bluetooth "ah" function,...
virtual void on_scan_end()
Called at the end of each scan duration period.
Definition ble_device.h:288
virtual bool parse_device(const ESPBTDevice &device)=0
static ESPBTUUID from_uuid(esp_bt_uuid_t uuid)
Source compatibility with the historical esp32_ble API (esp32 builds only).
const char * to_str(std::span< char, UUID_STR_LEN > output) const
Definition ble_device.h:93
static ESPBTUUID from_uint16(uint16_t uuid)
static ESPBTUUID from_raw(const char *data)
Definition ble_device.h:68
static ESPBTUUID from_raw(const std::string &data)
Definition ble_device.h:69
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
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_raw(std::initializer_list< uint8_t > data)
Definition ble_device.h:70
static ESPBTUUID from_uint32(uint32_t uuid)
bool operator!=(const ESPBTUUID &other) const
Definition ble_device.h:87
bool is_set() const
True if a UUID has been configured (not default-constructed).
Definition ble_device.h:99
ESPBTUUID as_128bit() const
Expand to the 128-bit Bluetooth Base UUID form.
const uint8_t * uuid128() const
Definition ble_device.h:102
bool operator==(const ESPBTUUID &other) const
const char * to_str(char *buf) const
Write "0xABCD" / "0xABCDEF01" / the dashed 128-bit form, or "None" for an unset UUID,...
std::vector< uint8_t > adv_data_t
Definition ble_device.h:38
uint64_t mac_lsb_first_to_uint64(const uint8_t *mac)
Pack a controller-order (LSB-first) MAC into the uint64 the API speaks.
Definition ble_device.h:160
void uint64_to_mac_msb_first(uint64_t address, uint8_t out[6])
Unpack a uint64 BLE address into printable (MSB-first) byte order — the order bd_addr_t / esp_bd_addr...
Definition ble_device.h:169
const char * tag
Definition log.h:74
ESPDEPRECATED("Use LightState::gamma_correct_lut() instead. Removed in 2026.9.0.", "2026.3.0") float gamma_correct(float value
Applies gamma correction of gamma to value.
const void size_t len
Definition hal.h:64
STL namespace.
static void uint32_t
void byteswap()
uint16_t length
Definition tt21100.cpp:0