29. Chapter Bluetooth

This chapter mainly introduces how to make simple data transmission through Bluetooth of ESP32-S3 WROOM and mobile phones.

29.1. Project Bluetooth Low Energy Data Passthrough

29.1.1. Component List

ESP32-S3 WROOM x1

Chapter00_00

USB cable x1

Chapter00_01

29.1.2. Component knowledge

ESP32-S3’s integrated Bluetooth function Bluetooth is a short-distance communication system, which can be divided into two types, namely Bluetooth Low Energy(BLE) and Classic Bluetooth. There are two modes for simple data transmission: master mode and slave mode.

29.1.2.1. Master mode

In this mode, works are done in the master device and it can connect with a slave device. And we can search and select slave devices nearby to connect with. When a device initiates connection request in master mode, it requires information of the other Bluetooth devices including their address and pairing passkey. After finishing pairing, it can connect with them directly.

29.1.2.2. Slave mode

The Bluetooth module in slave mode can only accept connection request from a host computer, but cannot initiate a connection request. After connecting with a host device, it can send data to or receive from the host device.

Bluetooth devices can make data interaction with each other, as one is in master mode and the other in slave mode. When they are making data interaction, the Bluetooth device in master mode searches and selects devices nearby to connect to. When establishing connection, they can exchange data. When mobile phones exchange data with ESP32-S3, they are usually in master mode and ESP32-S3 in slave mode.

../../../_images/Chapter27_00.png

29.1.3. Circuit

Connect Freenove ESP32-S3 to the computer using the USB cable.

../../../_images/Chapter27_01.png

29.1.4. Sketch

29.1.4.1. Lightblue

If you can’t install Serial Bluetooth on your phone, try 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#?platform=iphone.

../../../_images/Chapter27_02.png

Step1. Upload the code of Project 27.1 to ESP32-S3.

Step2. Click on serial monitor.

../../../_images/Chapter27_03.png

Step3. Set baud rate to 115200.

../../../_images/Chapter27_04.png

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

../../../_images/Chapter27_05.png

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

../../../_images/Chapter27_06.png

Click “Receive”. Select the appropriate Data format in the box to the right of Data Format. For example, HEX for hexadecimal, utf-string for character, Binary for Binary, etc. Then click SUBSCRIBE.

../../../_images/Chapter27_07.png

Back to the serial monitor on your computer. You can type anything in the left border of Send, and then click Send.

../../../_images/Chapter27_08.png

And then you can see the mobile Bluetooth has received the message.

../../../_images/Chapter27_09.png

Similarly, you can select “Send” on your phone. Set Data format, and then enter anything in the sending box and click Write to send.

../../../_images/Chapter27_10.png

And the computer will receive the message from the mobile Bluetooth.

../../../_images/Chapter27_11.png

And now data can be transferred between your mobile phone and computer via ESP32-S3 WROOM.

The following is the program code:

 1/**********************************************************************
 2  Filename    : BLE_USART
 3  Description : Esp32 communicates with the phone by BLE and sends incoming data via a serial port
 4  Auther      : www.freenove.com
 5  Modification: 2024/07/01
 6**********************************************************************/
 7#include "BLEDevice.h"
 8#include "BLEServer.h"
 9#include "BLEUtils.h"
10#include "BLE2902.h"
11
12BLECharacteristic *pCharacteristic;
13bool deviceConnected = false;
14uint8_t txValue = 0;
15long lastMsg = 0;
16String rxload="Test\n";
17
18#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" 
19#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
20#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
21
22class MyServerCallbacks: public BLEServerCallbacks {
23    void onConnect(BLEServer* pServer) {
24      deviceConnected = true;
25    };
26    void onDisconnect(BLEServer* pServer) {
27      deviceConnected = false;
28      //pServer->getAdvertising()->start(); //Reopen the pServer and wait for the connection.
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("ESP32S3_Bluetooth");
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}

Define the specified UUID number for BLE vendor.

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"

Write a Callback function for BLE server to manage connection of BLE.

1class MyServerCallbacks: public BLEServerCallbacks {
2    void onConnect(BLEServer* pServer) {
3      deviceConnected = true;
4    };
5    void onDisconnect(BLEServer* pServer) {
6      deviceConnected = false;
7      //pServer->getAdvertising()->start(); //Reopen the pServer and wait for the connection.
8    }
9};

Write Callback function with BLE features. When it is called, as the mobile terminal send data to ESP32-S3, it will store them into reload.

 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};

Initialize the BLE function and name it.

1setupBLE("ESP32S3_Bluetooth");

When the mobile phone send data to ESP32-S3 via BLE Bluetooth, it will print them out with serial port;

When the serial port of ESP32-S3 receive data, it will send them to mobile via BLE Bluetooth.

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

The design for creating the BLE server is:

  1. Create a BLE Server

  2. Create a BLE Service

  3. Create a BLE Characteristic on the Service

  4. Create a BLE Descriptor on the characteristic

  5. Start the service.

  6. Start advertising.

 1void setupBLE(String BLEName){
 2  const char *ble_name=BLEName.c_str();
 3  BLEDevice::init(ble_name);
 4  BLEServer *pServer = BLEDevice::createServer();
 5  pServer->setCallbacks(new MyServerCallbacks());
 6  BLEService *pService = pServer->createService(SERVICE_UUID); 
 7  pCharacteristic= pService->createCharacteristic(CHARACTERISTIC_UUID_TX,BLECharacteristic::PROPERTY_NOTIFY);
 8  pCharacteristic->addDescriptor(new BLE2902());
 9  BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX,BLECharacteristic::PROPERTY_WRITE);
10  pCharacteristic->setCallbacks(new MyCallbacks()); 
11  pService->start();
12  pServer->getAdvertising()->start();
13  Serial.println("Waiting a client connection to notify...");
14}

29.2. Project Bluetooth Control LED

In this section, we will control the LED with Bluetooth.

29.2.1. Component List

ESP32-S3 WROOM x1

Chapter01_00

GPIO Extension Board x1

Chapter01_01

Breadboard x1

Chapter01_02

Resistor 220Ω x1

Chapter01_04

Jumper M/M x2

Chapter19_02

LED x1

Chapter01_04

Micro USB Wire x1

Chapter08_00

29.2.2. Circuit

Connect Freenove ESP32-S3 to the computer using a USB cable.

Schematic diagram

Chapter27_12

Hardware connection.

If you need any support, please contact us via: support@freenove.com

Chapter27_13

29.2.3. Sketch

29.2.3.1. Sketch_Bluetooth_Control_LED

../../../_images/Chapter27_14.png

Compile and upload code to ESP32S3_Blueooth. The operation of the APP is the same as 27.1, you only need to change the sending content to “led_on” and “led_off” to operate LEDs on the ESP32-S3 WROOM. Data sent from mobile APP:

../../../_images/Chapter27_15.png

Display on the serial port of the computer:

../../../_images/Chapter27_16.png

The phenomenon of LED

../../../_images/Chapter27_17.png

Attention: If the sending content isn’t “led-on’ or “led-off”, then the state of LED will not change. If the LED is on, when receiving irrelevant content, it keeps on; Correspondingly, if the LED is off, when receiving irrelevant content, it keeps off.

The following is the program code:

 1/**********************************************************************
 2  Filename    : BLE_USART
 3  Description : Esp32 communicates with the phone by BLE and sends incoming data via a serial port
 4  Auther      : www.freenove.com
 5  Modification: 2024/07/01
 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;
17char rxload[20];
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#define LED 2
23
24class MyServerCallbacks : public BLEServerCallbacks {
25  void onConnect(BLEServer *pServer) {
26    deviceConnected = true;
27  };
28  void onDisconnect(BLEServer *pServer) {
29    deviceConnected = false;
30    //pServer->getAdvertising()->start(); //Reopen the pServer and wait for the connection.
31  }
32};
33
34class MyCallbacks : public BLECharacteristicCallbacks {
35  void onWrite(BLECharacteristic *pCharacteristic) {
36    String rxValue = pCharacteristic->getValue();
37    if (rxValue.length() > 0) {
38      for (int i = 0; i < 20; i++) {
39        rxload[i] = 0;
40      }
41      for (int i = 0; i < rxValue.length(); i++) {
42        rxload[i] = (char)rxValue[i];
43      }
44    }
45  }
46};
47
48void setupBLE(String BLEName) {
49  const char *ble_name = BLEName.c_str();
50  BLEDevice::init(ble_name);
51  BLEServer *pServer = BLEDevice::createServer();
52  pServer->setCallbacks(new MyServerCallbacks());
53  BLEService *pService = pServer->createService(SERVICE_UUID);
54  pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
55  pCharacteristic->addDescriptor(new BLE2902());
56  BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
57  pCharacteristic->setCallbacks(new MyCallbacks());
58  pService->start();
59  pServer->getAdvertising()->start();
60  Serial.println("Waiting a client connection to notify...");
61}
62
63void setup() {
64  pinMode(LED, OUTPUT);
65  setupBLE("ESP32S3_Bluetooth");
66  Serial.begin(115200);
67  Serial.println("\nThe device started, now you can pair it with Bluetooth!");
68}
69
70void loop() {
71  long now = millis();
72  if (now - lastMsg > 100) {
73    if (deviceConnected && strlen(rxload) > 0) {
74      if (strncmp(rxload, "led_on", 6) == 0) {
75        digitalWrite(LED, HIGH);
76      }
77      if (strncmp(rxload, "led_off", 7) == 0) {
78        digitalWrite(LED, LOW);
79      }
80      Serial.println(rxload);
81      memset(rxload,0,sizeof(rxload));
82    }
83    lastMsg = now;
84  }
85}

Use character string to handle function header file.

1#include "String.h"

Define a character array to save data from Bluetooth.

1char rxload[20];

Initialize the BLE Bluetooth and name it as “ESP32-S3”

1setupBLE("ESP32S3_Bluetooth");

Write a Callback function for BLE server to manage connection of BLE.

1class MyServerCallbacks : public BLEServerCallbacks {
2  void onConnect(BLEServer *pServer) {
3    deviceConnected = true;
4  };
5  void onDisconnect(BLEServer *pServer) {
6    deviceConnected = false;
7    //pServer->getAdvertising()->start(); //Reopen the pServer and wait for the connection.
8  }
9};

Write Callback function with BLE features. When it is called, as the mobile terminal send data to ESP32-S3, it will store them into reload.

1String rxValue = pCharacteristic->getValue();
2if (rxValue.length() > 0) {
3  for (int i = 0; i < 20; i++) {
4    rxload[i] = 0;
5  }
6  for (int i = 0; i < rxValue.length(); i++) {
7    rxload[i] = (char)rxValue[i];
8  }
9}

Compare the content in buffer array with “led_on” and “led_off” to see whether they are the same. If yes, execute the corresponding operation.

 1if (deviceConnected && strlen(rxload) > 0) {
 2  if (strncmp(rxload, "led_on", 6) == 0) {
 3    digitalWrite(LED, HIGH);
 4  }
 5  if (strncmp(rxload, "led_off", 7) == 0) {
 6    digitalWrite(LED, LOW);
 7  }
 8  Serial.println(rxload);
 9  memset(rxload,0,sizeof(rxload));
10}

After comparing the content of array, to ensure successful transmission next time, please empty the array.

1Serial.println(rxload);
2memset(rxload,0,sizeof(rxload));

29.2.3.2. Reference

strncmp() functions are often used for string comparisons, which are accurate and stable.

int strncmp(const char *str1, const char *str2, size_t n)

str1: the first string to be compared

str2: the second string to be compared

n: the biggest string to be compared

Return value: if stir1>str2, then return value>0.

If return value is 0, then the contents of str1 and str2 are the same.

If str1< str2, then return value<0.

Function memset is mainly used to clean and initialize the memory of array

void memset(void *s, int c, unsigned long n)

Function memset() is to set the content of a certain internal storage as specified value.

*s: the initial address of the content to clear out.

c:to be replaced as specified value

n: the number of byte to be replaced