bluetoothbluetooth-lowenergygattbluetooth-gattcharacteristics

Bluetooth GATT: Set value and flag field correct


i have some problems by understanding the flag field in Bluetooth characteristics.

For example the heart rate measurement characteristic:

Characteristic

And its flags:

Flags

According to my understanding, the first part of the value must contain the flags. For example 0x06 for:

The second part of the value is then byte(Heartrate).

In Python i fill the value like this:

value = []
value.append(dbus.Byte(0x06))
value.append(dbus.Byte(randint(90, 130)))

The whole thing also works perfectly. When I connect to the server with the app nRF connect I get all the info perfectly displayed with all the info.

Now about my problem:

I tried to implement the Weight Measurement Characteristic.

Weight Measurement

I want Weight in kg, BMI and height. So for my understanding i have to fill flag field with 0x08 for 00001000.

In Python it will look like this:

value = []
value.append(dbus.Byte(0x08))
value.append(dbus.Byte(randint(1, 13))) #weight
value.append(dbus.Byte(randint(1, 25))) #BMI
value.append(dbus.Byte(randint(1, 25))) #height

Now i get in nRF Connect App the message Invalid Data Syntax.

My Questions are:

  1. How to handle with the resolution 0.0001? Value = Height/0.0001 or Height*0.0001?
  2. What is meant by represented values M = 1, d=-1, ...?
  3. Why is my Value in the second python code invalid?

Thank you very very much for your help!

I'm using bluez5.63/test/example-gatt-server.py for my Server!


Solution

  • The usual way to build the value for a characteristic is to use the Python struct library to pack that values into bytes.

    The values sent in the characteristics are always bytes which can only represent integers. So to turn the height value to an integer it is saying that for every increment of 1 on the field value, the hight value goes up by 0.001. This means the decimal point needs to move 3 places to the right on the height value sent. So to send a height value of 0.001 you will actually send a value of 1. This means your messurment needs to be multiplied by value * 10**3 or if you prefer value / 0.001.

    For weight it is similar but in addition to moving the decimal point you also have to change the value. This can be value / 0.005 or value * (1 / 5) * 10 ** 3

    An example of how the python code might look:

    import struct
    
    weight_char = struct.Struct('<BHHH')
    
    
    def pack_flags(units, timestamp, user_id, bmi_height):
        flags = 0
        for idx, _flag in enumerate((units, timestamp, user_id, bmi_height)):
            flags |= _flag << idx
        return flags
    
    
    flags = pack_flags(False, False, False, True)
    weight = 42.4  # example weight in KG
    height = 1.49  # Height in meters
    bmi = 20.1
    
    value = weight_char.pack(flags,
                             int(weight * 0.2 * 10**3),
                             int(bmi * 10**1),
                             int(height * 10**3))
    print(f"Value to send: {value.hex()}")
    
    
    

    Which gives the output of:

    Value to send: 082021c900d205