ESP32 Arduino: HTTP server over soft AP

In this ESP32 tutorial, we will check how to setup an asynchronous HTTP web server with the device operating as soft Access Point. The tests of this ESP32 tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.


Introduction

In this ESP32 tutorial, we will check how to setup an asynchronous HTTP web server with the device operating as soft Access Point.

Thus, in order for a client to be able to reach the HTTP server, we don’t need to connect it to a router but rather to the WiFi network hosted by the ESP32.

The possibility of setting a HTTP server on the ESP32 working as soft AP is very useful since in real application scenarios, an IoT device may be deployed in a WiFi network to which the credentials are not known in code compile time.

Thus, we need to have a way of setting those credentials for the ESP32 to be able to connect to the WiFi network.

Although this could be done using, for example, serial communication, this would be impractical for some commercial applications where it will be the end user making the initial configuration for the device to start operating.

Thus, a possible way of solving this problem is making the ESP32 operate as soft AP when connected for the first time, starting a HTTP server that serves a configuration HTML webpage for the user to input the name and password of the WiFi network to which the device should connect to to be able to reach the Internet and operate.

One good example is a possible commercial IoT thermostat, which makes measurements of the environment temperature and sends it to the Internet. In this case, each unit would need to be configured for operating in each users’ house and thus this type of method for an initial configuration would be a good solution.

Naturally, designing this type of interface is a more complex scenario and in this introductory example we will set the server to simply return a “hello world” message.

Nonetheless, the HTTP web server examples from previous posts can also be tested with the ESP32 operating as soft AP, and they already include a tutorial on how to serve HTML and JavaScript. You can check more on the “Related Posts” section.

If you haven’t yet configured the ESP32 Arduino libraries needed for setting an asynchronous HTTP web server, please check here how to do it.

The tests of this ESP32 tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.

If you prefer a video tutorial, please check my YouTube channel below:


The code

In terms of coding, this example will be based on two previous tutorials we have been covering for the Arduino environment. The first one is how to set a soft AP (which can be consulted here) and the second one is how to configure a HTTP web server on the ESP32 (you can check it here).

One important thing to mention is that the HTTP server will be configured the exact same way it would be if we were connecting the ESP32 to a WiFi network hosted by a router, like we have been doing in the previous tutorials.

So, in terms of implementation, the interface we use to configure the server doesn’t need the awareness of which type of WiFi network is being used.

In terms of coding, we start by the includes needed. To set the soft AP, we need to include the WiFi.h library and the ESPAsyncWebServer.h library.

#include "WiFi.h"
#include "ESPAsyncWebServer.h"

In order for other devices to be able to connect to the soft AP, we need to specify its SSID (network name) and the password protecting it. We will declare these credentials as global variables.

const char *ssid = "MyESP32AP";
const char *password = "testpassword";

To finish the global declarations, we will need an instance of the AsyncWebServer class, which exposes a high level API that will allow us to configure the web server.

Remember from the previous tutorials that the constructor for this class receives as argument the port where the server will be listening for incoming HTTP requests. As usual, we will use the default HTTP port, which is 80.

AsyncWebServer server(80);

Moving on to the setup function, we will start it by opening a serial connection, since we will need to print the IP of the ESP32 for the client to be able to reach it.

Serial.begin(115200);

To start the soft AP, we simply need to call the softAP method of the WiFi external variable (this is the same variable we use to connect the ESP32 to a WiFi network).

This method receives as first input the name of the WiFi network we want to set and as second input its password. Just as a note, setting a password is not mandatory and we could have not specify it if we wanted our Access Point to be open.

WiFi.softAP(ssid, password);

As mentioned, we will need to know the ESP32 IP, in order for the client connected to its network to be able to send requests to it. We can obtain the IP by calling the softAPIP method on the same WiFi variable.

Serial.print("IP address: ");
Serial.println(WiFi.softAPIP());

Now that we have handled the WiFi network part, we need to set the server. To do it, we simply need to bind a route to a handling function, which will be executed when HTTP requests are performed to that route.

We will use the “/hello” route and set the server to listen to incoming HTTP GET requests.

The route handling function will simply return an HTTP OK code (200) and a “Hello World” message.

The code for this configuration can be seen below. If you need a detailed explanation on all the parameters and functions used in this configuration, please consult this post.

server.on("/hello", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", "Hello World");
});

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

With this call, we finish the setup function and since the server works asynchronously, the Arduino loop may be left empty. The final source code can be seen below.

#include "WiFi.h"
#include "ESPAsyncWebServer.h"

const char *ssid = "MyESP32AP";
const char *password = "testpassword";

AsyncWebServer server(80);

void setup(){
  Serial.begin(115200);

  WiFi.softAP(ssid, password);

  Serial.println();
  Serial.print("IP address: ");
  Serial.println(WiFi.softAPIP());

  server.on("/hello", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", "Hello World");
  });

  server.begin();
}

void loop(){}


Testing the code

To test the code, compile it and upload it to your ESP device and then open the Arduino IDE serial monitor. Once the soft AP is set, the IP of the ESP32 should get printed to the monitor, as shown in figure 1. Copy that IP.

ESP32 soft AP device IP.png

Figure 1 – IP of the ESP32.

At that moment, the WiFi network should already be detectable by your computer. Look for it in the available WiFi networks and connect to it using the password we have defined on the code. Figure 2 shows the network being detected on a machine running windows 8.

ESP32 soft AP detected on Windows 8 machine.png

Figure 2 – WiFi network hosted by the ESP32 being detected on Windows 8.

To finalize, after connected to that network, open a web browser of your choice and type the following in the address bar, changing #yourEspIp# by the value you have copied from the serial monitor.

http://#yourEspIp#/hello

You should get an output similar to figure 3, which shows the “Hello world” message being returned.

ESP32 HTTP server Hello World over soft AP Arduino.png

Figure 3 – ESP32 server returning the message to the client.


Related posts

71 thoughts on “ESP32 Arduino: HTTP server over soft AP”

    1. Hi!

      Taking into account the documentation, the webserver should be able to handle multiple clients:
      https://github.com/me-no-dev/ESPAsyncWebServer#why-should-you-care

      Nonetheless I haven’ yet tested that specific use case where multiple clients are connecting simultaneously, so I cannot confirm.

      But when you mention it cannot handle parallel requests, how did you try it? Multiple requests from the same machine?

      Or have ou tried to connect a lot of stations to the soft AP? I think the soft AP has a maximum limit of simultaneous stations it can handle, which is not very high. I don’t recall the exact number, but I think it was something around 4.

      Best regards,
      Nuno Santos

    1. Hi!
      Taking into account the documentation, the webserver should be able to handle multiple clients:
      https://github.com/me-no-dev/ESPAsyncWebServer#why-should-you-care
      Nonetheless I haven’ yet tested that specific use case where multiple clients are connecting simultaneously, so I cannot confirm.
      But when you mention it cannot handle parallel requests, how did you try it? Multiple requests from the same machine?
      Or have ou tried to connect a lot of stations to the soft AP? I think the soft AP has a maximum limit of simultaneous stations it can handle, which is not very high. I don’t recall the exact number, but I think it was something around 4.
      Best regards,
      Nuno Santos

  1. Hello
    Thank you for this tutorial, it is very interesting and tonight I’m going to sleep less stupid!
    I made a few years ago a thermostat with an arduino, ds18b20 … but that only worked internally (no wifi, BLE, …) now I have a esp32 (wemos d1 r32) and the goal is to make my esp32 communicate with an app via app inventor without going through the internet box.
    I am in the right place!
    I launched the program via the arduino IDE and it works fine, my smartphone connects well to the ESP32.
    I think I understand a little how everything works. Only I would like to know in general how to receive data sent by the APP and send sensor information. The goal would be to display temperatures on the APP and send the set temperature to esp32.
    Maybe there will be a tutorial on these actions?
    sorry for my English
    Thank you and continued to offer tutorials. They are very educational

    1. Hi!

      Thank you very much for your feedback, I’m very happy to know that you are finding the tutorials useful 🙂

      In your case, it’s more like an architectural decision in the first place, since there are plenty of options to solve your problem.

      To send data from the app to the ESP, a easy way is to setup a HTTP server, as done in this tutorial.

      If you want to send data from the ESP to the app, you can make it listening to HTTP requests (acting like a server) and having the ESP sending HTTP requests to it:
      https://techtutorialsx.com/2017/05/20/esp32-http-post-requests/

      Note that this is for a simple not scalable quick solution.

      If you want for instance to develop a product to sell with lots of ESPs and people using their own app, then I would send the ESP data to a remote server with a database and have the app also connect to that server, with the client credentials, and fetch the data to display it.

      As mentioned, there are plenty of options and that is the most interesting part of using an ESP32. It is a very powerful device that gives us higher level functionalities and allows us to focus on the architecture rather than having to optimize every bit of our program to be able to run in a resource constrained device.

      Hope this helps you achieving your goal.

      PS: You English is fine, I’m also not a native English speaker, so don’t worry 🙂

      Best regards,
      Nuno santos

  2. Hello
    Thank you for this tutorial, it is very interesting and tonight I’m going to sleep less stupid!
    I made a few years ago a thermostat with an arduino, ds18b20 … but that only worked internally (no wifi, BLE, …) now I have a esp32 (wemos d1 r32) and the goal is to make my esp32 communicate with an app via app inventor without going through the internet box.
    I am in the right place!
    I launched the program via the arduino IDE and it works fine, my smartphone connects well to the ESP32.
    I think I understand a little how everything works. Only I would like to know in general how to receive data sent by the APP and send sensor information. The goal would be to display temperatures on the APP and send the set temperature to esp32.
    Maybe there will be a tutorial on these actions?
    sorry for my English
    Thank you and continued to offer tutorials. They are very educational

    1. Hi!
      Thank you very much for your feedback, I’m very happy to know that you are finding the tutorials useful 🙂
      In your case, it’s more like an architectural decision in the first place, since there are plenty of options to solve your problem.
      To send data from the app to the ESP, a easy way is to setup a HTTP server, as done in this tutorial.
      If you want to send data from the ESP to the app, you can make it listening to HTTP requests (acting like a server) and having the ESP sending HTTP requests to it:
      https://techtutorialsx.com/2017/05/20/esp32-http-post-requests/
      Note that this is for a simple not scalable quick solution.
      If you want for instance to develop a product to sell with lots of ESPs and people using their own app, then I would send the ESP data to a remote server with a database and have the app also connect to that server, with the client credentials, and fetch the data to display it.
      As mentioned, there are plenty of options and that is the most interesting part of using an ESP32. It is a very powerful device that gives us higher level functionalities and allows us to focus on the architecture rather than having to optimize every bit of our program to be able to run in a resource constrained device.
      Hope this helps you achieving your goal.
      PS: You English is fine, I’m also not a native English speaker, so don’t worry 🙂
      Best regards,
      Nuno santos

  3. Hello,
    I’m trying to read a sensor, and send the data to a connected device via HTML. THe problem I’m having is the “server.on(“/hello”, HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, “text/plain”, “Hello World”);
    });” lambda. I understand how it works, but I don’t want to have to query the ESP continuously. Is there a way to send info directly to the connected device without using the pointer? OR, is there a way for the “server.on” statement to simply “send” the updated HTML variables/HTML page to the connected device.

    I’m currently using your sketch from above and it works great. I just need to modify it slightly. I’m a novice so, maybe I’m going about this all wrong. Sure would appreciate any guidance.

    Thank You,
    Charles

    1. Hi Charles,

      I did not understand your architecture very well. Are you trying to read the sensor and make that reading “available” in the ESP using the webserver code?

      When you say connected device, are you refering to something like a desktop or a laptop that is receiving the HTML from the ESP32 and displaying it in a web browser?

      Assuming that that is the architecture, then it is normal that you query the ESP whenever you want to get the current measurement.

      If when you say you don’t want to continuously query the ESP, I’m assuming that you want to get the new measurements in “real time”, like you want to see the current sensor value as soon as it changes.

      If that’s the case, constantly polling the ESP will indeed not scale.

      Unfortunately, you cannot update or push the updated HTML to the client when a new measurement is available. HTTP works the other way around, the client is the one who asks the server for the data.

      As a solution, I would establish a persistent socket or websocket connection, so the ESP could send the data to the reader whenever it has a new sensor measurement.

      Note that it would be a completely different architecture from the one shown in this tutorial.

      I don’t have any socket tutorial for the ESP, but I have some on web sockets:
      https://techtutorialsx.com/2017/11/03/esp32-arduino-websocket-server/
      https://techtutorialsx.com/2017/11/01/esp32-arduino-websocket-client/

      For the sockets, you can check the example from the Arduino libraries:
      https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/examples/WiFiClient/WiFiClient.ino

      The WiFiClient there is basically an abstraction for a socket connection.

      A final note: The lambda is just the third argument of the on method, not the whole statement.

      In short, a lambda is an anonymous function. So, instead of formally declaring a function with a name and a header, you can use the lambda for a more compact code, since you are not going to reuse the function that you pass to the on method.

      Hope this helps, but let me know a little bit more about your application so I cant try to help a little bit more.

      Best regards,
      Nuno Santos

  4. Hello,
    I’m trying to read a sensor, and send the data to a connected device via HTML. THe problem I’m having is the “server.on(“/hello”, HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, “text/plain”, “Hello World”);
    });” lambda. I understand how it works, but I don’t want to have to query the ESP continuously. Is there a way to send info directly to the connected device without using the pointer? OR, is there a way for the “server.on” statement to simply “send” the updated HTML variables/HTML page to the connected device.
    I’m currently using your sketch from above and it works great. I just need to modify it slightly. I’m a novice so, maybe I’m going about this all wrong. Sure would appreciate any guidance.
    Thank You,
    Charles

    1. Hi Charles,
      I did not understand your architecture very well. Are you trying to read the sensor and make that reading “available” in the ESP using the webserver code?
      When you say connected device, are you refering to something like a desktop or a laptop that is receiving the HTML from the ESP32 and displaying it in a web browser?
      Assuming that that is the architecture, then it is normal that you query the ESP whenever you want to get the current measurement.
      If when you say you don’t want to continuously query the ESP, I’m assuming that you want to get the new measurements in “real time”, like you want to see the current sensor value as soon as it changes.
      If that’s the case, constantly polling the ESP will indeed not scale.
      Unfortunately, you cannot update or push the updated HTML to the client when a new measurement is available. HTTP works the other way around, the client is the one who asks the server for the data.
      As a solution, I would establish a persistent socket or websocket connection, so the ESP could send the data to the reader whenever it has a new sensor measurement.
      Note that it would be a completely different architecture from the one shown in this tutorial.
      I don’t have any socket tutorial for the ESP, but I have some on web sockets:
      https://techtutorialsx.com/2017/11/03/esp32-arduino-websocket-server/
      https://techtutorialsx.com/2017/11/01/esp32-arduino-websocket-client/
      For the sockets, you can check the example from the Arduino libraries:
      https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/examples/WiFiClient/WiFiClient.ino
      The WiFiClient there is basically an abstraction for a socket connection.
      A final note: The lambda is just the third argument of the on method, not the whole statement.
      In short, a lambda is an anonymous function. So, instead of formally declaring a function with a name and a header, you can use the lambda for a more compact code, since you are not going to reuse the function that you pass to the on method.
      Hope this helps, but let me know a little bit more about your application so I cant try to help a little bit more.
      Best regards,
      Nuno Santos

  5. Graham Rimmington

    Anyone else seeing this error?
    C:\Users\grri0002\Documents\Arduino\SimpleWiFiServer\SimpleWiFiServer.ino\SimpleWiFiServer.ino.ino:4:31: fatal error: ESPAsyncWebServer.h: No such file or directory

    compilation terminated.

    Multiple libraries were found for “WiFi.h”
    Used: C:\Program Files (x86)\Arduino\hardware\espressif\esp32\libraries\WiFi
    Not used: C:\Users\grri0002\Documents\Arduino\libraries\WiFi
    exit status 1
    Error compiling for board MH ET LIVE ESP32MiniKit.

  6. Graham Rimmington

    Anyone else seeing this error?
    C:\Users\grri0002\Documents\Arduino\SimpleWiFiServer\SimpleWiFiServer.ino\SimpleWiFiServer.ino.ino:4:31: fatal error: ESPAsyncWebServer.h: No such file or directory
    compilation terminated.
    Multiple libraries were found for “WiFi.h”
    Used: C:\Program Files (x86)\Arduino\hardware\espressif\esp32\libraries\WiFi
    Not used: C:\Users\grri0002\Documents\Arduino\libraries\WiFi
    exit status 1
    Error compiling for board MH ET LIVE ESP32MiniKit.

  7. Pingback: ESP32 Arduino: Temperature, humidity and CO2 concentration web server | techtutorialsx

  8. Pingback: ESP32 Arduino: Temperature, humidity and CO2 concentration web server | techtutorialsx

Leave a Reply