ukBaz / python-bluezero

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

Uart example failure #321

Closed JeanPoll closed 2 years ago

JeanPoll commented 3 years ago

My setup: raspberrypi 4 Model B BlueZ 5.50 Python3

When I try the uart example, I'm running into the followin issues. Nordic nrf tools can connect but fails later, hereby the llogging from nrf Toolbox:

gatt.WriteDescriptor(00002902-0000-1000-8-000-00805f9b43fb,value=0x01-00) Error(0x1): GATT INVALID HANDLE

ukBaz commented 3 years ago

In the past there has been some confusion/changing of which is the Rx characteristic UUID and which is the Tx characteristics UUID. There is also the same around if it is notify or indicate. You can get a flavour around this with: https://github.com/lancaster-university/microbit-dal/issues number 259

It may be that the combination of those settings aren't quite correct for the nRF tool you are using. My tools of choice tend to be either https://play.google.com/store/apps/details?id=de.kai_morich.serial_bluetooth_terminal or https://www.nordicsemi.com/Software-and-tools/Development-Tools/nRF-Connect-for-mobile

It has worked with them when I've used them. I suspect the answer is to adjust those values for your setting. As to what should be in the example in Bluezero; I'm not sure what is the best answer. It is probably whatever works the most broadly. But I don't know how that is discovered.

a-krawciw commented 3 years ago

I have been running bluezero on a RPi 4 and the uart example has worked for me with the nRF Connect app as well as the nRF UART V2.0. However I have observed that the UART V2.0 app does not appear to request a notify so I have had to request notify in nRF connect within the TX characteristic.

ukBaz commented 3 years ago

I've taken some time to look at this today and I can't workout where the issue is. I can start the Bluezero Peripheral and then go into nRF Connect and enable the notifications on the TX characteristic. If I disconnect in nRF Connect and connect in UART V2.0 all works as expected.

Other experiments that I've tried are:

The StartNotify experiments seemed to work on the second time of connecting with UART V2.0

I can't workout how doing a StartNotify changes the CCCD on BlueZ. Maybe need to dive into the BlueZ code to better understand.

Any ideas or suggestions welcome.

denny61302 commented 3 years ago

I did the same experiments like you, but they failed.

Could you share how to use StartNotify method to enable the notification?

Edited:

I checked why my Cypress chip can send notification automatically and I found it use this protocol which is highlighted in the Bluetooth official spec..

image

I think using this function is the major difference between RPI and Cypress chip.

I am not sure we can implement some functionality on RPI with BlueZ.

ukBaz commented 3 years ago

In BlueZ the CCCD in controlled by StartNotify and StopNotify characteristic methods. With the nRF UART 2.0 and Adafruit Bluefruit Connect apps, they both send a request to start notifications when then first connect. If the current value on notifying is False then this works as expected. However, if the value has been set to True then it fails. This is because Bluezero's implementation of StartNotify does a test to see if calling the command toggles the state. https://github.com/ukBaz/python-bluezero/blob/392a115ace80a6d7257b76708ec24b99ec9e2e5d/bluezero/localGATT.py#L373-L386

This is why the experiments I ran with notifying = True only worked on the second attempt. On the first connection the CCCD never got changed to notifying because Bluezero thought it was already notifying and didn't change the state.

Reading the Bluetooth spec, it seems like 3.3.3.3 Client Characteristic Configuration is the section that defines the behaviour:

image

It seems to be working as expected for the UART example as the clients expect to have to set the value of notifications on connection.

jofleck commented 3 years ago

Are there any news? With iOS everything works as expected. Only my Android app returns 0x01 GATT_INVALID_HANDLE as error code while setting the descriptor. I found out that it works sometimes if I reboot the Raspi AND the android device

ukBaz commented 3 years ago

@jofleck: I think what I have found is that Notify should not have been a value that add_characteristic exposes. The characteristic should always be created with False and then StartNotify and StopNotify takes care of changing the value. I have not been able to repeatedly get it to fail. Can you say some more about the steps you are using to get it fail frequently on Android?

jofleck commented 3 years ago

I found this issue while devoloping the Android app for our project.

Steps to reproduce:

  1. start the GATT Server (in our case on a Raspi 4)
  2. connect an Android smartphone
  3. Stop the python script
  4. Restart the python script.
  5. Reconnect the the Android smartphone

Now nothing except restarting the Raspi and the Android device helps to get the Android smartphone working.

With iOS everything keeps working fine.

dustinkerstein commented 2 years ago

Have there been any updates on this issue? I'm running into the same thing with a Unity3D plugin. Thanks!

ukBaz commented 2 years ago

@dustinkerstein, I am not sure we are at the stage where we know where the error/issue is. Is it BlueZ, Bluezero, or maybe on the client side. What error reporting are you getting with the Unity3D plugin?

The GATT_INVALID_HANDLE error that has been reported above makes me think it could be a cache issue. Are the clients bonding (pairing) with the peripheral? Does refreshing the cache on the client help? Does this issue exist if the BlueZ example is used? https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test/example-gatt-server

dustinkerstein commented 2 years ago

Hey @ukBaz, I seem to think it's a mix of the client + maybe something else, possibly within bluezero or just the implementation of the ble-uart script. I tried that linked example-gatt-server but was unable to get it to show up in my BLE scans in nRF Toolbox under UART or the HeartRate category (and it also didn't show up in my Unity client). However, I have also been testing with a scripted derived from that example-gatt-server code, see here - https://scribles.net/creating-ble-gatt-server-uart-service-on-raspberry-pi/ - interestedly that code seems to run much more reliably, but I was having a little trouble adapting it to my uses (as it is currently based on stdin console input from the server). I'm sure it could be adapted, but I then found bluezero and it seems 10x simpler so I abandoned my work on that earlier script.

In my attempts to get the ble_uart script working, I went down a research hole around the importance of the descriptor in getting the notify behavior working. Ie. there's this special ID - "00002902-0000-1000-8000-00805f9b34fb" that Android particular seems to need. However, the script based on the example-gatt-server doesn't seem to use descriptors at all, at least in how the characteristics are interpreted on my Unity side. Though in the nRF Toolbox log, I can clearly see the notifications being enabled because of that descriptor...

Screenshot_20211019-073527

I got a little impatient last night and just ended up ordering a couple of these - https://www.adafruit.com/product/2267 - which abstracts away all of this complex GATT / BLE stuff in favor of a simple serial interface, which for me, is all I need.

Good luck in figuring out the root cause. I would still love to use a python-based BLE solution, so I'll stay tuned to any updates here. Thanks again.

dustinkerstein commented 2 years ago

@ukBaz, oh and in reference to your question about refreshing the cache on the client, I don't think that had any help. I tried "Reset the Bluetooth Module" in MacOS, and even though I'm not entirely sure what it does, it did not have any effect. One thing that did seem to work, was connecting with nRF Toolbox and sending/receiving a few working messages, and then trying in Unity. The first time after using nRF, Unity would work, but on subsequent runs, it would get stuck in that state where the notifying flag was false.

ukBaz commented 2 years ago

This issue has sat here for while so closing. Please re-open with more information if it is still an issue.