From 03bf2de7df3eacf011bc8fce61d3ff10f470a333 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 18 Oct 2026 13:59:19 -1000 Subject: [PATCH] [components] Decode BLE fields with the shared helpers (#21082) --- .../airthings_ble/airthings_listener.cpp | 6 ++---- .../atc_mithermometer/atc_mithermometer.cpp | 5 +++-- esphome/components/b_parasite/b_parasite.cpp | 13 +++++++------ esphome/components/ble_device_base/ble_device.cpp | 15 ++++++--------- .../bluetooth_connection/bluetooth_connection.h | 7 +++---- .../bthome_mithermometer/bthome_ble.cpp | 4 ++-- .../esp32_ble_client/ble_client_base.cpp | 7 +++---- .../pvvx_mithermometer/pvvx_mithermometer.cpp | 7 ++++--- esphome/components/ruuvi_ble/ruuvi_ble.cpp | 15 ++++++++------- .../components/thermopro_ble/thermopro_ble.cpp | 8 ++++---- esphome/components/xiaomi_ble/xiaomi_ble.cpp | 8 ++++---- .../xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp | 2 +- .../components/xiaomi_miscale/xiaomi_miscale.cpp | 7 ++++--- 13 files changed, 51 insertions(+), 53 deletions(-) diff --git a/esphome/components/airthings_ble/airthings_listener.cpp b/esphome/components/airthings_ble/airthings_listener.cpp index 5f0e2eb3ecf..c0762cb4c83 100644 --- a/esphome/components/airthings_ble/airthings_listener.cpp +++ b/esphome/components/airthings_ble/airthings_listener.cpp @@ -1,4 +1,5 @@ #include "airthings_listener.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include @@ -12,10 +13,7 @@ bool AirthingsListener::parse_device(const ble_device_base::ESPBTDevice &device) if (it.data.size() < 4) continue; - uint32_t sn = it.data[0]; - sn |= ((uint32_t) it.data[1] << 8); - sn |= ((uint32_t) it.data[2] << 16); - sn |= ((uint32_t) it.data[3] << 24); + uint32_t sn = encode_value_le(it.data.data()); char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE]; ESP_LOGD(TAG, "Found AirThings device Serial:%" PRIu32 " (MAC: %s)", sn, device.address_str_to(addr_buf)); diff --git a/esphome/components/atc_mithermometer/atc_mithermometer.cpp b/esphome/components/atc_mithermometer/atc_mithermometer.cpp index 95b482c8404..a495cb9dd2e 100644 --- a/esphome/components/atc_mithermometer/atc_mithermometer.cpp +++ b/esphome/components/atc_mithermometer/atc_mithermometer.cpp @@ -1,4 +1,5 @@ #include "atc_mithermometer.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome::atc_mithermometer { @@ -89,7 +90,7 @@ bool ATCMiThermometer::parse_message_(const std::vector &message, Parse } // temperature, 2 bytes, 16-bit signed integer (LE), 0.1 °C - const int16_t temperature = uint16_t(data[7]) | (uint16_t(data[6]) << 8); + const int16_t temperature = encode_value(&data[6]); result.temperature = temperature / 10.0f; // humidity, 1 byte, 8-bit unsigned integer, 1.0 % @@ -99,7 +100,7 @@ bool ATCMiThermometer::parse_message_(const std::vector &message, Parse result.battery_level = data[9]; // battery, 2 bytes, 16-bit unsigned integer, 0.001 V - const int16_t battery_voltage = uint16_t(data[11]) | (uint16_t(data[10]) << 8); + const int16_t battery_voltage = encode_value(&data[10]); result.battery_voltage = battery_voltage / 1.0e3f; return true; diff --git a/esphome/components/b_parasite/b_parasite.cpp b/esphome/components/b_parasite/b_parasite.cpp index 8bed59b3dbc..972d938c47b 100644 --- a/esphome/components/b_parasite/b_parasite.cpp +++ b/esphome/components/b_parasite/b_parasite.cpp @@ -1,4 +1,5 @@ #include "b_parasite.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome::b_parasite { @@ -62,29 +63,29 @@ bool BParasite::parse_device(const ble_device_base::ESPBTDevice &device) { } // Battery voltage in millivolts. - uint16_t battery_millivolt = data[2] << 8 | data[3]; + uint16_t battery_millivolt = encode_value(&data[2]); float battery_voltage = battery_millivolt / 1000.0f; // Temperature in 1000 * Celsius (protocol v1) or 100 * Celsius (protocol v2). float temp_celsius; if (protocol_version == 1) { - uint16_t temp_millicelsius = data[4] << 8 | data[5]; + uint16_t temp_millicelsius = encode_value(&data[4]); temp_celsius = temp_millicelsius / 1000.0f; } else { - int16_t temp_centicelsius = data[4] << 8 | data[5]; + int16_t temp_centicelsius = encode_value(&data[4]); temp_celsius = temp_centicelsius / 100.0f; } // Relative air humidity in the range [0, 2^16). - uint16_t humidity = data[6] << 8 | data[7]; + uint16_t humidity = encode_value(&data[6]); float humidity_percent = (100.0f * humidity) / (1 << 16); // Relative soil moisture in [0 - 2^16). - uint16_t soil_moisture = data[8] << 8 | data[9]; + uint16_t soil_moisture = encode_value(&data[8]); float moisture_percent = (100.0f * soil_moisture) / (1 << 16); // Ambient light in lux. - float illuminance = has_illuminance ? data[16] << 8 | data[17] : 0.0f; + float illuminance = has_illuminance ? encode_value(&data[16]) : 0.0f; if (battery_voltage_ != nullptr) { battery_voltage_->publish_state(battery_voltage); diff --git a/esphome/components/ble_device_base/ble_device.cpp b/esphome/components/ble_device_base/ble_device.cpp index f7fa488aac7..1cb44c8ace7 100644 --- a/esphome/components/ble_device_base/ble_device.cpp +++ b/esphome/components/ble_device_base/ble_device.cpp @@ -493,13 +493,13 @@ void ESPBTDevice::parse_adv_(const uint8_t *payload, uint16_t len) { case 0x19: // Appearance if (ad_data_len >= 2) - this->appearance_ = static_cast(ad_data[0]) | (static_cast(ad_data[1]) << 8); + this->appearance_ = encode_value_le(ad_data); break; case 0x02: // Incomplete List of 16-bit Service UUIDs case 0x03: // Complete List of 16-bit Service UUIDs for (uint8_t i = 0; (i + 1) < ad_data_len; i += 2) { - uint16_t uuid = (static_cast(ad_data[i + 1]) << 8) | ad_data[i]; + uint16_t uuid = encode_value_le(&ad_data[i]); this->service_uuids_.push_back(ESPBTUUID::from_uint16(uuid)); } break; @@ -507,9 +507,7 @@ void ESPBTDevice::parse_adv_(const uint8_t *payload, uint16_t len) { case 0x04: // Incomplete List of 32-bit Service UUIDs case 0x05: // Complete List of 32-bit Service UUIDs for (uint8_t i = 0; (i + 3) < ad_data_len; i += 4) { - uint32_t uuid = (static_cast(ad_data[i + 3]) << 24) | - (static_cast(ad_data[i + 2]) << 16) | (static_cast(ad_data[i + 1]) << 8) | - ad_data[i]; + uint32_t uuid = encode_value_le(&ad_data[i]); this->service_uuids_.push_back(ESPBTUUID::from_uint32(uuid)); } break; @@ -522,7 +520,7 @@ void ESPBTDevice::parse_adv_(const uint8_t *payload, uint16_t len) { case 0xFF: // Manufacturer Specific Data if (ad_data_len >= 2) { - uint16_t company_id = (static_cast(ad_data[1]) << 8) | ad_data[0]; + uint16_t company_id = encode_value_le(ad_data); ServiceData sd; sd.uuid = ESPBTUUID::from_uint16(company_id); sd.data.assign(ad_data + 2, ad_data + ad_data_len); @@ -532,7 +530,7 @@ void ESPBTDevice::parse_adv_(const uint8_t *payload, uint16_t len) { case 0x16: // Service Data — 16-bit UUID if (ad_data_len >= 2) { - uint16_t uuid = (static_cast(ad_data[1]) << 8) | ad_data[0]; + uint16_t uuid = encode_value_le(ad_data); ServiceData sd; sd.uuid = ESPBTUUID::from_uint16(uuid); sd.data.assign(ad_data + 2, ad_data + ad_data_len); @@ -542,8 +540,7 @@ void ESPBTDevice::parse_adv_(const uint8_t *payload, uint16_t len) { case 0x20: // Service Data — 32-bit UUID if (ad_data_len >= 4) { - uint32_t uuid = (static_cast(ad_data[3]) << 24) | (static_cast(ad_data[2]) << 16) | - (static_cast(ad_data[1]) << 8) | ad_data[0]; + uint32_t uuid = encode_value_le(ad_data); ServiceData sd; sd.uuid = ESPBTUUID::from_uint32(uuid); sd.data.assign(ad_data + 4, ad_data + ad_data_len); diff --git a/esphome/components/bluetooth_connection/bluetooth_connection.h b/esphome/components/bluetooth_connection/bluetooth_connection.h index b21d997b4fc..176a73dc33d 100644 --- a/esphome/components/bluetooth_connection/bluetooth_connection.h +++ b/esphome/components/bluetooth_connection/bluetooth_connection.h @@ -4,6 +4,7 @@ #pragma once #include "esphome/core/defines.h" +#include "esphome/core/helpers.h" #include "esphome/components/ble_device_base/ble_client_state.h" #include "esphome/components/ble_device_base/ble_device.h" @@ -124,10 +125,8 @@ inline void fill_128bit_uuid_array(std::array &out, const ble_devic if (uuid.type() == ESPBTUUID::Type::UUID128) { const uint8_t *u = uuid.uuid128(); // out[0] = bytes 8-15 (big-endian), out[1] = bytes 0-7 (big-endian) - out[0] = ((uint64_t) u[15] << 56) | ((uint64_t) u[14] << 48) | ((uint64_t) u[13] << 40) | ((uint64_t) u[12] << 32) | - ((uint64_t) u[11] << 24) | ((uint64_t) u[10] << 16) | ((uint64_t) u[9] << 8) | ((uint64_t) u[8]); - out[1] = ((uint64_t) u[7] << 56) | ((uint64_t) u[6] << 48) | ((uint64_t) u[5] << 40) | ((uint64_t) u[4] << 32) | - ((uint64_t) u[3] << 24) | ((uint64_t) u[2] << 16) | ((uint64_t) u[1] << 8) | ((uint64_t) u[0]); + out[0] = encode_value_le(&u[8]); + out[1] = encode_value_le(u); return; } // 16/32-bit UUID inserted into the Bluetooth base UUID: diff --git a/esphome/components/bthome_mithermometer/bthome_ble.cpp b/esphome/components/bthome_mithermometer/bthome_ble.cpp index c055c430413..b37d2782d56 100644 --- a/esphome/components/bthome_mithermometer/bthome_ble.cpp +++ b/esphome/components/bthome_mithermometer/bthome_ble.cpp @@ -408,7 +408,7 @@ bool BTHomeMiThermometer::handle_service_data_(const ble_device_base::ServiceDat } case 0x02: { // temperature if (this->temperature_ != nullptr) { - const int16_t raw = encode_uint16(value[1], value[0]); + const int16_t raw = encode_value_le(value); this->temperature_->publish_state(raw * 0.01f); reported = true; } @@ -424,7 +424,7 @@ bool BTHomeMiThermometer::handle_service_data_(const ble_device_base::ServiceDat } case 0x45: { // temperature (0.1C), e.g. Shelly BLU H&T if (this->temperature_ != nullptr) { - const int16_t raw = encode_uint16(value[1], value[0]); + const int16_t raw = encode_value_le(value); this->temperature_->publish_state(raw * 0.1f); reported = true; } diff --git a/esphome/components/esp32_ble_client/ble_client_base.cpp b/esphome/components/esp32_ble_client/ble_client_base.cpp index 6905ef82228..e627d58fc81 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.cpp +++ b/esphome/components/esp32_ble_client/ble_client_base.cpp @@ -680,18 +680,17 @@ float BLEClientBase::parse_char_value(uint8_t *value, uint16_t length) { case 0xD: // int12. case 0xE: // int16. if (length > 2) { - return (float) ((int16_t) (value[1] << 8) + (int16_t) value[2]); + return (float) encode_value(&value[1]); } [[fallthrough]]; case 0xF: // int24. if (length > 3) { - return (float) ((int32_t) (value[1] << 16) + (int32_t) (value[2] << 8) + (int32_t) (value[3])); + return (float) encode_uint24(value[1], value[2], value[3]); } [[fallthrough]]; case 0x10: // int32. if (length > 4) { - return (float) ((int32_t) (value[1] << 24) + (int32_t) (value[2] << 16) + (int32_t) (value[3] << 8) + - (int32_t) (value[4])); + return (float) encode_value(&value[1]); } } ESP_LOGW(TAG, "[%d] [%s] Cannot parse characteristic value of type 0x%x length %d", this->connection_index_, diff --git a/esphome/components/pvvx_mithermometer/pvvx_mithermometer.cpp b/esphome/components/pvvx_mithermometer/pvvx_mithermometer.cpp index 0d7f440f15e..462d64f937d 100644 --- a/esphome/components/pvvx_mithermometer/pvvx_mithermometer.cpp +++ b/esphome/components/pvvx_mithermometer/pvvx_mithermometer.cpp @@ -1,4 +1,5 @@ #include "pvvx_mithermometer.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome::pvvx_mithermometer { @@ -96,15 +97,15 @@ bool PVVXMiThermometer::parse_message_(const std::vector &message, Pars } // int16_t temperature; // x 0.01 degree [6,7] - const int16_t temperature = int16_t(data[6]) | (int16_t(data[7]) << 8); + const int16_t temperature = encode_value_le(&data[6]); result.temperature = temperature / 1.0e2f; // uint16_t humidity; // x 0.01 % [8,9] - const int16_t humidity = uint16_t(data[8]) | (uint16_t(data[9]) << 8); + const int16_t humidity = encode_value_le(&data[8]); result.humidity = humidity / 1.0e2f; // uint16_t battery_mv; // mV [10,11] - const int16_t battery_voltage = uint16_t(data[10]) | (uint16_t(data[11]) << 8); + const int16_t battery_voltage = encode_value_le(&data[10]); result.battery_voltage = battery_voltage / 1.0e3f; // uint8_t battery_level; // 0..100 % [12] diff --git a/esphome/components/ruuvi_ble/ruuvi_ble.cpp b/esphome/components/ruuvi_ble/ruuvi_ble.cpp index c781e282fe7..415885cfe2b 100644 --- a/esphome/components/ruuvi_ble/ruuvi_ble.cpp +++ b/esphome/components/ruuvi_ble/ruuvi_ble.cpp @@ -1,4 +1,5 @@ #include "ruuvi_ble.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome::ruuvi_ble { @@ -19,9 +20,9 @@ bool parse_ruuvi_data_byte(const ble_device_base::adv_data_t &adv_data, RuuviPar const float humidity = data[0] * 0.5f; const float pressure = (encode_uint16(data[3], data[4]) + 50000.0f) / 100.0f; - const float acceleration_x = static_cast(encode_uint16(data[5], data[6])) / 1000.0f; - const float acceleration_y = static_cast(encode_uint16(data[7], data[8])) / 1000.0f; - const float acceleration_z = static_cast(encode_uint16(data[9], data[10])) / 1000.0f; + const float acceleration_x = encode_value(&data[5]) / 1000.0f; + const float acceleration_y = encode_value(&data[7]) / 1000.0f; + const float acceleration_z = encode_value(&data[9]) / 1000.0f; const float battery_voltage = encode_uint16(data[11], data[12]) / 1000.0f; result.humidity = humidity; @@ -40,12 +41,12 @@ bool parse_ruuvi_data_byte(const ble_device_base::adv_data_t &adv_data, RuuviPar if (adv_data.size() != 24) return false; - const float temperature = static_cast(encode_uint16(data[0], data[1])) * 0.005f; + const float temperature = encode_value(data) * 0.005f; const float humidity = encode_uint16(data[2], data[3]) / 400.0f; const float pressure = (encode_uint16(data[4], data[5]) + 50000.0f) / 100.0f; - const float acceleration_x = static_cast(encode_uint16(data[6], data[7])) / 1000.0f; - const float acceleration_y = static_cast(encode_uint16(data[8], data[9])) / 1000.0f; - const float acceleration_z = static_cast(encode_uint16(data[10], data[11])) / 1000.0f; + const float acceleration_x = encode_value(&data[6]) / 1000.0f; + const float acceleration_y = encode_value(&data[8]) / 1000.0f; + const float acceleration_z = encode_value(&data[10]) / 1000.0f; const uint16_t power_info = encode_uint16(data[12], data[13]); const float battery_voltage = ((power_info >> 5) + 1600.0f) / 1000.0f; diff --git a/esphome/components/thermopro_ble/thermopro_ble.cpp b/esphome/components/thermopro_ble/thermopro_ble.cpp index 38a58137aec..159e36e5554 100644 --- a/esphome/components/thermopro_ble/thermopro_ble.cpp +++ b/esphome/components/thermopro_ble/thermopro_ble.cpp @@ -1,5 +1,6 @@ #include "thermopro_ble.h" #include +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome::thermopro_ble { @@ -113,16 +114,15 @@ void ThermoProBLE::update_device_type_(StringRef device_name) { } static inline uint16_t read_uint16(const uint8_t *data, std::size_t offset) { - return static_cast(data[offset + 0]) | (static_cast(data[offset + 1]) << 8); + return encode_value_le(&data[offset]); } static inline int16_t read_int16(const uint8_t *data, std::size_t offset) { - return static_cast(read_uint16(data, offset)); + return encode_value_le(&data[offset]); } static inline uint32_t read_uint32(const uint8_t *data, std::size_t offset) { - return static_cast(data[offset + 0]) | (static_cast(data[offset + 1]) << 8) | - (static_cast(data[offset + 2]) << 16) | (static_cast(data[offset + 3]) << 24); + return encode_value_le(&data[offset]); } // Battery calculation used with permission from: diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.cpp b/esphome/components/xiaomi_ble/xiaomi_ble.cpp index 90ea5c32094..1f752f55b10 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.cpp +++ b/esphome/components/xiaomi_ble/xiaomi_ble.cpp @@ -38,12 +38,12 @@ bool parse_xiaomi_value(uint16_t value_type, const uint8_t *data, uint8_t value_ } // temperature, 2 bytes, 16-bit signed integer (LE), 0.1 °C else if ((value_type == 0x1004) && (value_length == 2)) { - const int16_t temperature = encode_uint16(data[1], data[0]); + const int16_t temperature = encode_value_le(data); result.temperature = temperature / 10.0f; } // humidity, 2 bytes, 16-bit signed integer (LE), 0.1 % else if ((value_type == 0x1006) && (value_length == 2)) { - const int16_t humidity = encode_uint16(data[1], data[0]); + const int16_t humidity = encode_value_le(data); result.humidity = humidity / 10.0f; } // illuminance (+ motion), 3 bytes, 24-bit unsigned integer (LE), 1 lx @@ -69,8 +69,8 @@ bool parse_xiaomi_value(uint16_t value_type, const uint8_t *data, uint8_t value_ } // temperature + humidity, 4 bytes, 16-bit signed integer (LE) each, 0.1 °C, 0.1 % else if ((value_type == 0x100D) && (value_length == 4)) { - const int16_t temperature = encode_uint16(data[1], data[0]); - const int16_t humidity = encode_uint16(data[3], data[2]); + const int16_t temperature = encode_value_le(data); + const int16_t humidity = encode_value_le(&data[2]); result.temperature = temperature / 10.0f; result.humidity = humidity / 10.0f; } diff --git a/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp b/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp index ac1541c386d..83ba611e6fb 100644 --- a/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp +++ b/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp @@ -35,7 +35,7 @@ bool XiaomiHHCCJCY10::parse_device(const ble_device_base::ESPBTDevice &device) { const uint8_t *data = service_data.data.data(); if (this->temperature_ != nullptr) { - const int16_t temperature = encode_uint16(data[1], data[2]); + const int16_t temperature = encode_value(&data[1]); this->temperature_->publish_state((float) temperature / 10.0f); } diff --git a/esphome/components/xiaomi_miscale/xiaomi_miscale.cpp b/esphome/components/xiaomi_miscale/xiaomi_miscale.cpp index 438b9b55298..7c44eccd411 100644 --- a/esphome/components/xiaomi_miscale/xiaomi_miscale.cpp +++ b/esphome/components/xiaomi_miscale/xiaomi_miscale.cpp @@ -1,5 +1,6 @@ #include "xiaomi_miscale.h" #include "esphome/components/ble_device_base/ble_device.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome::xiaomi_miscale { @@ -92,7 +93,7 @@ bool XiaomiMiscale::parse_message_v1_(const std::vector &message, Parse const uint8_t *data = message.data(); // weight, 2 bytes, 16-bit unsigned integer, 1 kg - const int16_t weight = uint16_t(data[1]) | (uint16_t(data[2]) << 8); + const int16_t weight = encode_value_le(&data[1]); if (data[0] == 0x22 || data[0] == 0xa2) { result.weight = weight * 0.01f / 2.0f; // unit 'kg' } else if (data[0] == 0x12 || data[0] == 0xb2) { @@ -126,7 +127,7 @@ bool XiaomiMiscale::parse_message_v2_(const std::vector &message, Parse } // weight, 2 bytes, 16-bit unsigned integer, 1 kg - const int16_t weight = uint16_t(data[11]) | (uint16_t(data[12]) << 8); + const int16_t weight = encode_value_le(&data[11]); if (data[0] == 0x02) { result.weight = weight * 0.01f / 2.0f; // unit 'kg' } else if (data[0] == 0x03) { @@ -135,7 +136,7 @@ bool XiaomiMiscale::parse_message_v2_(const std::vector &message, Parse if (has_impedance) { // impedance, 2 bytes, 16-bit - const int16_t impedance = uint16_t(data[9]) | (uint16_t(data[10]) << 8); + const int16_t impedance = encode_value_le(&data[9]); result.impedance = impedance; if (impedance == 0 || impedance >= 3000) {