Two-Way Serial Bluetooth communication between two ESP32 boards

The purpose of this project was a need to establish a Two-Way Serial Bluetooth connection between two ESP32 boards for the project of a remote controller for the N7DDC automatic antenna tuner (ATU-100). As a novice in Arduino and ESP32 programming I was not able to figure out how to establish the Serial Bluetooth connection between the two ESP32 boards. All of the examples and projects I found were focused to the Bluetooth Low Energy (BLE), ESP-NOW two-way connection or to the connection between an Android mobile phone and a ESP32 bord via bluetooth serial. No complete solution on the internet at all nor in the documentation.

Two-Way Serial Bluetooth communication between two ESP32 boards

I combined several examples and solutions found on the internet together and based on them I was able successfully establish the connection between two ESP32 boards.

Honestly, the main issue was to successfully catch the state of the connection especially on the SERVER (Master) side. It worked well for the connection state when the connection was lost but it was difficult to catch the the state when the connection was established. Fortunately this sentence from ESP-IDF Programming Guide for ESP32 v4.2 gave me the direction and helped to solve the issue: „When the connection is established or failed, the callback is called with ESP_SPP_OPEN_EVT“ and „ESP_SPP_OPEN_EVT -> When SPP Client connection open, the event comes“.

The CLIENT (Slave) side worked pretty well from the beginning so I was able to indicate the state with the built-in LED (blue). Blinking LED indicates that the connection was not established or was lost and vice versa the solid light indicates that the connection is established.

The SERVER ( Master) side uses a two-colors LED (Blue/Red) to indicate the connection state. The red color indicates three states:

· The connection is not established yet
· The connection was lost
· There are reconnect attempts running including the bluetooth device reset

The blue color indicates that the connection is established and working now.
The schematic below shows an example of the the two-colors indication of the connection state. The R1 and R2 values on the schematic are approximate and calculated for my specific solution with the LL-309VBC2E-C-2B red/blue LED.

Server (Master) indication LEDs connection
You can copy my latest SERVER (MASTER) code below or download here:SerialToSerialBTMaster_v1_3_2_web.ino
/*****************************************************************************************
*     Serial Bluetooth communication between 2 ESP32 boards - OK1TK www.ok1tk.com        *
*                   The SERVER (Master) part code v1.32 - 04 May 2023                    *
******************************************************************************************/
#include "BluetoothSerial.h"                                                              // BT: Include the Serial bluetooth library
#define LED_BT_BLUE 2                                                                     // BT: Internal LED (or LED on the pin D2) for the connection indication (connected LED ON / disconnected LED OFF)
#define LED_BT_RED 15                                                                     // BT: LED (LED on the pin D4) for the connection indication (connected LED OFF / disconnected LED ON)
unsigned long previousMillisReconnect;                                                    // BT: Variable used for comparing millis counter for the reconnection timer
bool ledBtState = false;                                                                  // BT: Variable used to chage the indication LED state
bool SlaveConnected;                                                                      // BT: Variable used to store the current connection state (true=connected/false=disconnected)
int recatt = 0;                                                                           // BT: Variable used to count the reconnection attempts

// BT: Bluetooth availabilty check
#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#endif

String myName = "ESP32-BT-Master";                                                        // BT: Variable used to store the SERVER(Master) bluetooth device name; just for prinitng
String slaveName = "ESP32-BT-Slave";                                                      // BT: Variable used to store the CLIENT(Slave) bluetooth device name; just for prinitng; just for printing in this case
String MACadd = "03:B4:16:72:36:9C";                                                      // BT: Variable used to store the CLIENT(Slave) bluetooth device Mac address; just for prinitng; just for printing in this case
uint8_t address[6] = { 0x03, 0xB4, 0x16, 0x72, 0x36, 0x9C };                              // BT: Variable used to store the CLIENT(Slave) MAC address used for the connection; Use your own andress in the same format

BluetoothSerial SerialBT;                                                                 // BT: Set the Object SerialBT


// BT: Bt_Status callback function
void Bt_Status(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) {
  if (event == ESP_SPP_OPEN_EVT) {                                                        // BT: Checks if the SPP connection is open, the event comes// event == Client connected
    Serial.println ("Client Connected");                                                  // BT: Write to the serial monitor
    digitalWrite (LED_BT_BLUE, HIGH);                                                     // BT: Turn ON the BLUE bluetooth indication LED (solid light)
    digitalWrite (LED_BT_RED, LOW);                                                       // BT: Turn OFF the RED bluetooth indication LED
    SlaveConnected = true;                                                                // BT: Set the variable true = CLIENT is connected to the SERVER
    recatt = 0;                                                                           // BT: Reset the reconnect attempts counter
  }
  else if (event == ESP_SPP_CLOSE_EVT) {                                                  // BT: event == Client disconnected
    Serial.println("Client Disconnected");                                                // BT: Write to the serial monitor
    digitalWrite(LED_BT_RED, HIGH);                                                       // BT: Turn ON the RED bluetooth indication LED (solid light)
    digitalWrite(LED_BT_BLUE, LOW);                                                       // BT: Turn OFF the BLUE bluetooth indication LED
    SlaveConnected = false;                                                               // BT: Set the variable false = CLIENT connection lost
  }
}

void setup() {
  pinMode(LED_BT_BLUE, OUTPUT);                                                           // BT: Set up the onboard LED pin as output
  pinMode(LED_BT_RED, OUTPUT);                                                            // BT: Set up the onboard LED pin as output
  digitalWrite(LED_BT_RED, HIGH);                                                         // BT: Turn ON the RED LED = no connection established
  SlaveConnected = false;                                                                 // BT: Set the variable false = CLIENT is not connected
  Serial.begin(115200);                                                                   // Sets the data rate in bits per second (baud) for serial data transmission
  
  // BT: Define the Bt_Status callback
  SerialBT.register_callback(Bt_Status);
  // BT: Starts the bluetooth device with the name stored in the myName variable as SERVER(Master)
  SerialBT.begin(myName, true);
  Serial.printf("The device \"%s\" started in master mode, make sure slave BT device is on!\n", myName.c_str());
  SlaveConnect();                                                                         // BT: Calls the bluetooth connection function to cnnect to the CLIENT(Slave)
}

void SlaveConnect() {                                                                     // BT: This function connects/reconnects to the CLIENT(Slave)
  Serial.println("Function BT connection executed");                                      // BT: Write to the serial monitor
  Serial.printf("Connecting to slave BT device named \"%s\" and MAC address \"%s\" is started.\n", slaveName.c_str(), MACadd.c_str());  // BT: Write to the serial monitor
  SerialBT.connect(address);                                                              // BT: Establishing the connection with the CLIENT(Slave) with the Mac address stored in the address variable
}

void loop() {
  
  if (!SlaveConnected) {                                                                  // BT: Condition to evalute if the connection is established/lost 
    if (millis() - previousMillisReconnect >= 10000) {                                    // BT: Check that 10000ms is passed
      previousMillisReconnect = millis();                                                 // BT: Set previousMillisReconnect to current millis
      recatt++;                                                                           // BT: Increase the the reconnection attempts counter +1 
      Serial.print("Trying to reconnect. Attempt No.: ");                                 // BT: Write to the serial monitor
      Serial.println(recatt);                                                             // BT: Write the attempts count to the serial monitor
      Serial.println("Stopping Bluetooth...");                                            // BT: Write to the serial monitor
      SerialBT.end();                                                                     // BT: Close the bluetooth device
      Serial.println("Bluetooth stopped !");                                              // BT: Write to the serial monitor
      Serial.println("Starting Bluetooth...");                                            // BT: Write to the serial monitor
      SerialBT.begin(myName, true);                                                       // BT: Starts the bluetooth device with the name stored in the myName variable as SERVER(Master)
      Serial.printf("The device \"%s\" started in master mode, make sure slave BT device is on!\n", myName.c_str());
      SlaveConnect();                                                                     // BT: Calls the bluetooth connection function to cnnect to the CLIENT(Slave)
    }
    
  }
  // BT: Data send/receive via bluetooth
  if (Serial.available()) {                                                               // BT: Checks if there are data from the serial monitor available
    SerialBT.write(Serial.read());                                                        // BT: Sends the data via bluetooth
  }
  if (SerialBT.available()) {                                                             // BT: Checks if there are data from the bluetooth available
    Serial.write(SerialBT.read());                                                        // BT: Write the data to the serial monitor
  }
}
You can copy my latest CLIENT (SLAVE) code below or download here:SSerialToSerialBTSlave_v1.2.1_web.ino
/*****************************************************************************************
*     Serial Bluetooth communication between 2 ESP32 boards - OK1TK www.ok1tk.com        *
*                   The CLIENT (SLAVE) part code v1.21 - 01 May 2023                     *
******************************************************************************************/
#include "BluetoothSerial.h"                                                  // BT: Include the Serial bluetooth library 
#define LED_BT 2                                                              // BT: Internal LED (or LED on the pin D2) for the connection indication (connected solid/disconnected blinking)
unsigned long previousMillis;                                                 // BT: Variable used for comparing millis counter (LED blinking)
bool ledBtState = false;                                                      // BT: Variable used to chage the indication LED state
bool MasterConnected;                                                         // BT: Variable used to store the current connection state (true=connected/false=disconnected)
String device_name = "ESP32-BT-Slave";                                        // BT: Variable used to store the CLIENT(slave) bluetooth device name
String MACadd = "03:B4:16:72:36:9C";                                          // BT: Variable used to store the CLIENT(slave) bluetooth Mac address; Use your own MAC address

// BT: Bluetooth availabilty check
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)                           
#error Bluetooth is not enabled! Please run make menuconfig to and enable it
#endif
// BT: Serial Bluetooth availabilty check
#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#endif

BluetoothSerial SerialBT;                                                     // BT: Set the Object SerialBT

// BT: Bt_Status callback function
void Bt_Status (esp_spp_cb_event_t event, esp_spp_cb_param_t *param) {

  if (event == ESP_SPP_SRV_OPEN_EVT) {                                        // BT: Checks if the SPP Server connection is open, the event comes 
    Serial.println ("Client Connected");                                      // BT: Write to the serial monitor
    digitalWrite (LED_BT, HIGH);                                              // BT: Turn ON the bluetooth indication LED (solid light)
    MasterConnected = true;                                                   // BT: Set the variable true = SERVER is connected to the CLIENT
  }
  else if (event == ESP_SPP_CLOSE_EVT ) {                                     // BT: Checks if the SPP connection is closed, the event comes
    Serial.println ("Client Disconnected");                                   // BT: Write to the serial monitor
    digitalWrite (LED_BT, LOW);                                               // BT: Turn OFF the bluetooth indication LED
    MasterConnected = false;                                                  // BT: Set the variable false = SERVER connection lost
  }
}

void setup() {
  pinMode(LED_BT,OUTPUT);                                                     // BT: Set up the onboard LED pin as output
  Serial.begin(115200);                                                       // Sets the data rate in bits per second (baud) for serial data transmission
  
  // BT: Define the Bt_Status callback
  SerialBT.register_callback (Bt_Status);
  // BT: Starts the bluetooth device with the name stored in the device_name variable
  SerialBT.begin(device_name);
  Serial.printf("The device with name \"%s\" and MAC address \"%s\" is started.\nNow you can pair it with Bluetooth!\n", device_name.c_str(), MACadd.c_str());
}

void loop() {
  // BT: Blinking the bluetooth indication LED if the connection is not established
  if (!MasterConnected) {
    if (millis() - previousMillis >= 500) {                                     // BT: Checks if 500ms is passed
      if (ledBtState == false) {                                                // BT: Checks the leddState and toggles it 
      ledBtState = true;
    }
    else {
      ledBtState = false;
    }
    digitalWrite(LED_BT, ledBtState);                                             // BT: Set LED ON/OFF based onthe ledBtState variable
    previousMillis = millis();                                                    // BT: Set previousMillis to current millis
    }
    
  }
  // BT: Data send/receive via bluetooth
  if (Serial.available()) {                                                       // BT: Checks if there are data from the serial monitor available
    SerialBT.write(Serial.read());                                                // BT: Sends the data via bluetooth
  }
  if (SerialBT.available()) {                                                     // BT: Checks if there are data from the bluetooth available
    Serial.write(SerialBT.read());                                                // BT: Write the data to the serial monitor
  }
}

As I already mentioned I am a beginner in Arduino/ESP32 programming, I f you have any comment or idea how to make the code more effective and clear, please let me know.