Adsense HTML/JavaScript

Monday, April 4, 2022

CircuitPython BLE UART between XIAO BLE Sense and ESP32-C3/S3

It's a exercise of CircuitPython to implement BLE UART between server and client. All boards are flashed with CircuitPython 7.2.4 firmware, with adafruit_ble 8.2.3.


The server side run on Seeed XIAO BLE Sense (nRF52840) + Expansion board. The code modified from Adafruit CircuitPython ble_uart_echo_test.py example, or here, setup BLE UART Server, but display on SSD1306 I2C OLED instead of echo back.

The client side run on Ai-Thinker NodeMCU ESP-C3-32S-Kit and Espressif ESP32-S3-DevKitC-1. The code modified from ble_uart_echo_client.py, or here. The user enter text in REPL to send to server side and display on SSD1306 I2C OLED.

un-solved issue:

If server side offline and the BLE link disconnected, then server side online again and re-connected, the client side will fail; tested on both ESP-C3-32S-Kit and ESP32-S3-DevKitC-1.


Exercise code:

cpyXIAOBLE_ble_uart_server_ssd1306.py, run on server side.
"""
Run CircuitPython 7.2.4 on
Seeed XIAO nRF52840 Sense with nRF52840 + Expansion Board.
Modified from ble_uart_echo_test.py.
Act as BLE server, wait connection and
display received line on ssd13106 OLED.

libs need:
- adafruit_ble folder
- adafruit_displayio_ssd1306.mpy
"""
import os
import sys
import board
import busio
import displayio
import adafruit_displayio_ssd1306

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
from adafruit_ble import __name__ as BLE_NAME
from adafruit_ble import __version__ as BLE_VERSION

displayio.release_displays()

# Create the I2C interface and display object of SSD1306_I2C.
i2c = busio.I2C(board.SCL, board.SDA)

ssd1306_i2c_addr = 60
display_width =128
display_height = 64
display_bus = displayio.I2CDisplay(
    i2c, device_address=ssd1306_i2c_addr)
display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

# with displayio initialized, and have nothing displayed.
# displayio act like a REPL terminal.
# anything print() will be displayed on displayio also.

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(BLE_NAME, ":", BLE_VERSION)
print("=================================================")
print(adafruit_displayio_ssd1306.__name__, adafruit_displayio_ssd1306.__version__)
print("SCL: ", board.SCL)
print("SDA: ", board.SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
#=================================

ble = BLERadio()
uart = UARTService()
advertisement = ProvideServicesAdvertisement(uart)

#=== scroll up to print screen ===
print()
print()
print()
print(" ---- hello ----")

while True:
    ble.start_advertising(advertisement)
    print("Waiting to connect")
    while not ble.connected:
        pass
    print("Connected")
    while ble.connected:
        s = uart.readline()
        if s:
            print(s.decode())
            uart.write(s)

print("~ bye ~")

cpyESP32x3_ble_uart_client_repl.py, run on client side.
"""
Run CircuitPython 7.2.4 on
AITHinker ESP32-C3S_Kit with ESP32-C3FN4/ESP32-S3-DevKitC-1-N8R8 with ESP32S3.
Modified from ble_uart_echo_client.py.
Act as BLE client, connect to server,
get user input from REPL and send to server.

libs need:
- adafruit_ble folder
"""
import os
import sys
import time

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
from adafruit_ble import __name__ as BLE_NAME
from adafruit_ble import __version__ as BLE_VERSION

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(BLE_NAME, ":", BLE_VERSION)
print("=================================================")

ble = BLERadio()
while True:
    while ble.connected and any(
        UARTService in connection for connection in ble.connections
    ):
        for connection in ble.connections:
            if UARTService not in connection:
                continue
            
            uart = connection[UARTService]
            
            # input() will block the code.
            # if connection lost while waiting user input,
            # ConnectionError will thrown in uart.write()
            userinput = input("\nEnter something: ")
            print(userinput)
            
            try:
                uart.write(userinput)
            except ConnectionError as exc:
                print("ConnectionError:", exc)
            
    print("disconnected, scanning")
    for advertisement in ble.start_scan(ProvideServicesAdvertisement, timeout=1):
        if UARTService not in advertisement.services:
            continue
        ble.connect(advertisement)
        print("connected")
        break
    ble.stop_scan()




It you cannot open two Thonny instance, read last post How to open dual Thonny instance.



1 comment:

  1. Hello.
    I am new to CircuitPython development and would like to know if you could help me to develop around 𝗫𝗜𝗔𝗢 𝗕𝗟𝗘 𝗻𝗥𝗙𝟱𝟮𝟴𝟰𝟬 𝗦𝗲𝗻𝘀𝗲 sensors.
    I would like to communicate in bluetooth with several sensors to retrieve movement data.
    Thank you in advance for your answer.

    ReplyDelete