I was able to get the valid "Indoor Bike Data" values by using "nRF Connect for Mobile".
Issue is when I try to get "Indoor Bike Data" values using web bluetooth
, I get the data in a DataView
format which I am not sure how to parse the understandable values from.
I read some other stack overflow answers and did some random guesses and was able to get the "Resistance Level" by using below code
dataView.getInt16(6, true)
Not sure why using 6 and true was able to get the "Resistance Level"
I tried random numbers but was not able to get valid looking number for
Can I get help parsing above three numbers by parsing the dataView input that I am getting from indoor bike BLE device?
Thanks!
Below is the code for how I got dataView
from indoor bike BLE device.
const FITNESS_MACHINE_SERVICE_UUID = "00001826-0000-1000-8000-00805f9b34fb";
const INDOOR_BIKE_DATA_UUID = "00002ad2-0000-1000-8000-00805f9b34fb";
const handleClick = async () => {
const indoorBikeDevice = await navigator.bluetooth.requestDevice({
filters: [{ name: "MG03" }],
optionalServices: [FITNESS_MACHINE_SERVICE_UUID],
});
if (!indoorBikeDevice.gatt) return;
const server = await indoorBikeDevice.gatt.connect();
const service = await server.getPrimaryService(FITNESS_MACHINE_SERVICE_UUID);
const characteristic = await service.getCharacteristic(INDOOR_BIKE_DATA_UUID);
characteristic.addEventListener(
"characteristicvaluechanged",
async (event) => {
const dataView = (event.target as any).value as DataView;
console.log("dataView: ", dataView);
const resistanceLevel = dataView.getInt16(6, true);
console.log("resistanceLevel: ", resistanceLevel);
}
);
characteristic.startNotifications();
};
I looked at the link @Michael Kotzjan provided and after few trials I was able to get flags by running code below
// GATT_Specification_Supplement_v8.pdf
// 3.124.1 Flags field: The bits of this field are defined below.
for (let i = 0; i < 16; i++) {
console.log("flags[" + i + "] = " + !!((flags >>> i) & 1));
}
console.log
looked like below:
// flags[0] = false
// flags[1] = false
// flags[2] = true (Instantaneous Cadence present)
// flags[3] = false
// flags[4] = false
// flags[5] = true (Resistance Level present)
// flags[6] = true (Instantaneous Power present)
// flags[7] = false
// flags[8] = false
// flags[9] = false
// flags[10] = false
// flags[11] = false
// flags[12] = false
// ...
It seems like above true
flag values are telling me that Instantaneous Cadence present
, Resistance Level present
, and Instantaneous Power present
are available.
My issue was getting the value of those field and matching the value to the data from "nRF Connect for Mobile".
I blindly guessed numbers without any understanding and was able to match output numbers to "nRF Connect for Mobile" with the code below
characteristic.addEventListener(
"characteristicvaluechanged",
async (event) => {
const dataView = (event.target as any).value as DataView;
const instantaneousCadence = dataView.getUint16(3, true) / 512;
const resistanceLevel = dataView.getUint8(6);
const instantaneousPower = dataView.getInt16(8, true);
console.log(
[instantaneousCadence, resistanceLevel, instantaneousPower].join("|")
);
}
);
Even if I got the desired number, I still want to know why it worked?
For example, for the cadence: dataView.getUint16(3, true) / 512
why is the byte offset: 3 and I need to divided by 512? to get the rev/min?
byte offsets for resistance level and power are 6 and 8 and I am not sure where and how to get byte offsets?
You can search for your service in the Assigned Numbers Document provided by the Bluetooth SIG. Your INDOOR_BIKE_DATA_UUID
is a standard UUID with the 16-Bit representation of 0x2ad2. The Assigned Numbers Document shows this UUID as Indoor Bike Data, which is part of the Fitness Machine Service. The service specification contains a section regarding Indoor Bike Data:
The Indoor Bike Data characteristic is used to send training-related data to the Client from an indoor bike (Server). Included in the characteristic value is a Flags field (for showing the presence of optional fields), and depending upon the contents of the Flags field, it may include one or more optional fields as defined on the Bluetooth SIG Assigned Numbers webpage.
That means you need to read out the flags field to figure out which data fields are present on your bike and handle them accordingly. All information about the types and lengths of the data fields can be found in the documentation.