kevincar / bless

Cross-platform Bluetooth Low Energy Server Python Library
MIT License
78 stars 26 forks source link

GATT BLE Server: GATT dictionary with several services uuid can't be used by server, since an exception is thrown #84

Closed alexmac98 closed 1 year ago

alexmac98 commented 2 years ago

Hello, I'm developing a GATT BLE Server using your library. This server is supposed to advertise 4 services, so essentially the GATT configuration to be passed to the server via add_gatt() follows the pattern:

` {

: {: {"Properties": ..., "Permissions": ..., "Value": ...}}, : {: {"Properties": ..., "Permissions": ..., "Value": ...}}, : {: {"Properties": ..., "Permissions": ..., "Value": ...}}, : {: {"Properties": ..., "Permissions": ..., "Value": ...}}, }` However, after I add the GATT configuration to the server and start it `await server.start()`, an exception occurs: **raise DBusError._from_message(msg) dbus_next.errors.DBusError: Failed to parse advertisement.** If I try to advertise any single service, it works properly. In order to advertise the four services, I created 4 different GATT BLE servers, which is not ok, since it doesn't work as I expected (only one advertised service shows on the LightBlue app, but every characteristic advertised is displayed). I've also tried to add the 4 GATT configurations separately, and the same problem occurred. I don't know if I'm doing something wrong, but I've checked the GATT configurations and everything seems fine. Do you know why this might happen? Best regards and thank you in advance
kevincar commented 1 year ago

Thanks for bringing this up. I was able to localize the issue to Linux's BlueZ Advertisement API. The problem seemed to be that the advertisement failed to register when advertising more than one 32-bit service UUID. By restricting the advertisement to advertise only the primary service UUID, more than one service can now be broadcast.

This has been resolved an is now on the develop branch for now. Please reopen if the problem persists.

kosma commented 6 months ago

I think I am getting hit by this. I'm trying to register multiple services:

        gatt = {
            # Battery - public
            self.UUID_SERVICE_BATTERY: {
                self.UUID_CHARACTERISTIC_BATTERY_LEVEL: {
                    "Properties": GATTCharacteristicProperties.read,
                    "Permissions": GATTAttributePermissions.readable,
                    "Value": bytearray(b'\x69'),
                }
            },
            # Automation IO - catch-all for control - private
            self.UUID_SERVICE_AUTOMATION_IO: {
                self.UUID_CHARACTERISTIC_NUMBER_OF_DIGITALS: {
                    "Properties": GATTCharacteristicProperties.read,
                    "Permissions": GATTAttributePermissions.readable,
                    "Value": bytearray(b'\x01'),  # one digital
                },
                self.UUID_CHARACTERISTIC_CHARACTERISTIC_USER_DESCRIPTION: {
                    "Properties": GATTCharacteristicProperties.read,
                    "Permissions": GATTAttributePermissions.readable,
                    "Value": bytearray('WiFi'.encode()),
                },
                self.UUID_CHARACTERISTIC_CHARACTERISTIC_PRESENTATION_FORMAT: {
                    "Properties": GATTCharacteristicProperties.read,
                    "Permissions": GATTAttributePermissions.readable,
                    "Value": bytearray(b'\x01'),  # boolean
                },
                self.UUID_CHARACTERISTIC_DIGITAL: {
                    "Properties": GATTCharacteristicProperties.read | GATTCharacteristicProperties.encrypt_authenticated_write,
                    "Permissions": GATTAttributePermissions.readable | GATTAttributePermissions.writeable,
                    "Value": bytearray(b'\x00'),
                },
            },
            # WiFi password access - private
            self.UUID_SERVICE_WIFI: {
                self.UUID_CHARACTERISTIC_WIFI_SSID: {
                    "Properties": GATTCharacteristicProperties.encrypt_authenticated_read,
                    "Permissions": GATTAttributePermissions.readable,
                    "Value": bytearray(self.name.encode()),
                },
                self.UUID_CHARACTERISTIC_WIFI_PSK: {
                    "Properties": GATTCharacteristicProperties.encrypt_authenticated_read,
                    "Permissions": GATTAttributePermissions.readable,
                    "Value": bytearray(b'TODO'),
                },
            },
        }
        await self.server.add_gatt(gatt)

But only the first service is shown on the client side:

image

How do you suggest I proceed from here? I can slap all my characteristics into a single vendor-specific service - though I was hoping I could have multiple services for different functionalities on the device (some based on standard services, some vendor-specific).