mirror of
https://github.com/esphome/esphome.git
synced 2026-08-17 10:52:56 +08:00
[ble_device_base] [ble_client] Restore unset UUID state so notify sensors set up again (#18098)
This commit is contained in:
@@ -61,7 +61,7 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
break;
|
||||
}
|
||||
this->handle = chr->handle;
|
||||
if (this->descr_uuid_.get_uuid().len > 0) {
|
||||
if (this->descr_uuid_.is_set()) {
|
||||
auto *descr = chr->get_descriptor(this->descr_uuid_);
|
||||
if (descr == nullptr) {
|
||||
this->status_set_warning();
|
||||
|
||||
@@ -61,7 +61,7 @@ void BLETextSensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
break;
|
||||
}
|
||||
this->handle = chr->handle;
|
||||
if (this->descr_uuid_.get_uuid().len > 0) {
|
||||
if (this->descr_uuid_.is_set()) {
|
||||
auto *descr = chr->get_descriptor(this->descr_uuid_);
|
||||
if (descr == nullptr) {
|
||||
this->status_set_warning();
|
||||
|
||||
@@ -98,6 +98,8 @@ ESPBTUUID ESPBTUUID::from_raw(const char *data, size_t length) {
|
||||
|
||||
#ifdef USE_ESP32
|
||||
ESPBTUUID ESPBTUUID::from_uuid(esp_bt_uuid_t uuid) {
|
||||
if (uuid.len == 0) // the unset sentinel get_uuid() emits
|
||||
return {};
|
||||
if (uuid.len == ESP_UUID_LEN_16)
|
||||
return ESPBTUUID::from_uint16(uuid.uuid.uuid16);
|
||||
if (uuid.len == ESP_UUID_LEN_32)
|
||||
@@ -108,6 +110,10 @@ ESPBTUUID ESPBTUUID::from_uuid(esp_bt_uuid_t uuid) {
|
||||
esp_bt_uuid_t ESPBTUUID::get_uuid() const {
|
||||
esp_bt_uuid_t ret;
|
||||
switch (this->type_) {
|
||||
case Type::UNSET:
|
||||
ret.len = 0;
|
||||
memset(&ret.uuid, 0, sizeof(ret.uuid));
|
||||
break;
|
||||
case Type::UUID16:
|
||||
ret.len = ESP_UUID_LEN_16;
|
||||
ret.uuid.uuid16 = this->uuid_.uuid16;
|
||||
@@ -139,7 +145,8 @@ void ESPBTDevice::parse_scan_rst(const esp32_ble::BLEScanResult &scan_result) {
|
||||
#endif // USE_ESP32
|
||||
|
||||
ESPBTUUID ESPBTUUID::as_128bit() const {
|
||||
if (this->type_ == Type::UUID128)
|
||||
// Widening an unset UUID stays unset; expanding it would produce a set 0x0000 base UUID.
|
||||
if (this->type_ == Type::UNSET || this->type_ == Type::UUID128)
|
||||
return *this;
|
||||
uint8_t data[16];
|
||||
this->to_128bit_(data);
|
||||
@@ -149,6 +156,8 @@ ESPBTUUID ESPBTUUID::as_128bit() const {
|
||||
bool ESPBTUUID::contains(uint8_t data1, uint8_t data2) const {
|
||||
// Adjacent byte-pair search — identical semantics to esp32_ble::ESPBTUUID::contains.
|
||||
switch (this->type_) {
|
||||
case Type::UNSET:
|
||||
return false;
|
||||
case Type::UUID16:
|
||||
return (this->uuid_.uuid16 >> 8) == data2 && (this->uuid_.uuid16 & 0xFF) == data1;
|
||||
case Type::UUID32:
|
||||
@@ -173,6 +182,9 @@ const char *ESPBTUUID::to_str(char *buf) const {
|
||||
// Identical output format to esp32_ble::ESPBTUUID::to_str.
|
||||
char *pos = buf;
|
||||
switch (this->type_) {
|
||||
case Type::UNSET:
|
||||
memcpy(buf, "None", 5);
|
||||
return buf;
|
||||
case Type::UUID16:
|
||||
*pos++ = '0';
|
||||
*pos++ = 'x';
|
||||
@@ -207,6 +219,7 @@ const char *ESPBTUUID::to_str(char *buf) const {
|
||||
void ESPBTUUID::to_128bit_(uint8_t out[16]) const {
|
||||
// Bluetooth Base UUID 00000000-0000-1000-8000-00805F9B34FB (LSB-first), with the 16/32-bit
|
||||
// value placed at bytes 12..; identical expansion to esp32_ble::ESPBTUUID::as_128bit().
|
||||
// Callers screen out UNSET first (operator==, as_128bit); it would expand like 0x0000.
|
||||
static const uint8_t BASE[16] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
|
||||
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
if (this->type_ == Type::UUID128) {
|
||||
@@ -223,6 +236,8 @@ void ESPBTUUID::to_128bit_(uint8_t out[16]) const {
|
||||
bool ESPBTUUID::operator==(const ESPBTUUID &other) const {
|
||||
if (this->type_ == other.type_) {
|
||||
switch (this->type_) {
|
||||
case Type::UNSET:
|
||||
return true;
|
||||
case Type::UUID16:
|
||||
return this->uuid_.uuid16 == other.uuid_.uuid16;
|
||||
case Type::UUID32:
|
||||
@@ -232,6 +247,9 @@ bool ESPBTUUID::operator==(const ESPBTUUID &other) const {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Unset never equals a set UUID; 0x0000 is a valid value, distinct from "not configured".
|
||||
if (this->type_ == Type::UNSET || other.type_ == Type::UNSET)
|
||||
return false;
|
||||
// Different widths: expand both to the 128-bit Bluetooth Base UUID form and compare, so a
|
||||
// configured 16/32-bit UUID matches the equivalent 128-bit advertisement (esp32 parity).
|
||||
uint8_t a[16];
|
||||
|
||||
@@ -91,8 +91,11 @@ class ESPBTUUID {
|
||||
#if defined(__cpp_lib_span)
|
||||
const char *to_str(std::span<char, UUID_STR_LEN> output) const { return this->to_str(output.data()); }
|
||||
#endif
|
||||
enum class Type : uint8_t { UUID16, UUID32, UUID128 };
|
||||
// UNSET is the default-constructed state; get_uuid() reports it as len 0 (the historical sentinel).
|
||||
enum class Type : uint8_t { UNSET, UUID16, UUID32, UUID128 };
|
||||
Type type() const { return this->type_; }
|
||||
/// True if a UUID has been configured (not default-constructed).
|
||||
bool is_set() const { return this->type_ != Type::UNSET; }
|
||||
uint16_t uuid16() const { return this->uuid_.uuid16; }
|
||||
uint32_t uuid32() const { return this->uuid_.uuid32; }
|
||||
const uint8_t *uuid128() const { return this->uuid_.uuid128; }
|
||||
@@ -101,7 +104,7 @@ class ESPBTUUID {
|
||||
// Expand to the 128-bit Bluetooth Base UUID byte form (out is 16 bytes, little-endian).
|
||||
void to_128bit_(uint8_t out[16]) const;
|
||||
|
||||
Type type_{Type::UUID16};
|
||||
Type type_{Type::UNSET};
|
||||
union {
|
||||
uint16_t uuid16;
|
||||
uint32_t uuid32;
|
||||
|
||||
@@ -27,6 +27,60 @@ TEST(BleDeviceUuid, ThirtyTwoBitMatchesEquivalentLongForm) {
|
||||
EXPECT_TRUE(u32 == u128);
|
||||
}
|
||||
|
||||
// A default-constructed UUID is UNSET, the historical "not configured" sentinel
|
||||
// (len 0 through the esp32 get_uuid() adapter).
|
||||
TEST(BleDeviceUuid, DefaultConstructedIsUnset) {
|
||||
const ESPBTUUID unset;
|
||||
EXPECT_EQ(unset.type(), ESPBTUUID::Type::UNSET);
|
||||
EXPECT_TRUE(unset == ESPBTUUID());
|
||||
EXPECT_FALSE(unset == ESPBTUUID::from_uint16(0x1234));
|
||||
EXPECT_FALSE(unset.contains(0x00, 0x00));
|
||||
}
|
||||
|
||||
// Every factory yields a non-UNSET UUID, even for 0x0000: only default construction and a
|
||||
// failed text parse are unset, keeping type() != UNSET equivalent to the old len > 0 check.
|
||||
TEST(BleDeviceUuid, AllFactoriesProduceSetUuids) {
|
||||
const uint8_t raw[16] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
|
||||
0x00, 0x10, 0x00, 0x00, 0x34, 0x12, 0x00, 0x00};
|
||||
EXPECT_NE(ESPBTUUID::from_uint16(0x0000).type(), ESPBTUUID::Type::UNSET);
|
||||
EXPECT_NE(ESPBTUUID::from_uint32(0).type(), ESPBTUUID::Type::UNSET);
|
||||
EXPECT_NE(ESPBTUUID::from_raw(raw).type(), ESPBTUUID::Type::UNSET);
|
||||
EXPECT_NE(ESPBTUUID::from_raw_reversed(raw).type(), ESPBTUUID::Type::UNSET);
|
||||
EXPECT_NE(ESPBTUUID::from_raw("180F", 4).type(), ESPBTUUID::Type::UNSET);
|
||||
EXPECT_NE(ESPBTUUID::from_raw("0000180F", 8).type(), ESPBTUUID::Type::UNSET);
|
||||
EXPECT_NE(ESPBTUUID::from_raw(reinterpret_cast<const char *>(raw), 16).type(), ESPBTUUID::Type::UNSET);
|
||||
EXPECT_NE(ESPBTUUID::from_raw("6E400001-B5A3-F393-E0A9-E50E24DCCA9E").type(), ESPBTUUID::Type::UNSET);
|
||||
}
|
||||
|
||||
// 0x0000 is a valid short UUID on real devices (esphome/aioesphomeapi#1742); an unset
|
||||
// UUID must never compare equal to it. Unset equals only unset.
|
||||
TEST(BleDeviceUuid, UnsetIsNotEqualToZeroUuid) {
|
||||
EXPECT_FALSE(ESPBTUUID() == ESPBTUUID::from_uint16(0x0000));
|
||||
EXPECT_FALSE(ESPBTUUID::from_uint16(0x0000) == ESPBTUUID());
|
||||
const uint8_t base[16] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
|
||||
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
EXPECT_FALSE(ESPBTUUID() == ESPBTUUID::from_raw(base));
|
||||
EXPECT_TRUE(ESPBTUUID() == ESPBTUUID());
|
||||
EXPECT_FALSE(ESPBTUUID().as_128bit().is_set()); // widening preserves the unset state
|
||||
// A configured 0x0000 still matches its own 128-bit base UUID expansion.
|
||||
EXPECT_TRUE(ESPBTUUID::from_uint16(0x0000) == ESPBTUUID::from_raw(base));
|
||||
}
|
||||
|
||||
// is_set() is the sentinel check; an unset UUID prints as "None" instead of a
|
||||
// valid-looking all-zero 128-bit UUID.
|
||||
TEST(BleDeviceUuid, IsSetAndUnsetToStr) {
|
||||
char buf[UUID_STR_LEN];
|
||||
EXPECT_FALSE(ESPBTUUID().is_set());
|
||||
EXPECT_STREQ(ESPBTUUID().to_str(buf), "None");
|
||||
EXPECT_TRUE(ESPBTUUID::from_uint16(0x0000).is_set());
|
||||
EXPECT_STREQ(ESPBTUUID::from_uint16(0x0000).to_str(buf), "0x0000");
|
||||
}
|
||||
|
||||
// Text parsing of an invalid length historically produced a len-0 (unset) UUID.
|
||||
TEST(BleDeviceUuid, InvalidTextFormParsesToUnset) {
|
||||
EXPECT_EQ(ESPBTUUID::from_raw("nope", 3).type(), ESPBTUUID::Type::UNSET);
|
||||
}
|
||||
|
||||
TEST(BleDeviceUuid, DifferentUuidsDoNotMatch) {
|
||||
EXPECT_FALSE(ESPBTUUID::from_uint16(0x1234) == ESPBTUUID::from_uint16(0x1235));
|
||||
const uint8_t raw128[16] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
|
||||
|
||||
Reference in New Issue
Block a user