Skip to content

Instantly share code, notes, and snippets.

@passcod
Last active November 6, 2022 11:12
Show Gist options
  • Save passcod/2132f8d1ca33232108f00e86f6147e47 to your computer and use it in GitHub Desktop.
Save passcod/2132f8d1ca33232108f00e86f6147e47 to your computer and use it in GitHub Desktop.
Xiaomi Mi Scale 2 BLE Advertisement decode (service 0x181D) and ESPHome config
fn main() {
vec![
// real data
[0xa2, 0x0c, 0x49, 0xe6, 0x07, 0x0b, 0x06, 0x01, 0x16, 0x00], // start
[0x02, 0x0c, 0x49, 0xe6, 0x07, 0x0b, 0x06, 0x01, 0x20, 0x26], // load
[0x22, 0x0c, 0x49, 0xe6, 0x07, 0x0b, 0x06, 0x01, 0x20, 0x26], // stable
[0xa2, 0x0c, 0x49, 0xe6, 0x07, 0x0b, 0x06, 0x01, 0x20, 0x2a], // idle
]
.into_iter()
.map(decode)
.for_each(|payload| drop(dbg!(payload)));
}
#[derive(Debug)]
#[allow(dead_code)]
struct Data {
pub flags: u8,
pub has_weight: bool,
pub stabilised: bool,
pub unit: Unit,
pub weight: f64,
}
#[derive(Debug, Clone, Copy)]
enum Unit {
Jin,
Lb,
Kg,
Unknown,
}
use std::convert::TryFrom;
fn decode(payload: [u8; 10]) -> Data {
let flags = payload[0];
let stabilised = flags & (1 << 5) != 0;
let has_weight = flags & (1 << 7) == 0;
let unit = if flags & (1 << 4) != 0 {
Unit::Jin
} else if flags & (1 << 2) != 0 {
Unit::Lb
} else if flags & (1 << 1) != 0 {
Unit::Kg
} else {
Unit::Unknown
};
let weight_raw = u16::from_le_bytes([payload[1], payload[2]]);
println!("raw={:02x}{:02x} u16={weight_raw}", payload[1], payload[2]);
let mut weight = f64::try_from(weight_raw).unwrap() / 100_f64;
if let Unit::Kg = unit {
weight /= 2.0;
}
Data {
flags,
has_weight,
stabilised,
unit,
weight,
}
}
sensor:
- platform: template
name: "Bathroom Scale"
id: bathroom_scale
unit_of_measurement: "kg"
esp32_ble_tracker:
on_ble_service_data_advertise:
- mac_address: 70:87:9E:11:22:33
service_uuid: 181D
then:
- lambda: |-
uint8_t flags = x[0];
bool has_weight = (flags & (1 << 7)) == 0;
bool is_stable = (flags & (1 << 5)) != 0;
bool unit_jin = (flags & (1 << 4)) != 0;
bool unit_lb = (flags & (1 << 2)) != 0;
bool unit_kg = (flags & (1 << 1)) != 0;
ESP_LOGD("scale", "Flags: %u has_weight=%u is_stable=%u unit: jin=%u lb=%u kg=%u", flags, has_weight, is_stable, unit_jin, unit_lb, unit_kg);
uint16_t weight = (((uint16_t)x[2]) << 8) + x[1];
double weight_f = (static_cast<double>(weight) / 100.0) / 2.0; // kg
ESP_LOGD("scale", "Weight: raw=%x%x u16=%u kg=%f", x[1], x[2], weight, weight_f);
if (has_weight && is_stable) {
ESP_LOGI("scale", "Publish weight %f", weight_f);
id(bathroom_scale).publish_state(weight_f);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment