Chapter 8 BLE

Project 8.1 BLE USART

Component List

Freenove ESP32 Display x 1

Chapter01_02

USB cable x1

Chapter01_03

Component Knowledge

BLE(Bluetooth Low Energy)

Low Energy Bluetooth (BLE) is a new feature introduced in the Bluetooth 4.0 specification, specifically designed for low-power devices and suitable for applications involving intermittent transmission of small amounts of data.

The BLE architecture follows a client-server model and consists of the following key components:

GATT (Generic Attribute Protocol): The foundational protocol for BLE communication, defining a hierarchical data structure of services and characteristics.

Service: A collection of data that performs a specific function or feature, containing one or more characteristics.

Characteristic: A specific data point within a service, consisting of a value and descriptors.

UUID: A 128-bit universally unique identifier used to distinguish services and characteristics.

BLE device can function simultaneously as a Peripheral (providing services) and a Central (connecting to peripherals). In this section, we will learn how to configure the Freenove_ESP32_Display as a peripheral device to provide services.

Circuit

Connect Freenove ESP32 Display to the computer with USB cable.

../../../_images/Chapter01_04.png

Sketch

Next, we download the code to Freenove_ESP32_Display to test. Open”Sketch_08.1_BLE_USART” folder under “Freenove_ESP32_DisplaySketch” and double-click “Sketch_08.1_BLE_USART.ino”.

Sketch_08.1_BLE_USART

The following is the program code:

 1/*
 2* @ File:   Sketch_08.1_BLE_USART.ino
 3* @ Author: [Zhentao Lin]
 4* @ Date:   [2025-06-14]
 5*/
 6
 7#include "BLEDevice.h"
 8#include "BLEServer.h"
 9#include "BLEUtils.h"
10#include "BLE2902.h"
11#include "String.h"
12
13BLECharacteristic *pCharacteristic;
14bool deviceConnected = false;
15uint8_t txValue = 0;
16long lastMsg = 0;
17String rxload="Test\n";
18
19#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" 
20#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
21#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
22
23class MyServerCallbacks: public BLEServerCallbacks {
24    void onConnect(BLEServer* pServer) {
25      deviceConnected = true;
26    };
27    void onDisconnect(BLEServer* pServer) {
28      deviceConnected = false;
29    }
30};
31
32class MyCallbacks: public BLECharacteristicCallbacks {
33    void onWrite(BLECharacteristic *pCharacteristic) {
34      String rxValue = pCharacteristic->getValue();
35      if (rxValue.length() > 0) {
36        rxload="";
37        for (int i = 0; i < rxValue.length(); i++){
38          rxload +=(char)rxValue[i];
39        }
40      }
41    }
42};
43
44void setupBLE(String BLEName){
45  const char *ble_name=BLEName.c_str();
46  BLEDevice::init(ble_name);
47  BLEServer *pServer = BLEDevice::createServer();
48  pServer->setCallbacks(new MyServerCallbacks());
49  BLEService *pService = pServer->createService(SERVICE_UUID); 
50  pCharacteristic= pService->createCharacteristic(CHARACTERISTIC_UUID_TX,BLECharacteristic::PROPERTY_NOTIFY);
51  pCharacteristic->addDescriptor(new BLE2902());
52  BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX,BLECharacteristic::PROPERTY_WRITE);
53  pCharacteristic->setCallbacks(new MyCallbacks()); 
54  pService->start();
55  pServer->getAdvertising()->start();
56  Serial.println("Waiting a client connection to notify...");
57}
58
59void setup() {
60  Serial.begin(115200);
61  setupBLE("ESP32_BLE");
62}
63
64void loop() {
65  long now = millis();
66  if (now - lastMsg > 100) {
67    if (deviceConnected&&rxload.length()>0) {
68        Serial.println(rxload);
69        rxload="";
70    }
71    if(Serial.available()>0){
72        String str=Serial.readString();
73        const char *newValue=str.c_str();
74        pCharacteristic->setValue(newValue);
75        pCharacteristic->notify();
76    }
77    lastMsg = now;
78  }
79}

Code Explanation

Include the necessary header libraries.

1#include "BLEDevice.h"
2#include "BLEServer.h"
3#include "BLEUtils.h"
4#include "BLE2902.h"
5#include "String.h"

Define service UUID and characteristic UUID.

1#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" 
2#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
3#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

The MyServerCallbacks class handles device connection and disconnection events and updates the deviceConnected status.

1class MyServerCallbacks: public BLEServerCallbacks {
2    void onConnect(BLEServer* pServer) {
3      deviceConnected = true;
4    };
5    void onDisconnect(BLEServer* pServer) {
6      deviceConnected = false;
7    }
8};

The MyServerCallbacks class handles the received data and save them to the rxload string.

 1class MyCallbacks: public BLECharacteristicCallbacks {
 2    void onWrite(BLECharacteristic *pCharacteristic) {
 3      String rxValue = pCharacteristic->getValue();
 4      if (rxValue.length() > 0) {
 5        rxload="";
 6        for (int i = 0; i < rxValue.length(); i++){
 7          rxload +=(char)rxValue[i];
 8        }
 9      }
10    }
11};

Set the baud rate to 115200.

1Serial.begin(115200);

BLE Device Initialization, Service Creation, and Characteristic Setup

1setupBLE("ESP32_BLE");

The Loop function check the connection status and serial data every 100 milliseconds.

 1void loop() {
 2  long now = millis();
 3  if (now - lastMsg > 100) {
 4    if (deviceConnected&&rxload.length()>0) {
 5        Serial.println(rxload);
 6        rxload="";
 7    }
 8    if(Serial.available()>0){
 9        String str=Serial.readString();
10        const char *newValue=str.c_str();
11        pCharacteristic->setValue(newValue);
12        pCharacteristic->notify();
13    }
14    lastMsg = now;
15  }
16}

LightBlue

If you do not have this software installed on your phone, you can refer to this link:

https://apps.apple.com/us/app/lightblue/id557428110

../../../_images/Chapter08_00.png

Click “Upload” to upload the code to Freenove ESP32 Display.

Note

This chapter does not involve the use of the screen. After the code for this chapter, the screen may not light up, which is normal and not a hardware malfunction. If you need to verify whether the screen is functioning properly, please refer to Chapter 10 for testing.

../../../_images/Chapter08_01.png

Turn ON Bluetooth on your phone, and open the LightBlue APP.

../../../_images/Chapter08_02.png

In the Scan page, swipe down to refresh the name of Bluetooth that the phone searches for. Click the Connection button of ESP32_BLE.

../../../_images/Chapter08_03.png
Receiving Data

Click Notify

../../../_images/Chapter08_04.png

Click the top right corner to change the string type.

../../../_images/Chapter08_05.png

Select UTF-8 String, and click “Save”.

../../../_images/Chapter08_06.png

Click Subscribe

../../../_images/Chapter08_07.png

Send data on the serial monitor.

../../../_images/Chapter08_08.png

Data will be received on the LightBlue app.

../../../_images/Chapter08_09.png
Sending Data

Click Write

../../../_images/Chapter08_10.png

Click the top right corner to change the string type.

../../../_images/Chapter08_11.png

Select UTF-8 String and click “Save”.

../../../_images/Chapter08_12.png

Click “Write new value”

../../../_images/Chapter08_13.png

Enter the messages to send.

../../../_images/Chapter08_14.png

Set the baud rate to 115200, and the serial monitor will print the data received.

../../../_images/Chapter08_15.png

Project 8.2 BLE RGB

In this section we will control the RGB LED via BLE.

Component List

Freenove ESP32 Display x 1

Chapter01_02

USB cable x1

Chapter01_03

Circuit

Connect Freenove Freenove ESP32 Display to the computer using the USB cable.

../../../_images/Chapter01_04.png

Sketch

Next, we download the code to Freenove_ESP32_Display to test. Open “Sketch_08.2_BLE_RGB” folder under “Freenove_ESP32_DisplaySketch” and double-click “Sketch_08.2_BLE_RGB.ino”.

Sketch_08.2_BLE_RGB

The following is the program code:

  1/*
  2* @ File:   Sketch_08.2_BLE_RGB.ino
  3* @ Author: [Zhentao Lin]
  4* @ Date:   [2025-06-14]
  5*/
  6
  7#include "BLEDevice.h"
  8#include "BLEServer.h"
  9#include "BLEUtils.h"
 10#include "BLE2902.h"
 11#include "String.h"
 12
 13BLECharacteristic *pCharacteristic;
 14bool deviceConnected = false;
 15uint8_t txValue = 0;
 16long lastMsg = 0;
 17String rxload = "Test\n";
 18
 19#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
 20#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
 21#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
 22
 23#define RED_PIN 22
 24#define GREEN_PIN 16
 25#define BLUE_PIN 17
 26
 27void rgbInit(void) {
 28  pinMode(RED_PIN, OUTPUT);
 29  pinMode(GREEN_PIN, OUTPUT);
 30  pinMode(BLUE_PIN, OUTPUT);
 31}
 32
 33void setRGB(bool redLevel, bool greenLevel, bool blueLevel) {
 34  digitalWrite(RED_PIN, !redLevel);
 35  digitalWrite(GREEN_PIN, !greenLevel);
 36  digitalWrite(BLUE_PIN, !blueLevel);
 37}
 38
 39class MyServerCallbacks : public BLEServerCallbacks {
 40  void onConnect(BLEServer *pServer) {
 41    deviceConnected = true;
 42  };
 43  void onDisconnect(BLEServer *pServer) {
 44    deviceConnected = false;
 45  }
 46};
 47
 48class MyCallbacks : public BLECharacteristicCallbacks {
 49  void onWrite(BLECharacteristic *pCharacteristic) {
 50    String rxValue = pCharacteristic->getValue();
 51    if (rxValue.length() > 0) {
 52      rxload = "";
 53      for (int i = 0; i < rxValue.length(); i++) {
 54        rxload += (char)rxValue[i];
 55      }
 56    }
 57  }
 58};
 59
 60void setupBLE(String BLEName) {
 61  const char *ble_name = BLEName.c_str();
 62  BLEDevice::init(ble_name);
 63  BLEServer *pServer = BLEDevice::createServer();
 64  pServer->setCallbacks(new MyServerCallbacks());
 65  BLEService *pService = pServer->createService(SERVICE_UUID);
 66  pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
 67  pCharacteristic->addDescriptor(new BLE2902());
 68  BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
 69  pCharacteristic->setCallbacks(new MyCallbacks());
 70  pService->start();
 71  pServer->getAdvertising()->start();
 72  Serial.println("Waiting a client connection to notify...");
 73}
 74
 75void setup() {
 76  Serial.begin(115200);
 77  rgbInit();
 78  setRGB(0, 0, 0);
 79  setupBLE("ESP32_BLE");
 80}
 81
 82void loop() {
 83  long now = millis();
 84  if (now - lastMsg > 100) {
 85    if (deviceConnected && rxload.length() > 0) {
 86      Serial.println(rxload);
 87      if (strncmp(rxload.c_str(), "red_on", 6) == 0) {
 88        setRGB(1, 0, 0);
 89      } else if (strncmp(rxload.c_str(), "red_off", 7) == 0) {
 90        setRGB(0, 0, 0);
 91      } else if (strncmp(rxload.c_str(), "green_on", 8) == 0) {
 92        setRGB(0, 1, 0);
 93      } else if (strncmp(rxload.c_str(), "green_off", 9) == 0) {
 94        setRGB(0, 0, 0);
 95      } else if (strncmp(rxload.c_str(), "blue_on", 7) == 0) {
 96        setRGB(0, 0, 1);
 97      } else if (strncmp(rxload.c_str(), "blue_off", 8) == 0) {
 98        setRGB(0, 0, 0);
 99      }
100      rxload = "";
101    }
102    if (Serial.available() > 0) {
103      String str = Serial.readString();
104      const char *newValue = str.c_str();
105      pCharacteristic->setValue(newValue);
106      pCharacteristic->notify();
107    }
108    lastMsg = now;
109  }
110}

Code Explanation

Include the necessary header files.

1#include "BLEDevice.h"
2#include "BLEServer.h"
3#include "BLEUtils.h"
4#include "BLE2902.h"
5#include "String.h"

Define Service UUID and Characteristic UUID.

1#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
2#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
3#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

Define pins for the RGB LED.

1#define RED_PIN 22
2#define GREEN_PIN 16
3#define BLUE_PIN 17

The MyServerCallbacks class handles device connection and disconnection events and updates the deviceConnected status.

1class MyServerCallbacks : public BLEServerCallbacks {
2  void onConnect(BLEServer *pServer) {
3    deviceConnected = true;
4  };
5  void onDisconnect(BLEServer *pServer) {
6    deviceConnected = false;
7  }
8};

The MyCallbacks class handles the receiving data and save them to the rxload string.

 1class MyCallbacks : public BLECharacteristicCallbacks {
 2  void onWrite(BLECharacteristic *pCharacteristic) {
 3    String rxValue = pCharacteristic->getValue();
 4    if (rxValue.length() > 0) {
 5      rxload = "";
 6      for (int i = 0; i < rxValue.length(); i++) {
 7        rxload += (char)rxValue[i];
 8      }
 9    }
10  }
11};

Set the baud rate to 115200

1Serial.begin(115200);

Initialize RGB LED setting, initialize the BLE device, create services, and set up characteristics.

1rgbInit();
2setRGB(0, 0, 0);
3setupBLE("ESP32_BLE");

The Loop function checks the sending command every 100 milliseconds.

 1void loop() {
 2  long now = millis();
 3  if (now - lastMsg > 100) {
 4    if (deviceConnected && rxload.length() > 0) {
 5      Serial.println(rxload);
 6      if (strncmp(rxload.c_str(), "red_on", 6) == 0) {
 7        setRGB(1, 0, 0);
 8      } else if (strncmp(rxload.c_str(), "red_off", 7) == 0) {
 9        setRGB(0, 0, 0);
10      } else if (strncmp(rxload.c_str(), "green_on", 8) == 0) {
11        setRGB(0, 1, 0);
12      } else if (strncmp(rxload.c_str(), "green_off", 9) == 0) {
13        setRGB(0, 0, 0);
14      } else if (strncmp(rxload.c_str(), "blue_on", 7) == 0) {
15        setRGB(0, 0, 1);
16      } else if (strncmp(rxload.c_str(), "blue_off", 8) == 0) {
17        setRGB(0, 0, 0);
18      }
19      rxload = "";
20    }
21    if (Serial.available() > 0) {
22      String str = Serial.readString();
23      const char *newValue = str.c_str();
24      pCharacteristic->setValue(newValue);
25      pCharacteristic->notify();
26    }
27    lastMsg = now;
28  }
29}

Click “Upload” to upload the code to Freenove ESP32 Display.

Note

This chapter does not involve the use of the screen. After the code for this chapter, the screen may not light up, which is normal and not a hardware malfunction. If you need to verify whether the screen is functioning properly, please refer to Chapter 10 for testing.

../../../_images/Chapter08_16.png

Click “Write new value”

../../../_images/Chapter08_17.png

Enter the messages to send. Here we take “red_on” as an example.

../../../_images/Chapter08_18.png

The RGB LED on the Freenove ESP32 Display emits red light.

../../../_images/Chapter08_19.png

You can also use the following instructions to control the RGB LED:

red_off: red light off

green_on: green light on

green_off: green light off

blue_on: blue light on

blue_off: blue light off