ukBaz / python-bluezero

A simple Python interface to Bluez
MIT License
387 stars 112 forks source link

Allow services to be primary without forcing them to be advertised #354

Open HakanKartal opened 2 years ago

HakanKartal commented 2 years ago

I'm developing a BLE peripheral on a raspberry pi that will be controlled by an iPad using CoreBluetooth. In CB, only primary services can be discovered, but making services primary in bluezero also forces them to be advertised, in my case that made it exceed the advertisement size limit with even just two 128-bit UUIDs. I looked around in the peripheral.py file and commented line 41 and 42, which i assumed handled adding the services to the advertisement packet. This seems to have "fixed" my problem. Well, at least it made it so that the services are not advertised, but are set to primary.

Maybe it would be a good idea to allow bluezero to set the service as primary, but also separately control if it will be advertised or not. Maybe another parameter on the add_service function, something along the lines of advertised: bool? This would allow CoreBluetooth to be able to discover the services without hitting the advertisement size limit.

I haven't looked too deep into this but i think you could just replace:

def add_service(self, srv_id, uuid, primary):
        """
        Add the service information required

        :param srv_id: integer between 0 & 9999 as unique reference
        :param uuid: The Bluetooth uuid number for this service
        :param primary: boolean for if this service should be advertised

        """
        self.services.append(localGATT.Service(srv_id, uuid, primary))
        if primary:
            self.primary_services.append(uuid)

with:

def add_service(self, srv_id, uuid, primary, advertised):
        """
        Add the service information required

        :param srv_id: integer between 0 & 9999 as unique reference
        :param uuid: The Bluetooth uuid number for this service
        :param primary: boolean for if this service should be advertised

        """
        self.services.append(localGATT.Service(srv_id, uuid, primary))
        if advertised:
            self.advertised_services.append(uuid)

And then also renaming some members further in the API for coherency and completeness.

Running BlueZ 5.50 on a Raspberry pi 4b

I don't know when i will have some free time in the coming weeks but i don't mind picking this up if you guys think this is something worth implementing at all.

Any insight or opinions are greatly appreciated!

Regards, Hakan

ukBaz commented 2 years ago

The original vision for Bluezero was to have three levels of API. The thought being that through the use of "sensible defaults" people could get something up and running quickly. When they understood enough to want finer control they would switch to the low level APIs.

Having said that, your proposal for add_service seems a sensible one especially if advertised has a default value of True so that it isn't a breaking API change.

HakanKartal commented 2 years ago

Thanks for the quick reply! I understand the reasoning behind using those defaults. I think being able to control if a service gets advertised or not fits perfectly into the level 10 category of the three levels of API you mentioned. I'll fork the repo and find out if not appending primary services to the list in peripheral.py breaks anything further down setup process.