This ESP32 API guide describes how to implement an ESP32 Rest API server using PlatformIO. As you may already know, API stands for Application Programming Interface. The aim of this tutorial is to build an ESP32 API Web server so that the ESP32 exposes a set of Rest API. We can use these Rest APIs to interact with ESP32. We will focus our attention on developing JSON Rest APIs that use the GET and POST method. Through an ESP32 API server, we will implement four different Rest JSON APIs.

To apply this ESP32 API guide to a real use case, we will connect the ESP32 to a BME280 sensor to read the temperature, humidity, and pressure. Therefore, the ESP32 API Server will expose three different JSON APIs:

  • to read the temperature
  • to read the pressure
  • to read the humidity

Moreover, we will implement another JSON API that supports POST method to send data to the ESP32.

What you will learn…

  • How to develop ESP32 Rest APIs:
    • How to implement Rest JSON API that supports GET method
    • How to implement a Rest JSON API that supports POST method
  • How to implement an ESP32 API Web server to handle HTTP connections

How to develop an ESP32 API server

The first step is developing an ESP32 API Web server that handles the incomming client connections. As you should know already, a Rest API uses the HTTP protocol so it is necessary to create a Web server. Create a new project using your favorite IDE, I’m using PlatformIO, and use the code shown below:

#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>

const char *SSID = "your_wifi_ssid";
const char *PWD = "your_wifi_pwd";

// Web server running on port 80
WebServer server(80);

void connectToWiFi() {
  Serial.print("Connecting to ");
  Serial.println(SSID);
  
  WiFi.begin(SSID, PWD);
  
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
    // we can even make the ESP32 to sleep
  }
 
  Serial.print("Connected. IP: ");
  Serial.println(WiFi.localIP());
}

At line 9, the code defines the Web server listening on port 80. You can change this port if you like.

We have our Web server runnng on the ESP32. To make it an ESP32 API server, we have to add resources to handle.

How to add Rest API resources to the ESP32

Now, we have to add API resources to the ESP32. Our ESP32 API server must support:

  • /temperature – GET method – that returns the temperature
  • /pressure – GET method – that returns the pressure
  • /humidity – GET method – that returns the humidity
  • /env – GET – that returns all the previous information toghether

Let us add an API routing so that the Web server will dispatch the request to th right API handler:

// setup API resources
void setup_routing() {
  server.on("/temperature", getTemperature);
  server.on("/pressure", getPressure);
  server.on("/humidity", getHumidity);
  server.on("/env", getEnv);
 
  // start server
  server.begin();
}

The code assign to each resources the corresponding hanlder. Finally it starts the ESP32 API server.

How to implement the ESP32 Rest API

It is time to implement the Rest API. The code is simple:

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, "mBar");
  server.send(200, "application/json", buffer);
}
 
void getEnv() {
  Serial.println("Get env");
  jsonDocument.clear(); // Clear json buffer
  add_json_object("temperature", temperature, "°C");
  add_json_object("humidity", humidity, "%");
  add_json_object("pressure", pressure, "mBar");
  serializeJson(jsonDocument, buffer);
  server.send(200, "application/json", buffer);
}

Our ESP32 Rest API returns a JSON payload. To do it, the code uses the ArduinoJSON library. Finally the server return the payload to the client.

Return the JSON Payload

In this step, we will create the JSON payload that holds the information the client requested using the ESP32 Rest API:

#include <ArduinoJson.h>

// JSON data buffer
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; 
}

How to implement ESP32 Rest API with POST method

In the previous paragraph, we have described how to implement Rest JSON APIs that support HTTP GET method. This kind of API is used to get (or read) data. It is a read-only API.

Now we conver how to implement a Rest JSON API that uses the POST method. In this case, the client has to send a payload that is the information the client wants to send to the ESP32. Moreover, we suppose the payload is in JSON format.

Let us add the following resources to the ESP32 API server in the setup_routing() method:

server.on("/led", HTTP_POST, handlePost);

In this case we add another resource named led that explicity supports HTTP Post method. We use this Rest JSON API to control a led strip color.

Handle POST payload

To handle the POST payload that the ESP32 API server receives when the client invokes this Rest JSON API, it is necessary to add the following code:

void handlePost() {
  if (server.hasArg("plain") == false) {
    //handle error here
  }

  String body = server.arg("plain");
  deserializeJson(jsonDocument, body);
  
  // Get RGB components
  int red = jsonDocument["red"];
  int green = jsonDocument["green"];
  int blue = jsonDocument["blue"];

  // Respond to the client
  server.send(200, "application/json", "{}");
}

Notice that, we deserialize the JSON payload and the get the three color components. Finally, we send back a response to the client using an empty payload.

Recommended:
How to invoke HTTPS Rest JSON API using ESP8266: ClimaCell API example
#API and IoT the perfect convergence: Arduino Rest API

ESP32 Rest API Server: Full source code

This is the full source code:

#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <FreeRTOS.h>
 
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_NeoPixel.h>
 
const char *SSID = "your_wifi_ssid";
const char *PWD = "your_wifi_pwd";

#define NUM_OF_LEDS 8 
#define PIN 4
 
// Web server running on port 80
WebServer server(80);
 
// Sensor
Adafruit_BME280 bme;

// Neopixel LEDs strip
Adafruit_NeoPixel pixels(NUM_OF_LEDS, PIN, NEO_GRB + NEO_KHZ800);
 
// JSON data buffer
StaticJsonDocument<250> jsonDocument;
char buffer[250];
 
// env variable
float temperature;
float humidity;
float pressure;
 
void connectToWiFi() {
  Serial.print("Connecting to ");
  Serial.println(SSID);
  
  WiFi.begin(SSID, PWD);
  
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
    // we can even make the ESP32 to sleep
  }
 
  Serial.print("Connected. IP: ");
  Serial.println(WiFi.localIP());
}
 
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");
 
     // delay the task
     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, "mBar");
  server.send(200, "application/json", buffer);
}
 
void getEnv() {
  Serial.println("Get env");
  jsonDocument.clear();
  add_json_object("temperature", temperature, "°C");
  add_json_object("humidity", humidity, "%");
  add_json_object("pressure", pressure, "mBar");
  serializeJson(jsonDocument, buffer);
  server.send(200, "application/json", buffer);
}

void handlePost() {
  if (server.hasArg("plain") == false) {
    //handle error here
  }

  String body = server.arg("plain");
  deserializeJson(jsonDocument, body);
  
  // Get RGB components
  int red = jsonDocument["red"];
  int green = jsonDocument["green"];
  int blue = jsonDocument["blue"];

  Serial.print("Red: ");
  Serial.print(red);
  

  pixels.fill(pixels.Color(red, green, blue));
  pixels.show();

  // Respond to the client
  server.send(200, "application/json", "{}");
}
 
 
// setup API resources
void setup_routing() {
  server.on("/temperature", getTemperature);
  server.on("/pressure", getPressure);
  server.on("/humidity", getHumidity);
  server.on("/env", getEnv);
  server.on("/led", HTTP_POST, handlePost);
 
  // start server
  server.begin();
}


void setup_task() {
  xTaskCreate(
    read_sensor_data,    
    "Read sensor data",  
    1000,            
    NULL,            
    1,               
    NULL            
  );
}
 
void setup() {
   Serial.begin(9600);
 
   // Sensor setup
  if (!bme.begin(0x76)) {
    Serial.println("Problem connecting to BME280");
  }
  connectToWiFi();
  setup_task();
  setup_routing();  

  // Initialize Neopixel
  pixels.begin();
}
 
void loop() {
  server.handleClient();
}

A few things to notice:

  • The ESP32 connects to the BME280 to read temperature, pressure and humidity. The ESP32 retrieves this information using a specific task that runs very minute
  • The ESP32 connects to Neopixel RGB led strip that is controlled using the ESP32 Rest API (POST method)

Before using BME280 and Nexopixels, you have to install the libraries if you didn’t do it already. If you use PlatformIO you can look for the libraries using the Library Manager.

If you do not have these components you can use other components to or you can just experiment how to work with ESP32 Rest API.

ESP32 Schematic

The ESP32 schematic is shown below:

ESP32 schematic

How to test the ESP32 JSON Rest API

In this last step, we will test the ESP32 API server developed in the previous paragraph. There are several ways to test it, we will use Postman. You can download it freely.

Run the code on your ESP32 and open Postman.

To test the temperature API resource, get the ESP32 IP and then write:

http://192.168.1.169/temperature

Change the IP according your ESP32:

ESP32 Rest API resource: temperature

In the same way you can test other JSON API resources:

ESP 32 API server test
Rest JSON API using ESP 32

Finally:

ESP32 Rest API with JSON payload

Testing the Rest JSON API with Post

In this last step, we test the Rest JSON API using POST HTTO method. In this case, we will send data to the ESP32:

ESP32 API server with POST method

Notice that we have used the POST method to invoke the Rest API on ESP32. If you have connected the led strips you will notice that the LEDs will change colors.

Wrapping up

At the end of this post, you learned how to implement an ESP32 API server that exposes a set of ESP32 Rest API. We can use these APIs to interact with the ESP32 or to exchange data. This is very helpful because once you have implemented your APIs then you can integrate the ESP32 with external systems such as mobile apps or other platforms. You can build for example an home automation system.

LEAVE A REPLY

Please enter your comment!
Please enter your name here