Search code examples
pythonbluetoothdbusbluezbluetooth-gatt

Python bluez dbus: Custom GATT server how to notify int16 Value changed


I'm building a custom BLE GATT Server with Python. I took the original bluez example server and added a Temperature (0x2a6e) characteristic.

From the documentation, it should be a single field 'Temperature' sint16 (2 bytes)

I was able to add a ReadValue like this:

def ReadValue(self, options):
    return dbus.Int16(self.value).to_bytes(2, byteorder="little")

And it appears correctly in nRF Connect app

Now for the notifications, I tried many things, but it never sends the data to the client (btmon has no activity on the Server side). The main approach is this one:

self.PropertiesChanged(
    GATT_CHRC_IFACE,
    dbus.Dictionary(
        {
            "Value": dbus.Int16(self.value),
        },
        signature="sv",
    ),
    [],
)

This leads to the following in dbus (captured with dbus-monitor --system):

signal time=1659004882.858019 sender=:1.129 -> destination=(null destination) serial=26 path=/org/bluez/example/service0/char0; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
   string "org.bluez.GattCharacteristic1"
   array [
      dict entry(
         string "Value"
         variant             int16 156
      )
   ]
   array [
   ]

But it does not arrive at the mobile app.

I tried changing 'Value' to 'Temperature', adding 'variant_level=1' to Int16, ...

Sending raw bytes could work but I'm not sure how to assemble the payload.


Solution

  • I'm assuming self.value is an integer so it would be something like:

        self.PropertiesChanged(GATT_CHRC_IFACE, 
                               'Value',
                               dbus.Array(self.value.to_bytes(
                                              2, byteorder="little", signed=True), 
                                          signature='y'))
    

    Your ReadValue returns an array of bytes so I would expect the value to be the same on the notification. 0x2a6e is signed so you need to have signed=True on your to_bytes