Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duplicated notifications when reconnecting #83

Closed
djwmarcx opened this issue Jul 8, 2019 · 3 comments
Closed

Duplicated notifications when reconnecting #83

djwmarcx opened this issue Jul 8, 2019 · 3 comments
Assignees
Labels
bug Something isn't working

Comments

@djwmarcx
Copy link

djwmarcx commented Jul 8, 2019

  • bleak version: 0.4.3
  • Python version: Python 3.7.3
  • Operating System: Ubuntu 19.04 (Kernel 5.0.0-20-generic)

Description

I'm trying to maintain a connection to a BLE device permanently. In case of connection lost (caused by an out of range o standby situation), I am reconnecting and resubscribing for the same notifications callback.

To accomplish this, my code looks something like this (simplified):

while self.running
    async with BleakClient(device_mac, device="hci0", timeout=3) as bleak:
        bleak.start_notify("FANCY UUID", callback=notification_handler)
        while self.running and await bleak.is_connected():
            await asyncio.sleep(2)
            
def notification_handler(self, uuid, value):
    # do neat stuff

This seems to work, but every time I use start_notify the notification_handler method is triggered one additional time. Just to clarify: First connection, notification_handler is called 1 time per notification; second connection, notification_handler is called twice; an so on.

I verified the code and seems the problem is that DBUS is sending the notifications duplicated N times because of the resubscriptions. The cause of this is that when it's connecting, the library subscribes to PropertiesChanged rule which is only removed in case of controlled disconnection. I also tried to call disconnect function in case of uncontrolled disconnection but an exception is raised in such case.

  File "/snap/pycharm-community/125/helpers/pydev/pydevd.py", line 1741, in <module>
    main()
  File "/snap/pycharm-community/125/helpers/pydev/pydevd.py", line 1735, in main
    globals = debugger.run(setup['file'], None, None, is_module)
  File "/snap/pycharm-community/125/helpers/pydev/pydevd.py", line 1135, in run
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "/snap/pycharm-community/125/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "/home/marcx/btest/main.py", line 142, in <module>
    asyncio.get_event_loop().run_until_complete(main())
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "/home/marcx/btest/main.py", line 93, in main
    await task
  File "/home/marcx/btest/bleak_heart_rate_device.py", line 83, in start
    await self.bleak.disconnect()
  File "/home/marcx/btest/venv/lib/python3.7/site-packages/bleak/backends/client.py", line 45, in __aexit__
    await self.disconnect()
  File "/home/marcx/btest/venv/lib/python3.7/site-packages/bleak/backends/bluezdbus/client.py", line 131, in disconnect
    await self._bus.delMatch(rule_id).asFuture(self.loop)
  File "/home/marcx/btest/venv/lib/python3.7/site-packages/txdbus/client.py", line 185, in delMatch
    rule = self.match_rules[rule_id]
KeyError: 1

Not sure what to do here. I'm doing something wrong? It is a bug?

Thanks!

@hbldh hbldh added the bug Something isn't working label Jul 8, 2019
@hbldh
Copy link
Owner

hbldh commented Jul 8, 2019

If you let the BleakClient go and create a new one for each reconnect, does it still show multiple notifications? If so it is a bug in bleak, and I need to find a way to handle it.
It might be helped by work done in #82.

@hbldh hbldh self-assigned this Jul 8, 2019
@djwmarcx
Copy link
Author

djwmarcx commented Jul 9, 2019

Yes. In case of disconnection (is_connected() == False), the code is exiting the async with BleakClient(.. block and starting a new one, causing the duplicated notifications.

I've checked out the disconnect method (which is being called when leaving the async with block).
I can see that the library is removing all previously registered dbus rules (Including the PropChanged one, which seems to be the one who manages the notifications), but seem isn't working for that specific rule.

I've also checked the raw dbus messages with dbus-monitor and I can see the notifications coming duplicated in dbus. Looks like the RemoveMatch dbus message is not working as expected for the PropChanged rule.

When comparing the addMatch params vs the removeMatch params sent in runtime and I can't see anything obviously wrong, but I'm not a dbus expert, so...

Hope it helps.

Thank you :D

@JoeHut
Copy link
Contributor

JoeHut commented Jul 12, 2019

I have been looking a bit into this. The addMatch and delMatch routines work fine for the PropChanged rule. I have only very superficial understanding of DBus and BlueZ, so please challenge my assumptions.

When StartNotify is called, it is not saved as a rule and therefore not cleaned up when disconnect is called. BlueZ therefore stores the subscription even after disconnection. If the connection is reestablished and another StartNotify is called for the characteristic, the values are sent twice. I tried to fix it by basically storing the UUIDs we subscribe to in a list and call StopNotify for all of them on disconnect. This works but doesn't feel very elegant... If there is a better way, please let me know.

@hbldh hbldh closed this as completed in e418509 Aug 2, 2019
hbldh added a commit that referenced this issue Sep 7, 2019
Added example for set_disconnect_callback
hbldh added a commit that referenced this issue Oct 9, 2019
Bugfixes and improvements of client behaviour.

Merged #117
Merged #99
Merged #100
Fixes #101
Fixes #98
Fixes #104
Further fixes for #69, #83 and #86
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants