Skip to content

Week 11 Assignments - Embedded Networking and Communications

Board-to-Board Pushbutton LED Control using Arduino Bluetooth® Low Energy (BLE) Networking and Communication

Group Assignment

The group assignment for this week was to:

  • Send a message between two projects
  • Document your work to the group work page and reflect on your individual page what you learned

Outcomes

The group assignment page for this week is on the 2025 Charlotte Super Fab Lab group site for Week 11 - Embedded Networking and Communications.

What Was Learned

In the group assignment, we considered embedded communications using the I2C protocol using different combinations of development boards. This included I2C communication between a XIAO SAMD21 and XIAO ESP32C3, each with the same development board footprint, as well as between 2 XIAO ESP32C3 boards with different development board footprints.

We were able to (1) send messages between the boards and (2) use messaging to connect inputs and outputs across the boards. This provided us experience on:

  • Configuration and setup of I2C communication with unique board identities
  • Using I2C for communication between boards
  • Using I2C established communication channels for messaging to drive cross-platform input / output interactions

Individual Assignment

The individual assignment for this week was to:

  • Design, build and connect wired or wireless node(s) with network or bus addresses and a local input and/or output devices

Ardiuno Bluetooth® Low Energy

For the individual assignment, I considered the Ardunio Bluetooth® Low Energy (BLE) wireless communication protocol. The BLE protocol is designed for low power usage operation at low data rates.

The BLE protocol considers participating devices to act in a client-server model. "Peripheral devices" act as servers / data providers, such as providing sensor data. "Central devices" act as clients / data readers, retrieving information from peripheral devices.

A peripheral device may provide different types / categories of data, organized into "Services." For example, a sensor device might provide a weather service (including data on temperature and hummidity) and a separate battery service (including data on battery life for the device).

Each service provides individual data items, each referred to as a "Characteristic." For example, a weather service may provide a current temperature characteristic.

Arduino Bluetooth® Low Energy (BLE) Model1

For data communication in BLE, there are 3 identifiers used to uniquely address information. These include:

  • Device Address - each BLE device / board has a unique 48-bit "Bluetooth MAC" address
  • Service ID - each BLE service is identified by a "universally unique identifier" (UUID). It is a 16-bit UUID for standard services and a 128-bit UUID for custom services
  • Characteristic ID - each BLE characteristic may also be identified by a UUID, in the same format at the ID for the service it is a part of

Outcomes

To explore BLE wireless communication, I created a BLE connection between 2 development boards. The first board is the XIAO ESP32C3 microcontroller board that I developed previously in Week 8 - Electronics Production. The XIAO includes support for BLE protocols and has an external antenna. The second board is an Arduino UNO R4 WiFi that includes support for BLE protocols and has an internal antenna.

My XIAO development board has an onboard pushbutton, and the the Arduino UNO R4 WiFi has an onboard LED. In order to test inter-board communication using BLE, I planned to use the pushbutton on the XIAO board to control the onboard LED on the Arduino UNO R4 WiFi.

Programming Process / Environment Setup

For the programming process, I used the Arduino programming ecosystem with C++ code and utilized the Arduino IDE as the development environment.

  • In order to get started with BLE programming, I first had to install the ArduinoBLE library. This was done using the Arduino IDE Tools > Manage Libraries..., searching for "bluetooth", and installing the ArduinoBLE library by Arduino.

Coding BLE Server / Peripheral

I first worked on setting up the Arduino Uno R4 WiFi to be the BLE Server / Peripherial device. The device would maintain a byte variable (BLE characteristic) for the status of the onboard LED (0 for off, 1 for on). The peripheral would reference this value in order to set the status of the onboard LED. Client / central devices connected using BLE could access the LED service / characteristic and read or update the value (checking or changing the status of the LED).

Overall, the server should:

  • Start BLE operation
  • Set up the LED service with UUID
  • Set up the LED switch characteristic with UUID
  • Set up event handlers to respond to BLE events:
    • Messaging on device connect
    • Messaging on device disconnect
    • Messaging on switch value update
    • Set onboard LED in response to switch value update
  • Start advertising the service for connection

The Arduino IDE includes example programs for BLE communication. I adopted the Arduino BLE LED Peripheral example as the basis to drive the Arduino UNO R4 WiFi LED peripheral. The examples include both a basic version and version that uses events / callbacks. I explored the event-driven callback version.

The LEDCallback service and the swtich characteristic are identified by custom UUIDS:

  • LED Service UUID: 19B10000-E8F2-537E-4F6C-D104768A1214
  • LED Switch Characteristic UUID: 19B10001-E8F2-537E-4F6C-D104768A1214
Arduino BLE LED Peripheral - Event-Driven Callback Version
#include <ArduinoBLE.h>

BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // create service

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

const int ledPin = LED_BUILTIN; // pin to use for the LED

void setup() {
  Serial.begin(9600);
  while (!Serial);

  pinMode(ledPin, OUTPUT); // use the LED pin as an output

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting Bluetooth® Low Energy module failed!");

    while (1);
  }

  // set the local name peripheral advertises
  BLE.setLocalName("LEDCallback");
  // set the UUID for the service this peripheral advertises
  BLE.setAdvertisedService(ledService);

  // add the characteristic to the service
  ledService.addCharacteristic(switchCharacteristic);

  // add service
  BLE.addService(ledService);

  // assign event handlers for connected, disconnected to peripheral
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  // assign event handlers for characteristic
  switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);
  // set an initial value for the characteristic
  switchCharacteristic.setValue(0);

  // start advertising
  BLE.advertise();

  Serial.println(("Bluetooth® device active, waiting for connections..."));
}

void loop() {
  // poll for Bluetooth® Low Energy events
  BLE.poll();
}

void blePeripheralConnectHandler(BLEDevice central) {
  // central connected event handler
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLEDevice central) {
  // central disconnected event handler
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
}

void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
  // central wrote new value to characteristic, update LED
  Serial.print("Characteristic event, written: ");

  if (switchCharacteristic.value()) {
    Serial.println("LED on");
    digitalWrite(ledPin, HIGH);
  } else {
    Serial.println("LED off");
    digitalWrite(ledPin, LOW);
  }
}

In order to test whether the LED Peripheral setup was working properly, I used a general-purpose BLE utility - Blutility. Bluetility provides a basic UI to browse available devices, browse peripheral services and characteristics, and viewing / updating characteristic values.

I checked the basic operation using the Arduino IDE Serial Monitor output, as well as the LED operation.

Arduino UNO R4 WiFi BLE Peripheral - Serial Monitor Output
Connected event, central: ac:c9:06:0b:26:44
Characteristic event, written: LED on
Characteristic event, written: LED off
Characteristic event, written: LED on
Characteristic event, written: LED off
Characteristic event, written: LED on
Characteristic event, written: LED off

The video demonstration shows the LED Peripheral program running on the Arduino UNO R4 WiFi. Blutility is refreshed to detect BLE devices. The device named LEDCallback is selected, and that shows the avalable Services. Selecting the designated service shows the available characteristics. Selecting the available characteristic allows the value to be updated. Update of the LED switch characteristic triggers the value-written event handler. In the handler, setting the LED switch characteristic to a non-zero value turns the LED on. Setting the LED switch characteristic to a zero value turns the LED off.

Testing with Bluetility showed that the LED peripheral device setup seemed to be working properly.

Using Blutility to Connect via BLE with Arduino UNO R4 WiFi and Test Setting LED Switch Characteristic

Coding BLE Server / Peripheral

I next worked to set up my XIAO ESP32C3 development board to be the BLE Client / Central device. Overall, the client should:

  • Start BLE operation
  • Scan for available BLE devices - specifically for a device that is advertising the specific service UUID: 19b10000-e8f2-537e-4f6c-d104768a1214
  • Connect to the device
  • Access the LED Service / Switch Characteristic
  • Use BLE communication to set the LED switch status to correspond with the current status of the onboard pushbutton

The Arduino IDE includes example programs for BLE communication. I adopted the Arduino BLE LED Central control example as the basis to drive the Arduino UNO R4 WiFi LED peripheral.

Arduino BLE LED Central Control
#include <ArduinoBLE.h>

// variables for button
const int buttonPin = D7;
int oldButtonState = LOW;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // configure the button pin as input
  pinMode(buttonPin, INPUT);

  // initialize the Bluetooth® Low Energy hardware
  BLE.begin();

  Serial.println("Bluetooth® Low Energy Central - LED control");

  // start scanning for peripherals
  BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
}

void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();

    if (peripheral.localName() != "LEDCallback") {
      return;
    }

    // stop scanning
    BLE.stopScan();

    controlLed(peripheral);

    // peripheral disconnected, start scanning again
    BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
  }
}

void controlLed(BLEDevice peripheral) {
  // connect to the peripheral
  Serial.println("Connecting ...");

  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }

  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }

  // retrieve the LED characteristic
  BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10001-e8f2-537e-4f6c-d104768a1214");

  if (!ledCharacteristic) {
    Serial.println("Peripheral does not have LED characteristic!");
    peripheral.disconnect();
    return;
  } else if (!ledCharacteristic.canWrite()) {
    Serial.println("Peripheral does not have a writable LED characteristic!");
    peripheral.disconnect();
    return;
  }

  while (peripheral.connected()) {
    // while the peripheral is connected

    // read the button pin
    int buttonState = digitalRead(buttonPin);

    if (oldButtonState != buttonState) {
      // button changed
      oldButtonState = buttonState;

      if (buttonState) {
        Serial.println("button pressed");

        // button is pressed, write 0x01 to turn the LED on
        ledCharacteristic.writeValue((byte)0x01);
      } else {
        Serial.println("button released");

        // button is released, write 0x00 to turn the LED off
        ledCharacteristic.writeValue((byte)0x00);
      }
    }
  }

  Serial.println("Peripheral disconnected");
}

With the code for the central control loaded on to the XIAO ESP32C3, I I checked the basic operation using the Arduino IDE Serial Monitor output for both boards, as well as the LED operation.

XIAO ESP32C3 BLE Control - Serial Monitor Output
Bluetooth® Low Energy Central - LED control
Found f4:12:fa:63:5d:41 'LEDCallback' 19b10000-e8f2-537e-4f6c-d104768a1214
Connecting ...
Connected
Discovering attributes ...
Attributes discovered
button pressed
button released
button pressed
button released
button pressed
button released
Arduino UNO R4 WiFi BLE Peripheral - Serial Monitor Output
Connected event, central: 24:ec:4a:c9:9d:c6
Characteristic event, written: LED on
Characteristic event, written: LED off
Characteristic event, written: LED on
Characteristic event, written: LED off
Characteristic event, written: LED on
Characteristic event, written: LED off

LED Pushbutton Remote Control Over BLE