Reputation: 645
I am running a BLE server on an ESP32 which is sending the value of time periodically. This code is being run on Arduino IDE. On the other hand, I have a Python code running on my PC which needs to receive that value and display it on the GUI.
When I run the Python code, it connects to the ESP32 successfully but throws an error while trying to subscribe to the notifications from the ESP32. The error is as follows:
Exception in thread Thread-1 (start_ble_loop):
Traceback (most recent call last):
File "C:\Program Files\Python312\Lib\threading.py", line 1073, in _bootstrap_inner
self.run()
File "C:\Program Files\Python312\Lib\threading.py", line 1010, in run
self._target(*self._args, **self._kwargs)
File "E:\AC_Work\Task_9_Radar implementation\BLE GUI\gui_code.py", line 42, in start_ble_loop
loop.run_until_complete(connect_and_receive())
File "C:\Program Files\Python312\Lib\asyncio\base_events.py", line 684, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "E:\AC_Work\Task_9_Radar implementation\BLE GUI\gui_code.py", line 28, in connect_and_receive
await client.start_notify(BLE_CHARACTERISTIC_UUID, notification_handler)
File "D:\Users\26101179\AppData\Roaming\Python\Python312\site-packages\bleak\__init__.py", line 844, in start_notify
await self._backend.start_notify(characteristic, wrapped_callback, **kwargs)
File "D:\Users\26101179\AppData\Roaming\Python\Python312\site-packages\bleak\backends\winrt\client.py", line 981, in start_notify
await winrt_char.write_client_characteristic_configuration_descriptor_async(
OSError: [WinError -2140864509] The attribute cannot be written
My Arduino code is as follows:
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include "esp_bt_device.h"
#define SERVICE_UUID "12345678-1234-5678-1234-56789abcdef0"
#define CHARACTERISTIC_UUID "87654321-4321-6789-4321-67890abcdef0"
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
void printBLEMacAddress() {
const uint8_t* mac = esp_bt_dev_get_address();
Serial.print("ESP32 BLE MAC Address: ");
for (int i = 0; i < 6; i++) {
Serial.printf("%02X", mac[i]);
if (i < 5) Serial.print(":");
}
Serial.println();
}
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
}
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
pServer->getAdvertising()->start(); // Restart advertising
}
};
void setup() {
Serial.begin(115200);
BLEDevice::init("ESP32_BLE");
// Print BLE MAC Address
printBLEMacAddress();
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_NOTIFY
);
pService->start();
pServer->getAdvertising()->start();
Serial.println("BLE Server Started");
}
void loop() {
if (deviceConnected) {
String millisStr = String(millis()); // Get millis() value
pCharacteristic->setValue(millisStr.c_str());
pCharacteristic->notify(); // Send the value
Serial.println("Sent: " + millisStr);
}
delay(1000);
}
And my Python code is as follows:
import tkinter as tk
from bleak import BleakClient, BleakError
import asyncio
import time
import threading
# Values determined through nrfConnect
ESP32_BLE_MAC = "74:4D:BD:61:D2:6D"
BLE_CHARACTERISTIC_UUID = "87654321-4321-6789-4321-67890abcdef0"
async def connect_and_receive():
while True: # Keep retrying connection
try:
print("Attempting to connect to ESP32 BLE...")
label.config(text="Connecting to ESP32...")
async with BleakClient(ESP32_BLE_MAC) as client:
if client.is_connected:
print("Connected to ESP32 BLE")
label.config(text="Connected to ESP32")
def notification_handler(sender, data):
"""Callback function when new data is received."""
millis_value = int.from_bytes(data, byteorder="little")
label.config(text=f"Millis: {millis_value}")
# Subscribe to notifications
await client.start_notify(BLE_CHARACTERISTIC_UUID, notification_handler)
while True:
await asyncio.sleep(1) # Keep listening for data
except BleakError as e:
print(f"Connection failed: {e}")
label.config(text="ESP32 not found! Retrying...")
time.sleep(5) # Wait before retrying
# Function to run asyncio loop in a separate thread
def start_ble_loop():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(connect_and_receive())
# Tkinter GUI Setup
root = tk.Tk()
root.title("ESP32 BLE Monitor")
label = tk.Label(root, text="Waiting for connection...", font=("Arial", 16))
label.pack(pady=20)
# Start BLE communication in a separate thread
threading.Thread(target=start_ble_loop, daemon=True).start()
# Run the GUI
root.mainloop()
Any ideas what could be causing the problem?
Upvotes: 0
Views: 39
Reputation: 120
The data sent by ESP32 is actually a string, not a raw integer, but Python code is probably interpreting it as raw bytes and trying to convert into an integer. This approach might be better:
def notification_handler(sender, data):
millis_value = data.decode("utf-8") # decoding to read as string
label.config(text=f"Millis: {millis_value}")
According to Arduino code, there are recommendations to add BLE2902.h (it is a requirement for Windows OS)
in setup()
pCharacteristic->addDescriptor(new BLE2902());
Upvotes: 0