How to run a web server on Arduino

In this tutorial, I will show you how to start a web server on an Arduino device with WiFi, for exampleArduino MKR WiFi 1010.

We will connect to an existing WiFi network and be able to interact with Arduino through the browser in the following waysHTTP.

This is very interesting for various applications. From simple sensor data checking to sensor-based actionsHTTP requestcarried out.

We will start with the procedure defined in this procedureConnect to WiFi network using ArduinoTutorial:

#include <SPI.h>
#include <WiFiNINA.h>

void setup() {
  char ssid[] = SECRET_SSID;
  char pass[] = SECRET_PASS;

Serial.begin(9600); while (!Serial);

int status = WL_IDLE_STATUS; while (status != WL_CONNECTED) { Serial.print("Connecting to "); Serial.println(ssid); status = WiFi.begin(ssid, pass); delay(5000); }

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

void loop() {

}

Before setup(), add the following line:

WiFiServer server(80);

Initialize oneTCP protocolThe server is on port 80 and at the endsetup()call

server.begin();

Start the server.

Now, this is a TCP server, not an HTTP server. But since HTTP (TCP/IP Application Protocol) is built on top of TCP (Transport Layer), we can easily build HTTP server by ourselves.

First, we need to listen for client connections. We doloop():

void loop() {
  WiFiClient client = server.available();
  if (client) {

} }

The available() methodserverListen for incoming clients.

Insideif (client) {}Check that we are connected to an HTTP client. What we need to do is:

  • callclient.connected()Check whether the data is connected and there is data to be read
  • callclient.available()Get the number of bytes that can be read (to ensure that there is data to be read)
  • callclient.read()Read a byte from the incoming data (HTTP request sent by the client)
  • callclient.println()orclient.print()Send data to the client and establish an appropriate HTTP response
  • callclient.stop()End connection

We start to print each character sent by the client to the serial interface, and finally close the connection:

void loop() {
  WiFiClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
      }
    }
client.stop();

} }

Try to upload this program to Arduino. Point your browser to the IP address. You will see something similar on the serial interface. This is what the browser sends:

GET / HTTP/1.1
Host: 192.168.1.40
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: keep-alive

Note the ending empty line. This is the end of the HTTP request.

We need to intercept this empty line.

Each line in the HTTP request is terminated by a CR carriage return character (\r), and a LF line feed character (\n).

So the end of the request can be determined by 2 sets of those sequences: \r\n\r\n.

This simple algorithm will work, we just memorize 2 characters prior to the current one, and we check if we identify the sequence \n\r\n (the last 3 characters in that sequence are enough to determine the last line):

void loop() {
  WiFiClient client = server.available();
  if (client) {
<span style="color:#66d9ef">char</span> prevprev;
<span style="color:#66d9ef">char</span> prev;

<span style="color:#66d9ef">while</span> (client.connected()) {
  <span style="color:#66d9ef">if</span> (client.available()) {
    <span style="color:#66d9ef">char</span> c <span style="color:#f92672">=</span> client.read();
    Serial.write(c);

    <span style="color:#66d9ef">if</span> (prevprev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span> <span style="color:#f92672">&amp;&amp;</span> prev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\r'</span> <span style="color:#f92672">&amp;&amp;</span> c <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span>) {
      <span style="color:#75715e">//we can send the response!

}

    prevprev <span style="color:#f92672">=</span> prev;
    prev <span style="color:#f92672">=</span> c;
  }
}

client.stop();

} }

So now we can send the response inside the if, we can use client.println() for this, and we add a simple response like this:

HTTP/1.1 200 OK
Content-Type: text/html
Connection: close

<!DOCTYPE HTML> <html> test </html>

In this way:

client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("test");
client.println("</html>");
break;

The break; statement ends the while (client.connected()) {} block.

Here is the full program:

#include <SPI.h>
#include <WiFiNINA.h>

WiFiServer server(80);

void setup() { char ssid[] = SECRET_SSID; char pass[] = SECRET_PASS;

Serial.begin(9600); while (!Serial);

int status = WL_IDLE_STATUS; while (status != WL_CONNECTED) { Serial.print("Connecting to "); Serial.println(ssid); status = WiFi.begin(ssid, pass); delay(5000); }

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

server.begin(); }

void loop() { WiFiClient client = server.available(); if (client) {

<span style="color:#66d9ef">char</span> prevprev;
<span style="color:#66d9ef">char</span> prev;
<span style="color:#66d9ef">while</span> (client.connected()) {
  <span style="color:#66d9ef">if</span> (client.available()) {
    <span style="color:#66d9ef">char</span> c <span style="color:#f92672">=</span> client.read();
    Serial.write(c);

    <span style="color:#66d9ef">if</span> (prevprev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span> <span style="color:#f92672">&amp;&amp;</span> prev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\r'</span> <span style="color:#f92672">&amp;&amp;</span> c <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span>) {
      client.println(<span style="color:#e6db74">"HTTP/1.1 200 OK"</span>);
      client.println(<span style="color:#e6db74">"Content-Type: text/html"</span>);
      client.println(<span style="color:#e6db74">"Connection: close"</span>);
      client.println();
      client.println(<span style="color:#e6db74">"&lt;!DOCTYPE HTML&gt;"</span>);
      client.println(<span style="color:#e6db74">"&lt;html&gt;"</span>);
      client.println(<span style="color:#e6db74">"test"</span>);
      client.println(<span style="color:#e6db74">"&lt;/html&gt;"</span>);
      <span style="color:#66d9ef">break</span>;
    }

    prevprev <span style="color:#f92672">=</span> prev;
    prev <span style="color:#f92672">=</span> c;
  }
}

client.stop();

} }

Try it, you should see test showing up in the browser:

The approach works until you need to figure out how what the client asked us.

In that case you want to read each line, so this alternative approach works better:

void loop() {
  WiFiClient client = server.available();
  if (client) {
    String line = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
    <span style="color:#66d9ef">if</span> (c <span style="color:#f92672">!=</span> <span style="color:#e6db74">'\n'</span> <span style="color:#f92672">&amp;&amp;</span> c <span style="color:#f92672">!=</span> <span style="color:#e6db74">'\r'</span>) {
      line <span style="color:#f92672">+=</span> c;
    }

    <span style="color:#66d9ef">if</span> (c <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span>) {
      <span style="color:#66d9ef">if</span> (line.length() <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>) {
        client.println(<span style="color:#e6db74">"HTTP/1.1 200 OK"</span>);
        client.println(<span style="color:#e6db74">"Content-Type: text/html"</span>);
        client.println(<span style="color:#e6db74">"Connection: close"</span>);
        client.println();
        client.println(<span style="color:#e6db74">"&lt;!DOCTYPE HTML&gt;"</span>);
        client.println(<span style="color:#e6db74">"&lt;html&gt;"</span>);
        client.println(<span style="color:#e6db74">"test"</span>);
        client.println(<span style="color:#e6db74">"&lt;/html&gt;"</span>);
        <span style="color:#66d9ef">break</span>;
      } <span style="color:#66d9ef">else</span> {
        line <span style="color:#f92672">=</span> <span style="color:#e6db74">""</span>;
      }
    }
  }
}

client.stop();

} }

In the last else we can inspect the line because the line is terminated, and act accordingly to our needs.


More electronics tutorials: