Introduction: ESP32 Bluetooth Low Energy

About: Do you like technology? Follow my channel on Youtube and my Blog. In them I put videos every week of microcontrollers, arduinos, networks, among other subjects.

To fulfill the requests of several followers who have experience with small models of Arduino Bluetooth, today we’ll discuss ESP32 Bluetooth Low Energy. This is highly recommended for the Internet of Things. The Arduino TX RX model works as a serial; but the subject today is a bit different. This is because its power consumption is miniscule. Let us therefore find out more about the BLE and create a program for ESP32 to become a Bluetooth server. This will connect a smartphone application to send and receive data.

In our assembly, we have the temperature sensor, the buzzer, and the ESP32. We called the ESP32 and BLE scanner, which will locate our microcontroller. In the video, I show how to make the connection between the two, as well as the execution of some commands involving the LED and buzzer.

Step 1: Introduction

BLE is a protocol slightly different from traditional Bluetooth. It is best suited for low power IoT (Internet of Things) applications, since the capacity of the data packets is low.

Devices working with BLE can have two different functions on one connection: Central Device or Peripheral Device. Generally, the central devices are cell phones, tablets, computers, etc. These are central devices that receive data. Peripheral devices are sensors and low power devices that connect to the central device. We can also think of a client / server structure, where a mobile is the client and the sensor is the server that "serves" its data to the client.

GATT (Generic Attribute Profile) is how data is organized for communication between devices. GATT is composed of one or more services which, in turn, are composed of characteristics. There are standard GATT specifications for the most common application types found on the market. Several of these specifications can be found on the official Bluetooth website. The characteristics, in turn, are basically the values themselves.


The services and features are identified by a universally unique identifier (UUID). So, we can customize our own or use the existing ones.

As previously stated, we can have one or more services running on the same device, and each one can have its own characteristics.

For example, an ESP32 may be running a CLIMA service to send temperature and humidity data. At the same time, it can run a BATTERY service to send battery charge measurement data.

Step 2: Overview

We can send and receive data on both sides.

Example: ESP32 can send sensor data.

Example 2: The smartphone can send commands to the ESP32 to connect a relay.

Step 3: Some Applications of BLE

  • Heart rate sensors
  • M2M communication (machine-to-machine)
  • Automation of tasks in a residence
  • Remote Control
  • Proximity alert notification
  • Among others

Step 4: Comparative

Step 5: WiFi NodeMCU-32S ESP-WROOM-32

Step 6: Infrared Sensor MLX90614

I really like this sensor because, as I showed in another video, it can measure high temperatures because it works by infrared light. Also, the MLX90614 has an ambient temperature sensor, as it measures the temperature of itself and what it is seeing through its camera.

Step 7: Assembly

As already mentioned above, the assembly is quite simple, and it has a buffer connected on the GPIO23 and the i2c sensor connected on the GPIO21 and GPIO22.

Step 8: Libraries

Add the library "SparkFunMLX90614" for communication with the infrared sensor.

Access the link and download the library.

Unzip the file and paste it into the libraries folder of the Arduino IDE.

C: / Program Files (x86) / Arduino / libraries

Step 9: Program

We will run a program in which ESP32 will become a BLE server. When a device is connected to it, data from a temperature sensor will be sent in time intervals. The ESP32 may also receive data to command the ON / OFF of a LED and a Buzzer.

Step 10: Libraries and Variables

We will include the libraries and instantiate the object responsible for communication with the infrared temperature sensor. Through this object, we will send data to the client. We create a Boolean variable to control the connected device. I then define the pins that the Led and the buzzer will be connected to. Finally, we also define the IDs we will use for the service.

#include <Wire.h> //Biblioteca para I2C

#include <SparkFunMLX90614.h> //Biblioteca SparkFunMLX90614 (sensor IR)

#include <BLEDevice.h>

#include <BLEServer.h>

#include <BLEUtils.h>

#include <BLE2902.h>

//objeto responsável pela comunicação com o sensor de temperatura infravermelho IRTherm sensor; BLECharacteristic *characteristicTX; //através desse objeto iremos enviar dados para o client bool deviceConnected = false; //controle de dispositivo conectado const int LED = 2; //LED interno do ESP32 (esse pino pode variar de placa para placa) const int BUZZER = 23; //pino d BUZZER #define SERVICE_UUID "ab0828b1-198e-4351-b779-901fa0e0371e” #define CHARACTERISTIC_UUID_RX "4ac8a682-9736-4e5d-932b-e9b31405049c" #define CHARACTERISTIC_UUID_TX "0972EF8C-7613-4075-AD52-756F33D4DA91”

Step 11: Setup

We defined that the Bluetooth device name in this step is "ESP32-BLE" and created a BLE server. We set the callback of the server, because it is responsible for collecting the information received. We then create a service, as well as set the characteristics of sending data.

void setup() {
Serial.begin(115200); pinMode(LED, OUTPUT); pinMode(BUZZER, OUTPUT); // Create the BLE Device BLEDevice::init("ESP32-BLE"); // nome do dispositivo bluetooth // Create the BLE Server BLEServer *server = BLEDevice::createServer(); //cria um BLE server server->setCallbacks(new ServerCallbacks()); //seta o callback do server // Create the BLE Service BLEService *service = server->createService(SERVICE_UUID); // Create a BLE Characteristic para envio de dados characteristicTX = service->createCharacteristic( CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY ); characteristicTX->addDescriptor(new BLE2902());

In this stage of the Setup, we create the characteristics (this time) for the reception of data. We set the callback to receive the information and initialize the service. We propagate the signal from the ESP32, initialize the infrared temperature sensor, and select the temperature in Celsius, which could also be used in Fahrenheit or Kelvin.

// Create a BLE Characteristic para recebimento de dados
BLECharacteristic *characteristic = service->createCharacteristic( CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE ); characteristic->setCallbacks(new CharacteristicCallbacks()); // Start the service service->start(); // Start advertising (descoberta do ESP32) server->getAdvertising()->start(); //Inicializa sensor de temperatura infravermelho sensor.begin(); //Seleciona temperatura em Celsius sensor.setUnit(TEMP_C);//podemos ainda utilizar TEMP_F para Fahrenheit ou TEMP_K para Kelvin Serial.println(“Aguardando algum dispositivo conectar..."); } //fim setup

Step 12: Loop

In the Loop, we find that there is some device connected, and we try to read the sensor. If the action is carried out, we collect at room temperature. We convert the value to a char array, set this value, and send it to the smartphone.

void loop() {
//se existe algum dispositivo conectado if (deviceConnected) { //chamamos o método "read" do sensor para realizar a leitura da temperatura //read retornará 1 caso consiga realizar a leitura, ou 0 caso contrário if ( { //recupera a leitura da temperatura do ambiente float tempAmbiente = sensor.ambient(); //recupera a leitura da temperatura do objeto apontado pelo sensor //float tempObjeto = sensor.object(); // abaixo vamos converser o valor para um array de char char txString[8]; dtostrf(tempAmbiente, 2, 2, txString); // float_val, min_width, digits_after_decimal, char_buffer characteristicTX->setValue(txString); //seta o valor que a caracteristica notificará (enviar) characteristicTX->notify(); // Envia o valor para o smartphone } } delay(1000); }

Step 13: Callback - Features

I recall here that the Callback function is called whenever the device receives some information. Then, we define a characteristic class, return the pointer to the register containing the current value of the characteristic, and check if there are data (size greater than zero). I check if the value of rxValue is L1 (turns on the LED) or L0 (turns it off). I also analyze the buzzer: B1 turns on the buzzer, while B0 turns it off.

//callback para eventos das características
class CharacteristicCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *characteristic) { //retorna ponteiro para o registrador contendo o valor atual da caracteristica std::string rxValue = characteristic->getValue(); //verifica se existe dados (tamanho maior que zero) if (rxValue.length() > 0) { for (int i = 0; i < rxValue.length(); i++) { Serial.print(rxValue[i]); } Serial.println(); //L1 liga o LED | L0 desliga o LED if (rxValue.find("L1") != -1) { digitalWrite(LED, HIGH); } else if (rxValue.find("L0") != -1) { digitalWrite(LED, LOW); } // B1 liga o Buzzer | B0 desliga o Buzzer else if (rxValue.find("B1") != -1) { digitalWrite(BUZZER, HIGH); } else if (rxValue.find("B0") != -1) { digitalWrite(BUZZER, LOW); } } }//onWrite };

Step 14: Callback Server

Here, we have the callback to receive device connection events.

//callback para receber os eventos de conexão de dispositivos
class ServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected = true; }; void onDisconnect(BLEServer* pServer) { deviceConnected = false; } };

Step 15: App

We will use the BLE Scanner application. You can download it from the link below:

When you start the application, it will scan to find Bluetooth devices nearby. In our ESP32-BLE, you need to click connect.

When connecting, we will see this screen, which shows the status of the connection and also the services running on ESP32. CUSTOM SERVICE is the service we have created. Note that the UUID is the same as what is defined in the code.

When you click on the service (CUSTOM SERVICE), its characteristics will be listed.

When you click on W, a text box will open, so we can send the data to ESP32.

Our protocol:

B0> Turn off the BUZZER

B1> Turn on the BUZZER

L0> Turns off the LED

L1> LED or LED

Step 16: Files

Download the files: