ESP8266 : comprendre la programmation Web Server avec du code Arduino

L’ESP8266 peut se programme comme un Arduino classique mais son principal intérêt reste sa connexion Wi-Fi qui lui permet de publier des données sur un serveur ou un Dashboard en ligne (ThingSpeak, Freeboard.io), ou de créer facilement des objets connectés que l’on pourra piloter depuis un serveur domotique ou une application mobile (développée avec Blynk ou Cayenne par exemple). Dans ce tutoriel, nous allons apprendre comment programmer l’ESP8266 pour qu’il se comporte comme un serveur web. C’est à dire qu’on pourra interagir avec le programme, le GPIO… depuis une interface web accessible depuis un navigateur internet (sur le réseau local ou depuis internet en configurant le routeur).

Installer les librairies et cartes ESP8266 sur l’IDE Arduino

Avant de commencer, il est nécessaire de vérifier que toutes les librairies nécessaires sont installées.

http://arduino.esp8266.com/stable/package_esp8266com_index.json

IDE Arduino 1.6.8 esp8266 package

Vous pouvez regarder (par curiosité) les cartes gérées par la librairie ESP8266 et collant l’URL précédente dans un navigateur. En janvier 2017 (version 2.3.0), les cartes suivantes sont gérées :

  • Generic ESP8266 Module
  • Olimex MOD-WIFI-ESP8266(-DEV)
  • NodeMCU 0.9 (ESP-12 Module)
  • NodeMCU 1.0 (ESP-12E Module)
  • Adafruit HUZZAH ESP8266 (ESP-12)
  • ESPresso Lite 1.0
  • ESPresso Lite 2.0
  • Phoenix 1.0
  • Phoenix 2.0
  • SparkFun Thing
  • SweetPea ESP-210
  • WeMos D1
  • WeMos D1 mini
  • ESPino (ESP-12 Module)
  • ESPino (WROOM-02 Module)
  • WifInfo
  • ESPDuino

Allez dans le gestionnaire de carte et cherchez esp8266, puis cliquez sur installer.

IDE Arduino 1.6.x ajouter carte esp8266

En même temps que les cartes, toutes les librairies nécessaires ainsi que de nombreux exemples sont installés. Si les exemples ne sont pas visibles dans le menu Fichier -> Exemples -> Exemples for WeMos D1, quittez et relancez l’IDE Arduino.

Débuter avec la librairie ESP8266WiFi

Nous allons avancer par étapes pour comprendre comment créer un serveur web sur un ESP8266. Ouvrez l’exemple WiFiWebServer.

On a besoin au minium de la librairie ESP8266WiFi.h pour créer un serveur Web. Comme toutes les librairies, il faut pas mal fouiller pour connaître les méthodes disponibles, voici un petit aperçu pour mieux appréhender ce qu’on peut faire avec. le code source de la librairie est disponible ici. Cette librairie est une adaptation de l’ensemble des librairie développées pour l’Arduino. Vous pourrez également trouver pas mal d’infos ici

  • WiFiClient
    • uint8_t status()
    • int connect(IPAddress ip, uint16_t port)
    • int connect(const char *host, uint16_t port)
    • size_t write(uint8_t)
    • size_t write(const uint8_t *buf, size_t size)
    • size_t write_P(PGM_P buf, size_t size)
    • size_t write(Stream& stream)
    • int available()
    • read(uint8_t *buf, size_t size)
    • int peek()
    • size_t peekBytes(uint8_t *buffer, size_t length)
    • size_t peekBytes(char *buffer, size_t length)
    • void flush()
    • void stop()
    • uint8_t connected()
    • IPAddress remoteIP()
    • uint16_t remotePort()
    • IPAddress localIP()
    • uint16_t localPort()
    • bool getNoDelay()
    • void setNoDelay(bool nodelay)
    • void setLocalPortStart(uint16_t port)
    • static void stopAll();
    • static void stopAllExcept(WiFiClient * c)
  • WiFiServer
    • WiFiServer(IPAddress addr, uint16_t port)
    • WiFiServer(uint16_t port)
    • WiFiClient available(uint8_t* status = NULL)
    • bool hasClient()
    • void begin()
    • void setNoDelay(bool nodelay)
    • bool getNoDelay()
    • virtual size_t write(uint8_t)
    • uint8_t status()
    • void close()
    • void stop()
  • WiFiUDP
  • WiFiClientSecure
#include <ESP8266WiFi.h>
const char* ssid = "your-ssid";
const char* password = "your-password";

On créé une instance, un objet qui contiendra le serveur web. On communiquera avec lui sur le port 80, le port classique des requêtes HTTP utilisées par les navigateurs internet.

WiFiServer server(80);

La boucle setup.

void setup() {
  // Ouverture du port serie en 115200 baud pour envoyer des messages de debug à l'ide par exemple
  Serial.begin(115200);
  delay(10);

  // prepare GPIO2 (sortie)
  pinMode(2, OUTPUT);
  digitalWrite(2, 0);
  
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  // On se connecte a reseau WiFi avec le SSID et le mot de passe precedemment configure
  WiFi.begin(ssid, password);
  
  // On sort de la boucle uniquement lorsque la connexion a ete etablie.
  // Il faudrait ameliorer cette partie pour un fonctionnement sur batterie car en cas d'abscence du reseau
  // on va vider la batterie !
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  
  // connexion OK, on demarre le server web // Start the server
  server.begin();
  Serial.println("Server started");

  // On indique sur le port serie l'adresse ip de l'ESP pour le trouver facilement / Print the IP address
  Serial.println(WiFi.localIP());
}

Que se passe-t-il dans la boucle loop ?

On fait quelque chose uniquement si un client est connecté, c’est à dire qu’on réalise une requête HTTP sur l’ESP8266 depuis un navigateur internet

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

Lorsqu’un client se connecte, on l’indique sur le port série

Serial.println("new client");
while(!client.available()){
  delay(1);
}

On récupère la requête HTTP, ici l’URL saisie dans le navigateur tout simplement. On envoi sur le port série le contenu de la requête HTTP. On vide le tampon avec la méthode flush.

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

On recherche dans la requête HTTP ce que l’on doit faire. La méthode la plus simple est de passer les ordres à l’ESP8266 sous la forme d’une commande du type /gpio/etat_souhaite (0, 1 ou on/off). On ferra juste un test sur  une chaîne de caractères avec la commande indexOf sur la variable req. Ce type de stratégie convient pour de petits projets mais ça risque rapidement de devenir une source d’erreur avec l’empilage des if, else if.

int val;
if (req.indexOf("/gpio/0") != -1)
  val = 0;
else if (req.indexOf("/gpio/1") != -1)
  val = 1;
else {
  Serial.println("invalid request");
  client.stop();
  return;
}

On met à jour l’état du GPIO et on vide le tampon

digitalWrite(2, val);
client.flush();

On créé maintenant un page HTML qui contient l’état du GPIO. C’est une chaine texte qui contient le code HTML de la page. On intercale dans le code de la page, l’état du GPIO

String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
s += (val)?"high":"low";
s += "</html>\n";

On publie cette page au client avec la commande print, très facile !

client.print(s);

Voilà, vous pouvez maintenant piloter à distance tout matériel relié au GPIO (un relai, une led, un moteur, un servomoteur….) à laide d’une simple requête HTTP. Vous pouvez par exemple très simplement exécuter une commande depuis un logiciel domotique. Voici deux exemples, le premier pour Domoticz, le second pour Jeedom.

Ajouter un interface graphique HTML au projet Arduino

Maintenant, vous voudriez certainement pouvoir réaliser une petite interface pour vos projets ESP8266. Pour cela, nous avons besoin de connaître quelques rudiments d’HTML. Nous n’allons pas aller très loin dans l’apprentissage de l’HTML, juste apprendre les éléments importants pour démarrer et avoir un projet fonctionnel. Si vous avez besoin de plus d’éléments d’interface, je vous conseille w3schools qui est une référence dans l’apprentissage de l’HTML. Le site est en anglais mais il est très clair et très simple d’accès.

Dans un projet ESP8266, on peut créer des pages HTML en dynamique, c’est à dire qu’on construit une chaine texte qui contient le code de la page qu’on va ensuite afficher. C’est ce que nous allons faire. Mais l’ESP8266 est capable également de fonctionner comme un vrai site internet, c’est à dire qu’on peut installer sur la mémoire flash les pages HTML, du code javascript, les feuilles de style CSS… Nous n’irons pas jusque là dans ce premier tutoriel.

Je vous propose de créer une petite station météo pour avoir des données à actualiser régulièrement et créer un bouton pour activer / désactiver une sortie GPIO (juste une Led, pour l’exemple. J’ai utilisé le matériel suivant

esp8266 Wemos D1 mini Module ESP8266 ESP-12 ou Wemos D1 Mini
BMP180 Capteur de pression atmosphérique

BMP180

Broches DHT22 Capteur de température et d’humidité

DHT11 ou DHT22

jumper dupont Jumper Dupont
breadboard Breadboard

Câblage

Voici un tableau de repérage et de correspondance des broches entre Arduino et ESP8266.

Composant Broches Equivalence ESP8266 (Wemos D1 mini)
DHT22 VCC 5V
GND G
Data G5
BMP180 VCC 5V
GND G
SDA D2

On commence par déclarer les librairies nécessaires. N’oubliez pas d’installer les librairies depuis le gestionnaire de bibliothèques (DHT et BMP085).

Remarque. Vous risquez de rencontrez une erreur à la compilation adafruit_Sensor.h : No such file or directory. Dans ce cas téléchargez et décompressez la librairie manuellement depuis GitHub dans le dossier Arduino -> Librairie, puis relancez l’IDE pour quelle soit prise en compte.
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <DHT.h>
#include <Adafruit_BMP085.h>

On définit les variables du programme. Modifiez le réseau WiFi sur lequel vous allez vous connecter et le mot de passe de ce dernier.

#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";

On créé les objets dht, bmp et server

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

Cette première fonction permet de construire le code HTML de la page principale du programme. C’est une simple chaine de caractère. C’est un assemblage de chaînes. On peut facilement y inclure la valeur ou l’état d’une variable (par exemple l’état d’une sortie). En retour, la fonction renvoie une chaine contenant le code HTML de la 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://www.projetsdiy.fr'>www.projetsdiy.fr</p>";
  page += "</body></html>";
  return page;
}

Voyons un peu mieux comment est construit le code

Code HTML 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 : permet de définir la langue de la page

head : c’est l’entête de la page. Il contient différentes meta (paramètres)

  • http-equiv=’refresh’ : c’est une page que le navigateur devra rafraichir. Pour plus de types, allez ici
  • content=’10’ : toutes les 10 secondes

title : le titre de la page affiché dans la barre du navigateur

style : un style pour la page (couleur de fond, font à utiliser, couleur du texte

<body> C’est le contenu de la page affiché
<h1>ESP8266 Demo</h1> Un titre affiché en haut de la page
<h3>DHT22</h3> Un titre (h3, plus petit) pour le capteur DHT22
<ul>

<li>Température : xx°C</li>

<li>Humidité : xx%</li>

</ul>

Le bloc ul permet d’afficher sous forme de liste les informations. La même chose pour le 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>

Pour actualiser le GPIO, on utilise un formulaire.

On utilise ici un bouton radio pour changer l’état (On/Off) puis on envoi (submit) le contenu du formulaire avec un bouton.

L’option name permet de nommer la variable qui contiendra l’état que l’on souhaite récupérer dans le code Arduino. Ici LED.

</body> Toute balise ouverte doit être refermée (c’est mieux !)

La fonction handleRoot permet de surveiller si on reçoit un demande d’actualisation du GPIO en surveillant si l’argument LED est renvoyé par la page. Si c’est le cas, on exécute la fonction handleSubmit. A nous de créer

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

La fonction handleSubmit traite l’actualisation du GPIO. On récupère l’état de la variable LED. Attention, c’est une chaine de caractère, on doit donc tester “1” et non pas 1. On en profite pour affecter l’état du GPIO dans la variable etatLed sous la forme d’une chaine, c’est plus sympa à lire. Enfin on actualise l’affichage de la page HTML avec server.send. On récupère la page actualisée en appelant la fonction 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");
  }
}

Maintenant que toutes les fonctions sont créées, on peut appeler la fonction setup(). Elle initialise le BMP180, la connexion WiFi, branche la fonction qui s’occupe de la page principale et enfin on lance le serveur web

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" );
  
}

Il ne reste plus qu’à exécuter la fonction loop() pour relever régulièrement les mesures sur les capteurs. Contrairement à l’exemple précédent basé sur la librairie ESP8266WiFi, ici la librairie ESP8266WebServer nécessite de brancher la fonction callback server.handleClient() qui surveille la présence d’un client et délivre la page HTML demandée.

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

Voici le code source assemblé du projet qu’il vous suffit de coller dans un nouveau projet puis le téléverser

#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://www.projetsdiy.fr'>www.projetsdiy.fr</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");
  }
  
  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);
}

Récupérez l’adresse IP de la Wemos en ouvrant le moniteur série puis connectez vous à celle-ci depuis un navigateur internet pour accéder à l’interface de la mini station météo.

 esp8266 wemos d1 mini serveur server web dht22 bmp180 gpio

Voilà, nous savons maintenant comment créer un serveur web à l’aide d’un ESP8266, piloter le GPIO et afficher des mesures en provenance de capteurs. Nous n’avons vu ici que les principaux rudiment pour débuter mais il couvrent déjà une grande partie de ce que l’on a besoin pour développer de petits objets connectés. Dans le prochain tutoriel, nous verrons comment avoir une plus belle interface graphique en utilisant Bootstrap, un framework développé par un développeur travaillant chez Tweeter qui permet de créer de plus belles interfaces graphiques en HTML.

Voilà, vous êtes prêt pour aller plus loin maintenant ! Voici d’autres tutoriels plus avancés pour aller plus loin dans vos projets DIY d’objets connectés. Amusez-vous bien !

Remarque. Tout le tutoriel a été développé sur l’IDE Arduino 1.8.1 installé sur un Orange Pi Plus 2e (présenté ici) fonctionnant sous Armbian (Ubuntu 16.04 LTS). Suivez ce tutoriel pour savoir comment installer l’IDE Arduino sur Linux (ARM ou x86).
Print Friendly, PDF & Email

Inscrivez-vous à la newsletter hebdomadaire

Aucun spam et aucun autre usage ne sera fait de votre email. Vous pouvez vous désinscrire à tout moment.

Comparateur de prix

Bons plans

Les offres suivantes se terminent bientôt. Utilisez le coupon indiqué pour profiter du prix promo

Domotique et objets connectés à faire soi-même