Installation. De la connexion au WiFi à la page Web dynamique

Installation des outils

Elle repose sur l'installation des éléments suivantes :

  • l'IDE Arduino dans sa dernière version,
  • Visual Studio Code,
  • l'extension Arduino pour VS Code (version Microsoft).

En vidéo :

On ajoute ensuite les fichiers de définition des cartes à base d'ESP8266 dans Arduino.

Première application

Dans cette première application, on s'intéresse aux entrées/sorties. Je vous propose de câbler un circuit muni d'un bouton poussoir et d'une LED et vous explique comment coder un programme qui recopie l'état du bouton poussoir sur la LED. Enfin, le bouton poussoir est remplacé par un détecteur de mouvement.

Se connecter au réseau WiFi et gérer les événements WiFi

Dans cette partie, on découvre comment se connecter au réseau en abordant la gestion des événements de l'objet WiFi, ce que ne font pas les exemples courants dont la programmation bloquante est problématique. On commence par la création du projet et la connexion au réseau puis on procède à l'affichage d'informations diverses dont l'adresse IP. La fin de la vidéo s'attache à montrer comment utiliser les événements de l'objet WiFi pour prendre en compte les connexions, obtention d'adresse IP et déconnexion au moment où ils surviennent.

Code développé dans la vidéo :

#include "Arduino.h"
#include "ESP8266WiFi.h"
#include "InfoConnexion.h"

// Définition des entrées/sorties
#define PIN_LED_ROUGE 5
#define PIN_LED_VERTE 4

// Informations de connexion : cachées dans fichier InfoConnexion.h
// Vous pouvez décommenter ici ou créer comme moi un fichier InfoConnexion.h
//const char * SSID = "A définir";
//const char * PASSWORD = "A définir";

// Gestion des événements du WiFi
// Lorsque la connexion vient d'aboutir
void onConnected(const WiFiEventStationModeConnected& event);
// Lorsque l'adresse IP est attribuée
void onGotIP(const WiFiEventStationModeGotIP& event);

void setup() {

  // Mise en place d'une liaison série
  Serial.begin(9600L);
  delay(100);

  // Configuration des entrées/sorties
  pinMode(PIN_LED_ROUGE, OUTPUT);
  pinMode(PIN_LED_VERTE, OUTPUT);

  // Mode de connexion
  WiFi.mode(WIFI_STA);

  // Mode point d'accès
  WiFi.softAP("Objet LED");
 
  // Démarrage de la connexion
  WiFi.begin(SSID, PASSWORD);

  static WiFiEventHandler onConnectedHandler = WiFi.onStationModeConnected(onConnected);
  static WiFiEventHandler onGotIPHandler = WiFi.onStationModeGotIP(onGotIP);
}

void loop() {
  // Si l'objet est connecté au réseau, on effectue les tâches qui doivent l'être dans ce cas
  if (WiFi.isConnected()) {
    digitalWrite(PIN_LED_ROUGE, HIGH);
  }
  else {
    digitalWrite(PIN_LED_ROUGE, LOW);
  }

}

void onConnected(const WiFiEventStationModeConnected& event) {
  Serial.println("WiFi connecté");
  Serial.println("Adresse IP : " + WiFi.localIP().toString());
}

void onGotIP(const WiFiEventStationModeGotIP& event) {
  Serial.println("Adresse IP : " + WiFi.localIP().toString());
  Serial.println("Passerelle IP : " + WiFi.gatewayIP().toString());
  Serial.println("DNS IP : " + WiFi.dnsIP().toString());
  Serial.print("Puissance de réception : ");
  Serial.println(WiFi.RSSI());
}

Mettre en place un serveur Web

On découvre maintenant comment mettre en place un serveur Web de façon à pouvoir agir à distance, via un navigateur, sur le comportement de l'ESP8266. Ici, on allume ou on éteint une LED.

Code développé dans la vidéo :

#include "Arduino.h"
#include "ESP8266WiFi.h"
#include "InfoConnexion.h"
#include "ESP8266WebServer.h"

// Définition des entrées/sorties
#define PIN_LED_ROUGE 5
#define PIN_LED_VERTE 4

// Informations de connexion : cachées dans fichier InfoConnexion.h
// Vous pouvez décommenter ici ou créer comme moi un fichier InfoConnexion.h
//const char * SSID = "Votre SSID";
//const char * PASSWORD = "Votre mot de passe";

// Gestion des événements du WiFi
// Lorsque la connexion vient d'aboutir
void onConnected(const WiFiEventStationModeConnected& event);
// Lorsque l'adresse IP est attribuée
void onGotIP(const WiFiEventStationModeGotIP& event);

// Objet WebServer
ESP8266WebServer serverWeb(80);

// Fonctions du serveur Web
void switchLedOn() {
  digitalWrite(PIN_LED_VERTE, HIGH);
  serverWeb.send(200, "text/html", "Led On");
}

void switchLedOff() {
  digitalWrite(PIN_LED_VERTE, LOW);
  serverWeb.send(200, "text/html", "Led Off");
}

void handleRoot() {
  serverWeb.send(200, "text/html", "Page principale");
}

void setup() {

  // Mise en place d'une liaison série
  Serial.begin(9600L);
  delay(100);

  // Configuration des entrées/sorties
  pinMode(PIN_LED_ROUGE, OUTPUT);
  pinMode(PIN_LED_VERTE, OUTPUT);

  // Mode de connexion
  WiFi.mode(WIFI_STA);
 
  // Démarrage de la connexion
  WiFi.begin(SSID, PASSWORD);

  static WiFiEventHandler onConnectedHandler = WiFi.onStationModeConnected(onConnected);
  static WiFiEventHandler onGotIPHandler = WiFi.onStationModeGotIP(onGotIP);

  // Mise en place du serveur WebServer
  serverWeb.on("/switchLedOn", switchLedOn);
  serverWeb.on("/switchLedOff", switchLedOff);
  serverWeb.on("/", handleRoot);
  serverWeb.begin();
}

void loop() {
  // Si l'objet est connecté au réseau, on effectue les tâches qui doivent l'être dans ce cas
  if (WiFi.isConnected()) {
    digitalWrite(PIN_LED_ROUGE, HIGH);
    serverWeb.handleClient();
  }
  else {
    digitalWrite(PIN_LED_ROUGE, LOW);
  }

}

void onConnected(const WiFiEventStationModeConnected& event) {
  Serial.println("WiFi connecté");
  Serial.println("Adresse IP : " + WiFi.localIP().toString());
}

void onGotIP(const WiFiEventStationModeGotIP& event) {
  Serial.println("Adresse IP : " + WiFi.localIP().toString());
  Serial.println("Passerelle IP : " + WiFi.gatewayIP().toString());
  Serial.println("DNS IP : " + WiFi.dnsIP().toString());
  Serial.print("Puissance de réception : ");
  Serial.println(WiFi.RSSI());
}

Créer une page Web pour changer l'état d'une LED à distance

Maintenant que l'on sait traiter des requêtes html permettant de piloter le module par le WiFi, je vous propose de voir comment ajouter une page Web pour réaliser l'interface homme-machine du module. L'approche proposée ici repose l'usage de la directive PROGMEM pour stocker la page html dans la mémoire flash de l'ESP8266 et l'import cette page dans un objet String pour la modifier et indiquer l'état de la LED.

Code développé dans la vidéo :

#include "Arduino.h"
#include "ESP8266WiFi.h"
#include "InfoConnexion.h"
#include "ESP8266WebServer.h"

// Définition des entrées/sorties
#define PIN_LED_ROUGE 5
#define PIN_LED_VERTE 4

// Page html
const char index_html[] PROGMEM = R"=====(
  <!doctype html>
<html lang="fr">
    <head>
        <meta charset="utf-8">
        <title>Commande LED</title>
    </head>
    <body>
        <a href="/switchLedOn">
            <button>Allumer la LED</button>
        </a>
        <a href="/switchLedOff">
            <button>Eteindre la LED</button>
        </a>
    </body>
</html>
)=====";

// Informations de connexion : cachées dans fichier InfoConnexion.h
// Vous pouvez décommenter ici ou créer comme moi un fichier InfoConnexion.h
//const char * SSID = "Votre SSID";
//const char * PASSWORD = "Votre mot de passe";

// Gestion des événements du WiFi
// Lorsque la connexion vient d'aboutir
void onConnected(const WiFiEventStationModeConnected& event);
// Lorsque l'adresse IP est attribuée
void onGotIP(const WiFiEventStationModeGotIP& event);

// Objet WebServer
ESP8266WebServer serverWeb(80);

// Fonctions du serveur Web
void handleRoot() {
  serverWeb.send(200, "text/html", index_html);
}

void switchLedOn() {
  digitalWrite(PIN_LED_VERTE, HIGH);
  handleRoot();
}

void switchLedOff() {
  digitalWrite(PIN_LED_VERTE, LOW);
  handleRoot();
}

void setup() {
  // Mise en place d'une liaison série
  Serial.begin(9600L);
  delay(100);

  // Configuration des entrées/sorties
  pinMode(PIN_LED_ROUGE, OUTPUT);
  pinMode(PIN_LED_VERTE, OUTPUT);

  // Mode de connexion
  WiFi.mode(WIFI_STA);
 
  // Démarrage de la connexion
  WiFi.begin(SSID, PASSWORD);

  static WiFiEventHandler onConnectedHandler = WiFi.onStationModeConnected(onConnected);
  static WiFiEventHandler onGotIPHandler = WiFi.onStationModeGotIP(onGotIP);

  // Mise en place du serveur WebServer
  serverWeb.on("/switchLedOn", switchLedOn);
  serverWeb.on("/switchLedOff", switchLedOff);
  serverWeb.on("/", handleRoot);
  serverWeb.on("/index.html", handleRoot);
  serverWeb.begin();
}

void loop() {
  // Si l'objet est connecté au réseau, on effectue les tâches qui doivent l'être dans ce cas
  if (WiFi.isConnected()) {
    digitalWrite(PIN_LED_ROUGE, HIGH);
    serverWeb.handleClient();
  }
  else {
    digitalWrite(PIN_LED_ROUGE, LOW);
  }

}

void onConnected(const WiFiEventStationModeConnected& event) {
  Serial.println("WiFi connecté");
  Serial.println("Adresse IP : " + WiFi.localIP().toString());
}

void onGotIP(const WiFiEventStationModeGotIP& event) {
  Serial.println("Adresse IP : " + WiFi.localIP().toString());
  Serial.println("Passerelle IP : " + WiFi.gatewayIP().toString());
  Serial.println("DNS IP : " + WiFi.dnsIP().toString());
  Serial.print("Puissance de réception : ");
  Serial.println(WiFi.RSSI());
}

Rendre la page WEB dynamique

Il s'agit d'apporter une amélioration de la vidéo présentant la mise en place d'une page Web permettant le contrôle d'une LED à distance.
La page n'est plus rechargée à chaque interaction de l'utilisateur. Seule l'information d'état de la LED est mise à jour à partir d'un appel au serveur pour allumer ou éteindre la LED par un mécanisme de type AJAX avec l'avantage de limiter le trafic entre l'objet connecté et le navigateur. Un autre atout important est la disparition du scintillement provoqué par les mises à jour de la page Web lorsque celles-ci concernent la totalité de la page.

Code développé dans la vidéo avec correction %LED% a été ajouté à la page html pour que l'état de la LED soit renseigné lorsque la page d'index est appelée :

#include "Arduino.h"
#include "ESP8266WiFi.h"
#include "InfoConnexion.h"
#include "ESP8266WebServer.h"

// Définition des entrées/sorties
#define PIN_LED_ROUGE 5
#define PIN_LED_VERTE 4

// Page html
const char index_html[] PROGMEM = R"=====(
<!doctype html>
<html lang="fr">
    <head>
        <meta charset="utf-8">
        <title>Commande LED</title>
    </head>
    <body>
        <h1>Etat de la LED</h1>
        <h2 id="etatLED">%LED%</h2>
        <h1>Commande de la LED</h1>
        <button onclick="appelServeur('/switchLedOn', traiteReponse)">Allumer la LED</button>
        <button onclick="appelServeur('/switchLedOff', traiteReponse)">Eteindre la LED</button>

        <script>
            function appelServeur(url, cFonction) {
                var xhttp = new XMLHttpRequest();
                xhttp.onreadystatechange = function() {
                    if (this.readyState == 4 && this.status == 200) {
                        cFonction(this);
                    }
                };
                xhttp.open("GET", url, true);
                xhttp.send();
            }
            function traiteReponse(xhttp) {
                document.getElementById("etatLED").innerHTML = "LED " + xhttp.responseText;
            }
        </script>
    </body>
</html>
)=====";

// Informations de connexion : cachées dans fichier InfoConnexion.h
// Vous pouvez décommenter ici ou créer comme moi un fichier InfoConnexion.h
//const char * SSID = "Votre SSID";
//const char * PASSWORD = "Votre mot de passe";

// Gestion des événements du WiFi
// Lorsque la connexion vient d'aboutir
void onConnected(const WiFiEventStationModeConnected& event);
// Lorsque l'adresse IP est attribuée
void onGotIP(const WiFiEventStationModeGotIP& event);

// Objet WebServer
ESP8266WebServer serverWeb(80);

// Fonctions du serveur Web
void handleRoot() {
  String temp(reinterpret_cast<const __FlashStringHelper *> (index_html));
  if (digitalRead(PIN_LED_VERTE) == HIGH) temp.replace("%LED%", "LED allumée"); else temp.replace("%LED%", "LED éteinte"); 
  serverWeb.send(200, "text/html", temp);
}

void switchLedOn() {
  digitalWrite(PIN_LED_VERTE, HIGH);
  serverWeb.send(200, "text/plain", "allumée");
}

void switchLedOff() {
  digitalWrite(PIN_LED_VERTE, LOW);
  serverWeb.send(200, "text/plain", "éteinte");
}

void setup() {
  // Mise en place d'une liaison série
  Serial.begin(9600L);
  delay(100);

  // Configuration des entrées/sorties
  pinMode(PIN_LED_ROUGE, OUTPUT);
  pinMode(PIN_LED_VERTE, OUTPUT);

  // Mode de connexion
  WiFi.mode(WIFI_STA);
 
  // Démarrage de la connexion
  WiFi.begin(SSID, PASSWORD);

  static WiFiEventHandler onConnectedHandler = WiFi.onStationModeConnected(onConnected);
  static WiFiEventHandler onGotIPHandler = WiFi.onStationModeGotIP(onGotIP);

  // Mise en place du serveur WebServer
  serverWeb.on("/switchLedOn", switchLedOn);
  serverWeb.on("/switchLedOff", switchLedOff);
  serverWeb.on("/", handleRoot);
  serverWeb.on("/index.html", handleRoot);
  serverWeb.begin();
}

void loop() {
  // Si l'objet est connecté au réseau, on effectue les tâches qui doivent l'être dans ce cas
  if (WiFi.isConnected()) {
    digitalWrite(PIN_LED_ROUGE, HIGH);
    serverWeb.handleClient();
  }
  else {
    digitalWrite(PIN_LED_ROUGE, LOW);
  }

}

void onConnected(const WiFiEventStationModeConnected& event) {
  Serial.println("WiFi connecté");
  Serial.println("Adresse IP : " + WiFi.localIP().toString());
}

void onGotIP(const WiFiEventStationModeGotIP& event) {
  Serial.println("Adresse IP : " + WiFi.localIP().toString());
  Serial.println("Passerelle IP : " + WiFi.gatewayIP().toString());
  Serial.println("DNS IP : " + WiFi.dnsIP().toString());
  Serial.print("Puissance de réception : ");
  Serial.println(WiFi.RSSI());
}