/

How to run a Web Server on an Arduino

How to run a Web Server on an Arduino

In this tutorial, I will guide you on how to start a Web Server on an Arduino device with WiFi connectivity, such as the Arduino MKR WiFi 1010.

By connecting to an existing WiFi network, you can interact with the Arduino using your browser via HTTP. This opens up a wide range of possibilities, from simple checks of sensor data to performing actions based on HTTP requests.

To start, let’s use the code from the tutorial “Connect to a WiFi network using an Arduino”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#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 the setup() function, add this line to initialize a TCP server on port 80:

1
WiFiServer server(80);

Then, at the end of the setup() function, call server.begin() to start the server:

1
server.begin();

Now, we have a TCP server, but we want to create an HTTP server. Since HTTP is built on top of TCP, we can implement the HTTP server ourselves.

In the loop() function, let’s listen for client connections:

1
2
3
4
5
6
void loop() {
WiFiClient client = server.available();
if (client) {

}
}

The server.available() method listens for incoming client connections.

Within the if (client) block, we have an HTTP client connected. Here’s what we need to do:

  • Call client.connected() to check if the client is still connected and if there is data to read.
  • Call client.available() to get the number of bytes available for reading. This ensures that there is data to read.
  • Call client.read() to read one byte from the incoming data (the HTTP request sent by the client).
  • Call client.println() or client.print() to send data back to the client and build a proper HTTP response.
  • Call client.stop() to end the connection.

Let’s print each character sent by the client and close the connection at the end:

1
2
3
4
5
6
7
8
9
10
11
12
13
void loop() {
WiFiClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
}
}

client.stop();
}
}

Try uploading this program to your Arduino and point your browser to the Arduino’s IP address. You should see the HTTP request printed in the serial interface. It will look something like this:

1
2
3
4
5
6
7
8
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, which marks the end of the HTTP request.

To determine the end of the request, we need to detect two sets of sequence \r\n\r\n. We can achieve this by storing the previous two characters and checking if they form the sequence \n\r\n.

Here’s the updated code to handle the response:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void loop() {
WiFiClient client = server.available();
if (client) {
char prevprev;
char prev;

while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);

if (prevprev == '\n' && prev == '\r' && c == '\n') {
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;
}

prevprev = prev;
prev = c;
}
}

client.stop();
}
}

In this code, we send the HTTP response using client.println() and add a simple response message within the <html> tags.

Now you can try it out! When you point your browser to the Arduino’s IP address, you should see “test” displayed on the page.

With this approach, you can handle more advanced actions based on the client’s request. You can read each line of the request and act accordingly.

Here’s an alternative code snippet that reads each line of the request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void loop() {
WiFiClient client = server.available();
if (client) {
String line = "";
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);

if (c != '\n' && c != '\r') {
line += c;
}

if (c == '\n') {
if (line.length() == 0) {
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;
} else {
line = "";
}
}
}
}

client.stop();
}
}

In this code, we store each line in a String variable and evaluate the line when it is terminated by a newline character. This allows us to inspect the request and respond accordingly.

Tags: Arduino, Web Server, WiFi, HTTP, TCP, Internet of Things