ESP32 Arduino: HTTP communication between devices

In this tutorial we will check how to establish HTTP communication between two ESP32 devices. One of the devices will act as a server and the other as a client. This tutorial was tested using two different ESP32 board models: a Beetle board and a FireBeetle board, both from DFRobot.

Introduction

In this tutorial we will check how to establish HTTP communication between two ESP32 devices. One of the devices will act as a server and the other as a client.

In some application scenarios, there might be a need for multiples devices on a network to talk to each other.

For example, we might design an architecture where there’s a central node responsible for communicating with a remote server. This node could have the role of receiving data from the other devices and send it to the server and / or receiving configurations from the server and forward them to the devices.

Naturally there are many hypothetical scenarios to justify this machine-to-machine communication and there are also many ways of implementing it.

As already mentioned, in this tutorial we will cover how to use HTTP to allow two ESP32 devices to talk. One of them will act as a server, exposing an endpoint, and the other will act as a client, performing requests to that endpoint and receiving the data.

For this tutorial we will assume that the client will simply do a GET request and print the message returned by the server.

To setup the server, we will use the HTTP async web server library. You can check here an introductory tutorial on how to install it and how to get started.

For a detailed tutorial o how to do a GET request from a ESP32 using the Arduino core, please check here.

This tutorial was tested using two different ESP32 board models: a Beetle board and a FireBeetle board, both from DFRobot.

The server code

We will start our code by the library includes that will expose to us the functionality we need to set up the server.

We will need the WiFi.h library, to be able to connect the ESP32 to a WiFi network, and the ESPAsyncWebServer.h, which allows us to setup our HTTP web server.

#include <WiFi.h>
#include <ESPAsyncWebServer.h>

After this we need to declare the credentials of the WiFi network to which the device will connect. More specifically, we will need the network name (SSID) and password.

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPass";

Then we will instantiate an object of class AsyncWebServer, which we will use to setup the server. As input of the constructor we will pass the port where the server will be listening for incoming requests. We will be using port 80, which is the default HTTP port.

AsyncWebServer server(80);

Moving on to the Arduino setup, we will start by opening a serial connection, to output some results of our program, and then connect the device to the WiFi network, using the previously defined credentials.

After the connection is established we will print to the serial port the IP address assigned to the ESP32 on the network. This is the IP address we should use when specifying the destination endpoint for the HTTP request, on the client code covered in the next section.

Serial.begin(115200);
 
WiFi.begin(ssid, password);
 
while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
}
 
Serial.println(WiFi.localIP());

Then we will setup a server route by calling the on method on our AsyncWebServer object. As first input of the method we pass a string indicating the route endpoint, as second a constant indicating the HTTP method allowed and as third and last the route handling function.

We will set our route name as “/test” and it will only listen to HTTP GET requests. The implementation of the route handling function will consist o printing a message to the serial port indicating a request was received, and then sending back an answer to the client.

The route handling function receives as input a pointer to an object of class AsyncWebServerRequest. We can return an answer back to the client by calling the send method on this object, passing as first input the HTTP response code, as second input the content-type and as third input the response payload.

We will send the HTTP response code 200, which means success, we will set the content-type to “text/plain” and the payload will be a simple “Hello” message.

Note that we are going to specify the route handling function using the C++ lambda syntax.

server.on("/test", HTTP_GET, [](AsyncWebServerRequest *request){
    Serial.println("Request received");
    request->send(200, "text/plain", "Hello from server");
});

To finalize we simply need to call the begin method on our server object, so it starts listening to incoming requests.

server.begin();

The final code can be seen below. Note that the Arduino main loop can be left empty since the HTTP web server framework we are using works asynchronously, which means we don’t need to periodically call a function to explicitly handle the incoming client requests.

#include <WiFi.h>
#include <ESPAsyncWebServer.h>
 
const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPass";
 
AsyncWebServer server(80);
 
void setup(){
  
  Serial.begin(115200);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
 
  Serial.println(WiFi.localIP());
 
  server.on("/test", HTTP_GET, [](AsyncWebServerRequest *request){
    Serial.println("Request received");
    request->send(200, "text/plain", "Hello from server");
  });
 
  server.begin();
}
 
void loop(){}

The client code

We will also start the client code with the library includes. Like before, we need the WiFi.h, to be able to connect the ESP32 to a WiFi network. We will also need the HTTPClient.h library, which will expose higher level methods for us to perform HTTP requests.

#include <WiFi.h>
#include <HTTPClient.h>

After this we need to declare the WiFi credentials, so the client can connect to the network. In order for both devices to be able to talk with each other, we need to ensure that both are connected to the same WiFi network.

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPass";

Our Arduino setup function will consist on opening a serial connection and then connecting the device to the WiFi network.

void setup() {

  Serial.begin(115200);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  Serial.println("Connected to the WiFi network");

}

We will write the rest of our code in the Arduino main loop function, to ensure the client will periodically send a HTTP GET request to the server.

The first thing we will do is defining an object of class HTTPClient. This object will expose to us the methods we need to send the request to the server.

HTTPClient http;

Then we need to call the begin method on our HTTPClient object, to setup the request. As input, this method receives a string with the URL of the server endpoint we want to reach.

The URL should have the following format, where you should change #your_server_ESP_IP# by the IP of the ESP32 that is acting as a server:

http://#your_server_ESP_IP#/test

As already mentioned, after running the code from the previous section in the ESP32 that will act as a server, it should print its local IP address once it connects to the WiFi network. You just need to open the Arduino IDE serial monitor to obtain the address and use it here.

Below you can see how the code should look like. In this case, I’m using the IP of my ESP32 server device.

http.begin("http://192.168.1.78/test");

To send the actual request, we simply need to call the GET method on our HTTPClient object. This method takes no arguments and returns as output an integer with the HTTP response code from the server, in case the request is successfully sent.

Note however that if this method call returns a value lesser than 0, it means than an error occurred while sending the request. You can check the full list of possible errors here.

int httpCode = http.GET();

So, in case of success, we will print the HTTP response code and the payload returned by the server. To print the payload, we simply need to call the getString method on our server object.

In case of error, we will print a message to warn the user.

if (httpCode > 0) {
    
    String payload = http.getString();
    Serial.println(httpCode);
    Serial.println(payload);
}

else {
    Serial.println("Error on HTTP request");
}

To finalize, we need to call the end method to free the resources.

http.end(); 

The complete code can be seen below. Note that we have added a small 30 seconds delay between each iteration of the loop.

#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPass";

void setup() {

  Serial.begin(115200);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  Serial.println("Connected to the WiFi network");

}

void loop() {

  HTTPClient http;

  http.begin("http://192.168.1.78/test");
  int httpCode = http.GET();

  if (httpCode > 0) {
    
    String payload = http.getString();
    Serial.println(httpCode);
    Serial.println(payload);
  }

  else {
    Serial.println("Error on HTTP request");
  }

  http.end(); 

  delay(30000);

}

Testing the code

To test the end to end system, the first thing we should do is compiling and uploading the code to the ESP32 device that will act as a server.

Once the procedure finishes, you should open the Arduino IDE serial monitor. After the device finishes the connection to the WiFi network, it will print the local IP assigned to it on the network. As mentioned before, you should use that IP when specifying the URL of the server, on the client code.

After this, you should compile and upload the code to the ESP32 device that will act as a client. Open also the serial monitor to get the results.

If you go to the serial monitor connected to the server device, you should get an output similar to figure 1. As can be seen, the “Request received” messages are printed when requests from the client are received.

Output of the ESP32 acting as a server, which shows the messages getting printed when requests are received.
Figure 1 – Output of the ESP32 acting as a server, which shows the messages getting printed when requests are received.

If you analyze the results getting printed to the ESP32 that is acting as a client, you should get a result like figure 2, which shows the 200 status code and the “Hello” message from the server getting printed.

Output of the ESP32 acting as a client, showing the HTTP status code and response payload received from the server.
Figure 2 – Output of the ESP32 acting as a client, showing the HTTP status code and response payload received from the server.

Leave a Reply