spacecheese / bluez_peripheral

A library for building BLE peripherals using GATT and bluez
MIT License
38 stars 8 forks source link

Advertising without timeout #37

Open apaikan opened 9 months ago

apaikan commented 9 months ago

Hi, Im using the library on Raspberry Pi 4 and I would like to have the ble advertisement runs without timeout. If i set the timeout property of Advertisement class, it advertised for the requested time. But passing zero will immediately stop advertising as soon it starts. I have even tried with biggest possible value (65535) and it advertised for that amount of time (18h) then stop. But I cannot make it work for infinite time. Im running the similar simple code from documentation and nothing particular.

Thanks

spacecheese commented 9 months ago

Hello. There may be some kind of bug here. In my testing for #27 a value of 0 seemed to do this but I’m sure I’ve also had trouble with this in the past and the Bluez documentation doesn’t say anything about this. I will investigate further.

If you need a more immediate fix #22 added a release callback (available on master) to the Advertisement class which you could use to re-register when the advert times out.

spacecheese commented 9 months ago

Just tested this again on my Pi 4 and the advert without timeout of 0 isn't immediately being unregistered (at least on the latest master). Could you let me know what sudo btmon outputs when this happens.

apaikan commented 9 months ago

Hi there. sorry for late reply and thanks for taking care of the issue.

example code

here is my relevant part of the code:

    def asyncio_side_thread(self, loop):
        asyncio.set_event_loop(loop)
        loop.run_forever()

    def advertisment_release(self):
        Logger.info('BLE advertisment released!')

    async def main(self):
        # Alternativly you can request this bus directly from dbus_next.
        self.bus = await get_message_bus()
        await self.service.register(self.bus)

        adapter = await Adapter.get_first(self.bus)
        # Start an advert that will last for n seconds.
        advert = Advertisement(platform.node(), 
                               [self.service.SERVICE_ID],  # "1815"
                               self.service.APPEARANCE,  # 0x0080
                               timeout=self.BLE_ADVR_TIMEOUT,  # 0 
                               releaseCallback=self.advertisment_release) 
        await advert.register(self.bus, adapter)
        Logger.info(f"BLE server running...")            

With timeout=0, i get the release callback is called immediately:

[INFO] [1696887851.647533]: BLE server running...
[INFO] [1696887851.761254]: BLE advertisment released!

I should add that I have to run the async main() from a side thread to not block my process main thread which does other stuffs too.

  loop = asyncio.new_event_loop()
  self.thread = Thread(target=self.asyncio_side_thread, args=(loop,), daemon=True)
  self.thread.start()
  self.future = asyncio.run_coroutine_threadsafe(self.main(), loop=loop)

system info

$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 10 (buster)
Release:        10
Codename:       buster
$ cat /proc/version 
Linux version 5.10.17-v7l+ (dom@buildbot) (arm-linux-gnueabihf-gcc-8 (Ubuntu/Linaro 8.4.0-3ubuntu1) 8.4.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #1414 SMP Fri Apr 30 13:20:47 BST 2021
$ bluetoothd -v
5.50
dpkg --status bluez | grep '^Version:'
Version: 5.50-1.2~deb10u1+rpt2
spacecheese commented 9 months ago

Ah my Pi is on Debian 11 with bluez 5.55. I don't have an way of easily reflashing it at the moment but I'll update when I do. There are items in the bluez changelog for 5.53 and 5.55 that seem potentially relevant. This may need a version specific workaround.