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.
Just paste the image to retrieve it as a base64 encoded string.
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
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
Any ESP8266 ESP-12 module, for example Wemos D1 Mini | |
| Atmospheric pressure |
Temperature and humidity sensor | |
Jumper Dupont | |
Breadboard | |
Led (optional, follow the WiFi activity) | |
Resistor 220Ω (optional) |
Wiring
Here is a table of pin marking and correspondence between Arduino and ESP8266.
Sensor | Pin | ESP8266 Pin (Wemos D1 mini) |
DHT22 | VCC | 5V |
GND | G | |
Data | G5 | |
BMP180 | VCC | 5V |
GND | G | |
SDA | D2 | |
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 code | Explication |
<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)
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.
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!


![ESP8266. Understand the Arduino code of a web server with HTML interface 17 ESP8266, retrieve time from a time server (NTP), elapsed time since last Reset, store time in SPIFFS [Update]](https://diyprojects.io/media/thumbs_dir/esp8266-esp32-ntp-server-date-time-p1kd2tcezsw6960w9879hrjp22ze1xecqr9deieb14.jpg)


- How to store data on a micro SD card. Arduino code compatible ESP32, ESP8266
- Getting started Arduino. Receive commands from the serial port (ESP32 ESP8266 compatible)
- C++ functions print•println•printf•sprintf for Arduino ESP32 ESP8266. Combine•format → serial port
- C++ String functions. concat•c_srt•indexOf•replace•subString… for Arduino, ESP32, ESP8266
- How to assign a fixed IP to an ESP32 ESP8266 or ESP01 project
Its code works as you move along the article, but the final code isnt working
Exact, I had forgotten to declare de library ! #include . Thank you very much Shivam.
Thank you Shivam. I’ll check that.
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.
Solved my problem. Connected to a different network AP and it works! Now to fing the issue on my router WiFi. Thanks.
Awesome. Thank you very much for your return. I hope to see you soon for other projects.
Thank you very much Gerard. Have you changed the entry point? You must enter the page you want to reach on the web server that runs on esp8266. for example 192.168.1.35/measures. In my opinion, your code is correct. I hope this will help you solve the problem 🙂
Hello,
All code is running properly but the led is not toggling please Help..
add this line on setup
pinMode(LEDPIN, OUTPUT);
Right Pedro ! Thank you very much. It’s updated
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?
Hello Flag. In the loop loop() you must miss the line WiFiClient client = server.available();
https://uploads.disquscdn.com/images/9f94bc0d5155f6081e55354de75378f1d12347726cd575d9fa9823a1c4df2c13.png Thank you for the reply. I checked and that statement is in the sketch. I basically copied/pasted from the article. I’ll attach a screen capture of the IDE compiler output. Thanks again for any help.
Effectively. I also re-checked my code by doing like you a simple copy pasted. I have no mistakes. Can you try to delete temporary compilation files?
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.
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.