DEV Community

Cover image for Reading Xiaomi Mi Scale data with Web Bluetooth Scanning API
Henry Lim
Henry Lim

Posted on • Edited on

35 6

Reading Xiaomi Mi Scale data with Web Bluetooth Scanning API

The Web Bluetooth API provides the ability to connect and interact with Bluetooth Low Energy (BLE) peripherals. It was introduced in Chrome 56 on macOS back in January 2017.

Reading the weight data

Note: This demo only works on the first generation of Mi Body Composition Scale which was released in 2017 (Model Number: XMTZC02HM).

To capture the BLE advertising packets from the Xiaomi Mi Scale, we will need to use the Web Bluetooth Scanning API

However, the Web Bluetooth Scanning API is still under development. You need to use Chrome 79+ with the chrome://flags/#enable-experimental-web-platform-features flag enabled to use the API.

const options = { acceptAllAdvertisements: true }
// Or use can filter by device name: MIBCS
// const options = { filters: [ { name: 'MIBCS' } ] }
const scan = await navigator.bluetooth.requestLEScan(options)
view raw 1.js hosted with ❤ by GitHub

navigator.bluetooth.requestLEScan() will start scanning for the advertising packets. Right before that, the permission prompt will popup asking the user for permission to access Bluetooth.

After the user has granted permission, we can listen to the advertising packets by using the advertisementreceived event:

navigator.bluetooth.addEventListener('advertisementreceived', event => {
console.log('Advertisement received.');
console.log('Device Name: ' + event.device.name);
console.log('Device ID: ' + event.device.id);
console.log('RSSI: ' + event.rssi);
console.log('TX Power: ' + event.txPower);
console.log('UUIDs: ' + event.uuids);
event.manufacturerData.forEach((valueDataView, key) => {
console.log('Manufacturer', key, valueDataView);
});
event.serviceData.forEach((valueDataView, key) => {
console.log('Service', key, valueDataView);
});
});
view raw 2.js hosted with ❤ by GitHub

The advertisementreceived event will return information like Device Local Name, Device ID, Received Signal Strength Indicator (RSSI), Transmit power (TX Power), Service UUIDs, Manufacturer Data, and Service Data.

To retrieve the payload data from Xiaomi Mi Scale, we need to get the data from serviceData.

navigator.bluetooth.addEventListener('advertisementreceived', event => {
event.serviceData.forEach((valueDataView) => {
console.log(valueDataView.buffer)
})
})
view raw 3.js hosted with ❤ by GitHub

The output result of "valueDataView.buffer"

The payload format for the Mi Scale

Next, to get the weight data, we need to get the value of bytes 11 and 12 (which are little-endian) then divide the value by 200.

navigator.bluetooth.addEventListener('advertisementreceived', event => {
event.serviceData.forEach((valueDataView) => {
// valueDataView.buffer: [2, 4, -28, 7, 5, 10, 14, 8, 31, 125, 2, 48, 7]
const buffer = new Uint8Array(valueDataView.buffer)
const weight = ((buffer[12] << 8) + buffer[11]) / 200
console.log('Weight:', weight, 'KG')
// Weight: 9.2
})
})
view raw 4.js hosted with ❤ by GitHub

With that, we have successfully retrieved the weight data from Xiaomi Mi Scale using the Web Bluetooth Scanning API.

Extra: Reading the Impedance Data

The Xiaomi Mi Scale is also able to measure information like muscle mass, bone mass, body fat, and more through Bioelectrical Impedance Analysis (BIA). 

We can get the impedance data from bytes 9 and 10:

navigator.bluetooth.addEventListener('advertisementreceived', event => {
event.serviceData.forEach((valueDataView) => {
// valueDataView.buffer: [2, 4, -28, 7, 5, 10, 14, 8, 31, 125, 2, 48, 7]
const buffer = new Uint8Array(valueDataView.buffer)
const impedance = (buffer[10] << 8) + buffer[9]
console.log('Impedance:', weight)
// Impedance: 637
})
})
view raw 5.js hosted with ❤ by GitHub

Next, we can convert the impedance value using this algorithm. The output should look something like this:


Try It Out

Note: There's no way to get the impedance data if you are wearing socks, but I don't want to show my ugly feet… (And yes, that's a T-Rex socks)

Demo: https://scale.limhenry.xyz
GitHub (Source Code): github.com/limhenry/web-bluetooth-mi-scale


References

  1. Web Bluetooth Documentation: Link
  2. Web Bluetooth Scanning API Sample: Link
  3. Xiaomi Mi Scale BLE (Unofficial) Documentation: Link
  4. TypedArray or DataView: Understanding byte order: Link

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (7)

Collapse
 
anshulganar profile image
anshul-g-AnAr

It was great reference for me and really helped to understand how this works but I'm having different scale is there any way to to get the payload from it. , if I'm not able to find it from manufacturer.

Collapse
 
zawszy profile image
Zawszy

Hi, does it matter what xiaomi scale is used? Will this work: kogan.com/au/buy/xiaomi-mi-smart-s...

Collapse
 
upieez profile image
Samuel Huang

That's so cool I never knew we could intercept the data like that. How did you manage to figure that out?

Collapse
 
henrylim96 profile image
Henry Lim

All thanks to this amazing documentation actually. Without that documentation/reverse engineering information, I would never figure out how to properly decode the BLE advertising packets.

I just decided to build it using Web Bluetooth API, since I realized no one did it before. (Same idea but built using other language: Android, Node.js, Python)

Collapse
 
upieez profile image
Samuel Huang

Awesome thanks for the insights!

Collapse
 
tomeuw34 profile image
Tomeu Barcelo

Hi, I downloaded your code from github. I have it in a local project, I have installed node correctly. But I don't get the message to access the Bluetooth device. I get a console.log with the following message: "Web Bluetooth Scanning is experimental on this platform. See github.com/WebBluetoothCG/web-blue..."

I use Chrome 79+ with the chrome://flags/#enable-experimental-web-platform-features flag enabled to use the API.

I don't know what's going on.

Thank you. Regards

Collapse
 
spyrou42 profile image
Konrad

Hi, very cool ! It's amazing that we can connect to the scale from the Web.
I saw on a teardown on some Xiaomi scales that they are 4 load cells. Is there any way to access data for each sensor ?

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more