pythonbluetooth-lowenergyesp32micropythongatt

micropython aioble esp32: charactrictic.written() never returns (even upon a write)


I am working with ESP32-C3.
I created a BLE GATT Server, I want to exchange data with it bidirectionally.
I am using nRF Connect android app for debugging.
Charactrictic #1 is used to send data from ESP to nRF Connect. It works fine.
Charactrictic #2 is used to receive data from nRF Connect on ESP32.
It doesn't work: connection, data = await recv_char.written(timeout_ms=_ADV_INTERVAL_MS) awaits infinitely and never returns. Even when I make a write in NRF Connect. Below is my code, mostly copy-pasted from examples. Please help me find the mistake in data reception on the ESP32 side.

import sys

sys.path.append('')

import asyncio
import aioble
import bluetooth
import machine
import time

led = machine.Pin(8, machine.Pin.OUT)
GATT_UUID = bluetooth.UUID(0x1802)
GATT_CHAR_UUID = bluetooth.UUID("90D3D001-C950-4DD6-9410-2B7AEB1DD7D8")
RECV_CHAR_UUID = bluetooth.UUID("90D3D002-C950-4DD6-9410-2B7AEB1DD7D8")
_ADV_INTERVAL_MS = 250_000
# Register GATT server, the service and characteristics
ble_service = aioble.Service(GATT_UUID)
sensor_characteristic = aioble.Characteristic(ble_service, GATT_CHAR_UUID, read=True, notify=True, write=True,
                                              capture=True)
recv_char = aioble.Characteristic(ble_service, RECV_CHAR_UUID, write=True, notify=True, capture=True)

# Register service(s)
aioble.register_services(ble_service)


def _decode_data(data):
    try:
        if data is not None:
            # Decode the UTF-8 data
            number = int.from_bytes(data, 'big')
            return number
    except Exception as e:
        print("Error decoding temperature:", e)
        return None


async def peripheral_task():
    while True:
        try:
            async with await aioble.advertise(_ADV_INTERVAL_MS, name="MYNAME",
                                              services=[GATT_UUID], ) as connection:
                print("Connection from", connection.device)
                await connection.disconnected()
        except asyncio.CancelledError:
            # Catch the CancelledError
            print("Peripheral task cancelled")
        except Exception as e:
            print("Error in peripheral_task:", e)
        finally:
            # Ensure the loop continues to the next iteration
            await asyncio.sleep_ms(100)


async def wait_for_write():
    while True:
        try:
            connection, data = await recv_char.written(timeout_ms=_ADV_INTERVAL_MS)
            # Here it fails ^
            print('OLOLO')
            print(data)
            # print(type)
            data = _decode_data(data)
            print('Connection: ', connection)
            print('Data: ', data)
            if data == 1:
                print('Turning LED ON')
                led.value(1)
            elif data == 0:
                print('Turning LED OFF')
                led.value(0)
            else:
                print('Unknown command')
        except asyncio.CancelledError:
            # Catch the CancelledError
            print("Wait4Write task cancelled")
        except Exception as e:
            print("Error in Wait4write_task:", e)
        finally:
            # Ensure the loop continues to the next iteration
            await asyncio.sleep_ms(500)


def _encode_data(data):
    return str(data).encode('utf-8')


async def sensor_task():
    while True:
        value = b'Hello World!'
        sensor_characteristic.write(_encode_data(value), send_update=True)
        # print('New value written: ', value)
        await asyncio.sleep_ms(1000)


# Run tasks
async def ble_main():
    t1 = asyncio.create_task(peripheral_task())
    t2 = asyncio.create_task(sensor_task())
    t3 = asyncio.create_task(wait_for_write())
    await asyncio.gather(t1, t2, t3)

I tried various methods of sending data in nRF Connect, also tried to send and receive data in one charactristic. Then I split sending and receiving into 2 distinct characteristics. No effect.


Solution

  • I solved my own problem.

    The mistake was:

    GATT_UUID = bluetooth.UUID(0x1802)

    I changed that UUID to a 128-bit unique one, and it worked. Hope this post helps someone.