How to control an ESP32 via Bluetooth

Introduction

Bluetooth is a communication system between devices that is now very widespread. We find it in our cell phones, computers, headphones and all those devices that need to communicate data over short distances and without wires. One of our favorite devices, the NodeMCU ESP32, has this type of communication natively (in addition to the well-known WiFi).

We have already met a Bluetooth device in a previous article: How to make a bluetooth datalogger for temperature and humidity using Arduino MEGA. In that case we used an HC-05 module that communicates with Arduino via the serial port. In the case of the ESP32 however, its Bluetooth controller exchanges data on the serial port without the need for external devices. This definitely simplifies its management which takes place through a special library.

To have a practical example of the potential of this type of communication with the ESP32, we will use a DHT22 sensor to measure ambient temperature and humidity and two red LEDs which we will command in two different ways:

  • a LED can only be ON or OFF
  • the other LED can be adjusted in brightness from a minimum value (LED OFF) to a maximum value (LED ON at maximum brightness) passing through the intermediate values

With Bluetooth communication we will be able to read the temperature and humidity values ​​detected by the DHT22 and modify the variables that control the status of the two LEDs (one boolean which controls the LED which can only be turned ON or OFF and the other integer to control the brightness of the other LED) via a mobile application (the one used here is for Android) which will connect via Bluetooth to our device.

What components do we need?

The list of components is not particularly long:

Project realization

The wiring diagram

Before realizing the real circuit let’s look at the pinout of the board:

ESP32 pinout
ESP32 pinout

We will use GPIO 14 to connect the DHT22 sensor.

The DHT22 sensor pinout is as follows:

The DHT22 sensor and its pinout
The DHT22 sensor and its pinout

We’ll use GPIOs 16 and 17 to connect the LEDs.

The LED connected to pin 17 is the one that can only be set ON or OFF. The GPIO17 will be set to HIGH to turn the LED ON and LOW to turn it OFF.

The LED connected to pin 16 is the one whose brightness can be adjusted. To obtain this result, it will be driven by the ESP32 via a PWM signal whose duty cycle varies as the value contained in a specific variable varies, a value that goes from 0 (LED OFF) to 255 (LED completely ON) passing through the intermediate values.

The commands to manage the two LEDs will be sent to the ESP32 via an application installed on the mobile phone.

At this point you can proceed with the creation of the circuit by following the wiring diagram below. Unfortunately, the ESP32 NodeMCU is too large to fit on the breadboard, which is why it will be connected with flying leads to the rest of the circuit.

The two LEDs are connected to the ESP32 via two 100Ω resistors to limit the current flowing through them and avoid burning them (and burning the two digital outputs).

The LED has two terminals (called anode and cathode) and, like all diodes, it is a component that has its own polarity: it passes the current when it is forward polarized (i.e. the voltage at the anode is greater than that at the cathode) and it blocks current when it is reverse polarized (i.e. the anode voltage is lower than the cathode voltage). The voltage between the anode and cathode, which we will indicate with Vd, varies according to the color of the light emitted. In particular we have that:

  • Vd = 1.8 V for red LEDs
  • Vd = 1.9 V for yellow LEDs
  • Vd = 2 V for green LEDs
  • Vd = 2 V for orange LEDs
  • Vd = 3 V for blu LEDs
  • Vd = 3 V for white LEDs

Below is the assembly diagram created with Fritzing:

The wiring diagram
The wiring diagram

As you can see, the sensor power is taken from the 3.3V output of the NodeMCU (pin 3V3). It is necessary to feed it with 3.3V so that its output is also 3.3V as the digital pins of the NodeMCU do not accept voltages higher than 3.3V.

WARNING: in the ESP32 NodeMCU the maximum voltage tolerated by the digital inputs is equal to 3.3V. Any higher voltage would damage it irreparably!!

How do we identify the anode and cathode of the LED? We do this by looking at its terminals. The longest corresponds to the anode. Also, the LED body has a flattening at one point on the edge indicating that the nearby terminal is the cathode.

So if an LED doesn’t light up it’s possible that it’s wired upside down. In this case, to make it work, simply reverse the wiring.

How do you calculate the resistance to connect to the LED?

Please note: this paragraph deals with the calculation of the limiting resistance in a theoretical way and requires a minimum knowledge of the basics of Electrotechnics. Therefore it is not essential for understanding the rest of the project and can be skipped by the reader not interested in such theoretical aspects.

As we have already said, the resistor between the generic GPIO and the LED serves to limit the current flowing through the LED. But how can we calculate its resistance value? Ohm’s Law comes to our aid which says that the potential difference across a resistor (i.e. the voltage measured at the ends of the resistor) is proportional to the current I flowing through it and the constant of proportionality is precisely the resistance value of the resistor R:

V2 - V1 = RI

Please note: for the sake of precision it must be pointed out that while the resistor is the physical component (the actual object), the resistance is its value. So it is improper (even if it happens frequently) to call the resistor with the term resistance.

We can see Ohm’s Law on a simple circuit consisting of a voltage source (the circle on the left) and a resistor:

Representation of Ohm's Law
Representation of Ohm’s Law

The voltage (or potential difference) V2 – V1 impressed by the voltage source on the resistor is equal to the product of R by I.

Now let’s see a slightly more complex scheme where the usual voltage generator, the resistor and a red LED are present:

Circuit for calculating the current limiting resistor on the LED
Circuit for calculating the current limiting resistor on the LED

In our case the Vg represents the voltage present at the digital output of the ESP32 when it is HIGH and is therefore equal to 3.3V.

Vd is the voltage across the diode (between anode and cathode) when it is forward biased (ie when it is carrying current). Having chosen a red LED, we know from the previous table that Vd = 1.8V.

We need to determine the R-value of the resistor. We still have one unknown: the value of the current I which must flow in the circuit when the pin is in the HIGH state.

Please note: when the digital pin is in the LOW state its voltage (ie Vg) is zero, it follows that also the current I in the circuit is zero.

LEDs generally cannot withstand currents greater than 20mA, so we impose a maximum current of 15mA to be on the safe side.

By Kirchhoff’s voltage law we have that:

Vg - Vr - Vd = 0

From which we derive that:

Vr = Vg - Vd 

Passing to the real values, we have that:

Vr = 3.3V - 1.8V

It follows that:

Vr = 1.5V

But, by Ohm’s Law, we have that:

Vr = RI

from which:

R = Vr / I

Substituting the real values:

R = 1.5V / 0.015A

The result is a value of R equal to 100Ω.

The sketch

Let’s create the PlatformIO project

We have already seen the procedure for creating a PlatformIO project in the article How to create a project for NodeMCU ESP8266 with PlatformIO.

Although it refers to the ESP8266 board, the procedure is similar.
Simply, when choosing the platform, you will have to choose the AZ-Delivery ESP-32 Dev Kit C V4.

Of the libraries indicated, install, following the procedure, the DHT sensor library for ESPx by Bernd Giesecke (which is used to read the data transmitted by the DHT22 temperature and humidity sensor) and leave the other two alone (WiFiManager and UniversalTelegramBot).

Then install the BluetoothSerial by Seeed library as shown in the following image:

Installing the BluetoothSerial library
Installing the BluetoothSerial library

Now edit the platformio.ini file to add these two lines:

monitor_speed = 115200
upload_speed = 921600

so that the file looks like this:

[env:az-delivery-devkit-v4]
platform = espressif32
board = az-delivery-devkit-v4
monitor_speed = 115200
upload_speed = 921600
framework = arduino
lib_deps = 
	beegee-tokyo/DHT sensor library for ESPx@^1.18
	mbed-seeed/[email protected]+sha.f56002898ee8

Of course you can download the project from the following link:

Replace the main.cpp file of the project you created with the one present in the zip file.

Now let’s see how the sketch works.

The sketch begins with including the necessary libraries and a check on the Bluetooth configuration:

#include <Arduino.h>
#include "DHTesp.h"
#include "BluetoothSerial.h"

/* Check if Bluetooth configurations are enabled in the SDK */
/* If not, then you have to recompile the SDK */
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

The SerialBT object is then defined which will manage the Bluetooth and the BTData variable in which the data will transit through the serial port:

BluetoothSerial SerialBT;
byte BTData;

The dht object is then created which is used to read the sensor and the GPIO to which to connect it is defined:

DHTesp dht;
#define  DHT22_PIN 14  

and the project variables are defined:

float temperature;
float humidity;
int led1Status = 3;
bool led2Status = false;

The pin in which to connect the LED controlled with the PWM and the operating parameters of the PWM signal are then defined:

// set the pin for the PWM LED
const int ledPinPWM = 16;  // 16 corresponds to GPIO16

// set the PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;

Then the pin for the LED is defined which can only be ON or OFF:

const int ledPinBool = 17;  // 17 corresponds to GPIO17

The variables:

unsigned long measureDelay = 3000;                //    NOT LESS THAN 2000!!!!!   
unsigned long lastTimeRan;

time the readings by the DHT22 (in this case the reading takes place every 3 seconds). It is advisable not to go below this value as the DHT22 takes about 2 seconds to take a reading.

At this point there is the setup function:

The serial port is activated:

Serial.begin(115200);
delay(2000);

Bluetooth is then activated:

SerialBT.begin();
Serial.println("Bluetooth Started! Ready to pair...");

If you want to assign a specific name to the ESP32 Bluetooth device, you need to specify it as an argument to the SerialBT.begin() function. For example, if you want to name it myESP32BT, enter SerialBT.begin(“myESP32BT”).
If you leave the command without a parameter, such as SerialBT.begin(), the default name ESP32 will be applied.

Immediately afterwards the connection of the DHT22 to the ESP32 via the GPIO14 is defined:

dht.setup(DHT22_PIN, DHTesp::DHT22); // Connect DHT sensor to GPIO 14

Finally the channels for the two LEDs are configured:

// configure LED PWM functionalitites
ledcSetup(ledChannel, freq, resolution);
  
// attach the channel to the GPIO to be controlled
ledcAttachPin(ledPinPWM, ledChannel);

pinMode(ledPinBool, OUTPUT);

At this point there is the loop function:

The first part prints on the Serial Monitor the character sent by the application on the mobile phone (which we will see later) to the ESP32:

if(SerialBT.available())
{
  BTData = SerialBT.read();
  Serial.write(BTData);
}

The following block deals with the management of the commands to turn the first LED ON and OFF:

if(BTData == '1')
{
  led2Status = true;
}

if(BTData == '0')
{
  led2Status = false;
}

When we send the 1 character, the led2Status variable is set to true while if we send the 0 character the variable is set to false.

In the first case the LED will turn ON, in the second it will turn OFF.

The next block manages the value of the led1Status variable which regulates the duty cycle of the PWM signal which, in turn, regulates the brightness of the second LED:

if(BTData == '+')
{
  led1Status++;
}

if(BTData == '-')
{
  led1Status--;
}

When we send the + character, the led1Status variable is incremented while if we send the character the variable is decremented.

The next block deals with sending the temperature and humidity values ​​to the mobile phone:

if(BTData == 'T')
{
  String temperatureString = "Temperature: " +  String(temperature) + "\n";
  int size = temperatureString.length();
  for(int i = 0; i < size; i++)
  {
    SerialBT.write(temperatureString[i]);
  }    
}

if(BTData == 'U')
{
  String humidityString = "Humidity: " + String(humidity) + "\n";
  int size = humidityString.length();
  for(int i = 0; i < size; i++)
  {
    SerialBT.write(humidityString[i]);
  }    
}

If the T character is sent, the device responds by sending the current temperature value. If the U character is sent, the device responds by sending the current humidity value.

Finally starts an if block which contains some functions inside it.

The condition inside the if determines the time frame with which the measurements are made:

if (millis() > lastTimeRan + measureDelay)  {

So the described events happen every measureDelay ms thanks to this condition.

Continuing with the if, we see that the measurements of the physical quantities of our interest are made and the lastTimeRan variable is updated with the current value in ms:

humidity = dht.getHumidity();
temperature = dht.getTemperature();

lastTimeRan = millis();

Immediately afterwards, the states of the two LEDs are set consistently with the values ​​contained in the led1Status and led2Status variables, set via the command sent via Bluetooth:

ledcWrite(ledChannel, led1Status);

if(led2Status) {
  digitalWrite(ledPinBool, HIGH);
} else {
  digitalWrite(ledPinBool, LOW);
} 

At this point you just have to load the sketch on the board and see how to use the control application.

The Serial Bluetooth Terminal application

To send the Bluetooth commands to the ESP32 I chose to use Kai Morich’s Serial Bluetooth Terminal application. You can download it from the Play Store.

Now turn ON Bluetooth in your smartphone and search for Bluetooth devices. You should see a list of Paired Devices and Available Devices. Go to Available Devices.

Select ESP32 if you left the SerialBT.begin() line without a parameter in the sketch, otherwise choose the device with the name you put as a parameter in that line. Your mobile phone will ask you if you want to pair it with ESP32 (or with the name you set for it). At this point give OK. No need for passwords.

Open the Serial Bluetooth Terminal application and click on the point indicated in the following image:

Click on the point indicated to bring out the menu
Click on the point indicated to bring out the menu

Select the Devices item as shown in the figure below:

Select the Devices item
Select the Devices item

Another menu will open from which you will have to select your device (for example ESP32):

Select your device
Select your device

Now click on the point indicated in the following image to connect the application to the selected device:

Connect the application to the device
Connect the application to the device

Hopefully the connection should establish:

Connection successful
Connection successful

Now you need to record the commands to be sent to the device with macros in the application. Hold down the M1 key. The menu for editing it will open:

Let's make the first macro
Let’s make the first macro

Instead of M1, put the + character in the Name field and fill the Value field with the + character, then save by pressing at the indicated point:

The first macro is ready
The first macro is ready

Repeating the exact same procedure, perform the following associations:

  • on M2 put the character in the Name and Value fields
  • on M3 put the word ON in the Name field and the character 1 in the Value field
  • on M4 put the word OFF in the Name field and the character 0 in the Value field
  • on M5 put the word TEMP in the Name field and the character T in the Value field
  • on M6 put the word HUM in the Name field and the character U in the Value field

At the end you should have a screen like this:

Here's what the screen looks like after recording all the macros
Here’s what the screen looks like after recording all the macros

At this point you can use the application.

By pressing the + key you will increase the brightness of the PWM controlled LED while by pressing the key you will decrease it.

Pressing the ON key will turn ON the other LED, pressing the OFF key will turn it OFF.

By pressing the TEMP key you will see the temperature detected by the DHT22 appear on the application screen while by pressing the HUM key you will see the humidity detected by the sensor appear.

Here’s an example of what they look like:

The running application that communicates with the ESP32 via Bluetooth
The running application that communicates with the ESP32 via Bluetooth

Video demonstrating how it works

The video below demonstrates the general operation:

Practical demonstration of operation
Scroll to Top