Arduino Web Server: What it is and how to set One Up. Should you use a Synchronous or an Asynchronous web server? Are either of these any use for your Arduino Application?

Arduino web server: A web server conjures up images of huge machines dishing out pages from an underground bunker...

bunker with rows of arduino web servers and man typing pages

...But even a small Arduino unit can serve web pages!

You are probably here because you want to find out how to control your Arduino over the web, and in this tutorial you'll understand the differences between a synchronous and an ascynchronous web server. In addition you will learn the limitations of both these things and learn why websockets can overcome these limitations.

What is a Web Server?

A web server is simply a processor with storage memory connected to the web, that outputs a web page when it receives a request for a specific page. Of course, for a global server of the type that ISPs (Internet Service Providers) use, they need a lot of storage space, and when a lot of people require access to the same page they need a lot of processing power to deliver those pages.

An Arduino web server simply retrieves a stored piece of html code (the language that describes how to render web pages) sending that information over the internet to your web browser. The browser interprets the HTML code displaying it on the screen in readable format.

One complication is that the HTML code itself often uses Cascading Style Sheets (CSS) and Javascript to operate the web page. It means that in order to get the needed operation of the web page you may need to learn the basics of CSS and Javascript. For the simplest operations its not too difficult but as things get more complicated it becomes easier to use an external framework such as Blynk.

You can make a simple webserver using an internet capable microcontroller. A good choice for that is an ESP32, as it has all the Wifi hardware ready for you to use. You could of course use an Arduino Uno with an Ethernet shield, and then connect that to your router using a cable. The coding for that would be virtually the same but with the ESP32 you don't need cables.

Synchronous Arduino Web Server

A synchronous web server is a pain in the butt and that's because:

It operates in a blocking manner.
  1. When a request for a page is received it stops all other actions until that request has been completed.
  2. During the current request the synchronous webserver will not respond to any other requests.
  3. During the current request it won't allow any other actions!

From these statements alone you can see that you really should not use a synchronous web server. It is in fact why most people use an asynchronous web server.

You may find a use for it, if for instance you need to save memory or resources, since a synchronous server is easier to implement.

Example Code Synchronous Web Server

Here's an example of a synchronous web server running on an ESP32.


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

const char* ssid = "YourWiFiSSID";
const char* password = "YourWiFiPassword";

WebServer server(80);

void handleRoot() {
  server.send(200, "text/plain", "Hello from ESP32! SYNC");
}

void handleNotFound() {
  server.send(404, "text/plain", "404 Not Found");
}

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

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

  Serial.println("WiFi connected!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("Web server started.");
}

void loop() {
  server.handleClient();
}

For the code to operate put in your own router name and password.

Once programmed into the ESP32 look at the serial monitor to find out the IP address of your ESP32. This is the local address assigned by your router (yours will be different to mine). In my case it is:

IP address: 192.168.0.62

Type the IP address into your browser. This should result in the following text on the browser screen:

Hello from ESP32! SYNC

Note the difference in loop function between sync and async.

You can see, in the synchronous code (above), that the function server.handleClient() is called in the main loop. This is because the code is simpler and does not use interrupts or event driven actions so it has to directly invoke code from the synchronous web server library.

Synchronous web server resources

Sketch uses 758613 bytes (24%) of program storage space. Maximum is 3145728 bytes.
Global variables use 44404 bytes (13%) of dynamic memory, leaving 283276 bytes for local variables.

Asynchronous Arduino Web Server

On the other hand, an asynchronous web server requires use of interrupts and event driven code, and thus it uses more resources. However its advantages far outweigh the extra resource usage because:

  1. The server can handle multiple page requests.
  2. The processor can continue with other tasks while waiting for events or responses.

Your code can continue while the asynchronous Arduino web server works in the background. In addition, if several browsers request the same page, your Arduino can handle it in a timely manner and deliver those pages efficiently.

Example Code Asynchronous Web Server


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

const char* ssid = "YourWiFiSSID";
const char* password = "YourWiFiPassword";

AsyncWebServer server(80);

void handleRoot(AsyncWebServerRequest *request) {
  request->send(200, "text/plain", "Hello from ESP32! ASYNC");
}

void handleNotFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "404 Not Found");
}

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

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

  Serial.println("WiFi connected!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, handleRoot);
  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("Web server started.");
}

void loop() {
  // Nothing to be done here in an asynchronous server
}

Again enter your own router name and password and type the IP address into the browser. The text you see should is:

    Hello from ESP32! ASYNC

Actually it does not look like anything has changed - but a lot more is going on under the hood. You can see from the resource usage below that more is being done.

Note the difference in loop function between sync and async.

You can see, in the asynchronous code (above), that the loop() function is empty. This is because the code is more complex using interrupts and event driven actions. It means the asynchronous server is able to operate independently in the background, while your own program does its thing!

Asynchronous web server resources

Sketch uses 777153 bytes (24%) of program storage space. Maximum is 3145728 bytes.
Global variables use 43100 bytes (13%) of dynamic memory, leaving 284580 bytes for local variables.

Comparison of memory used

In fact using the Asynchronous Arduino web server library increases the Flash usage by:

    18540 - nearly 20kBytes.

That is not a lot for an ESP32 since:

    (18540/3145728)*100 = 0.59%

If you were using an Arduino Mega 2560 with shield it is :

    (18540/ 262,144)*100 = 7%

If you were using an Arduino Uno with a shield it is:

    (18540/32768)*100 = 56%

So you probably don't want to use an asynchronous server with an Uno!

A practical (Useless/Informative) Example!

This example is going to show you why both synchronous and asynchronous servers are useless!

The example is going to send data from the ESP32 and send it to the web page where you can read the value on the browser web page.

You would think that the following code does exactly what you want. It updates a counter value every second and that value is inserted into the web page ready for you to read.

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

const char* ssid = "YourWiFiSSID";
const char* password = "YourWiFiPassword";

AsyncWebServer server(80);
int counter = 0;

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 WiFi");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    String message = "Counter: " + String(counter);
    request->send(200, "text/plain", message);
  });

  server.begin();
}

void loop() {
  counter++;
  delay(1000); // Increase the counter every second
}

So what is wrong with this?

Simply put you have to refresh the browser page every time you want to find out the current counter value. This is an absolute pain, and for looking at sensor data is really quite useless.

There are only two scenarios that you would do this:

  1. You only want to see the data very infrequently.
  2. You have a resource limited processor and must save memory.

What you really want is to connect the web page dynamically to the ESP32 so that there is direct communication from the ESP32 to the web browser and vice versa.

Instant bi-directional Comms

Old AJAX

It used to be that you had to use AJAX...

jax edited image for AI cleaner
(Image created using AI has no relationship with the real product).

...No, not that Ajax!

The software AJAX stands for "Asynchronous JavaScript And XML". This code was specifically designed to allow web pages to be updated without needing to refresh the entire page, also allowing asynchronous page updates i.e. exactly what you need to update a sensor reading to a web page.

The advantage of AJAX is a set of techniques that use existing technologies such as javascript, XML and JSON and is therefore compatible with older browsers.

The only problem with AJAX is that it is client centric meaning that the client (ESP32) must initiate a communication sequence and requires slightly more work to make bidirectional communication work. AJAX was initially designed for one way communincation from client (browser) to server(ESP32). It is however possible to create a two-way communication using AJAX techniques with more software and more effort with specific techniques.

New Websocket

New websocket technology overcomes these problems because it allows real-time, bidirectional communication between the ESP32 and the browser. Websockets may not be supported by older browsers (hence mentioning AJAX which is supported by older browsers)

Websockets are  the way to go if you want to have real-time, bidirectional communication between the ESP32 and browser (and don't care about users of older browser versions).

Conclusions

For an Arduino Web server there are two options:

  1. A synchronous Arduino Webserver.
  2. An asynchronous Arduino Web Server.

Bottom line:

    They are both fairly useless! when you want
    to view sensor data in a web browser page!

You do need at least one type of html page server, so use the asynchronous server to serve your HTML pages; but:

If you want real time bi-directional communication:

        (P.S. You DO)...

             ...then use websockets as well!


Note: Parts of this page were written using chatgpt as a research assistant. Some images were created using leonardo.ai, and bing dall-e.


Comments

Have your say about what you just read! Leave me a comment in the box below.

Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.



Privacy Policy | Contact | About Me

Site Map | Terms of Use