1

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:

  • Heart Rate Value Format is set to uint8
  • Sensor Contact detected = true
  • Sensor Contact Supported = true

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!

Nicooost
  • 76
  • 6
  • 1
    In the `GATT Specification Supplement` document at https://www.bluetooth.com/specifications/assigned-numbers/ Take a look at section "2.3 Values and represented values" where it explains about represented values – ukBaz Nov 01 '22 at 12:11

1 Answers1

1

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
ukBaz
  • 6,985
  • 2
  • 8
  • 31
  • Thank you very much! In my case i have to split these Bytes in dbus.Byte() elements to send the value, but this is just a small function! – Nicooost Nov 01 '22 at 14:34
  • 1
    I thought D-Bus did the correct thing if you passed a bytes object to the characteristic write... but maybe not. You could use a list comprehension... something like `[dbus.Byte(b) for b in value]` – ukBaz Nov 01 '22 at 14:54
  • i tried: self.PropertiesChanged(GATT_CHRC_IFACE, { 'Value': value.hex() }, []) --------------------------------------------------------------------------------------------------------------- No error, but nothing in logs or on Screen in the nRF Connect app, so probably nothing arrives – Nicooost Nov 01 '22 at 15:54
  • and: self.PropertiesChanged(GATT_CHRC_IFACE, { 'Value': value }, []) -----------------------------------------------------------------------------------------Error: Updating value: b'\x08\x08\x07x\x00\xf6\x06' Traceback (most recent call last): self.PropertiesChanged(GATT_CHRC_IFACE, { 'Value': value }, []) File "/usr/lib/python3/dist-packages/dbus/decorators.py", line 325, in emit_signal message.append(signature=signature, *args) ValueError: embedded null byte – Nicooost Nov 01 '22 at 15:55
  • OK, I didn't realise you were doing this with `ChangedProperties` which has the signature `@dbus.service.signal(DBUS_PROP_IFACE, signature='sa{sv}as')`. So you will need to define what dbus object it is inside the array. Did `[dbus.Byte(b) for b in value]` work? i.e. `self.PropertiesChanged(GATT_CHRC_IFACE, { 'Value': [dbus.Byte(b) for b in value]}, [])` – ukBaz Nov 01 '22 at 16:11