ESP8266 Arduino: Asynchronous HTTP web server

The objective of esp8266 tutorial is to explain how to set an asynchronous HTTP web server on the ESP8266, using the Arduino core. This tutorial was tested on a DFRobot’s ESP8266 development board.

Introduction

The objective of this tutorial is to explain how to set an asynchronous HTTP web server on the ESP8266, using the Arduino core.

As a simple example, we will setup a server route that receives HTTP GET requests and returns a random number to the client, generated by the ESP8266.

In order to setup the server using a high level API, we will use this library, which takes care of all the lower level details. The library is also available for the ESP32 and you can check here an introductory tutorial for that microcontroller.

Installing the libraries

As mentioned in the introduction section, we will need to install the ESPAsyncWebServer library in order to access the high level functions needed to setup the HTTP webserver.

Additionally, we will also need to install the ESPAsyncTCP library, which is an asynchronous TCP library for the ESP8266. This library is used under the hood by the ESPAsyncWebServer library and thus is a dependency that we need to satisfy.

In order to install the libraries, we can download their source code and place it under the Arduino libraries folder of our installation.

To download each library, go to their GitHub page and click the “Clone or download” button at the top of the page, as indicated in figure 1.

Figure 1 – Downloading the libraries source code.

Then, simply select the “Download ZIP” option and the files should be transferred to your computer.

After that, extract the files to your Arduino IDE libraries directory, which is usually located in the following path:

C:\Users\UserName\Documents\Arduino\libraries

Take in consideration that the extracted folders should have a -master appended in the name. Delete that appended -master and keep the remaining name.

Once the procedure is complete for both of the libraries, they should be available to use on the Arduino environment.

The code

We start the code by making the necessary library includes. First of all, we will need the ESP8266WiFi.h, so we can connect the device to a WiFi network and later receive the HTTP requests.

Then, we will also need to include the two libraries we have just installed, namely the ESPAsyncTCP.h and the ESPAsyncWebServer.h.

We will also declare two global variables which will hold the credentials of the WiFi network to which we are going to connect the ESP8266. We will need both the network SSID (network name) and password.

To finalize the global variables section, we will declare an object of class AsyncWebServer, which will expose the methods needed for us to setup the HTTP server and handle the incoming requests.

It’s important to take in consideration that the constructor of this class receives as input the port where the HTTP server will be listening for incoming requests. This value is relevant for the client to be able to connect to the server.

In our case, we will use port 80, which is the default HTTP port. Thus, since our client will be a web browser, it will use port 80 by default and we don’t need to explicitly specify it. In case we use a port different than 80, we need to specify it when contacting the server using a web browser.

AsyncWebServer server(80);

Moving on to the setup function, we will open a serial connection and then we will connect the ESP8266 to the WiFi network to which we provided the credentials as global variables.

After the connection is established, we will print the ESP8266 IP on the local network, so we can then reach the server. Please note that we will only be able to reach the web server from inside the local network to which the ESP is connected.

In order to reach the web server from outside the local network we would need to portforward the router, which is a more advanced procedure that we will not cover here.

Serial.println(WiFi.localIP());

Now that we have connected the device to a WiFi network and obtained its local IP, we will handle the web server configuration.

Thus, we will setup a server route and a handling function that will be executed when a request is made on that route. To do it, we simply call the on method on our previously declared server object.

As first input of this method, we pass a string with the route where the server will be listening for incoming requests. We will be listening on the “/rand” route.

As second argument, we need to pass an enumerated value which indicates the HTTP methods allowed on the route. For this example, since we are simply getting random numbers generated by the ESP8266, we will be listening only for HTTP GET requests. Thus we pass the HTTP_GET value.

As third and final argument, the on method receives the handling function that will be executed upon receiving the request. This function needs to follow a fixed signature, more precisely, it needs to return void and receive as input a pointer to an object of class AsyncWebServerRequest.

Each client that makes a request will have one of these objects associated with it and we will also use this object to send back the response.

In order to keep the code compact and to avoid declaring a named function, we will define our route handling function as a C++ lambda.

Although for this simple example the overhead of declaring a named function wouldn’t be big, for more complex projects where we have many routes that have simple implementations, declaring a named function for each one would make the code more complex.

To send back a response to the client, we just need to call the send method of the AsyncWebServerRequest object that we receive on our handling function.

This method receives as first input the HTTP return code, which will be 200 (OK) for our example.

As second argument, it receives the content-type, which will be “text/plain“, since we are simply going to return a random number.

As third argument we will pass the actual content to be returned to the client. In our case, it will be a random number that we can generate by calling the Arduino random functionThe random function can be called passing as input the upper bound (exclusive) of the random generated numbers. We will pass 1000 and thus this function should return a value between 0 and 999.

Note that we need to convert the integer returned by the random function to a string, so we can pass it to the send method.

To finalize the server setup, we need to call the begin method of the server object, so the server starts listening for incoming requests. With this we finish the Arduino setup function.

server.begin();

Since the server implementation is asynchronous, we don’t need to call any handling function on the main loop, which we can leave empty. This is a better approach regarding the original ESP8266 HTTP server implementation, where we would need to call a client handling function periodically. You can check here a tutorial on that implementation.

Testing the code

To test the code, first compile it and upload it to your ESP8266 microcontroller using the Arduino IDE.

When the uploading procedure finishes, open the Arduino IDE serial monitor and wait for the device to connect to the WiFi network. Once it is connected with success, an IP should get printed. Copy that IP.

Finally, to make the request to the server and obtain the random number, open a web browser of your choice. On the address bar, type the following, changing {yourDeviceIp} by the IP you just copied.

You should get an output similar to figure 2, which shows the random number returned by the ESP8266. Naturally, each request should return a different number, since a value between 0 and 999 is being randomly generated.

Figure 2 – Random number generated by the ESP8266.

Final notes

This simple example illustrates how to setup an asynchronous HTTP server on the ESP8266, which removes the overhead of periodically needing to check for incoming requests.

This is a far superior approach since, as mentioned in the library page, it allows handling more than one connection at the same time.

One important thing to mention is that we have the freedom to do whatever we want on the handling function. In our simple example, we were just generating a random number, but we could have been sending commands to some actuator or retrieving measurements from a sensor.