I'm trying to learn how to implement a BLE peripheral device using bleno. I would like to discover and read from the peripheral using noble. For example sake, I want to know how I would implement a simple smart scale that reports back weight, BMI etc following the Weight Measurement GATT spec.
What I can't figure out is if reading multiple pieces of information from a characteristic is possible. The Weight Measurement GATT spec makes it seem like in a single noble characteristic.read()
you can simultaneously retrieve Weight, BMI, Height etc.
For example, this simple bleno characteristic:
'use strict';
const bleno = require('bleno');
const flags = {
IMPERIAL_WEIGHT: 1 << 0,
USER_ID_PRESENT: 1 << 2,
BMI_AND_HEIGHT_PRESENT: 1 << 3
};
module.exports.flags = flags;
module.exports.WeightMeasureCharacteristic = class WeightMeasureCharacteristic extends bleno.Characteristic {
constructor(scale) {
super({
uuid: '2A9D',
properties: ['read'],
descriptors: []
});
this._scale = scale;
}
onReadRequest(offset, callback) {
//Not sure what `offset` means here or how it gets populated...Help!
let data = new Buffer.alloc(8); //1(flags)+2(weightImp)+1(userId)+2(BMI)+2(heightImp)
//Write supported value fields as bit flags
data.writeUInt8(flags.IMPERIAL_WEIGHT | flags.USER_ID_PRESENT | flags.BMI_AND_HEIGHT_PRESENT), 0);
//Write out weight (lbs) - offset 1 byte
data.writeUInt16LE(100.01, 1);
//Write out user id - offset 12 bytes (flags+Imperial, no need to include offset for SI or Timestamp since the flags indicated those are not supported)
data.writeUInt8(69, 3);
//Write out BMI - offset 13 bytes (after UserId)
data.writeUInt16LE(18.6, 4);
//Write out Height Imperial - offset 17 bytes (after Height SI)
data.writeUInt16LE(72.2, 6);
callback(this.RESULT_SUCCESS, data);
}
}
If someone was able to implement/pseudocode onReadRequest()
above I think it would help things click in my head.
Questions:
- Does the
C<number>
value in the "Field Requirement" column of the spec indicate theoffset
value passed intoonReadRequest()
? If a consumer wanted to get "Weight - SI"(C1
) they would somehow construct a noblecharacteristic.read()
that triggers anonReadRequest(1,function())
? If so, how is thecharacteristic.read()
constructed? - How do I construct a noble
characteristic.read()
to get the value of theFlags
? - How do I construct a noble
characteristic.read()
that will return me multiple (or all) properties in one read? Ex: Give me all values this peripheral supports (Weight - SI, BMI etc). - If my peripheral supports imperial weight, user id, bmi, and height how do I populate the
data
for the callback inonReadRequest()
. Is what I have above correct? - How is
offset
populated & what does it mean inonReadRequest(offset,callback)
?
Or, am I doing this all wrong? Should I have a characteristic for each value? Ex: a single characteristic for weight - SI, and another characteristic for BMI? I would like to avoid this, would prefer to save round trips and get multiple values in one call.
An attempt to answer your question:
C<number>
means, but I believe that each field (Weight, BMI, Height, etc.) is represented as a group of one or more octets. Notice how at the bottom of the spec it saysThus, I believe that in order to get the "Weight - SI" field, you would do something like: