ukBaz / python-bluezero

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

Application gets stuck during Connection #322

Closed Owenber123 closed 3 years ago

Owenber123 commented 3 years ago

Hello, I have been debugging my application for quite some time now and have never seen this problem. I am able to create a Device with a Central object but once I attempt to connect to it my application freezes. I do not get any timouts or exceptions. When I check the bluetoothctl device list I do not see the device but when run a quick scan I am able to see the device and connect to it just fine. I was convinced that the Central object checked for the devices presence during initialization. I have pushed this device to the side and am moving forward but do not know how to handle this if others follow suit. Any advise would be great. I added some snippets of the Device creation and connection. Thanks, Owen

ukBaz commented 3 years ago

Generally speaking, I advise people to avoid scanning for devices inside of their application. This adds lots of complexity for no benefit in most cases. Once you have done a scan and connected inside of bluetoothctl then there shouldn't be a need to scan again. If the device you wish to connect to is sometimes out of range, then handling the timeout on connection involves less complexity than scanning.

If you do really, really, really need scanning then you have two choices:

  1. Synchronously.

Let the discovery run for a period and then proceed. e.g.

adapter.nearby_discovery(timeout=discoveryTimeout)

The application of this is that when a new device is discovered it gets added to the list of devices.

  1. Asynchronously If you are looking for a new device then you need to associate function with the on_device_found: https://github.com/ukBaz/python-bluezero/blob/06480a3430e55325a10d3854db509efbfc412ba4/bluezero/adapter.py#L90 If you are checking for the existence of a already discovered then a connection to the PropertiesChanged signal would need to be done for the device similar to what has been done for the adapter. https://github.com/ukBaz/python-bluezero/blob/master/bluezero/adapter.py#L99

This has the benefit of you get a signal that the device has been discovered or the RSSI has changed on a known device. but requires to program your application in asynchronous.

ukBaz commented 3 years ago

As you seem to be trying to do this synchronously I've had an attempt at how I would do this and have come up with the following:

from bluezero import adapter
from bluezero import device

ubit = 'E9:06:4D:45:FC:8D'
rpi = 'B8:27:EB:22:57:E0'

dongle = adapter.Adapter()
searching = True

def keep_trying(attempts):
    fails = 0
    while searching:
        for dev in device.Device.available():
            if dev.address == ubit:
                remote = device.Device(rpi, ubit)
                try:
                    remote.connect(timeout=2)
                    return remote
                except:
                    pass
        fails += 1
        print(f'fails = {fails}')
        if fails > attempts:
            return None
        dongle.nearby_discovery(3)

my_dev = keep_trying(10)

if my_dev:
    print('Great, connected', my_dev.connected)
    my_dev.disconnect()
    while my_dev.connected:
        print('Disconnecting...')
        sleep(1)
else:
    print('failed to connect')
Owenber123 commented 3 years ago

ukBaz,

I gave this implementation a try. It works very similar to what I am doing above, I guess the device is found in the list. The application gets stuck during the remote.connect(). No exceptions are thrown during this function call. I have yet to debug beyond the Device object during the connect and am hoping you have some ideas with your great knowledge of bluezero. My device object is very similar and based off of the Microbit object and works for the majority of devices. I will be running hardware tests today in case its not software related.

Thanks in advanced, Owen

ukBaz commented 3 years ago

I'm struggling to understand what you are referring to when you say "get stuck during the remote.connect()". When it tries to connect to a device that isn't there, then it will be trying for 35 seconds before timing out. This can be changed n the above code by adding a shorter timeout to the connect statement. e.g.

                    remote.connect(timeout=2)

I've updated the example above to fail faster with the connect. Is this what you are referring to?

Owenber123 commented 3 years ago

It is stuck in the:

        while not self.rmt_device.services_resolved:
            sleep(0.5)

This means we are connected but the characteristics cannot be resolved I believe. Any ideas?

ukBaz commented 3 years ago

You would need to narrow down if the issue is with remote device never resolving its services. Or if it is somewhere on the Linux side not getting the update.

To monitor D-Bus traffic use the following in a separate terminal:

sudo busctl monitor org.bluez

To monitor Bluetooth traffic:

sudo btmon

This are both very verbose, so not easy.

Owenber123 commented 3 years ago

I was not able to solve the problem with the information gathered by those commands, however, the Central device was using a USB Ethernet Adapter in order to avoid WIFI interference. This was accidentally removed and the problem stopped occurring. I have no idea why but this is going to be my solution. Thanks

ukBaz commented 3 years ago

Thanks for letting me know. I'll close this ticket as I don't think there is anything else to do here.