IanHarvey / bluepy

Python interface to Bluetooth LE on Linux
Other
1.6k stars 491 forks source link

Attempting to read from a Characteristic with more than 20 bytes throws an BTLEInternalError exception #459

Open js82jumper opened 3 years ago

js82jumper commented 3 years ago

I have a BTLE device that I have been working with to get the basic gatt information from. I have been successfully reading values from it for a couple days now and today the device would disconnect when it starts reading Characteristics that return more than 20 bytes from any of the characteristics. I set debug on for bluepy.btle and I get this output from my script:


Characteristic


UUID: 00002a4a-0000-1000-8000-00805f9b34fb Property: READ Sent: rd 18

Got: "rsp=$stat\x1estate=$disc\x1emtu=h0\x1esec='low\n" Stopping /usr/local/lib/python3.7/dist-packages/bluepy/bluepy-helper 52656164204572726f72

The debug output messages then stop while my script continues to read the next few characteristics until eventually I get to one and I get this:


Characteristic


UUID: 00002a4d-0000-1000-8000-00805f9b34fb Property: READ WRITE NO RESPONSE WRITE 52656164204572726f72 Write Handle: 34 Traceback (most recent call last): File "btlab.py", line 87, in dev.writeCharacteristic(handle=characteristic.getHandle(), val=characteristic.read(), withResponse=False) File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 197, in read return self.peripheral.readCharacteristic(self.valHandle) File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 529, in readCharacteristic self._writeCmd("rd %X\n" % handle) File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 302, in _writeCmd raise BTLEInternalError("Helper not started (did you call connect()?)") bluepy.btle.BTLEInternalError: Helper not started (did you call connect()?)

The one above happens to have a write in it but I don't think that matters because I commented out the stuff to write to the characteristics and the one above will continue fine but I get the same problem later when I get to a custom service that returns some values that are very long (504 bytes).

Does anyone have any ideas why after a few days of being able to read these long characteristics suddenly it would start disconnecting the device?

Thanks

js82jumper commented 3 years ago

I'm not sure what the underlying issue is but I found steps to fix it.

If I use bletoothctl:

  1. power on
  2. agent on
  3. default-agent
  4. discoverable on
  5. scan on
  6. scan off #after 10 seconds or so
  7. trust
  8. pair
  9. connect
  10. discoverable off

Now my device is in the list of Bluetooth Devices and I can get data from it.

If I run this code:

_addr_type        = btle.ADDR_TYPE_PUBLIC
_bt_adapter_iface = 0
dev = btle.Peripheral('xx:xx:xx:xx:xx:xx', _addr_type, _bt_adapter_iface)

I get this output:

Running  /usr/local/lib/python3.7/dist-packages/bluepy/bluepy-helper
Sent:  conn xx:xx:xx:xx:xx:xx public hci0

Got: '# bluepy-helper.c version 1.3.0 built at 06:27:58 on Jul 16 2019\n'
Got: "rsp=$stat\x1estate=$tryconn\x1edst='xx:xx:xx:xx:xx:xx\x1emtu=h0\x1esec='low\n"
Got: "rsp=$stat\x1estate=$disc\x1emtu=h0\x1esec='low\n"
Stopping  /usr/local/lib/python3.7/dist-packages/bluepy/bluepy-helper
Failed to connect to peripheral xx:xx:xx:xx:xx:xx, addr type: public

As long as the device is connected to the host I can not get a connection through btle.Peripheral().

If I pair the device to another system without removing it from this host (Raspberry Pi 4b) then I can connect to the device with the code above, and I can get GATT characteristic information for anything that is 20 bytes or less. Reading anything longer causes the BTLEInternalError exception issue.

If I remove the device (bluetoothctl remove ) then I can connect to the device with the code above, read the GATT information including the characteristics with long 20+ byte values, but I can't get any other data from it.

Is there any reason why I cannot get GATT information from the device when it is connected to the host?

RenierM26 commented 2 years ago

Hi @js82jumper,

Did you try:

dev.writeCharacteristic(handle=characteristic.getHandle(), val=characteristic.read(), withResponse=True)

There's a note in the code about the way bluez handles messages with/without response. Seems to have issues processing more than 20 bytes without "withResponse=True" (some or other MTU issue)

js82jumper commented 2 years ago

Hi @RenierM26 ,

I'll have to try to revisit this when I get a chance. Turned out there was an issue with the device. The firmware had some of the code for handling more than 20 bytes commented out. On an attempt to process a message, the device would acknowledge that it was going to do a >20 byte message, but would never send the message to start. Both host and client would then sit there until the device would give up and shut down, and the exception above would be thrown. This was causing issues not only with itself, but it was causing exceptions on other OS's as well.