Arduino - Web Server

In this tutorial, we will learn how to turn an Arduino Uno R4 WiFi into a web server. By accessing the web pages hosted on the Arduino Web Server through a web browser on your PC or smartphone, you'll be able to read values from the Arduino and even control it. Here's a breakdown of what we'll learn to program the Arduino Uno WiFi to achieve:

Arduino web server

Hardware Required

1×Arduino UNO R4 WiFi
1×USB Cable Type-C
1×(Optional) 9V Power Adapter for Arduino
1×(Recommended) Screw Terminal Block Shield for Arduino Uno
1×(Optional) Transparent Acrylic Enclosure For Arduino Uno

Or you can buy the following sensor kit:

1×DIYables Sensor Kit 30 types, 69 units
Please note: These are Amazon affiliate links. If you buy the components through these links, We will get a commission at no extra cost to you. We appreciate it.

Reading the sensor value from Arduino via Web

This is relatively simple. The Arduino code does the following tasks:

  • Creating a web server that listens for HTTP requests from a web browser.
  • Upon receiving a request from a web browser, the Arduino responds with the following information:
    • HTTP header
    • HTTP body: This includes HTML content and the value read from the sensor.

    Below is the Arduino code that performs the above tasks:

    /* * Created by ArduinoGetStarted.com * * This example code is in the public domain * * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server */ #include <WiFiS3.h> const char ssid[] = "YOUR_WIFI"; // change your network SSID (name) const char pass[] = "YOUR_WIFI_PASSWORD"; // change your network password (use for WPA, or use as key for WEP) int status = WL_IDLE_STATUS; WiFiServer server(80); float getTemperature() { return 26.9456; // YOUR SENSOR IMPLEMENTATION HERE // simulate the temperature value float temp_x100 = random(0, 10000); // a ramdom value from 0 to 10000 return temp_x100 / 100; // return the simulated temperature value from 0 to 100 in float } void setup() { //Initialize serial and wait for port to open: Serial.begin(9600); String fv = WiFi.firmwareVersion(); if (fv < WIFI_FIRMWARE_LATEST_VERSION) Serial.println("Please upgrade the firmware"); // attempt to connect to WiFi network: while (status != WL_CONNECTED) { Serial.print("Attempting to connect to SSID: "); Serial.println(ssid); // Connect to WPA/WPA2 network. Change this line if using open or WEP network: status = WiFi.begin(ssid, pass); // wait 10 seconds for connection: delay(10000); } server.begin(); // you're connected now, so print out the status: printWifiStatus(); } void loop() { // listen for incoming clients WiFiClient client = server.available(); if (client) { // read the HTTP request header line by line while (client.connected()) { if (client.available()) { String HTTP_header = client.readStringUntil('\n'); // read the header line of HTTP request if (HTTP_header.equals("\r")) // the end of HTTP request break; Serial.print("<< "); Serial.println(HTTP_header); // print HTTP request to Serial Monitor } } // send the HTTP response // send the HTTP response header client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println("Connection: close"); // the connection will be closed after completion of the response client.println(); // the separator between HTTP header and body // send the HTTP response body client.println("<!DOCTYPE HTML>"); client.println("<html>"); client.println("<head>"); client.println("<link rel=\"icon\" href=\"data:,\">"); client.println("</head>"); client.println("<p>"); client.print("Temperature: <span style=\"color: red;\">"); float temperature = getTemperature(); client.print(temperature, 2); client.println("&deg;C</span>"); client.println("</p>"); client.println("</html>"); client.flush(); // give the web browser time to receive the data delay(10); // close the connection: client.stop(); } } void printWifiStatus() { // print your board's IP address: Serial.print("IP Address: "); Serial.println(WiFi.localIP()); // print the received signal strength: Serial.print("signal strength (RSSI):"); Serial.print(WiFi.RSSI()); Serial.println(" dBm"); }

    Quick Steps

    • If this is the first time you use Arduino Uno R4, see how to setup environment for Arduino Uno R4 on Arduino IDE.
    • Copy the above code and open with Arduino IDE
    • Change the wifi information (SSID and password) in the code to yours
    • Click Upload button on Arduino IDE to upload code to Arduino
    • Open the Serial Monitor
    • Check out the result on Serial Monitor.
    COM6
    Send
    Attempting to connect to SSID: YOUR_WIFI IP Address: 192.168.0.2 signal strength (RSSI):-39 dBm
    Autoscroll Show timestamp
    Clear output
    9600 baud  
    Newline  
    • Take note of the IP address displayed, and enter this address into the address bar of a web browser on your smartphone or PC.
    • As a result, you will see the following output on the Serial Monitor.
    COM6
    Send
    Attempting to connect to SSID: YOUR_WIFI IP Address: 192.168.0.2 signal strength (RSSI):-41 dBm New HTTP Request << GET / HTTP/1.1 << Host: 192.168.0.2 << Connection: keep-alive << Cache-Control: max-age=0 << Upgrade-Insecure-Requests: 1 << User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) << Accept: text/html,application/xhtml+xml,application/xml << Accept-Encoding: gzip, deflate << Accept-Language: en-US,en;q=0.9
    Autoscroll Show timestamp
    Clear output
    9600 baud  
    Newline  
    • Once you access the web browser using the IP address, you will be presented with a very basic web page displaying information about the Arduino board. The page will look like the following:
    Arduino Uno R4 temperature web browser

    To make the web page look fantastic with a graphic user interface (UI), check out the final section of this tutorial.

Controlling the Arduino via Web

Controlling something connected to Arduino is a bit more challenging than just reading a value. That's because Arduino has to understand the request it receives from the web browser to know what action to take. Here's what the Arduino code does in this case:

  • Creating a web server that listens for HTTP requests from a web browser.
  • Handling the request received from the web browser by doing the following:
    • Reads the HTTP request header.
    • Analyzes the HTTP request header to determine the specific control command needed.
    • Controls the device or thing connected to the Arduino based on the received control command.
    • Sends back an HTTP response.
    • Additionally, it can send an HTTP response body with HTML content to display information about the control state (if needed).

    For a more comprehensive and detailed example, I recommend checking out the tutorials listed below:

Separating HTML content into another file on Arduino IDE

If you want to create a simple web page with minimal content, you can embed the HTML directly into the Arduino code, as explained earlier.

However, if you want to make a more sophisticated and impressive web page with larger content, it becomes inconvenient to include all the HTML, CSS, and Javascript directly in the Arduino code. In this situation, you can use a different approach to manage the code:

  • The Arduino code will be placed in a .ino file, just like before.
  • The HTML code (HTML, CSS, Javascript) will be placed in a separate .h file. This allows you to keep the web page content separate from the Arduino code, making it easier to manage and modify.

To do so, we need to do two major steps:

  • Preparing HTML content
  • Programming Arduino

Preparing HTML content

  • Create an HTML file on your local PC that contains the HTML content (HTML, CSS, and Javascript) for your UI design.
  • In the HTML file, where data from Arduino should be displayed, use an arbitrary value.
  • Test and modify it until you are satisfied.
  • In the HTML file, where data from Arduino should be displayed, replace the arbitrary value with a special name, for example, TEMPERATURE_MARKER. Later, in the Arduino code, we will use the String.replace("TEMPERATURE_MARKER", real_value); function to update the value provided by Arduino.
  • We will put the HTML content in the .h file on the Arduino IDE. See the next step.

Programming Arduino

  • Open the Arduino IDE and create a new sketch. Give it a name, for example, ArduinoGetStarted.com.ino.
  • Copy the code provided below and paste it to the created file.
/* * Created by ArduinoGetStarted.com * * This example code is in the public domain * * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server */ #include <WiFiS3.h> #include "index.h" const char ssid[] = "YOUR_WIFI"; // change your network SSID (name) const char pass[] = "YOUR_WIFI_PASSWORD"; // change your network password (use for WPA, or use as key for WEP) int status = WL_IDLE_STATUS; WiFiServer server(80); float getTemperature() { // YOUR SENSOR IMPLEMENTATION HERE // simulate the temperature value float temp_x100 = random(0, 10000); // a ramdom value from 0 to 10000 return temp_x100 / 100; // return the simulated temperature value from 0 to 100 in float } void setup() { //Initialize serial and wait for port to open: Serial.begin(9600); String fv = WiFi.firmwareVersion(); if (fv < WIFI_FIRMWARE_LATEST_VERSION) Serial.println("Please upgrade the firmware"); // attempt to connect to WiFi network: while (status != WL_CONNECTED) { Serial.print("Attempting to connect to SSID: "); Serial.println(ssid); // Connect to WPA/WPA2 network. Change this line if using open or WEP network: status = WiFi.begin(ssid, pass); // wait 10 seconds for connection: delay(10000); } server.begin(); // you're connected now, so print out the status: printWifiStatus(); } void loop() { // listen for incoming clients WiFiClient client = server.available(); if (client) { // read the HTTP request header line by line while (client.connected()) { if (client.available()) { String HTTP_header = client.readStringUntil('\n'); // read the header line of HTTP request if (HTTP_header.equals("\r")) // the end of HTTP request break; Serial.print("<< "); Serial.println(HTTP_header); // print HTTP request to Serial Monitor } } // send the HTTP response // send the HTTP response header client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println("Connection: close"); // the connection will be closed after completion of the response client.println(); // the separator between HTTP header and body // send the HTTP response body float temp = getTemperature(); String html = String(HTML_CONTENT); html.replace("TEMPERATURE_MARKER", String(temp, 2)); // replace the marker by a real value client.println(html); client.flush(); // give the web browser time to receive the data delay(10); // close the connection: client.stop(); } } void printWifiStatus() { // print your board's IP address: Serial.print("IP Address: "); Serial.println(WiFi.localIP()); // print the received signal strength: Serial.print("signal strength (RSSI):"); Serial.print(WiFi.RSSI()); Serial.println(" dBm"); }
  • Change the WiFi information (SSID and password) in the code to yours
  • Create the index.h file On Arduino IDE by:
Arduino IDE 2 adds file
  • Either click on the button just below the serial monitor icon and choose New Tab, or use Ctrl+Shift+N keys.
  • Give file's name index.h and click OK button
Arduino IDE 2 adds file index.h
  • Copy the below code and paste it to the index.h.
/* * Created by ArduinoGetStarted.com * * This example code is in the public domain * * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server */ const char *HTML_CONTENT = R""""( REPLACE_YOUR_HTML_CONTENT_HERE )"""";
  • Replace the line REPLACE_YOUR_HTML_CONTENT_HERE by your HTML content you prepared before. There is no problem with new line character. The below is an example of index.h file:
/* * Created by ArduinoGetStarted.com * * This example code is in the public domain * * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server */ const char *HTML_CONTENT = R""""( <!DOCTYPE html> <html> <head> <title>Arduino - Web Temperature</title> <meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7"> <meta charset="utf-8"> <link rel="icon" href="https://diyables.io/images/page/diyables.svg"> <style> body { font-family: "Georgia"; text-align: center; font-size: width/2pt;} h1 { font-weight: bold; font-size: width/2pt;} h2 { font-weight: bold; font-size: width/2pt;} button { font-weight: bold; font-size: width/2pt;} </style> <script> var cvs_width = 200, cvs_height = 450; function init() { var canvas = document.getElementById("cvs"); canvas.width = cvs_width; canvas.height = cvs_height + 50; var ctx = canvas.getContext("2d"); ctx.translate(cvs_width/2, cvs_height - 80); update_view(TEMPERATURE_MARKER); } function update_view(temp) { var canvas = document.getElementById("cvs"); var ctx = canvas.getContext("2d"); var radius = 70; var offset = 5; var width = 45; var height = 330; ctx.clearRect(-cvs_width/2, -350, cvs_width, cvs_height); ctx.strokeStyle="blue"; ctx.fillStyle="blue"; //5-step Degree var x = -width/2; ctx.lineWidth=2; for (var i = 0; i <= 100; i+=5) { var y = -(height - radius)*i/100 - radius - 5; ctx.beginPath(); ctx.lineTo(x, y); ctx.lineTo(x - 20, y); ctx.stroke(); } //20-step Degree ctx.lineWidth=5; for (var i = 0; i <= 100; i+=20) { var y = -(height - radius)*i/100 - radius - 5; ctx.beginPath(); ctx.lineTo(x, y); ctx.lineTo(x - 25, y); ctx.stroke(); ctx.font="20px Georgia"; ctx.textBaseline="middle"; ctx.textAlign="right"; ctx.fillText(i.toString(), x - 35, y); } // shape ctx.lineWidth=16; ctx.beginPath(); ctx.arc(0, 0, radius, 0, 2 * Math.PI); ctx.stroke(); ctx.beginPath(); ctx.rect(-width/2, -height, width, height); ctx.stroke(); ctx.beginPath(); ctx.arc(0, -height, width/2, 0, 2 * Math.PI); ctx.stroke(); ctx.fillStyle="#e6e6ff"; ctx.beginPath(); ctx.arc(0, 0, radius, 0, 2 * Math.PI); ctx.fill(); ctx.beginPath(); ctx.rect(-width/2, -height, width, height); ctx.fill(); ctx.beginPath(); ctx.arc(0, -height, width/2, 0, 2 * Math.PI); ctx.fill(); ctx.fillStyle="#ff1a1a"; ctx.beginPath(); ctx.arc(0, 0, radius - offset, 0, 2 * Math.PI); ctx.fill(); temp = Math.round(temp * 100) / 100; var y = (height - radius)*temp/100.0 + radius + 5; ctx.beginPath(); ctx.rect(-width/2 + offset, -y, width - 2*offset, y); ctx.fill(); ctx.fillStyle="red"; ctx.font="bold 34px Georgia"; ctx.textBaseline="middle"; ctx.textAlign="center"; ctx.fillText(temp.toString() + "°C", 0, 100); } window.onload = init; </script> </head> <body> <h1>Arduino - Web Temperature</h1> <canvas id="cvs"></canvas> </body> </html> )"""";
  • Now you have the code in two files: ArduinoGetStarted.com.ino and index.h
  • Click Upload button on Arduino IDE to upload code to Arduino
  • Access the web page of Arduino board via web browser as before. You will see it as below:
Arduino temperature web browser

For a more comprehensive and detailed illustration, please refer to the Arduino - DS18B20 Temperature Sensor via Web tutorial

※ NOTE THAT:

  • If you make changes to the HTML content within the index.h file but don't modify anything in the ArduinoGetStarted.com.ino file, the Arduino IDE won't refresh or update the HTML content when you compile and upload the code to the ESP32.
  • To force the Arduino IDE to update the HTML content in this situation, you need to make a modification in the ArduinoGetStarted.com.ino file. For example, you can add an empty line or insert a comment. This action triggers the IDE to recognize that there have been changes in the project, ensuring that your updated HTML content gets included in the upload.

Arduino Web Server - Multiple Pages

Check out this Arduino - Web Server Multiple Pages tutorial.

The Best Arduino Starter Kit

※ OUR MESSAGES