ESP8266 Arduino: Asynchronous HTTP web server

The objective of this 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 FireBeetle 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.

This tutorial was tested on a DFRobot’s ESP8266 FireBeetle board.


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.

ESP32 Async Arduino HTTP webserver

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.

#include "ESP8266WiFi.h"
#include "ESPAsyncTCP.h"
#include "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.

const char* ssid = "YourNetworkName";
const char* password = "YourNetworkPassword";

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.

WiFi.begin(ssid, password);

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

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.

server.on("/rand", HTTP_GET, [](AsyncWebServerRequest *request){
// Handling function implementation
});

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 function

The 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.

server.on("/rand", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", String(random(1000)));
});

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.

You can check the full source code for this ESP8266 tutorial below.

#include "ESP8266WiFi.h"
#include "ESPAsyncTCP.h"
#include "ESPAsyncWebServer.h"

const char* ssid = "YourNetworkName";
const char* password =  "YourNetworkPassword";

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("/rand", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", String(random(1000)));
  });

  server.begin();
}

void loop(){}

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.

http://#yourDeviceIp#/rand

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.

ESP8266 Arduino async http server random number generation.png

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.


Related posts

 

21 thoughts on “ESP8266 Arduino: Asynchronous HTTP web server”

  1. Is it possible to run async server instances while running in softAP mode and actually creating the wifi network? Or does ESPAsyncServer only run on an existing wifi network?

      1. I flashed it, then ran it. It seems to works fine in softAP mode with Async server on 8266. I had a another esp8266 on the broadcast wifi, acting as a client posting values to it to change led state. What I really need, is to have multiple ones posting simultaneously to affect other pins, in order to ensure that it doesn’t affect its asynchronous function somehow. I don’t need it for my application at all anymore, but its good to know for the future and for others, which s why I posted this comment. SoftAP +Async on 8266 seems to work.

  2. Is it possible to run async server instances while running in softAP mode and actually creating the wifi network? Or does ESPAsyncServer only run on an existing wifi network?

      1. I flashed it, then ran it. It seems to works fine in softAP mode with Async server on 8266. I had a another esp8266 on the broadcast wifi, acting as a client posting values to it to change led state. What I really need, is to have multiple ones posting simultaneously to affect other pins, in order to ensure that it doesn’t affect its asynchronous function somehow. I don’t need it for my application at all anymore, but its good to know for the future and for others, which s why I posted this comment. SoftAP +Async on 8266 seems to work.

  3. Hi thank you very much for this post, but we are not able to include these libraries in our project.It will be very helpful if you instruct us

  4. Hi, I am using ESPAsyncWebServer for a HomeBridge lock project.
    I am still trying to learn Arduino and ESP because I am not from this field but have enormous interest in them and found myself loving them.
    I have always tried to stay away from http/client/server because I thought these topics were pretty hard to understand but since starting this hobby project, I found them getting easier to understand especially after your tutorials. For that, I thank you.

    Now, my problem is as follows.
    I was trying to send a http.GET request as a httpClient to ASyncWebServer set up on the same ESP8266 like:

    server.on(“/lockTargetState/1”, HTTP_ANY, [](AsyncWebServerRequest *request){
    request->send(200, “text/plain”, “OK”);

    http.begin(“http://192.168.1.100/lockCurrentState/1”);
    http.GET();

    }

    That gives me a http.code -1 “connection refused” error.
    So, I thought it must be because of the httpGet request inside the server handler function and thus move the httpGet out of the lambda function and instead just used a boolean flag inside lambda function so that the httpGet request can be called from the main loop.

    But the “-1 connection refused” error still persists.
    I thought it was because I was using both Server and httpClient inside the same sketch and/or same ESP8266, so, I inserted the httpGet JSON example link and it works and I got JSON response but when I reverted to the problem link, the error returns. I searched google and found that there are people who have multiple servers and multiple clients on the same ESP and have no problem with them.

    I think my problem is due to the client trying to send httpGet request as a client while on the same server. But actually I have no idea. I’ve been stuck in this situation for like 2 weeks already. I’ve even added boolean flags like
    while(!serverBusy){;}
    to check and wait if the server is handling clients before sending httpGet request but still getting connection refused.

    Please kindly advise.

  5. If I make a Static connection using a wrong gateway I get the HTTP response but I can’t access to the web server interface. What can I do in that case?

Leave a Reply

Discover more from techtutorialsx

Subscribe now to keep reading and get access to the full archive.

Continue reading