From 7adaeacd0b2ca50f89e7a9fb3ad82821dd0dfc2b Mon Sep 17 00:00:00 2001 From: Alexander Leisentritt Date: Sat, 2 Nov 2019 18:55:10 +0100 Subject: [PATCH] refactored xiaomi ble data parsing (#823) --- esphome/components/xiaomi_ble/xiaomi_ble.cpp | 48 +++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.cpp b/esphome/components/xiaomi_ble/xiaomi_ble.cpp index 1172f6ee0a..e6884e5ea6 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.cpp +++ b/esphome/components/xiaomi_ble/xiaomi_ble.cpp @@ -91,17 +91,6 @@ optional parse_xiaomi(const esp32_ble_tracker::ESPBTDevice &d return {}; } - uint8_t raw_offset = is_lywsdcgq || is_cgg1 ? 11 : 12; - - const uint8_t raw_type = raw[raw_offset]; - const uint8_t data_length = raw[raw_offset + 2]; - const uint8_t *data = &raw[raw_offset + 3]; - const uint8_t expected_length = data_length + raw_offset + 3; - const uint8_t actual_length = device.get_service_data().size(); - if (expected_length != actual_length) { - // ESP_LOGV(TAG, "Xiaomi %s data length mismatch (%u != %d)", type, expected_length, actual_length); - return {}; - } XiaomiParseResult result; result.type = XiaomiParseResult::TYPE_HHCCJCY01; if (is_lywsdcgq) { @@ -111,7 +100,42 @@ optional parse_xiaomi(const esp32_ble_tracker::ESPBTDevice &d } else if (is_cgg1) { result.type = XiaomiParseResult::TYPE_CGG1; } - bool success = parse_xiaomi_data_byte(raw_type, data, data_length, result); + + uint8_t raw_offset = is_lywsdcgq || is_cgg1 ? 11 : 12; + + // Data point specs + // Byte 0: type + // Byte 1: fixed 0x10 + // Byte 2: length + // Byte 3..3+len-1: data point value + + const uint8_t *raw_data = &raw[raw_offset]; + uint8_t data_offset = 0; + uint8_t data_length = device.get_service_data().size() - raw_offset; + bool success = false; + + while (true) { + if (data_length < 4) + // at least 4 bytes required + // type, fixed 0x10, length, 1 byte value + break; + + const uint8_t datapoint_type = raw_data[data_offset + 0]; + const uint8_t datapoint_length = raw_data[data_offset + 2]; + + if (data_length < 3 + datapoint_length) + // 3 fixed bytes plus value length + break; + + const uint8_t *datapoint_data = &raw_data[data_offset + 3]; + + if (parse_xiaomi_data_byte(datapoint_type, datapoint_data, datapoint_length, result)) + success = true; + + data_length -= data_offset + 3 + datapoint_length; + data_offset += 3 + datapoint_length; + } + if (!success) return {}; return result;