---
title: "Small web server"
url: "https://maker.wiznet.io/teddy/projects/small-web-server/"
markdown_url: "https://maker.wiznet.io/teddy/projects/small-web-server/md"
type: "UCC: User Created Content"
author: "SenseBox"
author_url: "https://edu.books.sensebox.de/de/projekte/webserver.html"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "SenseBox"
original_url: "https://edu.books.sensebox.de/de/projekte/webserver.html"
published: "2023-10-04"
language: "en"
tags: ["Arduino", "W5500", "Webserver"]
hardware: ["Arduino 101", "WIZnet W5500 Ethernet Shield"]
likes: 0
views: 2628
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# Small web server

> Learn to access an Arduino's SD card website, control pins via webpage, with prior experience recommended.

Original author: SenseBox (source: https://edu.books.sensebox.de/de/projekte/webserver.html)

## Components

- **Arduino 101** x 1 ([docs](https://software.intel.com/en-us/iot/hardware/curie))
- **WIZnet W5500 Ethernet Shield** x 1

## Article

## **Small web server**

## **Objectives of the station**

In this station we want to learn how to access a website that is stored on the Arduino's SD card. Individual pins of the Arduino should then be switched via this page.

The project is more complex than the entry-level projects; So you should have some experience from other projects before you start with the web server. The topics of network access and HTML are so extensive that we can only touch on them in this project. Further information is easy to find on the internet!

## **materials**

- [Ethernet-Shield](https://edu.books.sensebox.de/de/GLOSSARY.html#ethernet-shield)

#### **Materials that are not included in the senseBox**

- AND Cable

## **Basics**

### **Ethernet-Shield**

An Ethernet shield is included in the senseBox. This allows you to connect the [Arduino](https://edu.books.sensebox.de/de/GLOSSARY.html#arduino) to the network using the LAN cable.

Since it is usually very difficult to access a school network via the Internet, we will only access the [Arduino](https://edu.books.sensebox.de/de/GLOSSARY.html#arduino) via the local network .

If you still want to make the [Arduino](https://edu.books.sensebox.de/de/GLOSSARY.html#arduino) accessible via the Internet and have access to your router, there is the possibility of doing this via *port forwarding* . You can find more information about this [**here .**](http://www.pcwelt.de/ratgeber/Crashkurs__Fernzugriff_und_Portfreigaben-Via_Internet_ins_Heimnetz-8324897.html)

### **Webserver**

A web server (English server 'servant') is a computer with web server software (in our case the [Arduino](https://edu.books.sensebox.de/de/GLOSSARY.html#arduino) ) that transmits documents to clients such as web browsers. For us, the document is the content of index.htm.

## **Construction**

![](https://raw.githubusercontent.com/sensebox/resources/master/images/edu/server.jpg)

## **Task 1**

Three libraries are required for the server:

```plaintext
#include <Ethernet.h>
#include <TextFinder.h>
#include <SD.h>
```

**Attention ***It is important that you use our version of the Ethernet library (see *[***Downloads***](https://edu.books.sensebox.de/de/downloads.html)* ). Our *[*Ethernet shield*](https://edu.books.sensebox.de/de/GLOSSARY.html#ethernet-shield)* does not work with the *[*Arduino*](https://edu.books.sensebox.de/de/GLOSSARY.html#arduino)* standard library . The Arduino environment will always want to 'update' the Ethernet library; you can't do that.*

The MAC address and the IP address of the [Arduino](https://edu.books.sensebox.de/de/GLOSSARY.html#arduino) server must then be set in two variables. In addition, pin 4 must be set as an SD card pin. We also define an `File`object `webFile`in which the HTML page is stored.

```plaintext
// MAC-Adresse des Ethernet-Shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// Lokale IP zum aufrufen des Webservers
IPAddress ip(192, 168, 0, 42);
// Pin der SD-Karte
byte sdPin = 4;
File webFile;
```

We now have to assign a port to the server. We also introduce a variable that defines whether we are in test mode. In this case, additional status information is output via the serial port, which, however, slows down the system.

```plaintext
// Server port
EthernetServer server(80);
boolean testmode = false;// Auf true setzen falls etwas nicht funktioniert.
Dann werden Informationen über die serielle Schnittstelle ausgegeben.
```

In the setup method, the mac address and the IP address are passed to the server in the first step. It is then checked whether there is access to the SD card and whether a file with the name `index.htm`exists on the card. If the variable was set `testmode`to `true`, status information is output via the serial interface. This can help you find errors.

```plaintext
void setup() {
  if(testmode) Serial.begin(9600);
  Ethernet.begin(mac, ip); // Client starten
  server.begin();          // Server starten

  if(testmode) Serial.println("Initialisiere SD-Karte...");
  if(!SD.begin(sdPin)) {
    if(testmode)Serial.println("Initialisierung der SD-Karte fehlgeschlagen!");
    return;
  }
  if(testmode) Serial.println("SD-Karte erfolgreich initialisiert.");

  if(!SD.exists("index.htm")) {
    if(testmode) Serial.println("Datei (index.htm) wurde nicht gefunden!");
    return;
  }
  if(testmode) {
    Serial.println("Datei (index.htm) wurde gefunden.");
    Serial.println("Verbraucher schalten");
  }
}
```

The `loop`method is divided into two areas. In the first part, actions on the website are evaluated, in the second part the website is read from the SD card and sent to the browser.

### **Evaluation of inquiries**

If the client is available, it waits `finder`for a request from the client. If he gets this, he searches for the keyword “pin” and saves the next two characters in the variables `typ`, `pin`and `val`. Depending on the type, an action is then carried out. By default, types D, A and a are defined. D = switch digital pin A = switch analog pin a = read out analog pin

```plaintext
void loop() {
  /**********************
   * Anfragen auswerten *
   **********************/
  EthernetClient client = server.available(); // Auf Anfrage warten
  if(client) {
    TextFinder finder(client);

    if(finder.find("GET")) { //erkennt Aktion auf der Website
      while(finder.findUntil("pin", "\n\r")) {// Bis das Schlüsselwort "pin" erkannt wird
        char typ = char(client.read());
        int  pin = int(finder.getValue());
        int  val = int(finder.getValue());

        if(typ == 'D') {
          pinMode(pin, OUTPUT);
          digitalWrite(pin, val);
          if(testmode)Serial.print(" - D"+String(pin));
        }
        else if(typ == 'A') {
          analogWrite(pin, val);
          if(testmode)Serial.print(" - A"+String(pin));
        }
        else if(typ == 'a') { // a -> Sensorwert auslesen und ausgeben
          val = analogRead(pin);
          if(testmode)Serial.print(" - a"+String(pin));
        }
        else {
          if(testmode) Serial.print(" - Falscher Typ");
        }
        //Hier können neue Befehle definiert werden die aus dem Browser gestartet werden.
        if(testmode) {
          if(val==1) Serial.println(" ein");
          else if(val==0) Serial.println(" aus");
          else Serial.println(" "+ val);
        }
      }
    }
```

### **View web form**

Every line of the HTML document is read and sent to the browser. Since the storage space for variables is very limited, the string is split at every space or line break. The string is then searched for specific keywords. These can be `filter`defined as required in the method. These keywords can then be replaced with sensor values.

```plaintext
    /************************
    * Webformular anzeigen  *
    ************************/
    boolean current_line_is_blank = true;         // eine HTTP-Anfrage endet mit einer Leerzeile und einer neuen Zeile
    String htmlline = "";
    while (client.connected()) {
      if (client.available()) {                   // Wenn Daten vom Server empfangen werden

        char c = client.read();                   // empfangene Zeichen einlesen
        if (c == '\n' && current_line_is_blank) { // wenn neue Zeile und Leerzeile empfangen
          // Standard HTTP Header senden
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println();

          // Website von SD-Karte laden
          webFile = SD.open("index.htm");  // Website laden
          if (webFile) {
            while(webFile.available()) {
              char temp = char(webFile.read());
              //Bei jedem Leerzeichen wird ein neuer String generiert
              if((int(temp) != 10)&&(int(temp) != 32)&&(int(temp) != 13)){
                htmlline = htmlline + char(temp);
              }
              else {
                htmlline = filter(htmlline); //Ersetzt Schlüsselwörter zum Beispiel durch Sensorwerte
                client.println(htmlline);
                if(testmode) Serial.println(htmlline);
                htmlline = "";
              }
            }
            webFile.close();
          }
          break;
        }
        if (c == '\n') {
          current_line_is_blank = true;
        }
        else if (c != '\r') {
          current_line_is_blank = false;
        }
      }
    }
    delay(1);
    client.stop();
  }
}

//Ersetzt Schlüsselwörter zum Beispiel durch Sensorwerte
// Es können nach belieben neue Schlüsselwörter definerit und durch andern Text ersätzt werden
String filter(String htmlline){
  htmlline.replace("sa0en",String(analogRead(A0)));
  htmlline.replace("sa1en","No sensor");
  htmlline.replace("sa2en","No sensor");
  htmlline.replace("sa3en","No sensor");
  htmlline.replace("sa4en","No sensor");
  htmlline.replace("sa5en","No sensor");
  return htmlline;
}
```

### **HTML Dokument**

Our first little website looks like this: ![](https://raw.githubusercontent.com/sensebox/resources/master/images/edu/webserver_htm.png)

You have to copy this code and save it in a text file. You then have to change the name of the text file to index.htm. The HTML document must then be saved on the SD card and inserted into the Ethernet shield.

```plaintext
<!DOCTYPE html>
<html>
<head>
  <title>Arduino Server senseBox</title>
  <style type="text/css">
    h2 { margin-bottom:5px; }
    table {width: 40%;} th { background-color: #666; color: #fff; } tr { background-color: #fffbf0; color: #000; } tr:nth-child(odd) { background-color: #e4ebf2 ; } </style>
    </style>
</head>
<body>
  <img src="sensebox_logo_neu.png" alt="sensebox" width="700" height="150"/>
  <h1>Arduino Server senseBox</h1>
  <!-- D for digitalWrite, A for analogWrite, d for digitalRead, a for analogRead -->
  <table>
    <tr> <td>Digitale Ausg&auml;nge</td> <td> Aktion </td><td>Analoge Ausg&auml;nge</td><td>Aktion</td></td></tr>
    <tr> <td>Pin0:</td> <td> <a href="/?pinD0=1" target="ifr">Ein</a> <a href="/?pinD0=0" target="ifr">Aus</a> </td> <td> Pin A0:</td> <td><a href="/?pinA0=1" target="ifr">Ein</a> <a href="/?pinA0=0" target="ifr">Aus </a> <a href="/?pina0=2" target="ifr"> getValue </a></td></tr>
    <tr> <td>Pin1:</td> <td> <a href="/?pinD1=1" target="ifr">Ein</a> <a href="/?pinD1=0" target="ifr">Aus</a> </td> <td> Pin A1:</td> <td> <a href="/?pinA1=1" target="ifr">Ein</a> <a href="/?pinA1=0" target="ifr">Aus</a> <a href="/?pina1=2" target="ifr"> getValue </a></td></tr>
    <tr> <td>Pin2:</td> <td> <a href="/?pinD2=1" target="ifr">Ein</a> <a href="/?pinD2=0" target="ifr">Aus</a> </td> <td> Pin A2:</td> <td> <a href="/?pinA2=1" target="ifr">Ein</a> <a href="/?pinA2=0" target="ifr">Aus</a> <a href="/?pina2=2" target="ifr"> getValue </a></td></tr>
    <tr> <td>Pin3:</td> <td> <a href="/?pinD3=1" target="ifr">Ein</a> <a href="/?pinD3=0" target="ifr">Aus</a> </td> <td> Pin A3:</td> <td> <a href="/?pinA3=1" target="ifr">Ein</a> <a href="/?pinA3=0" target="ifr">Aus</a> <a href="/?pina3=2" target="ifr"> getValue </a></td></tr>
    <tr> <td>Pin4:</td> <td> <a href="/?pinD4=1" target="ifr">Ein</a> <a href="/?pinD4=0" target="ifr">Aus</a> </td> <td> Pin A4:</td> <td> <a href="/?pinA4=1" target="ifr">Ein</a> <a href="/?pinA4=0" target="ifr">Aus</a> <a href="/?pina4=2" target="ifr"> getValue </a></td></tr>
    <tr> <td>Pin5:</td> <td> <a href="/?pinD5=1" target="ifr">Ein</a> <a href="/?pinD5=0" target="ifr">Aus</a> </td> <td> Pin A5:</td> <td> <a href="/?pinA5=1" target="ifr">Ein</a> <a href="/?pinA5=0" target="ifr">Aus</a> <a href="/?pina5=2" target="ifr"> getValue </a></td></tr>
    <tr> <td>Pin6:</td> <td> <a href="/?pinD6=1" target="ifr">Ein</a> <a href="/?pinD6=0" target="ifr">Aus</a> </td> <td></td></tr>
    <tr> <td>Pin7:</td> <td> <a href="/?pinD7=1" target="ifr">Ein</a> <a href="/?pinD7=0" target="ifr">Aus</a> </td> <td></td></tr>
    <tr> <td>Pin8:</td> <td> <a href="/?pinD8=1" target="ifr">Ein</a> <a href="/?pinD8=0" target="ifr">Aus</a> </td> <td></td></tr>
    <tr> <td>Pin9:</td> <td> <a href="/?pinD9=1" target="ifr">Ein</a> <a href="/?pinD9=0" target="ifr">Aus</a> </td> <td></td></tr>
    <tr> <td>Pin10:</td> <td> <a href="/?pinD10=1" target="ifr">Ein</a> <a href="/?pinD10=0" target="ifr">Aus</a> </td> <td></td></tr>
    <tr> <td>Pin11:</td> <td> <a href="/?pinD11=1" target="ifr">Ein</a> <a href="/?pinD11=0" target="ifr">Aus</a> </td> <td></td></tr>
    <tr> <td>Pin12:</td> <td> <a href="/?pinD11=1" target="ifr">Ein</a> <a href="/?pinD12=0" target="ifr">Aus</a> </td> <td></td></tr>
    <tr> <td>Pin13:</td> <td> <a href="/?pinD13=1" target="ifr">Ein</a> <a href="/?pinD13=0" target="ifr">Aus</a> </td> <td></td></tr>
  </table>
  <iframe name="ifr" style="display:none;" width="0" height="0"></iframe>
</body>
</html>
```

---

Source: https://maker.wiznet.io/teddy/projects/small-web-server/
