ESP8266. Understand the Arduino code of a web server with HTML interface

interface html arduino esp8266 web server
Share on facebook
Share on twitter
Share on linkedin
Share on pinterest
Share on email
Share on whatsapp
drapeau france

The ESP8266 can be programmed as a classic Arduino but its main interest is its Wi-Fi connection, which allows it to publish data to a server or an online Dashboard (ThingSpeak, Freeboard.io), or to easily create connected objects Which can be controlled from a home automation server or a mobile application (developed with Blynk or Cayenne for example). 

 

In this tutorial we will learn how to program the ESP8266 to behave like a Web Server. That is to say that we can interact with the program, the GPIO … from a web interface accessible from a web browser.

In this tutorial, we are going to learn how to add a web server to Arduino code for ESP8266. The Web server will display data collected or stored in the flash memory of the ESP8266 and interact from a WEB interface. We can for example control a relay connected to the GPIO …

Install the ESP8266 SDK on the Arduino IDE

If the ESP8266 SDK is already installed on your environment, you can skip to the next paragraph.

Before starting, you will need to install on the Arduino IDE the ESP8266 SDK from the manufacturer Espressif which allows you to develop and compile Arduino code for the ESP8266.

Everything is explained in detail in this tutorial

Getting started with the ESP8266WiFi library

The ESP8266WiFi library is a complete adaptation (a port) of the WiFi library for Arduino made by Espressif.

This is very handy because – in principle – porting an existing Arduino code to an ESP8266 requires almost no change.

We will use the WiFiWebServer example installed with the SDK to explain how we set up a WEB server on an ESP8266. One will not detail all the available methods here, everything is available here.

The best is to take an example to understand the basics of the library.

Create a new sketch and paste the following code.

This small program creates a web server which will be accessible from any internet browser by entering the IP address of the ESP8266 module. You can modify the state of an output (GPIO) of the ESP8266 by entering an HTTP request of this form directly in the address bar to light up the LED.

IP_ESP8266/LED=ON

or to switch off the LED

IP_ESP8266/LED=OFF

Before uploading, don’t forget to change the WiFi network name (SSID) and password.

#include <Arduino.h>
// Load Wi-Fi library
#include <ESP8266WiFi.h>

// Replace with your network credentials
const char* SSID = "REPLACE_WITH_YOUR_SSID"; 
const char* PASSWORD = "REPLACE_WITH_YOUR_PASSWORD";

// Set web server port number to 80
WiFiServer server(80);

// Assign output variables to GPIO pins
const int output = 4;

void setup() {
  Serial.begin(115200);
  // Initialize the output and set it to LOW
  pinMode(output, OUTPUT);
  digitalWrite(output, LOW);

  // Connect to Wi-Fi network with SSID and PASSWORD
  Serial.print("Connecting to ");
  Serial.println(SSID);
  WiFi.begin(SSID, PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address 
  Serial.println("");
  Serial.println("WiFi connected at IP address:");
  Serial.println(WiFi.localIP());

  // Start Web Server
  server.begin();
}

// Main loop
void loop(){
  // Create a client and listen for incoming clients
  WiFiClient client = server.available();   
  
  // Do nothing if server is not available
  if (!client) {
     return;
  }
  
  // Wait a client 
  while(!client.available()){}
  
  // A new client is connected, get the request
  String request = client.readStringUntil('\r');
  Serial.println(request);
  client.flush();

  int value = LOW;
  if (request.indexOf("/LED=ON") != -1) 
  {
    digitalWrite(output, HIGH);
    value = HIGH;
  } 
  if (request.indexOf("/LED=OFF") != -1)
  {
    digitalWrite(output, LOW);
    value = LOW;
  }
  
  // Display GPIO status
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println(""); 

  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.print("GPIO status: "); 

  if(value == HIGH) {
    client.print("ON");  
  } else {
    client.print("OFF");
  }

  client.println("<br><br>");
  client.println("Switch manually GPIO state");
  client.println("<br><br>");
  client.println("Turn <a href=\"/LED=ON\">ON</a><br>");
  client.println("Turn <a href=\"/LED=OFF\">OFF</a><br>");
  client.println("</html>");

  Serial.println("");
  
}

How does this code work?

To create a Web server, we declare the ESP8266WiFi library

#include <ESP8266WiFi.h>

We create an instance (of a C ++ object) which will contain the web server on port 80. Port 80 is the standard port for internet pages.

WiFiServer server(80);

You can connect an LED to an output of the ESP8266 to confirm the operation of the controls.

const int output = D4;

The web server starts up at runtime after the ESP8266 is connected to the WiFi network

WiFi.begin(SSID, PASSWORD); 
while (WiFi.status() != WL_CONNECTED) { 
   delay(500); 
   Serial.print("."); 
} 
server.begin();

Now, in the loop loop, just wait for a user to login from a web browser

To do this, we check that the server is started. If not, nothing more is done.

WiFiClient client = server.available();
if (!client) {
  return;
}

What happens in the loop loop?

We do something only if a client is connected, i.e. we make an HTTP request on the ESP8266 from an internet browser

WiFiClient client = server.available();
if (!client) {
  return;
}

As soon as a client connects to the web server – by entering the IP address of the ESP8266 in the address bar of the browser – we get the HTTP request in a variable of type String (string)

String request = client.readStringUntil('\r'); 
Serial.println(request); 
client.flush();

Open the serial monitor and enter this command in the address bar of the browser, replacing with the IP address of the ESP8266

IP_ESP8266/LED=ON

You should get a message like this on the serial monitor, this is the request we just got on the ESP8266

GET /LED=OFF HTTP/1.1

As it is a simple character string, it will suffice to test the different cases with the command indexOf on the variable req.

if (request.indexOf("/LED=ON") != -1) { 
   digitalWrite(output, HIGH); 
   value = HIGH; 
} if (request.indexOf("/LED=OFF") != -1) { 
   digitalWrite(output, LOW); 
   value = LOW; 
}

It only remains to create a display back. The client.println() and client.print() methods allow you to send text to the browser as you would on the serial monitor

if (request.indexOf("/LED=ON") != -1) { 
   digitalWrite(output, HIGH); 
   value = HIGH; 
} if (request.indexOf("/LED=OFF") != -1) { 
   digitalWrite(output, LOW); 
   value = LOW; 
}

Il ne reste plus qu’à créer un affichage en retour. Les méthodes client.println() et client.print() permettent d’envoyer sur le navigateur du texte comme on le ferait sur le moniteur série

client.println("HTTP/1.1 200 OK"); 
client.println("Content-Type: text/html"); 
client.println(""); 
client.println("<!DOCTYPE HTML>"); 
client.println("<html>"); 
client.print("GPIO status: "); 
if(value == HIGH) { 
  client.print("ON"); 
} else { 
  client.print("OFF"); 
}

Now you can remotely control any hardware connected to the GPIO (a relay, a led, a motor, a servo …) using a simple HTTP request. For example, you can simply execute a command from a home automation software. Here are two examples, the first for Domoticz, the second for Jeedom.

Tip, how to add a favicon

It is very easy to add a favicon, the small icon displayed next to the title of the web page on the internet browser

First of all, you have to retrieve the image you want to display in the form of a base64 encoded character string. From your search engine, find an image converter to a base64 string. For example png to base64 converter to convert an image to PNG format.

You can for example use base64-image.de which supports many image formats. All you have to do is drop the image to be converted to base64 in the drag & drop images anywhere field.

image converter online esp8266

Just paste the image to retrieve it as a base64 encoded string.

image base64 favico esp8266

Then just add a head section by pasting. Replace base64_image_string with the base64 string. Modify the type of the image (jpg, png …)

client.println("<!DOCTYPE HTML>");
  client.println("<head>");
  client.println("<link rel='icon' href='base64_image_string' type='image/x-png' />");
  client.println("</head>");
  client.println("<html>");

There you go, the page now has a favicon in the address bar

esp8266 favico webserver

Add an HTML GUI to your projects

Now, you would definitely want to make a small interface for your ESP8266 projects. For this, we need to know some basics of HTML. We are not going to go very far in learning HTML, just learn the important elements to get started and have a working project. If you need more interface elements, I recommend w3scholls which is a reference in learning HTML.

In a project ESP8266, we can create HTML pages in dynamic, ie we build a text string that contains the code of the page that will then be displayed. That’s what we’re going to do. But the ESP8266 is also able to function as a real website, ie we can install on HTML flash pages, javascript code, CSS style sheets … We will not go Until now in this first tutorial.

I propose to create a small weather station to have data to update regularly and create a button to activate / deactivate a GPIO output (just a Led, for example.) I used the following hardware

esp8266 Wemos D1 miniAny ESP8266 ESP-12 module, for example Wemos D1 Mini
 BMP180Atmospheric pressure

BMP180

Broches DHT22Temperature and humidity sensor

DHT11 or DHT22

jumper dupontJumper Dupont
breadboardBreadboard
led 3mmLed (optional, follow the WiFi activity)
resistance 220ohmsResistor 220Ω (optional)

Wiring

Here is a table of pin marking and correspondence between Arduino and ESP8266.

SensorPinESP8266 Pin (Wemos D1 mini)
DHT22VCC5V
GNDG
DataG5
BMP180VCC5V
GNDG
SDAD2

We begin by declaring the necessary libraries. Do not forget to install the libraries from the library manager (DHT and BMP085).

Note. You might encounter an error when compiling adafruit_Sensor.h: No such file or directory. In this case, download and unpack the library manually from GitHub in the Arduino -> Library folder and then restart the IDE for it to take effect.

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <DHT.h>
#include <Adafruit_BMP085.h>

Program variables are defined. Modify the WiFi network to which you will connect and the WiFi network password.

#define ssid      "ssid"       // WiFi SSID
#define password  "password"  // WiFi password
#define DHTTYPE   DHT22       // DHT type (DHT11, DHT22)
#define DHTPIN    D4          // Broche du DHT / DHT Pin
#define LEDPIN    D3          // Led
float   t = 0 ;
float   h = 0 ;
float   p = 0;
String  etatLed = "OFF";

We create the dht, bmp and server objects

DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP085 bmp;
ESP8266WebServer server ( 80 );

This first function makes it possible to construct the HTML code of the main page of the program. It is a simple chain of character. It is an assembly of chains. You can easily include the value or state of a variable (for example, the status of an output). In return, the function returns a string containing the HTML code of the page.

String getPage(){
  String page = "<html lang=fr-FR><head><meta http-equiv='refresh' content='10'/>";
  page += "<title>ESP8266 Demo - www.projetsdiy.fr</title>";
  page += "<style> body { background-color: #fffff; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }</style>";
  page += "</head><body><h1>ESP8266 Demo</h1>";
  page += "<h3>DHT22</h3>";
  page += "<ul><li>Temperature : ";
  page += t;
  page += "°C</li>";
  page += "<li>Humidite : ";
  page += h;
  page += "%</li></ul><h3>BMP180</h3>";
  page += "<ul><li>Pression atmospherique : ";
  page += p;
  page += " mbar</li></ul>";
  page += "<h3>GPIO</h3>";
  page += "<form action='/' method='POST'>";
  page += "<ul><li>D3 (etat: ";
  page += etatLed;
  page += ")<INPUT type='radio' name='LED' value='1'>ON";
  page += "<INPUT type='radio' name='LED' value='0'>OFF</li></ul>";
  page += "<INPUT type='submit' value='Actualiser'>";
  page += "<br><br><p><a hrf='https://diyprojects.io'>diyprojects.io</p>";
  page += "</body></html>";
  return page;
}

Let’s see a little better how the code is built

HTML codeExplication
<html lang=fr-FR>
 <head>
   <meta http-equiv='refresh' content='10'/>
   <title>ESP8266 Demo - www.projetsdiy.fr</title>
   <style> body { background-color: #fffff; 
   font-family: Arial, Helvetica, Sans-Serif; 
   Color: #000088; }</style>
 </head>
Lang: set the language of the page

Head: this is the header of the page. It contains different meta (parameters)

  • http-equiv = ‘refresh’: this is a page that the browser will need to refresh. For more types, go here
  • content = ’10 ‘: every 10 seconds

title: the title of the page displayed in the browser bar

style: a style for the page (background color, font to use, text color

<body>
Content of the page
<h1>ESP8266 Demo</h1>
Title
<h3>DHT22</h3>
sub-title (littler) for DHT22 sensor
<ul>
 <li>Température : xx°C</li>
 <li>Humidité : xx%</li>
</ul>
The ul block is used to display the information in a list. The same for the BMP180
<form action='/' method='POST'>
 <ul>
  <li>D3 (etat: xx)
   <INPUT type='radio' name='LED' value='1'>ON
   <INPUT type='radio' name='LED' value='0'>OFF
  </li>
 </ul>
 <INPUT type='submit' value='Actualiser'>
</form>
To update the GPIO, a form is used.Here we use a radio button to change the state (On / Off) and then submit the contents of the form with a button.

The name option lets you name the variable that will contain the state you want to retrieve in the Arduino code. Here LED.

</body>
Any open tag must be closed (better!)

The handleRoot function is used to monitor whether a request to update the GPIO is received by monitoring whether the LED argument is returned by the page. If so, execute the handleSubmit function. It’s up to us

void handleRoot(){ 
  if ( server.hasArg("LED") ) {
    handleSubmit();
  } else {
    server.send ( 200, "text/html", getPage() );
  }  
}

The handleSubmit function processes updating the GPIO. The status of the LED variable is retrieved. It is a chain of character, so we must test “1” and not 1. We take advantage of it to affect the state of the GPIO in the variable etatLed in the form of a string, it is more fun to read. Finally we update the display of the HTML page with server.send. The updated page is retrieved by calling the getPage () function.

void handleSubmit() {
  // Actualise le GPIO / Update GPIO 
  String LEDValue;
  LEDValue = server.arg("LED");
  Serial.println("Set GPIO "); Serial.print(LEDValue);
  if ( LEDValue == "1" ) {
    digitalWrite(LEDPIN, 1);
    etatLed = "On";
    server.send ( 200, "text/html", getPage() );
  } else if ( LEDValue == "0" ) {
    digitalWrite(LEDPIN, 0);
    etatLed = "Off";
    server.send ( 200, "text/html", getPage() );
  } else {
    Serial.println("Err Led Value");
  }
}

Now that all functions are created, you can call the setup() function. It initializes the BMP180, the WiFi connection, connects the function that takes care of the main page and finally launches the web server

void setup() {
  Serial.begin ( 115200 );
  // Initialisation du BMP180 / Init BMP180
  if ( !bmp.begin() ) {
    Serial.println("BMP180 KO!");
    while(1);
  } else {
    Serial.println("BMP180 OK");
  }
  
  WiFi.begin ( ssid, password );
  // Attente de la connexion au réseau WiFi / Wait for connection
  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 ); Serial.print ( "." );
  }
  // Connexion WiFi établie / WiFi connexion is OK
  Serial.println ( "" ); 
  Serial.print ( "Connected to " ); Serial.println ( ssid );
  Serial.print ( "IP address: " ); Serial.println ( WiFi.localIP() );

  // On branche la fonction qui gère la premiere page / link to the function that manage launch page 
  server.on ( "/", handleRoot );

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

All that remains is to execute the loop() function to regularly read the measurements on the sensors. Unlike the previous example based on the ESP8266WiFi library, here the ESP8266WebServer needs to connect the callback function server.handleClient() which monitors the presence of a client and delivers the requested HTML page.

void loop() {
  server.handleClient();
  t = dht.readTemperature();
  h = dht.readHumidity();
  p = bmp.readPressure() / 100.0F;
  delay(1000);
}

Here is the assembled source code of the project that you simply paste into a new project and then upload it

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <DHT.h>
#include <Adafruit_BMP085.h>

#define ssid      "xx"       // WiFi SSID
#define password  "xxxxxx"  // WiFi password
#define DHTTYPE   DHT22       // DHT type (DHT11, DHT22)
#define DHTPIN    D4          // Broche du DHT / DHT Pin
#define LEDPIN    D3          // Led
float   t = 0 ;
float   h = 0 ;
float   p = 0;
String  etatLed = "OFF";

// Création des objets / create Objects
DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP085 bmp;
ESP8266WebServer server ( 80 );

String getPage(){
  String page = "<html lang=fr-FR><head><meta http-equiv='refresh' content='10'/>";
  page += "<title>ESP8266 Demo - www.projetsdiy.fr</title>";
  page += "<style> body { background-color: #fffff; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }</style>";
  page += "</head><body><h1>ESP8266 Demo</h1>";
  page += "<h3>DHT22</h3>";
  page += "<ul><li>Temperature : ";
  page += t;
  page += "°C</li>";
  page += "<li>Humidite : ";
  page += h;
  page += "%</li></ul><h3>BMP180</h3>";
  page += "<ul><li>Pression atmospherique : ";
  page += p;
  page += " mbar</li></ul>";
  page += "<h3>GPIO</h3>";
  page += "<form action='/' method='POST'>";
  page += "<ul><li>D3 (etat: ";
  page += etatLed;
  page += ")";
  page += "<INPUT type='radio' name='LED' value='1'>ON";
  page += "<INPUT type='radio' name='LED' value='0'>OFF</li></ul>";
  page += "<INPUT type='submit' value='Actualiser'>";
  page += "<br><br><p><a hrf='https://diyprojects.io'>diyprojects.io</p>";
  page += "</body></html>";
  return page;
}
void handleRoot(){ 
  if ( server.hasArg("LED") ) {
    handleSubmit();
  } else {
    server.send ( 200, "text/html", getPage() );
  }  
}

void handleSubmit() {
  // Actualise le GPIO / Update GPIO 
  String LEDValue;
  LEDValue = server.arg("LED");
  Serial.println("Set GPIO "); Serial.print(LEDValue);
  if ( LEDValue == "1" ) {
    digitalWrite(LEDPIN, 1);
    etatLed = "On";
    server.send ( 200, "text/html", getPage() );
  } else if ( LEDValue == "0" ) {
    digitalWrite(LEDPIN, 0);
    etatLed = "Off";
    server.send ( 200, "text/html", getPage() );
  } else {
    Serial.println("Err Led Value");
  }
}

void setup() {
  Serial.begin ( 115200 );
  // Initialisation du BMP180 / Init BMP180
  if ( !bmp.begin() ) {
    Serial.println("BMP180 KO!");
    while(1);
  } else {
    Serial.println("BMP180 OK");
  }
  
  pinMode(LEDPIN, OUTPUT); 
  WiFi.begin ( ssid, password );
  // Attente de la connexion au réseau WiFi / Wait for connection
  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 ); Serial.print ( "." );
  }
  // Connexion WiFi établie / WiFi connexion is OK
  Serial.println ( "" ); 
  Serial.print ( "Connected to " ); Serial.println ( ssid );
  Serial.print ( "IP address: " ); Serial.println ( WiFi.localIP() );

  // On branche la fonction qui gère la premiere page / link to the function that manage launch page 
  server.on ( "/", handleRoot );

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

void loop() {
  server.handleClient();
  t = dht.readTemperature();
  h = dht.readHumidity();
  p = bmp.readPressure() / 100.0F;
  delay(1000);
}

Retrieve the IP address of the Wemos by opening the serial monitor and then connect to it from a web browser to access the interface of the mini weather station.

esp8266 wemos d1 mini serveur server web dht22 bmp180 gpio

Here, we now know how to create a web server using an ESP8266, drive the GPIO and display measurements from sensors. We have seen here only the basic rudiments to begin but they already cover much of what is needed to develop small connected objects. In the next tutorial we will see how to have a better graphical interface using Bootstrap, a framework developed by a developer working at Tweeter which allows to create more beautiful graphical interfaces in HTML.

Here are other articles that may interest you to go further from this tutorial. Good developments!

Click to rate this post!
[Total: 0 Average: 0]

Are you having a problem with this topic?

Maybe someone has already found the solution, visit the forum before asking your question
Ask your question

Share on facebook
Share on twitter
Share on linkedin
Share on pinterest
Share on email
Share on whatsapp

Did you like this project ? Don't miss any more projects by subscribing to our weekly newsletter!

16 Comments
  1. Its code works as you move along the article, but the final code isnt working

  2. Thanks for the project. I have compiled and uploaded the final sketch, and as I did not have a BMP180 handy I commented out the check to prevent it going into a KO loop. Everything seems fine. I get feedback on the serial monitor. I get “Connected to NETGEARXX
    IP address: 192.168.1.35
    HTTP server started” but when I try to access the ip address it times out. First time I experience this with the ESP8266. Turned off firewall and antivirus. Still times out. Any suggestions are appreciated. I also tried commenting out the p = bmp.readPressure() / 100.0F; but this too did not help.

  3. The line :
    String req = client.readStringUntil(‘r’);
    generates a compiler error ¨ client was not declared in this scope¨
    Using arduino IDE 1.8.4
    Any suggestions?

  4. Hi All,

    Anybody can tell me how we can put this output on a dedicated LCD monitor via HDMI cable, which we are getting in our browser, by typing the IP address in URL?

    It will be something like we takes output from ESP2866 on a small CLI screen but here this out will be go directly on LCD screen attached to ESP2866.

    I hope you got what I want to say.

    Thank you.

  5. Hello!

    I would like to discuss with You the issue of cooperation. Interested in placing a banner on Your website on a regular basis. The theme of the banner is mobile phones, gadgets. We work on an advance payment.

    I will wait For your answer to my question. mail. Sincerely, Anna.

    Leave a Reply

    DIY Projects
    %d bloggers like this: