hbldh / bleak

A cross platform Bluetooth Low Energy Client for Python using asyncio
MIT License
1.6k stars 279 forks source link

bleak.exc.BleakError: Characteristic 00002011-0000-1000-8000-00805f9b34fb not found! #1379

Closed Thm14 closed 1 month ago

Thm14 commented 10 months ago

Description

I need to measure the accelerations of a moving object. For this, I am using the Arduino Nano 33, which has the integrated sensor IMU LSM9DS1, so I am trying to read and save the accelerations from the sensor and be able to keep them in the computer, all through communication BLE, for this, I am using a code that I found on the web (I attach them below, credits to: Antony García González from PanamaHitek, [https://panamahitek.com/comunicacion-inalambrica-entre-arduino-y-python-usando-ble/]) the problem is that I get an error: raise BleakError(f"Characteristic {char_specifier} not found!") bleak.exc.BleakError: Characteristic 00002011-0000-1000-8000-00805f9b34fb not found!

The first thing I thought was that the UUID must be misspelled or it had to be another, I used two applications on my cell phone: nRF Connect and BLE Scanner to know the characteristics, and in my opinion, the numbers are fine (they are the same as the script), but the error continues

What I Did

File "C:\Users\Tomás Herrera Muño\Dropbox\PhD PUC\Tesis\Proyecto Towing Tank\Arduino\Códigos\Nano 33 BLE\read_Nano33.py", line 46, in run
    await client.start_notify("00002011-0000-1000-8000-00805f9b34fb", handle_accel_notification)
  File "C:\Users\Tomás Herrera Muño\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\bleak\__init__.py", line 705, in start_notify
    raise BleakError(f"Characteristic {char_specifier} not found!")
bleak.exc.BleakError: Characteristic 00002011-0000-1000-8000-00805f9b34fb not found!

Logs

Include any relevant logs here.

Arduino script:
#include <ArduinoBLE.h>
#include <Arduino_LSM9DS1.h>

// Declare a BLE service with UUID "1001"
BLEService IMUservice("1001");

// Declare two BLE characteristics for the accelerometer and gyroscope data, both with UUIDs "2001" and "2011" respectively.
// The characteristics are readable and notify, and have a maximum data length of 20 bytes.
BLECharacteristic accelData("2001", BLERead | BLENotify, 20);
BLECharacteristic gyroData("2011", BLERead | BLENotify, 20);

void setup() {
  // Initialize the BLE module
  if (!BLE.begin()) {
    // If the BLE module fails to initialize, enter an infinite loop
    while (1) {
    }
  }

  // Initialize the IMU
  if (!IMU.begin()) {
    // If the IMU fails to initialize, enter an infinite loop
    while (1) {
    }
  }

  // Set the device name and local name to "IMU"
  BLE.setDeviceName("IMU");
  BLE.setLocalName("IMU");

  // Add the service to the BLE module
  BLE.setAdvertisedService(IMUservice);

  // Add the two characteristics to the service
  IMUservice.addCharacteristic(accelData);
  IMUservice.addCharacteristic(gyroData);

  // Add the service to the BLE module
  BLE.addService(IMUservice);

  // Set the connection interval for the BLE connection
  BLE.setConnectionInterval(8, 8);

  // Enable the BLE module to be connectable
  BLE.setConnectable(true);

  // Start advertising the BLE connection
  BLE.advertise();
}

void loop() {
  float acX, acY, acZ, gX, gY, gZ;

  // Get the connected BLE central device
  BLEDevice central = BLE.central();
  if (central) {
    // If there is a connected BLE central device, enter an infinite loop
    while (central.connected()) {
      // Read the accelerometer data from the IMU device
      IMU.readAcceleration(acX, acY, acZ);

      // Create a string with the accelerometer data
      String accelString = String(acX) + "," + String(acY) + "," + String(acZ);

      // Write the accelerometer data to the BLE characteristic
      accelData.writeValue(accelString.c_str());

      // Read the gyroscope data from the IMU device
      IMU.readGyroscope(gX, gY, gZ);

      // Create a string with the gyroscope data
      String gyroString = String(gX) + "," + String(gY) + "," + String(gZ);

      // Write the gyroscope data to the BLE characteristic
      gyroData.writeValue(gyroString.c_str());

      // Wait 7 milliseconds before sending the next data
      delay(7);
    }
  }
}

Python script:

import asyncio, time, json
from bleak import BleakClient

# Function to handle accelerometer data received as a notification
def handle_accel_notification(sender, data):
    # Split the data into separate x, y, z values
    x, y, z = data.decode().split(',')
    acX = float(x)
    acY = float(y)
    acZ = float(z)

    # Get the current time
    timestamp = time.time()

    # Create a dictionary with the accelerometer data
    accel_data = {"acc_x": acX, "acc_y": acY, "acc_z": acZ, "Timestamp": timestamp}

    # Write the accelerometer data to a JSON file
    with open("data.json", "a") as json_file:
        json.dump(accel_data, json_file)
        json_file.write(',\n')

# Function to handle gyroscope data received as a notification
def handle_gyro_notification(sender, data):
    # Split the data into separate x, y, z values
    gx, gy, gz = data.decode().split(',')
    gX = float(gx)
    gY = float(gy)
    gZ = float(gz)

    # Get the current time
    timestamp = time.time()

    # Create a dictionary with the gyroscope data
    gyro_data = {"gy_x": gX, "gy_y": gY, "gy_z": gZ, "Timestamp": timestamp}

    # Write the gyroscope data to a JSON file
    with open("data.json", "a") as json_file:
        json.dump(gyro_data, json_file)
        json_file.write(',\n')

# Asynchronous function to connect to the BLE peripheral
async def run(address, loop):
    async with BleakClient(address, loop=loop) as client:
        # Start receiving notifications for the accelerometer data
        await client.start_notify("00002011-0000-1000-8000-00805f9b34fb", handle_accel_notification)

        # Start receiving notifications for the gyroscope data
        await client.start_notify("00002011-0000-1000-8000-00805f9b34fb", handle_gyro_notification)

        # Continuously run the loop
        while True:
            await asyncio.sleep(0.001)

# Address of the BLE peripheral to connect to
address = "7E:36:B3:47:6F:DA"

# Get the event loop
loop = asyncio.get_event_loop()

# Run the asynchronous function
loop.run_until_complete(run(address, loop))
dlech commented 10 months ago

What happens when you run the service_explorer.py example with this device?

Does it work if you use 128-bit UUIDs on the arduino instead of 16-bit UUIDs?

Thm14 commented 10 months ago

Dlech thanks for your comment! I tried both UUID settings. When using service_explorer.py, the message is: usage: service_explorer.py [-h] (--name | --address

) [--macos-use-bdaddr] [--services [ ...]] [-d] service_explorer.py: error: one of the arguments --name --address is required

dlech commented 10 months ago

You need to provide the correct command line parameters so that the script will connect to your device.

Thm14 commented 10 months ago

I see, I'm new to python, I don't know much about the nomenclature, I understand that it should be: python service_explorer.py--IMU--7E:36:B3:47:6F:DA ?? which would be the name: IMU and the address: 7E:36:B3:47:6F:DA, I don't know if it is with those hyphens, if it has a space or not, or if some other input parameter is missing to perform the scan...

dlech commented 10 months ago

python service_explorer.py--IMU--7E:36:B3:47:6F:DA ??

python service_explorer.py --address 7E:36:B3:47:6F:DA

or

python service_explorer.py --name IMU
Thm14 commented 10 months ago

Hello!!!, I was able to run the code "service explorer", it gives the following results:

C:\Users\Tomás Herrera Muño\Dropbox\PhD PUC\Tesis\Proyecto Towing Tank\Arduino\Códigos\Nano 33 BLE>python service_explorer.py --address 7E:36:B3:47:6F:DA
2023-07-31 09:28:30,443 __main__ INFO: starting scan...
2023-07-31 09:28:30,751 __main__ INFO: connecting to device...
2023-07-31 09:28:31,229 __main__ INFO: connected
2023-07-31 09:28:31,229 __main__ INFO: [Service] 00001800-0000-1000-8000-00805f9b34fb (Handle: 1): Generic Access Profile
2023-07-31 09:28:31,245 __main__ ERROR:   [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb (Handle: 2): Device Name (read), Error: Could not read characteristic handle 2: Unreachable
2023-07-31 09:28:31,246 __main__ ERROR:   [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb (Handle: 4): Appearance (read), Error: Not connected
2023-07-31 09:28:31,247 __main__ INFO: [Service] 00001801-0000-1000-8000-00805f9b34fb (Handle: 6): Generic Attribute Profile
2023-07-31 09:28:31,247 __main__ INFO:   [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb (Handle: 7): Service Changed (indicate)
2023-07-31 09:28:31,248 __main__ ERROR:     [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 9): Client Characteristic Configuration, Error: Not connected
2023-07-31 09:28:31,248 __main__ INFO: [Service] 00001101-0000-1000-8000-00805f9b34fb (Handle: 10): Serial Port
2023-07-31 09:28:31,249 __main__ ERROR:   [Characteristic] 00002101-0000-1000-8000-00805f9b34fb (Handle: 11): Vendor specific (read,notify), Error: Not connected
2023-07-31 09:28:31,250 __main__ ERROR:     [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 13): Client Characteristic Configuration, Error: Not connected
2023-07-31 09:28:31,251 __main__ ERROR:   [Characteristic] 00002102-0000-1000-8000-00805f9b34fb (Handle: 14): Vendor specific (read,notify), Error: Not connected
2023-07-31 09:28:31,251 __main__ ERROR:     [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 16): Client Characteristic Configuration, Error: Not connected
2023-07-31 09:28:31,252 __main__ ERROR:   [Characteristic] 00002103-0000-1000-8000-00805f9b34fb (Handle: 17): Vendor specific (read,notify), Error: Not connected
2023-07-31 09:28:31,252 __main__ ERROR:     [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 19): Client Characteristic Configuration, Error: Not connected
2023-07-31 09:28:31,253 __main__ INFO: disconnecting...
2023-07-31 09:28:31,261 __main__ INFO: disconnected

Apparently it's not reading the characteristic, and that's why many errors come out later...

dlech commented 10 months ago

You are supposed to pay the Bluetooth SIG if you want your own 16-bit UUID. The 16-bit UUIDs you are using may be blocked by Windows. For both of these reasons, I have suggested using 128-bit UUIDs instead.

Thm14 commented 10 months ago

I tried that and now the error is another: in start_notify await winrt_char.write_client_characteristic_configuration_descriptor_async(OSError: [WinError -2147467260] Operación anulada

dlech commented 10 months ago

It looks like the device is disconnecting before it finishes enumerating the characteristics. I would log Bluetooth packets to see what is going on. Probably something misconfigured on the Arduino or a Windows caching issue.

Thm14 commented 10 months ago

Finally I was able to measure, they were the UUID of the IMU that the board brings, the correct ones for my ARDUINO NANO 33 BLE board are:

// Declare a BLE service with UUID:
BLEService IMUservice("19B10010-E8F2-537E-4F6C-D104768A1214");
// Declare two BLE characteristics for the accelerometer and gyroscope data, both with UUIDs:
BLECharacteristic accelData("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 20);
BLECharacteristic gyroData("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 20);