ukBaz / BLE_GATT

Python package for using BlueZ D-Bus API to create a Client
MIT License
29 stars 5 forks source link

Failed to connect: le-connection-abort-by-local #9

Closed DsapPH closed 2 years ago

DsapPH commented 2 years ago

When connecting to a BLE peripheral it does not always connect 100% of the time.

Error:

[bluetooth]# connect EA:30:3F:F9:10:2E
Attempting to connect to EA:30:3F:F9:10:2E
[CHG] Device EA:30:3F:F9:10:2E Connected: yes
Failed to connect: org.bluez.Error.Failed le-connection-abort-by-local
[CHG] Device EA:30:3F:F9:10:2E Connected: no 

Steps taken. bluetoothctl scan on scan off devices # check if the devices is there connect MAC

I have also tried using other commands I've seen online such as trust or pair before connect however it does not help. The same issue arise in python. Where using device = BLE_GATT.Central(MAC) and then doing device.connect. My assumption is something may be wrong with my BlueZ. I can take BLE phone apps such as nRF connection and connect to the device without issue. Are there steps I can take towards better debugging this.

ukBaz commented 2 years ago

The fact that you are unable to connect with bluetoothctl suggests it is an issue with the underlying BlueZ. You shouldn't need to a scan every time. If the device is in the devices list then you shouldn't need to scan again.

What puts it into a state where you can't connect? Is it after you have run your script previously? Could it be the peripheral is not being disconnected from correctly?

You can reset the Bluetooth adapter on the RPi with sudo service bluetooth restart

Does service bluetooth status show errors?

To get Bluetooth debug information on Linux when running your script have separate terminals open with the following running to get more debug information:

DsapPH commented 2 years ago

Doing service restart and service status I get 1 error.

pi@raspberrypi:~/BaseStationFW $ service bluetooth status
● bluetooth.service - Bluetooth service
     Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2022-04-20 09:47:42 EDT; 4s ago
       Docs: man:bluetoothd(8)
   Main PID: 211948 (bluetoothd)
     Status: "Running"
      Tasks: 1 (limit: 4165)
        CPU: 82ms
     CGroup: /system.slice/bluetooth.service
             └─211948 /usr/local/libexec/bluetooth/bluetoothd --experimental

Apr 20 09:47:41 raspberrypi systemd[1]: Starting Bluetooth service...
Apr 20 09:47:42 raspberrypi bluetoothd[211948]: Bluetooth daemon 5.64
Apr 20 09:47:42 raspberrypi systemd[1]: Started Bluetooth service.
Apr 20 09:47:42 raspberrypi bluetoothd[211948]: Starting SDP server
Apr 20 09:47:42 raspberrypi bluetoothd[211948]: Bluetooth management interface 1.18 initialized
Apr 20 09:47:42 raspberrypi bluetoothd[211948]: Battery Provider Manager created
Apr 20 09:47:42 raspberrypi bluetoothd[211948]: Failed to set privacy: Rejected (0x0b)
Apr 20 09:47:42 raspberrypi bluetoothd[211948]: Adv Monitor Manager created with supported features:0x00000000, enabled features:0x00000000, max number of supported>
Apr 20 09:47:42 raspberrypi bluetoothd[211948]: Endpoint registered: sender=:1.34 path=/MediaEndpoint/A2DPSink/sbc
Apr 20 09:47:42 raspberrypi bluetoothd[211948]: Endpoint registered: sender=:1.34 path=/MediaEndpoint/A2DPSource/sbc

The error being the Failed to set privacy: Rejected (0x0b)

Restarting the service then doing a scan on, scan off, connect shows the same Failed to connect.

I dont believe it is a disconnect issue. If I do get a successful connection and then use disconnect then another connect I can get the same issue.

Using journalctl -f -u bluetooth I don't get any new logging when a connection error occurs.

running sudo busctl monitor org.bluez and then doing the steps to connect I can see it set the connection to True which i assume it means it will connect. Then I see the error shows up but it doesn't give much of a clearly understanding.

‣ Type=error  Endian=l  Flags=1  Version=1 Cookie=254  ReplyCookie=140
  Sender=:1.103  Destination=:1.105
  ErrorName=org.bluez.Error.Failed  ErrorMessage="le-connection-abort-by-local"
  UniqueName=:1.103
  MESSAGE "s" {
          STRING "le-connection-abort-by-local";
  };

Then it sets the connection back to false.

Is any of this information helpful? I haven't used a tool like wireshark before so I want to check that more debugging needs to happen before I try using it. Would an uninstall of BlueZ and reinstall of BlueZ on my raspberry pi be helpful in fixing this? I have no problem wiping and setting it up again before cloning my project back on it.

ukBaz commented 2 years ago

The Failed to set privacy: Rejected (0x0b) is a known issue and I don't believe is the source of your issue.

You don't need to use wireshark to read the results from btmon; although it can just help to make it slightly easier to read the log.

You can try a fresh install if you think you have messed around with things and would benefit from returning to a known state. Although you need to make sure you do all the updates as the BT firmware is often moving on.

One other thing to try if the peripheral you are connecting to is Bluetooth Low Energy (BLE) only, and that is to configure the RPi to be BLE only. This is done in the /etc/bluetooth/main.conf file by changing ControllerMode to the following:

ControllerMode = le

These are all just general pointers as this is an issue with BlueZ and not BLE_GATT.

If you search LE connection abort by local in https://lore.kernel.org/all/20210930153703.BlueZ.v7.3.Idd761b9b9f4620480db8889e7885a17952c2c13a@changeid/T/ it appears that error message is part of a drive to improve error reporting. However, there doesn't seem to be enough to pin this down. Hopefully btmon will give us more. If you wanted to report it on the BlueZ Slack then you will need to have some details from btmon.

DsapPH commented 2 years ago

Understood, I'll look into btmon as well as using wireshark on it.

Having done the fresh install it seems to have fixed this error. I do now run into a new one. GDBus.Error:org.bluez.Error.Failed: Software caused connection abort (36) I haven't updated BlueZ yet, could this be what has caused this. Are there other ways to update BlueZ other than building from source?

Makes sense I can start posting about these in BlueZ forums and not on this repository as its BlueZ issues. Feel free to close this since the le-connection-abort-by-local is also not showing up anymore.

DsapPH commented 2 years ago

I do have one other question that may be related to this repository. Which is why I consistently run into an issue where BLE_GATT.Central(MAC) tells me that it doesn't see the device and the way to fix it is doing a manual bluetoothctl scan. Is this something I can call it to do in python to avoid this issue?

ukBaz commented 2 years ago

Can you say a little bit more about "consistently"?

There needs to be a step that puts the remote device in to the list of devices BlueZ knows about. This should be a one-time provisioning step for a new remote device. By your use of "consistently" I'm understanding that it is not a one-time provisioning step for you. E.g. you have done the bluetoothctl scan and connect. You then use your script and it works initially until it suddenly stops working and the only fix is to do the provisioning again. Is my reading of what you've written correct?

To do the all the options in Python for provisioning a new device adds a lot of complexity. As this should only be a one-time provisioning step when a new device is added, I took the decision not to add that complexity to the library so it would be good to understand why you are seeing this is not a one-time provisioning step.

ukBaz commented 2 years ago

Are there other ways to update BlueZ other than building from source?

The short answer to this is no.

I would also ask why you are upgrading and running with --experimental? If you are on the latest version of your Linux OS the version of BlueZ should be absolutely fine for what BLE_GATT needs. BlueZ is split between user space and kernel space. The above steps you describe are updating the user space only. Unless you have a strong driver for the upgrade, you are best to use the version that ships in your OS install.

DsapPH commented 2 years ago

Are there other ways to update BlueZ other than building from source?

The short answer to this is no.

I would also ask why you are upgrading and running with --experimental? If you are on the latest version of your Linux OS the version of BlueZ should be absolutely fine for what BLE_GATT needs. BlueZ is split between user space and kernel space. The above steps you describe are updating the user space only. Unless you have a strong driver for the upgrade, you are best to use the version that ships in your OS install.

Gotcha I thought you needed the experimental flag, not that it was base in BlueZ. I'm running this off the newest Raspbian so if thats good then I won't upgrade.

DsapPH commented 2 years ago

Yes thats the issue with provisioning. The moment I disconnect from a connection I wont be able to find the device till I scan again.

When I do scan I see it find new devices

[bluetooth]# scan on
Discovery started
[CHG] Controller E4:5F:01:70:F2:18 Discovering: yes
[NEW] Device 67:9C:15:DF:68:F7 name
[NEW] Device F3:13:9A:79:71:D0 name
[NEW] Device E3:5E:CC:72:64:4C name
[NEW] Device E8:70:2A:E4:9A:8C name
[NEW] Device 46:C7:F2:CA:C9:E2 name
[NEW] Device 6A:80:40:C0:16:E9 name
[NEW] Device 7F:C1:65:59:A1:20 name

Doing scan off I see it change devices.

[bluetooth]# scan off
Discovery stopped
[CHG] Device F4:F8:D6:99:3B:9E name is nil
[CHG] Device 57:BD:21:2C:3C:09 name is nil
[CHG] Device 57:BD:21:2C:3C:09 name is nil
[CHG] Device E8:72:90:1E:33:36 name is nil
[CHG] Device E8:72:90:1E:33:36 name is nil
[CHG] Device 6C:4A:85:00:7B:5B name is nil
[CHG] Controller E4:5F:01:70:F2:18 Discovering: no

Shortly after doing that I see it delete devices. No input from me triggers this.

[DEL] Device 7F:C1:65:59:A1:20 name
[DEL] Device EA:6F:79:9A:FC:3F name
[DEL] Device F3:13:9A:79:71:D0 name
[DEL] Device E3:5E:CC:72:64:4C name
[DEL] Device 67:9C:15:DF:68:F7 name

When it comes to the device I am trying to connect too it won't be in that delete list. However If i wait longer and do nothing I then see it get deleted. If I connect to the device then disconnect, and wait it will also delete it. So I'm curious what I can do about this?

ukBaz commented 2 years ago

The latest version of Raspberry Pi OS/Raspbian should be fine for BLE_GATT. No need for the --experimental flag either.

ukBaz commented 2 years ago

Shortly after doing that I see it delete devices. No input from me triggers this.

If you do a connect inside of bluetoothctl then that should stop BlueZ from deleting it automatically. After connecting once it should not be deleted.

When BlueZ does a scan it can possibly find a lot of devices over time. To manage this list of devices, BlueZ will delete any device it thinks is not of interest. If you connect to a device, it will understand that it is a device of interest and should not delete it.

So to be clear the steps inside bluetoothctl are:

scan on
scan off
connect xx:xx:xx:xx:xx:xx
disconnect

That device should then stay in the devices list until you delete it. If that is not happening then let me know, but that sounds like a bug in BlueZ.

DsapPH commented 2 years ago

Yes those are the steps I am taking and shortly after the disconnect it deletes the device like everything else.

ukBaz commented 2 years ago

OK, I'll try to reproduce over the weekend. This is with BlueZ 5.53?

DsapPH commented 2 years ago

I'm not confident on the BlueZ version. Is there a command I can run in order to see this?

Also for system I am running a Rasberry PI with Raspbian.

pi@raspberrypi:~/BaseStationFW $ cat /etc/os-release 
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
ukBaz commented 2 years ago

You can find the version of Bluez with either bluetoothd -v or bluetoothctl -v

DsapPH commented 2 years ago

Perfect and I am on BlueZ 5.55

DsapPH commented 2 years ago

For BLE we made both the client and the peripheral. They are gonna be hard coded as pairs. Is it possible to manually add the mac of the device to the device_list file? This would be useful since I could run that bash command in python before creating the device and trying to connection.

ukBaz commented 2 years ago

I've wiped a Raspberry Pi and started from scratch with a clean install of the latest Raspbery Pi OS. This uses BlueZ 5.55 and demonstrates the issue you are describing of deleting the device even if it has been connected to. Reading through the commits for the BlueZ repo I've found various mentions to "since the introduction of the new 30 seconds timeout when setting a device as temporary", but I can't find the actual commit where it was introduced so I don't know exactly what the new rules are.

Anyway, after a little experimentation the following procedure seemed to stop my device being deleted/removed

scan on
scan off
connect xx:xx:xx:xx:xx:xx
trust
disconnect

Can you try this on your system and see if it resolves the issue for you also.

DsapPH commented 2 years ago

Great find. This solved the issue of needing to scan between each connect. The devices is staying known, including during reboots.

I think that was everything in this ticket besides the Software Abort issue which is something for BlueZ forums. If that was everything feel free to close the ticket. Appreciate all the help with this.

ukBaz commented 2 years ago

Great! Glad we found a solution.

And I've learnt something new also :-)