IanHarvey / bluepy

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

BTLEDisconnected Error while working with notifications - Rasberry Pi 4 & Arduino Nano 33 BLE Sense #424

Open juanpervers opened 3 years ago

juanpervers commented 3 years ago

Hi everyone, I'm struggling with getting notifications feed from Arduino Nano 33 BLE sense. On the Arduino site everything seems to be OK - when I use LightBlue app, I can sign up for notification from any of my characteristics and it can run for hours. When I try it on the RPi, I get this error ALMOST every time. In one of 50 cases the program runs and reads notifications flawlessly, sometimes it reads 5 - 10 notifications, bot mostly it just crashes with following error:

Traceback (most recent call last):

  File "2.py", line 63, in <module>
    if arduino.waitForNotifications(1):
  File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 560, in waitForNotifications
    resp = self._getResp(['ntfy','ind'], timeout)
  File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 407, in _getResp
    resp = self._waitResp(wantType + ['ntfy', 'ind'], timeout)
  File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 362, in _waitResp
    raise BTLEDisconnectError("Device disconnected", resp)
bluepy.btle.BTLEDisconnectError: Device disconnected

The data from Arduino are UTF-8 coded strings. As stated in BluePy docs, readCharacteristic returns bytes. Can this be the issue? I cannot simply change the output format from Arduino, is there any chance to change it, before it runs through the handleNotifications method? I'm fairly new to Python and BLE, so please pardon my code. Any advise would be great. Thanks!

from bluepy.btle import *

class MyDelegate(DefaultDelegate):
    def _init__(self):
        DefaultDelegate._init__(self)

    def handleNotification(self,cHandle,data):
        string_data = data.decode(encoding='utf-8')
        print(string_data)

arduino1_MAC = "C2:C4:8B:0D:D5:96"
arduino_sensor_service_UUID = "c0877e75-f55c-4899-adcc-ccc9008cfc29"
arduino1_addr_type = "public"
arduino1_iface = 0

arduino = Peripheral(arduino1_MAC,arduino1_addr_type,arduino1_iface)
arduino.withDelegate(MyDelegate())

if (arduino.getState() == "conn"):
    for i in range(1):

        #without this the getServiceByUUID method crashes...
        arduino.getServices()

        #returns an instance of Service object
        arduino_sensor_service = arduino.getServiceByUUID(arduino_sensor_service_UUID)

        #returns a list of Characteristic objects
        arduino_sensor_characteristics = arduino_sensor_service.getCharacteristics()

        #create new list for characteristic handles
        arduino_sensor_characteristic_handles = []

        #create new list for CCC handles
        arduino_sensor_characteristic_cccHandles = []

        #get handle from each characteristic, its current value, compute cccHandle and store it
        for j in range(len(arduino_sensor_characteristics)):

            #display list of all characteristic handles, characteristics current values and type of values
            #print(arduino_sensor_characteristics[j].getHandle(),arduino_sensor_characteristics[j].read(),type(arduino_sensor_characteristics[j].read()))

            #stores list of all characteristic handle
            arduino_sensor_characteristic_handles.append(arduino_sensor_characteristics[j].getHandle())

            #stores list of all Client Characteristic Configuration handles to turn on notifications with
            arduino_sensor_characteristic_cccHandles.append(arduino_sensor_characteristic_handles[j] +1)

            #displays current values of characteristics under cccHandles and type of value
            #print(arduino.readCharacteristic(arduino_sensor_characteristic_cccHandles[j]),type(arduino.readCharacteristic(arduino_sensor_characteristic_cccHandles[j])))

        print(arduino_sensor_characteristic_cccHandles)

    turn_on_notifications = "\x01\x00"
    parameter = bytes(turn_on_notifications, 'utf-8')

    try:
        #this handle is 100% correct
        response = arduino.writeCharacteristic(13,parameter,withResponse=True)
        print(response)

        while True:
            if arduino.waitForNotifications(1):
                continue
            print("Waiting")
        print("Escaped while loop")
    finally:
        arduino.disconnect()