In this tutorial, we will learn how to build a rest API web server using ESP32 that implements different REST APIs. We will create APIs that will be used to communicate with ESP32 using GET and POST requests. To send and receive data from ESP32 through REST APIs, we will use the postman application. Additionally, we will interface ESP32 with a BME280 sensor and an RGB LED. The ESP32 will acquire temperature, pressure, and humidity readings from the BME280 that we can get from ESP32 using an HTTP GET request. Whereas, we will use POST method to control the RGB LED. In summary, ESP32 rest API web server will present four different JSON based Rest APIs
- Temperature reading from BME280 (IP_address/temperature)
- Humidity reading from BME280 (IP_address/humidity)
- Pressure reading from BME280 (IP_address/pressure)
- Control RGB LED (IP_address/led)
We will require the following components for this project:
Required Components:
- ESP32 development board
- BME280 sensor
- RGB LED
- Connecting Wires
- Breadboard
REST API Web Server ESP32 Circuit Diagram
In this section we will connect the ESP32 board with BME280 sensor and RGB LED to proceed with our project.
The connection of BME280 with the ESP32 board is very easy. We have to connect the VCC terminal with 3.3V, ground with the ground (common ground), SCL of the sensor with SCL of the module, and SDA of the sensor with the SDA pin of the ESP modules.
The I2C pin in ESP32 for SDA is GPIO21 and for SCL is GPIO22
BME280 | ESP32 |
VCC | 3.3V |
GND | GND |
SCL | GPIO22 |
SDA | GPIO21 |
ESP32 with RGB LED Module (Common Cathode)
We are using the common cathode RGB LED module for this project. The table below shows the connections we are using between the LED module and ESP32.
RGB LED Module | ESP32 |
R | GPIO5 |
G | GPIO18 |
B | GPIO19 |
– | GND |
The red, green, and blue pins of the RGB LED module will be connected with GPIO pins of ESP32 board. We will use GPIO, GPIO, and GPIO to connect with each colour pin. You can use any appropriate GPIO pin.
Schematic Diagram
Follow the schematic diagram below and connect the three devices accordingly.
All the connections between the devices are the same as we listed them in the tables above.
You may like to read these BME280 tutorials:
- BME280 with ESP32 – Display Values on OLED ( Arduino IDE)
- ESP32 Send Sensor Readings to ThingSpeak using Arduino IDE (BME280)
- MicroPython: BME280 with ESP32
- MicroPython: BME280 Web Server with ESP32/ESP8266
Installing Required Libraries for ESP32 Rest API Web Server
Before we proceed further, you should make sure that you have the latest version of Arduino IDE installed on your system. Moreover, you should also install an ESP32 add-on in Arduino IDE. If your IDE does not have the plugin installed you can visit the link below:
Installing ESP32 library in Arduino IDE and upload code
Installing ArduinoJSON Library
You will have to install the ArduinoJSON library by Benoit Blanchon as we will be dealing with JSON script. Open your Arduino Library Manager by clicking Sketch > Include Library > Manage Libraries. Type ‘ArduinoJSON’ in the search tab and press enter. Install the library version 6.17.2 which is highlighted below.
ESP32 Rest API Web Server Arduino Sketch
Our ESP32 (client) will make an HTTP GET request to the API server. As a response, we will receive a string consisting of the JSON object with details regarding the BME280 sensor data. Likewise, to control the RGB LED, the client will send a string consisting of JSON objects with details regarding the RGB values to ESP32.
Open your Arduino IDE and go to File > New to open a new file. Copy the code given below in that file. For this code to work with your ESP32 board you will have to replace the Wi-Fi network credentials.
#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <FreeRTOS.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
const char *SSID = "YOUR_SSID";
const char *PWD = "YOUR_PASSWORD";
const int red_pin = 5;
const int green_pin = 18;
const int blue_pin = 19;
// Setting PWM frequency, channels and bit resolution
const int frequency = 5000;
const int redChannel = 0;
const int greenChannel = 1;
const int blueChannel = 2;
const int resolution = 8;
WebServer server(80);
Adafruit_BME280 bme;
StaticJsonDocument<250> jsonDocument;
char buffer[250];
float temperature;
float humidity;
float pressure;
void setup_routing() {
server.on("/temperature", getTemperature);
server.on("/pressure", getPressure);
server.on("/humidity", getHumidity);
server.on("/data", getData);
server.on("/led", HTTP_POST, handlePost);
server.begin();
}
void create_json(char *tag, float value, char *unit) {
jsonDocument.clear();
jsonDocument["type"] = tag;
jsonDocument["value"] = value;
jsonDocument["unit"] = unit;
serializeJson(jsonDocument, buffer);
}
void add_json_object(char *tag, float value, char *unit) {
JsonObject obj = jsonDocument.createNestedObject();
obj["type"] = tag;
obj["value"] = value;
obj["unit"] = unit;
}
void read_sensor_data(void * parameter) {
for (;;) {
temperature = bme.readTemperature();
humidity = bme.readHumidity();
pressure = bme.readPressure() / 100;
Serial.println("Read sensor data");
vTaskDelay(60000 / portTICK_PERIOD_MS);
}
}
void getTemperature() {
Serial.println("Get temperature");
create_json("temperature", temperature, "°C");
server.send(200, "application/json", buffer);
}
void getHumidity() {
Serial.println("Get humidity");
create_json("humidity", humidity, "%");
server.send(200, "application/json", buffer);
}
void getPressure() {
Serial.println("Get pressure");
create_json("pressure", pressure, "hPa");
server.send(200, "application/json", buffer);
}
void getData() {
Serial.println("Get BME280 Sensor Data");
jsonDocument.clear();
add_json_object("temperature", temperature, "°C");
add_json_object("humidity", humidity, "%");
add_json_object("pressure", pressure, "hPa");
serializeJson(jsonDocument, buffer);
server.send(200, "application/json", buffer);
}
void handlePost() {
if (server.hasArg("plain") == false) {
}
String body = server.arg("plain");
deserializeJson(jsonDocument, body);
int red_value = jsonDocument["red"];
int green_value = jsonDocument["green"];
int blue_value = jsonDocument["blue"];
ledcWrite(redChannel, red_value);
ledcWrite(greenChannel,green_value);
ledcWrite(blueChannel, blue_value);
server.send(200, "application/json", "{}");
}
void setup_task() {
xTaskCreate(
read_sensor_data,
"Read sensor data",
1000,
NULL,
1,
NULL
);
}
void setup() {
Serial.begin(115200);
ledcSetup(redChannel, frequency, resolution);
ledcSetup(greenChannel, frequency, resolution);
ledcSetup(blueChannel, frequency, resolution);
ledcAttachPin(red_pin, redChannel);
ledcAttachPin(green_pin, greenChannel);
ledcAttachPin(blue_pin, blueChannel);
if (!bme.begin(0x76)) {
Serial.println("BME280 not found! Check Circuit");
}
Serial.print("Connecting to Wi-Fi");
WiFi.begin(SSID, PWD);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.print("Connected! IP Address: ");
Serial.println(WiFi.localIP());
setup_task();
setup_routing();
}
void loop() {
server.handleClient();
}
How does the Code Works?
Now, let us understand how each part of the code works.
Importing Libraries
Firstly, we will import the relevant libraries which are necessary for this project.
WiFi.h library is used to connect our ESP32 module with the local WIFI network. The Adafruit_Sensor and the Adafruit_BME280 libraries which we installed earlier are also included as they are necessary as we have to interface the sensor with the ESP32. The ArduinoJSON.h will be used for the JSON script.
#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <FreeRTOS.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
The WebServer object will be used to set up the ESP32 web server. We will pass the default HTTP port which is 80, as the input to the constructor. This will be the port where the server will listen to the requests.
WebServer server(80);
Then, we define the Adafruit_BME280 object named bme by setting it on the default I2C GPIO pins of ESP32.
Adafruit_BME280 bme;
The following three float variables will store the temperature, humidity and pressure readings acquired from the BME280 sensor.
float temperature;
float humidity;
float pressure;
RGB LED Parameters
The following lines specify the GPIO pins of ESP32 connected with each of the colour pins of the RGB LED. Here we are using the same GPIO pins as shown in the schematic diagram above. You can use any suitable output pin of ESP32.
const int red_pin = 5;
const int green_pin = 18;
const int blue_pin = 19;
The following variables define the PWM frequency, channels and the bit resolution. The brightness of the LED will be controlled through the duty cycle. When we define the PWM parameters for each LED it includes the frequency of the signal, led channels and resolution. We have set the frequency at 5000 Hz. For defining the PWM channel we can choose between a total of sixteen PWM channels in ESP32. You can use any channel from 0-15. We have set the PWM channel to 0, 1, 2 for three LEDs respectively. Additionally, we have set the PWM resolution to 8 bits as it is the optimal resolution to obtain the maximum frequency. Although you can use resolution between 1-16 bits. As we are using 8-bit resolution, thus the duty cycle value will vary between 0-255 which we will map to 0-100%.
Recommended Reading: ESP32 PWM with Arduino IDE – LED fading example
// Setting PWM frequency, channels and bit resolution
const int frequency = 5000;
const int redChannel = 0;
const int greenChannel = 1;
const int blueChannel = 2;
const int resolution = 8;
ESP32 Rest API
The following function sends the request to the appropriate API handler.
void setup_routing() {
server.on("/temperature", getTemperature);
server.on("/pressure", getPressure);
server.on("/humidity", getHumidity);
server.on("/data", getData);
server.on("/led", HTTP_POST, handlePost);
server.begin();
}
Our ESP32 Rest API server handles four different rest APIs. We will use the on() method on the server object to listen to the incoming HTTP requests. The server will receive a request on the following URLs:
- /temperature: This will return the current temperature in degree Celsius
- /pressure: This will return the current pressure in hPa
- /humidity: This will return the current humidity in %
- /data: This will return BME280 sensor data consisting of temperature, pressure and humidity
Here each resource (HTTP GET): “temperature”, “pressure”, “humidity” and “data” is allocated to its corresponding handler:
- temperature -> getTemperature
- pressure -> getPressure
- humidity -> getHumisity
- data -> getData
Moreover, the “led” resource will be used for the HTTP POST method. This Rest JSON API will be used to control the RGB LED. To start the API server, we will call the begin() on our server object.
The JSON payload consists of the information that the client requested via the ESP32 Rest API. We will include a tag, a value, and a unit for the GET method. For example, if the client requests the temperature then temperature, along with its value and unit will be sent.
StaticJsonDocument<250> jsonDocument;
char buffer[250];
void create_json(char *tag, float value, char *unit) {
jsonDocument.clear();
jsonDocument["type"] = tag;
jsonDocument["value"] = value;
jsonDocument["unit"] = unit;
serializeJson(jsonDocument, buffer);
}
void add_json_object(char *tag, float value, char *unit) {
JsonObject obj = jsonDocument.createNestedObject();
obj["type"] = tag;
obj["value"] = value;
obj["unit"] = unit;
}
We take BME280 sensor readings by using bme.readTemperature(), bme.readPressure() and bme.readHumidity(). These functions measure ambient temperature, barometric pressure and relative humidity respectively. We use a specific task that runs after every 60 seconds to acquire the BME280 sensor readings.
void read_sensor_data(void * parameter) {
for (;;) {
temperature = bme.readTemperature();
humidity = bme.readHumidity();
pressure = bme.readPressure() / 100;
Serial.println("Read sensor data");
vTaskDelay(60000 / portTICK_PERIOD_MS);
}
}
The following functions will be used as handlers for their corresponding resources. The ESP32 Rest API will return a JSON payload to the client.
void getTemperature() {
Serial.println("Get temperature");
create_json("temperature", temperature, "°C");
server.send(200, "application/json", buffer);
}
void getHumidity() {
Serial.println("Get humidity");
create_json("humidity", humidity, "%");
server.send(200, "application/json", buffer);
}
void getPressure() {
Serial.println("Get pressure");
create_json("pressure", pressure, "hPa");
server.send(200, "application/json", buffer);
}
void getData() {
Serial.println("Get BME280 Sensor Data");
jsonDocument.clear();
add_json_object("temperature", temperature, "°C");
add_json_object("humidity", humidity, "%");
add_json_object("pressure", pressure, "hPa");
serializeJson(jsonDocument, buffer);
server.send(200, "application/json", buffer);
}
HTTP POST
The following function handles the POST payload received by the ESP32 API server after the client requests the “led” Rest JSON API. This will ultimately control the colour of the RGB LED. The JSON payload is deserialized using the deserializeJson() function. The RGB values for red, green and blue get saved in the integer variables ‘red_value’,’green_value’ and blue_value’ respectively. By using ledcWrite() we will generate the PWM with the duty cycle values accessed from the RGB values stored in their corresponding variables.
An empty payload is sent as a response to the client.
void handlePost() {
if (server.hasArg("plain") == false) {
}
String body = server.arg("plain");
deserializeJson(jsonDocument, body);
int red_value = jsonDocument["red"];
int green_value = jsonDocument["green"];
int blue_value = jsonDocument["blue"];
ledcWrite(redChannel, red_value);
ledcWrite(greenChannel,green_value);
ledcWrite(blueChannel, blue_value);
server.send(200, "application/json", "{}");
}
setup()
Inside the setup() function, we will open a serial connection at a baud rate of 115200.
Serial.begin(115200);
By using ledcSetup(), we will initialize the PWM parameters for the RGB LED. This function takes in three parameters. The channel number, frequency, and resolution of the PWM channel.
ledcSetup(redChannel, frequency, resolution);
ledcSetup(greenChannel, frequency, resolution);
ledcSetup(blueChannel, frequency, resolution);
Secondly, we will use ledcAttach() to attach the led pins to the respective channels.
ledcAttachPin(red_pin, redChannel);
ledcAttachPin(green_pin, greenChannel);
ledcAttachPin(blue_pin, blueChannel);
Then, the BME280 sensor gets initialized and in case of failure, an error message is printed on the serial monitor.
if (!bme.begin(0x76)) {
Serial.println("BME280 not found! Check Circuit");
}
The following section of code will connect our ESP32 board with the local network whose network credentials we already specified above. After the connection will be established, the IP address of the ESP32 board will get printed on the serial monitor. This will help us to make a request to the server.
Serial.print("Connecting to Wi-Fi");
WiFi.begin(SSID, PWD);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.print("Connected! IP Address: ");
Serial.println(WiFi.localIP());
Moreover, call the following functions as well for a successful initialization of the project.
setup_task();
setup_routing();
loop()
Inside the loop() function we will call handleClient() on the server object so that the server can listen to the HTTP requests continuously.
void loop() {
server.handleClient();
}
Demonstration
Make sure you choose the correct board and COM port before uploading your code to the board. Go to Tools > Board and select ESP32 Dev Module.
Next, go to Tools > Port and select the appropriate port through which your board is connected.
Click on the upload button to upload the code into the ESP32 development board.
After you have uploaded your code to the development board, press its ENABLE button.
In your Arduino IDE, open up the serial monitor and set the baud rate to 115200. You will be able to see the IP address of your ESP32 module after it successfully connects with the local Wi-Fi.
Download and install the latest version of Postman in your system. We will test our ESP32 Rest API with this application.
Now open the Postman app on your system and select the GET method. Type http://IP_ADDRESS/temperature and press the send button. Immediately we will get the response as a JSON payload.
Type http://IP_ADDRESS/pressure and press the send button. Immediately we will get the response as a JSON payload.
Type http://IP_ADDRESS/humidity and press the send button. Immediately we will get the response as a JSON payload.
Type http://IP_ADDRESS/data and press the send button. Immediately we will get the response as a JSON payload.
Now to control the RGB LED, select the POST option. Now type http://IP_ADDRESS/led then specify the RGB values and press the send button. Immediately the RGB LED will light up in the appropriate colour.
Here we are specifying red=255,green=0,blue=0 thus the RGB lights up in RED.
Here we are specifying red=0,green=0,blue=255 thus the RGB lights up in Blue.
To find the RGB values associated with a color, go to the following website: https://www.w3schools.com/colors/colors_picker.asp , pick your color and you will be able to obtain the RGB values.
Watch the video below demonstration:
You may also like to read:
- ESP32 Data Logging to Firebase Realtime Database
- IoT Based Fire Detection using ESP32 and Flame Sensor with Email Alert
- ESP32-CAM Capture and Save Photo to Firebase Storage
- Create a Wi-Fi Manager for ESP32 using AsyncWebServer library
- ESP32-CAM Take and Send Photos via Email using an SMTP Server
- IoT Sound Pollution Monitoring System using ESP32 – Decibel Meter
- ESP32 Web Server Control DC Motor Speed using L298N Driver
- IoT Based Analog and Digital Clock using OLED and ESP32/ESP8266
Are you selling it as a device.