androidreact-nativeandroid-bluetoothreact-native-ble-plx

get weight from GATT characteristics value in react-native-ble-plx


I am developing an react-native app that gets the weight value of a scale(MI SCALE2) that supports Bluetooth.(I have no knowledge of bluetooth.)


// version

"react-native": "0.66.1",

"react-native-ble-plx": "https://github.com/below/react-native-ble-plx",


I was able to get these values ​​when I got on the scale.

# feature
{"data": [33, 0, 0, 0], "type": "Buffer"}

# Weight
{"data": [2, 156, 74, 178, 7, 1, 7, 22, 33, 1], "type": "Buffer"}
{"data": [2, 156, 74, 178, 7, 1, 7, 22, 33, 1], "type": "Buffer"}
{"data": [2, 156, 74, 178, 7, 1, 7, 22, 33, 1], "type": "Buffer"}
{"data": [2, 156, 74, 178, 7, 1, 7, 22, 33, 2], "type": "Buffer"}
{"data": [2, 156, 74, 178, 7, 1, 7, 22, 33, 2], "type": "Buffer"}
{"data": [34, 156, 74, 178, 7, 1, 7, 22, 33, 2], "type": "Buffer"}
{"data": [162, 156, 74, 178, 7, 1, 7, 22, 33, 6], "type": "Buffer"}

After reading the Q&A in several places, I know that it is necessary to combine the value of the feature with the value of the weight array.

I want to know how to get the weight value from my result like "94.9kg, 95.5kg, ..."

Below is the code I wrote.


manager.startDeviceScan(null, null, (error, device) => {
      if (error) {
        console.log('error : ' + error);
        return;
      }

      console.log(device.name);

      if (device.name === 'MI SCALE2') {
        console.log('detected!!');
        manager.stopDeviceScan();
        device
          .connect()
          .then(device => {
            return device.discoverAllServicesAndCharacteristics();
          })
          .then(device => {
            return device.services();
          })
          .then(services => {
            const result = services.filter(id => id.uuid.indexOf('181d') != -1); // 181d is Weight Scale -> org.bluetooth.service.weight_scale;
            return result[0].characteristics();
          })
          .then(characters => {
            const resultDateObject = characters.filter(
              data => data.uuid.indexOf('2a2b') != -1, // 2a2b is Current Time -> org.bluetooth.characteristic.current_time;
            );
            const resultWeightFeature = characters.filter(
              data => data.uuid.indexOf('2a9e') != -1, // 2a9e is Weight Scale Feature -> org.bluetooth.characteristic.weight_scale_feature
            );
            const resultWeight = characters.filter(
              data => data.uuid.indexOf('2a9d') != -1, // 2a9d is Weight Measurement -> org.bluetooth.characteristic.weight_measurement;
            );
            const resultPosition2D = characters.filter(
              data => data.uuid.indexOf('2a2f') != -1, // 2a2f is Position 2D -> org.bluetooth.characteristic.position_2d;
            );
            
            // const DeviceID = resultWeightFeature[0].deviceID;
            // const ServiceUUID = resultWeightFeature[0].serviceUUID;
            // const DateCharacterUUID = resultDateObject[0].uuid;
            // const WeightFeatureCharacterUUID = resultWeightFeature[0].uuid;
            // const WeightCharacterUUID = resultWeight[0].uuid;
            // const PositionCharacterUUID = resultPosition2D[0].uuid;

            resultWeight[0].monitor((error, characteristic) => {
              if (error) {
                console.log('error:::::', error);
                return;
              }
              let your_bytes = Buffer.from(characteristic.value, "base64");
              console.log(your_bytes);
            })
            return resultWeightFeature[0].read();

          }).then(feature => {
            let feature_bytes = Buffer.from(feature.value, "base64");
            console.log('feature.value');
            console.log(feature_bytes);
          })
      }
    });


Solution

  • As far as I understand your Code, your weight scale makes use of Bluetooth Weight Scale Profile and Weight Scale Service. The data you find in the corresponding characteristics needs to be interpreted as described in Personal Health Devices Transcoding

    Edit: You can find more information on the data structure here: GATT Specification Supplement 5

    example:

    Feature([33,0,0,0]) => 0x00000011 => ...00 0010 0001 =>

    value description
    1 Time Stamp Supported: True
    0 Multiple Users Supported: False
    0 BMI Supported: False
    0100 Weight Measurement Resolution: Resolution of 0.05 kg or 0.1 lb
    000 Height Measurement Resolution: Not specified

    Weight = [34, 156, 74, 178, 7, 1, 7, 22, 33, 2] => 0x22 0x9c 0x4a 0xb2 0x07 0x01 0x07 0x16 0x21 0x02

    First byte is a flags field => 0x22 => 0010 0010

    value description
    0 Measurement Units: SI
    1 Time Stamp present: True
    0 User ID present: False
    0 BMI and Height present: False
    0010 Reserved for Future Use

    Weight in kilograms with resolution 0.005 (uint16) => 0x4a9c => 95,5 kg

    Time Stamp 0xb2 0x07 0x01 0x07 0x16 0x21 0x02

    year(uint16) => 0x07b2 => 1970

    month(uint8) => 0x01 => 1

    day(uint8) => 0x07 => 7

    hours(uint8) => 0x16 => 22

    minutes(uint8) => 0x21 => 33

    seconds(uint8) => 0x02 => 2

    date 1970-01-07T22:33:02