One simple way of communicating between two BLE devices is to use a simulated "UART". A UART provides a bi-directional byte stream, so that both ends of a connection can transmit and receive bytes with each other.

There are standard BLE UART services, such as the Nordic UART Service (NUS). The Adafruit Bluefruit Connect app uses NUS to talk to BLE boards.

Once you get the UART service working, it's easy to invent your own ad hoc protocol that sends and receives commands and data over the serial stream.

BLE UART Python eval() Example

Here's a simple example that uses BLE UART to send a text string from a host computer to a CircuitPython board over BLE. The board calls the Python function eval() on the string, to evaluate it as a Python expression, and sends the result back as a string to the host computer. For instance, the host might send 2+2, and the board will send back 4.

To try this example, first install this library from the latest library bundle on your BLE-capable CircuitPython board, such as a Feather nRF52840 or a Circuit Playground Bluefruit:

  • adafruit_ble

Then copy the program below to CIRCUITPY on your CircuitPython board as code.py:

# Provide an "eval()" service over BLE UART.

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

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

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:
            try:
                result = str(eval(s))
            except Exception as e:
                result = repr(e)
            uart.write(result.encode("utf-8"))

Now copy the second program to your host computer, and run it. Wait for it to connect to your board, and then type some Python expressions at the Eval: prompt. 

# Connect to an "eval()" service over BLE UART.

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

ble = BLERadio()

uart_connection = None

while True:
    if not uart_connection:
        print("Trying to connect...")
        for adv in ble.start_scan(ProvideServicesAdvertisement):
            if UARTService in adv.services:
                uart_connection = ble.connect(adv)
                print("Connected")
                break
        ble.stop_scan()

    if uart_connection and uart_connection.connected:
        uart_service = uart_connection[UARTService]
        while uart_connection.connected:
            s = input("Eval: ")
            uart_service.write(s.encode("utf-8"))
            uart_service.write(b'\n')
            print(uart_service.readline().decode("utf-8"))

Here's an example of running the ble_eval_client.py program on a Raspberry Pi Zero W, talking to a Circuit Playground Bluefruit.

Note that errors, like division by zero, are caught and reported. Also note you can only type Python expressions, not statements. So a = 3 doesn't work.

This guide was first published on Oct 27, 2020. It was last updated on Oct 27, 2020.

This page (BLE UART) was last updated on Oct 23, 2021.

Text editor powered by tinymce.