ESP32 Neopixel Status Indicator et Sensor PCB Shield avec Wi-Fi Manager

ESP32 Neopixel Status Indicator et Sensor PCB Shield avec Wi-Fi Manager

Dans ce projet, nous allons créer un blindage PCB indicateur d’état pour l’ESP32 comprenant deux rangées de LED néopixels RVB adressables, un capteur BME280 et un bouton-poussoir. Nous allons programmer la carte pour afficher un serveur Web avec les lectures du capteur BME280 et afficher la plage de température et d’humidité sur les LED (comme deux barres de progression). Nous allons également configurer un Wi-Fi Manager⁠—les voyants indiquent s’il est déjà connecté à un réseau Wi-Fi ou s’il est en mode point d’accès.

ESP32 Neopixel Status Indicator et Sensor PCB Shield avec Wi-Fi Manager

Le Wi-Fi Manager vous permet de connecter les cartes ESP32 à différents points d’accès (réseaux) sans avoir à coder en dur les informations d’identification du réseau (SSID et mot de passe) et à télécharger un nouveau code sur la carte. Votre ESP rejoindra automatiquement le dernier réseau enregistré ou configurera un point d’accès que vous pourrez utiliser pour configurer les informations d’identification du réseau.

En suivant ce projet, vous en apprendrez plus sur les concepts suivants :

  • Contrôler individuellement deux « bandes » de LED RVB adressables avec l’ESP32 ;
  • Créez un serveur Web avec l’ESP32 à l’aide des événements envoyés par le serveur (SSE);
  • Gérer les champs de saisie HTML pour enregistrer les données sur votre carte (SSID et mot de passe) ;
  • Enregistrez les variables de manière permanente à l’aide de fichiers sur le système de fichiers ;
  • Créez votre propre gestionnaire Wi-Fi à l’aide de la bibliothèque ESPAsyncWebServer ;
  • Basculer entre le mode station et le mode point d’accès ;
  • Et beaucoup plus…

Pour mieux comprendre le fonctionnement de ce projet, nous vous conseillons de jeter un œil aux tutoriels suivants :

Regardez le didacticiel vidéo

YouTube video

Ressources

Vous pouvez trouver toutes les ressources nécessaires pour construire ce projet dans les liens ci-dessous (ou vous pouvez visiter le Page du projet GitHub):

Aperçu du projet

Avant de passer directement au projet, examinons les fonctionnalités de PCB Shield (matériel et logiciel).

Caractéristiques du blindage PCB

Le bouclier est conçu avec des broches d’en-tête pour empiler la carte ESP32. Pour cette raison, si vous souhaitez construire et utiliser notre PCB, vous devez vous procurer la même carte de développement ESP32. Nous utilisons le Kit de développement ESP32 DOIT V1 carte (le modèle avec 36 GPIO).

Indicateur d'état ESP32 et circuit imprimé de blindage de capteur

Si vous souhaitez suivre ce projet et avoir un modèle ESP32 différent, vous pouvez assembler le circuit sur une planche à pain, ou vous pouvez modifier la disposition et le câblage du PCB pour qu’ils correspondent au brochage de votre carte ESP32. Tout au long de ce projet, nous fournissons tous les fichiers nécessaires si vous avez besoin de modifier le PCB.

De plus, vous pouvez suivre ce projet en assemblant le circuit sur une planche à pain si vous ne souhaitez pas construire un blindage PCB.

Le bouclier est composé de :

  • Capteur de température, d’humidité et de pression BME280 ;
  • Bouton;
  • Deux rangées de 5 LED RVB adressables (WS2812B).
Indicateur d'état ESP32 Bouclier de capteur LED RVB Aperçu

Si vous répliquez ce projet sur une planche à pain, au lieu de LED RVB adressables WS2812B individuelles, vous pouvez utiliser bandes LED RVB adressables.

Affectation des broches du blindage PCB

Le tableau suivant montre l’affectation des broches pour chaque composant sur le blindage :

Composant Affectation des broches ESP32
BME280 GPIO 21 (SDA), GPIO 22 (SCL)
Bouton GPIO 18
LED RVB adressables (rangée 1) GPIO 27
LED RVB adressables (rangée 2) GPIO 32

Fonctionnalités du logiciel PCB

Vous pouvez programmer le bouclier de plusieurs manières différentes. Nous allons programmer l’ESP32 pour qu’il ait les fonctionnalités suivantes :

Serveur Web

Serveur Web pour afficher les lectures du capteur BME280 : température, humidité et pression. Il affiche également l’heure de la dernière mise à jour. Les lectures sont mises à jour automatiquement toutes les 30 secondes à l’aide d’événements envoyés par le serveur. En savoir plus sur les événements envoyés par le serveur dans ce projet.

Tableau du serveur Web des lectures du capteur ESP32 BME280

Interface visuelle (DEL RVB adressables)

Les LED RVB sur le bouclier se comportent comme une barre de progression indiquant la plage de valeurs de température et d’humidité. Plus la température est élevée, plus le nombre de LED allumées est identique pour les relevés d’humidité. Les valeurs de température sont affichées dans une couleur orange/jaune et l’humidité est affichée dans une couleur bleu sarcelle.

Indicateur d'état ESP32 Bouclier du capteur Vue d'ensemble des LED RVB Lectures du capteur

Gestionnaire Wi-Fi

Le Wi-Fi Manager vous permet de connecter la carte ESP32 à différents points d’accès (réseaux) sans avoir à coder en dur les informations d’identification du réseau (SSID et mot de passe) et de télécharger un nouveau code sur votre carte. Votre ESP rejoindra automatiquement le dernier réseau enregistré ou configurera un point d’accès que vous pourrez utiliser pour configurer les informations d’identification du réseau.

Mot de passe SSID du serveur Web de la page Web du gestionnaire Wi-Fi ESP32

Lorsque la carte est en mode Access Point (Wi-Fi Manager), toutes les LED sont allumées en rouge. Lorsque la carte est en mode station (serveur Web avec relevés de capteur), toutes les LED sont temporairement allumées en vert/bleu sarcelle avant d’afficher la plage de température et d’humidité.

Indicateur d'état ESP32 Bouclier de capteur LED RVB Gestionnaire Wi-Fi

Tester le circuit sur une planche à pain

Avant de concevoir et de construire le PCB, il est important de tester le circuit sur une planche à pain. Si vous ne voulez pas faire de PCB, vous pouvez toujours suivre ce projet en assemblant le circuit sur une planche à pain.

Pièces requises

Pour assembler le circuit sur une planche à pain, vous avez besoin des pièces suivantes (les pièces pour le PCB sont présentées dans une section ultérieure) :

Vous pouvez utiliser les liens précédents ou accéder directement à MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !

1680128806 261 ESP32 Neopixel Status Indicator et Sensor PCB Shield avec Wi Fi

Après avoir rassemblé toutes les pièces, assemblez le circuit en suivant le schéma de principe suivant :

Indicateur d'état ESP32 Bouclier de capteur LED RVB Bouclier Diagramme de planche à pain

*Nous avons fini par ne pas utiliser le bouton-poussoir pour ce projet particulier, il n’est donc pas nécessaire de l’inclure dans votre circuit.


Conception du PCB

Pour concevoir le circuit et le PCB, nous avons utilisé EasyEDA, un logiciel basé sur un navigateur, pour concevoir des PCB. Si vous souhaitez personnaliser votre PCB, vous devez télécharger les fichiers suivants :

Je ne suis pas un expert en conception de PCB. Cependant, la conception de PCB simples comme celui que nous utilisons dans ce didacticiel est simple. La conception du circuit fonctionne comme dans n’importe quel autre outil logiciel de circuit, vous placez certains composants et vous les câblez ensemble. Ensuite, vous affectez chaque composant à une empreinte.

Schéma de circuit EasyEDA ESP32 Neopixel Shield PCB

Après avoir assigné les pièces, placez chaque composant. Lorsque vous êtes satisfait de la disposition, effectuez toutes les connexions et routez votre PCB.

Bouclier PCB Neopixels Easyeda ESP32

Enregistrez votre projet et exportez les fichiers Gerber.

Remarque : vous pouvez récupérer les fichiers du projet et les modifier pour personnaliser le bouclier selon vos propres besoins.

Commander les PCB chez PCBWay

Ce projet est parrainé par PCBWay. PCBWay est un service complet de fabrication de cartes de circuits imprimés.

Commander les PCB chez PCBWay

Transformez vos circuits de planche à pain de bricolage en circuits imprimés professionnels – obtenez 10 cartes pour environ 5 $ + expédition (qui variera selon votre pays).

Une fois que vous avez vos fichiers Gerber, vous pouvez commander le PCB. Suivez les étapes suivantes.

1. Téléchargez les fichiers Gerber – cliquez ici pour télécharger le fichier .zip

2. Accédez au site Web PCBWay et ouvrez la page PCB Instant Quote.

PCBWay Order PCB ouvre la page de devis instantané

3. PCBWay peut récupérer tous les détails du PCB et les remplit automatiquement pour vous. Utilisez le « PCB de commande rapide (paramètres de remplissage automatique) ».

PCBWay Commander les paramètres de remplissage automatique des PCB

4. Appuyez sur le bouton « + Ajouter un fichier Gerber » pour télécharger les fichiers Gerber fournis.

PCBWay Order PCB ajouter un bouton de fichier gerber

Et c’est tout. Vous pouvez également utiliser OnlineGerberViewer pour vérifier si votre PCB est comme il se doit.

ESP32 Neopixel PCB Shield PCBWay Visionneuse Gerber

Si vous n’êtes pas pressé, vous pouvez utiliser la méthode d’expédition China Post pour réduire considérablement vos coûts. À notre avis, nous pensons qu’ils surestiment le délai d’expédition de China Post.

PCBWay Order PCB Chine après la méthode d'expédition

Vous pouvez augmenter la quantité de votre commande de PCB et changer la couleur du masque de soudure. Comme d’habitude, nous avons commandé la couleur bleue.

ESP32 Neopixel PCB Shield PCBWay Détails

Une fois que vous êtes prêt, vous pouvez commander les PCB en cliquant sur « Enregistrer dans le panier » et terminer votre commande.

Déballage des PCB

Après environ une semaine d’utilisation de la méthode d’expédition DHL, j’ai reçu les PCB à mon bureau.

Indicateur d'état et bouclier de capteur Unboxing PCBWay

Comme d’habitude, tout est bien emballé et les PCB sont vraiment de haute qualité. Les lettres sur la sérigraphie sont vraiment bien imprimées et faciles à lire.

Nous sommes vraiment satisfaits du service PCBWay. Voici quelques autres projets que nous avons construits à l’aide du service PCBWay :

Souder les composants

Dans notre PCB, nous avons utilisé des LED SMD, des résistances SMD et des condensateurs SMD. Ceux-ci peuvent être un peu difficiles à souder, mais le PCB est bien meilleur. Si vous n’avez jamais soudé de SMD auparavant, nous vous recommandons de regarder quelques vidéos pour savoir comment procéder. Vous pouvez également vous procurer un kit de soudure SMD DIY pour vous entraîner un peu.

Voici une liste de tous les composants nécessaires pour assembler le PCB :

Indicateur d'état ESP32 et pièces de bouclier de capteur

Voici les outils de soudure que nous avons utilisés :

Mini fer à souder portatif TS80

Commencez par souder les composants SMD. Ensuite, soudez les broches de l’en-tête. Et enfin, soudez les autres composants ou utilisez des broches d’en-tête si vous ne souhaitez pas connecter les composants de manière permanente.

Voici à quoi ressemble le Shield ESP32 après avoir assemblé toutes les pièces.

Carte ESP32 Blindage PCB Neopixels

La carte ESP32 doit s’empiler parfaitement sur les broches d’en-tête de l’autre côté du PCB.

Indicateur d'état PCB Shield Stack ESP32

Programmation du bouclier

Comme mentionné précédemment, nous allons programmer la carte pour qu’elle ait les fonctionnalités suivantes :

  • Serveur Web pour afficher les lectures du capteur BME280 (mode station) ;
  • Interface visuelle (LED RVB adressables) : les LED RVB sur le bouclier se comportent comme deux barres de progression indiquant la plage de valeurs de température et d’humidité ;
  • Gestionnaire Wi-Fi : l’ESP32 rejoindra automatiquement le dernier réseau enregistré ou configurera un point d’accès que vous pourrez utiliser pour configurer les informations d’identification du réseau.

Le schéma suivant résume le fonctionnement du projet.

ESP32 Shield WiFi Manager Comment ça marche
  • Lorsque l’ESP démarre pour la première fois, il essaie de lire les fichiers ssid.txt, pass.txt et ip.txt (1) ;
  • Si les fichiers sont vides (2) (la première fois que vous lancez la carte, les fichiers sont vides), votre carte est définie comme point d’accès et toutes les LED s’allument en rouge (3) ;
  • En utilisant n’importe quel appareil compatible Wi-Fi avec un navigateur, vous pouvez vous connecter au point d’accès nouvellement créé (nom par défaut ESP-WIFI-MANAGER) ;
  • Après avoir établi une connexion avec l’ESP-WIFI-MANAGER, vous pouvez vous rendre à l’adresse IP par défaut 192.168.4.1 pour ouvrir une page Web qui vous permet de configurer votre SSID et votre mot de passe (4) ;
  • Le SSID, le mot de passe et l’adresse IP soumis sur le formulaire sont enregistrés dans les fichiers correspondants : ssid.txt, pass.txt et ip.txt (5) ;
  • Après cela, la carte ESP redémarre (6) ;
  • Cette fois, après le redémarrage, les fichiers ne sont pas vides, donc l’ESP va essayer de se connecter au réseau Wi-Fi en mode station en utilisant les paramètres que vous avez insérés sur le formulaire (7) ;
  • S’il établit une connexion, le processus est terminé avec succès (8) (toutes les LED sont temporairement allumées en vert/bleu sarcelle) ;
  • Vous pouvez accéder à la page Web principale qui affiche les lectures des capteurs (9) et les LED s’allument en fonction de la plage de température et d’humidité (10). Sinon, il définira le point d’accès (3) et vous pourrez accéder à l’adresse IP par défaut (192.168.4.1) pour ajouter une autre combinaison SSID/mot de passe.

Conditions préalables

Nous allons programmer la carte ESP32 à l’aide de l’IDE Arduino. Assurez-vous donc que le module complémentaire de carte ESP32 est installé.

Si vous souhaitez programmer l’ESP32/ESP8266 en utilisant VS Code + PlatformIO, suivez le tutoriel suivant :

Installation de bibliothèques (Arduino IDE)

Pour ce projet, vous devez installer toutes ces bibliothèques dans votre IDE Arduino.

Vous pouvez installer les quatre premières bibliothèques à l’aide du gestionnaire de bibliothèque Arduino. Accédez à Esquisse > Inclure la bibliothèque > Gérer les bibliothèques et recherchez le nom de la bibliothèque.

Les bibliothèques ESPAsyncWebServer et AsynTCP ne peuvent pas être installées via le gestionnaire de bibliothèque Arduino, vous devez donc copier les fichiers de bibliothèque dans le dossier Bibliothèques d’installation Arduino. Alternativement, dans votre IDE Arduino, vous pouvez aller à Sketch> Inclure la bibliothèque> Ajouter une bibliothèque .zip et sélectionner les bibliothèques que vous venez de télécharger.

Installation de bibliothèques (VS Code + PlatformIO)

Si vous programmez l’ESP32 à l’aide de PlatformIO, vous devez inclure les bibliothèques dans le fichier platformio.ini comme ceci :

[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32doit-devkit-v1
framework = arduino
monitor_speed = 115200
lib_deps = adafruit/Adafruit NeoPixel @ ^1.7.0
           adafruit/Adafruit Unified Sensor @ ^1.1.4
           adafruit/Adafruit BME280 Library @ ^2.1.2
           arduino-libraries/Arduino_JSON @ 0.1.0

Téléchargeur de système de fichiers

Avant de continuer, vous devez avoir installé le plugin ESP32 Uploader dans votre IDE Arduino. Suivez le tutoriel suivant avant de continuer :

Si vous utilisez VS Code avec PlatformIO, suivez le didacticiel suivant pour apprendre à télécharger des fichiers sur le système de fichiers :

Organiser vos fichiers

Pour garder le projet organisé et le rendre plus facile à comprendre, nous allons créer cinq fichiers différents pour construire le serveur Web :

  • Esquisse Arduino qui gère le serveur Web ;
  • index.html : pour définir le contenu de la page web en mode station pour afficher les relevés des capteurs ;
  • style.css : pour styliser la page Web ;
  • script.js : pour programmer le comportement de la page Web : gérer les réponses du serveur Web, les événements, mettre à jour l’heure, etc. ;
  • wifimanager.html : pour définir le contenu de la page web pour afficher le Wi-Fi Manager lorsque l’ESP32 est en mode point d’accès.
Fichiers du gestionnaire Wi-Fi du serveur Web ESP32

Vous devez enregistrer les fichiers HTML, CSS et JavaScript dans un dossier appelé data dans le dossier d’esquisse Arduino, comme indiqué dans le diagramme précédent. Nous allons télécharger ces fichiers sur le système de fichiers ESP32 (SPIFFS).

Vous pouvez télécharger tous les fichiers du projet :

Création des fichiers HTML

Pour ce projet, vous avez besoin de deux fichiers HTML. Un pour construire la page principale qui affiche les lectures des capteurs (index.html) et un autre pour construire la page Wi-Fi Manager (wifimanager.html).

index.html

Copiez ce qui suit dans le fichier index.html.

<!DOCTYPE html>
<html>
  <head>
    <title>ESP IOT DASHBOARD</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" type="image/png" href="https://www.raspberryme.com/esp32-status-indicator-sensor-pcb/favicon.png">
      <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
    <link rel="stylesheet" type="text/css" href="style.css">
  </head>
  <body>
    <div class="topnav">
      <h1>ESP WEB SERVER SENSOR READINGS</h1>
    </div>
    <div class="content">
      <div class="card-grid">
        <div class="card">
          <p class="card-title">BME280 Sensor Readings</p>
          <p>
            <table>
              <tr>
                <th>READING</th>
                <th>VALUE</th>
              </tr>
              <tr>
                <td>Temperature</td>
                <td><span id="temp"></span> &deg;C</td>
              </tr>
              <tr>
                <td>Humidity</td>
                <td><span id="hum"></span> &percnt;</td>
              </tr>
              <tr>
                <td>Pressure</td>
                <td><span id="pres"></span> hPa</td>
              </tr>
            </table>
          </p>
          <p class="update-time">Last update: <span id="update-time"></span></p>  
        </div>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>

Afficher le code brut

Ce fichier crée un tableau pour afficher les lectures des capteurs. Voici le paragraphe qui affiche le tableau :

<p>
  <table>
    <tr>
      <th>READING</th>
      <th>VALUE</th>
    </tr>
    <tr>
      <td>Temperature</td>
      <td><span id="temp"></span> &deg;C</td>
    </tr>
    <tr>
       <td>Humidity</td>
       <td><span id="hum"></span> &percnt;</td>
    </tr>
    <tr>
      <td>Pressure</td>
      <td><span id="pres"></span> hPa</td>
    </tr>
  </table>
</p>

Pour créer un tableau en HTML, commencez par les balises

et

. Cela enferme l’ensemble du tableau. Pour créer une ligne, utilisez les balises

et

. Le tableau est défini avec une série de lignes. Utilisez la paire

pour délimiter chaque ligne de données. L’en-tête du tableau est défini à l’aide des balises

et

, et chaque cellule du tableau est définie à l’aide des balises

et

.

Notez que les cellules pour afficher les lectures des capteurs ont des balises avec des identifiants spécifiques pour les manipuler ultérieurement en utilisant JavaScript pour insérer les lectures mises à jour. Par exemple, la cellule pour la valeur de température a l’id temp.

<td><span id="temp"></span> &deg;C</td>

Enfin, il y a un paragraphe pour afficher la dernière fois que les lectures ont été mises à jour :

<p class="update-time">Last update: <span id="update-time"></span></p>

Il y a une balise avec l’identifiant de mise à jour. Cela sera utilisé plus tard pour insérer la date et l’heure à l’aide de JavaScript.

wifimanager.html

Copiez ce qui suit dans le fichier wifimanager.html.

<!DOCTYPE html>
<html>
<head>
  <title>ESP Wi-Fi Manager</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
  <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
  <div class="topnav">
    <h1>ESP Wi-Fi Manager</h1>
  </div>
  <div class="content">
    <div class="card-grid">
      <div class="card">
        <form action="/" method="POST">
          <p>
            <label for="ssid">SSID</label>
            <input type="text" id ="ssid" name="ssid"><br>
            <label for="pass">Password</label>
            <input type="text" id ="pass" name="pass"><br>
            <label for="ip">IP Address</label>
            <input type="text" id ="ip" name="ip" value="192.168.1.200">
            <input type ="submit" value ="Submit">
          </p>
        </form>
      </div>
    </div>
  </div>
  <script src="script.js"></script>
</body>
</html>

Afficher le code brut

Ce fichier crée un formulaire HTML pour insérer le SSID et le mot de passe du réseau que vous souhaitez que l’ESP32 rejoigne. Vous pouvez également insérer l’adresse IP que vous souhaitez attribuer à votre ESP32. L’image suivante montre la page Web Wi-Fi Manager : trois champs de saisie et un bouton d’envoi.

Page Web du gestionnaire Wi-Fi ESP32

Nous voulons envoyer les valeurs soumises sur les champs de saisie au serveur lorsque nous cliquons sur le bouton Soumettre.

Voici le formulaire HTML avec les trois champs de saisie :

<form action="/" method="POST">
  <p>
    <label for="ssid">SSID</label>
    <input type="text" id ="ssid" name="ssid"><br>
    <label for="pass">Password</label>
    <input type="text" id ="pass" name="pass"><br>
    <label for="ip">IP Address</label>
    <input type="text" id ="ip" name="ip" value="192.168.1.200">
    <input type ="submit" value ="Submit">
  </p>
</form>

C’est le champ d’entrée pour le SSID :

<label for="ssid">SSID</label>
<input type="text" id ="ssid" name="ssid"><br>

Le champ de saisie du mot de passe :

<label for="pass">Password</label>
<input type="text" id ="pass" name="pass"><br>

Le formulaire HTML contient différents éléments de formulaire. Tous les éléments du formulaire sont inclus dans cette balise

. Il contient des contrôles (les champs de saisie) et des étiquettes pour ces contrôles.

De plus, la balise

doit inclure l’attribut action qui spécifie ce que vous voulez faire lorsque le formulaire est soumis (il redirige vers l’URL root /, afin que nous restions sur la même page). Dans notre cas, nous souhaitons envoyer ces données au serveur (ESP32) lorsque l’utilisateur clique sur le bouton Soumettre. L’attribut method spécifie la méthode HTTP (GET ou POST) utilisée lors de la soumission des données du formulaire. Dans ce cas, nous utiliserons la méthode HTTP POST.

<form action="/" method="POST">

POST est utilisé pour envoyer des données à un serveur pour créer/mettre à jour une ressource. Les données envoyées au serveur avec POST sont stockées dans le corps de la requête HTTP. Dans ce cas, après avoir soumis les valeurs dans les champs de saisie, le corps de la requête HTTP POST ressemblerait à ceci :

POST /
Host: localhost
ssid: YOUR-NETWORK-SSID
pass: YOUR-PASSWORD
ip: IP-ADDRESS

Le crée un bouton de soumission avec le texte « Submit ». Lorsque vous cliquez sur ce bouton, les données soumises dans le formulaire sont envoyées au serveur.

<input type ="submit" value ="Submit">

Et enfin, il y a un champ de saisie pour l’adresse IP que vous souhaitez attribuer à l’ESP en mode station. Par défaut, nous le définissons sur 192.168.1.200. Vous pouvez définir une autre adresse IP par défaut ou supprimer le paramètre value – il n’aura pas de valeur par défaut, le réseau attribue automatiquement une adresse IP valide à votre carte.

<label for="ip">IP Address</label>
<input type="text" id ="ip" name="ip" value="192.168.1.200">

Création du fichier CSS

Copiez les styles suivants dans votre fichier style.css.

html {
  font-family: Arial, Helvetica, sans-serif; 
  display: inline-block; 
  text-align: center;
}
h1 {
  font-size: 1.8rem; 
  color: white;
}
p { 
  font-size: 1.4rem;
}
.topnav { 
  overflow: hidden; 
  background-color: #0A1128;
}
body {  
  margin: 0;
}
.content { 
  padding: 50px;
}
.card-grid { 
  max-width: 800px; 
  margin: 0 auto; 
  display: grid; 
  grid-gap: 2rem; 
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.card { 
  background-color: white; 
  box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}
.card-title { 
  font-size: 1.2rem;
  font-weight: bold;
  color: #034078
}
th, td {
  text-align: center;
  padding: 8px;
}
tr:nth-child(even) {
  background-color: #f2f2f2
}
tr:hover {
  background-color: #ddd;
}  
th {
  background-color: #50b8b4;
  color: white;
}
table {
  margin: 0 auto;
  width: 90%
}
.update-time {
  font-size: 0.8rem;
  color:#1282A2;
}

Afficher le code brut

Ce fichier stylise les pages Web précédentes.

Création du fichier JavaScript

Copiez ce qui suit dans le fichier script.js.

// Get current sensor readings when the page loads  
window.addEventListener('load', getReadings);

//Function to add date and time of last update
function updateDateTime() {
  var currentdate = new Date(); 
  var datetime =  currentdate.getDate() + "/"
  + (currentdate.getMonth()+1)  + "/" 
  + currentdate.getFullYear() + " at "  
  + currentdate.getHours() + ":"  
  + currentdate.getMinutes() + ":" 
  + currentdate.getSeconds();
  document.getElementById("update-time").innerHTML = datetime;
  console.log(datetime);
}

// Function to get current readings on the webpage when it loads for the first time
function getReadings() {
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var myObj = JSON.parse(this.responseText);
      console.log(myObj);
      document.getElementById("temp").innerHTML = myObj.temperature;
      document.getElementById("hum").innerHTML = myObj.humidity;
      document.getElementById("pres").innerHTML = myObj.pressure;
      updateDateTime();
    }
  };
  xhr.open("GET", "/readings", true);
  xhr.send();
}

// Create an Event Source to listen for events
if (!!window.EventSource) {
  var source = new EventSource('/events');

  source.addEventListener('open', function(e) {
    console.log("Events Connected");
  }, false);

  source.addEventListener('error', function(e) {
    if (e.target.readyState != EventSource.OPEN) {
      console.log("Events Disconnected");
    }
  }, false);

  source.addEventListener('new_readings', function(e) {
    console.log("new_readings", e.data);
    var obj = JSON.parse(e.data);
    document.getElementById("temp").innerHTML = obj.temperature;
    document.getElementById("hum").innerHTML = obj.humidity;
    document.getElementById("pres").innerHTML = obj.pressure;
    updateDateTime();
  }, false);
}

Afficher le code brut

Ce JavaScript gère les événements envoyés par le serveur et met à jour les lectures des capteurs sur les lieux correspondants. Il demande également la date et l’heure chaque fois qu’une nouvelle lecture est disponible. Ce fichier demande également les dernières lectures de capteur lorsque vous ouvrez une connexion avec le serveur.

Jetons un coup d’œil au fichier JavaScript et voyons comment cela fonctionne.

Obtenir des lectures

Lorsque vous accédez à la page Web pour la première fois, celle-ci demande au serveur d’obtenir les lectures actuelles des capteurs. Sinon, nous devrons attendre l’arrivée de nouvelles lectures de capteurs (via les événements envoyés par le serveur), ce qui peut prendre un certain temps en fonction de l’intervalle que vous avez défini sur le serveur.

Ajoutez un écouteur d’événement qui appelle la fonction getReadings lors du chargement de la page Web.

window.addEventListener('load', getReadings);

L’objet window représente une fenêtre ouverte dans un navigateur. La méthode addEventListener() définit une fonction à appeler lorsqu’un certain événement se produit. Dans ce cas, nous appellerons la fonction getReadings lors du chargement des pages (« load ») pour obtenir les lectures actuelles du capteur.

fonction updateDateTime()

La fonction updateDateTime() obtient la date et l’heure actuelles et les place dans l’élément HTML avec l’identifiant update-time.

function updateDateTime() {
  var currentdate = new Date(); 
  var datetime =  currentdate.getDate() + "/"
  + (currentdate.getMonth()+1)  + "/" 
  + currentdate.getFullYear() + " at "  
  + currentdate.getHours() + ":"  
  + currentdate.getMinutes() + ":" 
  + currentdate.getSeconds();
  document.getElementById("update-time").innerHTML = datetime;
  console.log(datetime);
}

fonction getReadings()

Examinons maintenant la fonction getReadings. Il envoie une requête GET au serveur sur l’URL /readings et gère la réponse, une chaîne JSON contenant les lectures du capteur. Il place également les valeurs de température, d’humidité et de pression sur les éléments HTML avec les identifiants correspondants.

function getReadings() {
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var myObj = JSON.parse(this.responseText);
      console.log(myObj);
      document.getElementById("temp").innerHTML = myObj.temperature;
      document.getElementById("hum").innerHTML = myObj.humidity;
      document.getElementById("pres").innerHTML = myObj.pressure;
      updateDateTime();
    }
  };
  xhr.open("GET", "/readings", true);
  xhr.send();
}

Gérer les événements

Maintenant, nous devons gérer les événements envoyés par le serveur (Server-Sent Events).

Créez un nouvel objet EventSource et spécifiez l’URL de la page qui envoie les mises à jour. Dans notre cas, il s’agit de /events.

if (!!window.EventSource) {
  var source = new EventSource('/events');

Une fois que vous avez instancié une source d’événement, vous pouvez commencer à écouter les messages du serveur avec addEventListener().

Ce sont les écouteurs d’événements par défaut, comme indiqué dans AsyncWebServer Documentation.

source.addEventListener('open', function(e) {
  console.log("Events Connected");
}, false);

source.addEventListener('error', function(e) {
  if (e.target.readyState != EventSource.OPEN) {
    console.log("Events Disconnected");
  }
}, false);

Ensuite, ajoutez un écouteur d’événement pour l’événement ‘new_readings’.

source.addEventListener('new_readings', function(e) {
  console.log("new_readings", e.data);
  var obj = JSON.parse(e.data);
  document.getElementById("temp").innerHTML = obj.temperature;
  document.getElementById("hum").innerHTML = obj.humidity;
  document.getElementById("pres").innerHTML = obj.pressure;
  updateDateTime();
}, false);

Lorsque de nouvelles lectures sont disponibles, l’ESP envoie un événement (« new_readings ») au client avec une chaîne JSON qui contient les lectures du capteur.

La ligne suivante imprime le contenu du message sur la console :

console.log("new_readings", e.data);

Ensuite, convertissez les données en un objet JSON avec la méthode parse() et enregistrez-les dans la variable obj.

var obj = JSON.parse(e.data);

La chaîne JSON se présente au format suivant :

{
  "temperature" : "25",
  "humidity" : "50",
  "pressure" : "1015"
}

Vous pouvez obtenir la température avec obj.temperature, l’humidité avec obj.humidity et la pression avec obj.pressure.

Les lignes suivantes placent les données reçues dans les éléments avec les identifiants correspondants (temp, hum et pres) sur la page Web.

document.getElementById("temp").innerHTML = obj.temperature;
document.getElementById("hum").innerHTML = obj.humidity;
document.getElementById("pres").innerHTML = obj.pressure;

Esquisse Arduino

Copiez le code suivant dans votre IDE Arduino ou dans le fichier main.cpp si vous utilisez PlatformIO.

/*********
  Rui Santos
  Complete instructions at https://Raspberryme.com/esp32-status-indicator-sensor-pcb/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/

#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "SPIFFS.h"
#include <Arduino_JSON.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

// Create an Event Source on /events
AsyncEventSource events("/events");

// Search for parameter in HTTP POST request
const char* PARAM_INPUT_1 = "ssid";
const char* PARAM_INPUT_2 = "pass";
const char* PARAM_INPUT_3 = "ip";

//Variables to save values from HTML form
String ssid;
String pass;
String ip;

// File paths to save input values permanently
const char* ssidPath = "/ssid.txt";
const char* passPath = "/pass.txt";
const char* ipPath = "/ip.txt";

IPAddress localIP;
//IPAddress localIP(192, 168, 1, 200); // hardcoded

// Set your Gateway IP address
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 0, 0);

// Timer variables (check wifi)
unsigned long previousMillis = 0;
const long interval = 10000;  // interval to wait for Wi-Fi connection (milliseconds)

// WS2812B Addressable RGB LEDs
#define STRIP_1_PIN    27  // GPIO the LEDs are connected to
#define STRIP_2_PIN    32  // GPIO the LEDs are connected to
#define LED_COUNT  5  // Number of LEDs
#define BRIGHTNESS 50  // NeoPixel brightness, 0 (min) to 255 (max)
Adafruit_NeoPixel strip1(LED_COUNT, STRIP_1_PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip2(LED_COUNT, STRIP_2_PIN, NEO_GRB + NEO_KHZ800);

// Create a sensor object
Adafruit_BME280 bme;         // BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)

//Variables to hold sensor readings
float temp;
float hum;
float pres;

// Json Variable to Hold Sensor Readings
JSONVar readings;

// Timer variables (get sensor readings)
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;

//-----------------FUNCTIONS TO HANDLE SENSOR READINGS-----------------//

// Init BME280
void initBME(){
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

// Get Sensor Readings
void getSensorReadings(){
  temp = bme.readTemperature();
  hum = bme.readHumidity();
  pres= bme.readPressure()/100.0F;
}

// Return JSON String from sensor Readings
String getJSONReadings(){
  readings["temperature"] = String(temp);
  readings["humidity"] =  String(hum);
  readings["pressure"] = String(pres);
  String jsonString = JSON.stringify(readings);
  return jsonString;
}

//Update RGB LED colors accordingly to temp and hum values
void updateColors(){
  strip1.clear();
  strip2.clear();

  //Number of lit LEDs (temperature)
  int tempLEDs;
  if (temp<=0){
    tempLEDs = 1;
  }
  else if (temp>0 && temp<=10){
    tempLEDs = 2;
  }
  else if (temp>10 && temp<=20){
    tempLEDs = 3;
  }
  else if (temp>20 && temp<=30){
    tempLEDs = 4;
  }
  else{
    tempLEDs = 5;
  }

  //Turn on LEDs for temperature
  for(int i=0; i<tempLEDs; i++) {
    strip1.setPixelColor(i, strip1.Color(255, 165, 0));
    strip1.show();   
  }
  
  //Number of lit LEDs (humidity)
  int humLEDs = map(hum, 0, 100, 1, LED_COUNT);

  //Turn on LEDs for humidity
  for(int i=0; i<humLEDs; i++) { // For each pixel...
    strip2.setPixelColor(i, strip2.Color(25, 140, 200));
    strip2.show();
  }
}

//-----------------FUNCTIONS TO HANDLE SPIFFS AND FILES-----------------//

// Initialize SPIFFS
void initSPIFFS() {
  if (!SPIFFS.begin(true)) {
    Serial.println("An error has occurred while mounting SPIFFS");
  }
  else{
    Serial.println("SPIFFS mounted successfully");
  }
}

// Read File from SPIFFS
String readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s\r\n", path);

  File file = fs.open(path);
  if(!file || file.isDirectory()){
    Serial.println("- failed to open file for reading");
    return String();
  }
  
  String fileContent;
  while(file.available()){
    fileContent = file.readStringUntil('\n');
    break;     
  }
  return fileContent;
}

// Write file to SPIFFS
void writeFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Writing file: %s\r\n", path);

  File file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("- failed to open file for writing");
    return;
  }
  if(file.print(message)){
    Serial.println("- file written");
  } else {
    Serial.println("- frite failed");
  }
}

// Initialize WiFi
bool initWiFi() {
  if(ssid=="" || ip==""){
    Serial.println("Undefined SSID or IP address.");
    return false;
  }

  WiFi.mode(WIFI_STA);
  localIP.fromString(ip.c_str());

  if (!WiFi.config(localIP, gateway, subnet)){
    Serial.println("STA Failed to configure");
    return false;
  }
  WiFi.begin(ssid.c_str(), pass.c_str());
  Serial.println("Connecting to WiFi...");

  unsigned long currentMillis = millis();
  previousMillis = currentMillis;

  while(WiFi.status() != WL_CONNECTED) {
    currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      Serial.println("Failed to connect.");
      return false;
    }
  }

  Serial.println(WiFi.localIP());
  return true;
}

void setup() {
  // Serial port for debugging purposes
  Serial.begin(115200);
  
  // Initialize strips
  strip1.begin();
  strip2.begin();
  
  // Set brightness 
  strip1.setBrightness(BRIGHTNESS);
  strip2.setBrightness(BRIGHTNESS);
  
  // Init BME280 senspr
  initBME();
  
  // Init SPIFFS
  initSPIFFS();

  // Load values saved in SPIFFS
  ssid = readFile(SPIFFS, ssidPath);
  pass = readFile(SPIFFS, passPath);
  ip = readFile(SPIFFS, ipPath);
  /*Serial.println(ssid);
  Serial.println(pass);
  Serial.println(ip);*/

  if(initWiFi()) {
    // If ESP32 inits successfully in station mode light up all pixels in a teal color
    for(int i=0; i<LED_COUNT; i++) { // For each pixel...
      strip1.setPixelColor(i, strip1.Color(0, 255, 128));
      strip2.setPixelColor(i, strip2.Color(0, 255, 128));

      strip1.show();   // Send the updated pixel colors to the hardware.
      strip2.show();   // Send the updated pixel colors to the hardware.
    }

    //Handle the Web Server in Station Mode
    // Route for root / web page
    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
      request->send(SPIFFS, "/index.html", "text/html");
    });
    server.serveStatic("/", SPIFFS, "/");

    // Request for the latest sensor readings
    server.on("/readings", HTTP_GET, [](AsyncWebServerRequest *request){
      getSensorReadings();
      String json = getJSONReadings();
      request->send(200, "application/json", json);
      json = String();
    });

    events.onConnect([](AsyncEventSourceClient *client){
      if(client->lastId()){
        Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
      }
    });
    server.addHandler(&events);
    
    server.begin();
  }
  else {
    // else initialize the ESP32 in Access Point mode
    // light up all pixels in a red color
    for(int i=0; i<LED_COUNT; i++) { // For each pixel...
      strip1.setPixelColor(i, strip1.Color(255, 0, 0));
      strip2.setPixelColor(i, strip2.Color(255, 0, 0));
      //strip1.setPixelColor(i, strip1.Color(128, 0, 21));
      //strip2.setPixelColor(i, strip2.Color(128, 0, 21));

      strip1.show();   // Send the updated pixel colors to the hardware.
      strip2.show();   // Send the updated pixel colors to the hardware.
    }

    // Set Access Point
    Serial.println("Setting AP (Access Point)");
    // NULL sets an open Access Point
    WiFi.softAP("ESP-WIFI-MANAGER", NULL);

    IPAddress IP = WiFi.softAPIP();
    Serial.print("AP IP address: ");
    Serial.println(IP); 

    // Web Server Root URL For WiFi Manager Web Page
    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
      request->send(SPIFFS, "/wifimanager.html", "text/html");
    });
    
    server.serveStatic("/", SPIFFS, "/");
    
    // Get the parameters submited on the form 
    server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
      int params = request->params();
      for(int i=0;i<params;i++){
        AsyncWebParameter* p = request->getParam(i);
        if(p->isPost()){
          // HTTP POST ssid value
          if (p->name() == PARAM_INPUT_1) {
            ssid = p->value().c_str();
            Serial.print("SSID set to: ");
            Serial.println(ssid);
            // Write file to save value
            writeFile(SPIFFS, ssidPath, ssid.c_str());
          }
          // HTTP POST pass value
          if (p->name() == PARAM_INPUT_2) {
            pass = p->value().c_str();
            Serial.print("Password set to: ");
            Serial.println(pass);
            // Write file to save value
            writeFile(SPIFFS, passPath, pass.c_str());
          }
          // HTTP POST ip value
          if (p->name() == PARAM_INPUT_3) {
            ip = p->value().c_str();
            Serial.print("IP Address set to: ");
            Serial.println(ip);
            // Write file to save value
            writeFile(SPIFFS, ipPath, ip.c_str());
          }
          //Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
        }
      }
      request->send(200, "text/plain", "Done. ESP will restart, connect to your router and go to IP address: " + ip);
      delay(3000);
      // After saving the parameters, restart the ESP32
      ESP.restart();
    });
    server.begin();
  }
}

void loop() {
  // If the ESP32 is set successfully in station mode...
  if (WiFi.status() == WL_CONNECTED) {

    //...Send Events to the client with sensor readins and update colors every 30 seconds
    if (millis() - lastTime > timerDelay) {
      getSensorReadings();
      updateColors();
      
      String message = getJSONReadings();
      events.send(message.c_str(),"new_readings" ,millis());
      lastTime = millis();
    }
  }
}

Afficher le code brut

Comment fonctionne le code

Examinons le code et voyons comment cela fonctionne.

Tout d’abord, incluez toutes les bibliothèques nécessaires :

#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "SPIFFS.h"
#include <Arduino_JSON.h>
#include <Adafruit_BME280.h>

Les variables suivantes sont utilisées pour rechercher le SSID, le mot de passe et l’adresse IP sur la requête HTTP POST effectuée lors de la soumission du formulaire.

// Search for parameter in HTTP POST request
const char* PARAM_INPUT_1 = "ssid";
const char* PARAM_INPUT_2 = "pass";
const char* PARAM_INPUT_3 = "ip";

Les variables ssid, pass et ip enregistrent les valeurs du SSID, du mot de passe et de l’adresse IP soumis sur le formulaire.

// Variables to save values from HTML form
String ssid;
String pass;
String ip;

Le SSID, le mot de passe et l’adresse IP, une fois soumis, sont enregistrés dans des fichiers sur le système de fichiers ESP. Les variables suivantes font référence au chemin de ces fichiers.

// File paths to save input values permanently
const char* ssidPath = "/ssid.txt";
const char* passPath = "/pass.txt";
const char* ipPath = "/ip.txt";

L’adresse IP de la station est soumise sur le formulaire Wi-Fi Manager. Cependant, vous devez définir la passerelle et le sous-réseau dans votre code :

IPAddress localIP;
//IPAddress localIP(192, 168, 1, 200); // hardcoded

// Set your Gateway IP address
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 0, 0);

Paramètres WS2812B

Définissez les broches qui contrôlent les LED RVB. Dans ce cas, nous avons deux lignes individuelles connectées aux GPIO 27 et 32.

#define STRIP_1_PIN    27  // GPIO the LEDs are connected to
#define STRIP_2_PIN    32  // GPIO the LEDs are connected to

Définissez le nombre de LED et la luminosité. Vous pouvez modifier la luminosité si vous le souhaitez.

#define LED_COUNT  5  // Number of LEDs
#define BRIGHTNESS 20  // NeoPixel brightness, 0 (min) to 255 (max)

Enfin, initialisez deux objets Adafruit_Neopixel pour contrôler chaque bande : bande1 (température) et bande2 (humidité) :

Adafruit_NeoPixel strip1(LED_COUNT, STRIP_1_PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip2(LED_COUNT, STRIP_2_PIN, NEO_GRB + NEO_KHZ800);

initBME()

La fonction initBME() initialise le capteur BME280 sur les broches I2C par défaut ESP32 :

void initBME(){
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

En savoir plus sur le capteur BME280 : ESP32 avec capteur BME280 utilisant Arduino IDE (pression, température, humidité).

getSensorReadings()

Les fonctions getSensorReadings() obtiennent la température, l’humidité et la pression du capteur BME280 et enregistrent les valeurs des variables temp, hum et pres.

// Get Sensor Readings
void getSensorReadings(){
  temp = bme.readTemperature();
  hum = bme.readHumidity();
  pres= bme.readPressure()/100.0F;
}

getJSONReadings()

La fonction getJSONReadings() renvoie une chaîne JSON à partir des valeurs actuelles de température, d’humidité et de pression.

// Return JSON String from sensor Readings
String getJSONReadings(){
  readings["temperature"] = String(temp);
  readings["humidity"] =  String(hum);
  readings["pressure"] = String(pres);
  String jsonString = JSON.stringify(readings);
  return jsonString;
}

mettre à jour les couleurs ()

La fonction updateColors() allume les LED RVB en fonction de la plage de valeurs de température et d’humidité.

Tout d’abord, vous devez effacer les bandes à l’aide de la méthode clear() :

strip1.clear();
strip2.clear();

Nous devons déterminer combien de LED nous voulons allumer, en tenant compte des valeurs de température et d’humidité. Nous enregistrons le nombre de LED pour éclairer les variables tempLEDs et humLEDs.

Pour la température, si la température est égale ou inférieure à zéro degré Celsius, nous allumons une LED :

if (temp<=0){
  tempLEDs = 1;
}

Voici les autres gammes :

  • 0 2 LED
  • 10 3 LED
  • 20 4 LED
  • 30 5 LED
//Number of lit LEDs (temperature)
int tempLEDs;
if (temp<=0){
  tempLEDs = 1;
}
else if (temp>0 && temp<=10){
  tempLEDs = 2;
}
else if (temp>10 && temp<=20){
  tempLEDs = 3;
}
else if (temp>20 && temp<=30){
      tempLEDs = 4;
}
else{
  tempLEDs = 5;
}

Après avoir déterminé combien de LED doivent être allumées, nous devons réellement allumer ces LED. Pour allumer une LED, nous pouvons utiliser la méthode setPixelColor() sur l’objet strip1 suivie de la méthode show(). Nous avons besoin d’une boucle for pour allumer toutes les LED.

//Turn on LEDs for temperature
for(int i=0; i<tempLEDs; i++) {
  strip1.setPixelColor(i, strip1.Color(255, 165, 0));
  strip1.show();   
}

Nous suivons une procédure similaire pour l’humidité. Tout d’abord, déterminez combien de LED doivent être allumées :

//Number of lit LEDs (humidity)
int humLEDs = map(hum, 0, 100, 1, LED_COUNT);

Et enfin, allumez les leds d’humidité (strip2) :

for(int i=0; i<humLEDs; i++) { // For each pixel...
  strip2.setPixelColor(i, strip2.Color(25, 140, 200));
  strip2.show();
}

initSPIFFS()

Cette fonction initialise le système de fichiers ESP32 SPIFFS. Dans ce projet, nous sauvegardons les fichiers HTML, CSS et JavaScript pour créer les pages du serveur Web sur le système de fichiers. Nous avons également les fichiers .txt pour enregistrer le SSID, le mot de passe et l’adresse IP.

void initSPIFFS() {
  if (!SPIFFS.begin(true)) {
    Serial.println("An error has occurred while mounting SPIFFS");
  }
  else{
    Serial.println("SPIFFS mounted successfully");
  }
}

lireFichier()

La fonction readFile() lit et renvoie le contenu d’un fichier.

String readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s\r\n", path);

  File file = fs.open(path);
  if(!file || file.isDirectory()){
    Serial.println("- failed to open file for reading");
    return String();
  }
  
  String fileContent;
  while(file.available()){
    fileContent = file.readStringUntil('\n');
    break;     
  }
  return fileContent;
}

écrireFichier()

Les fonctions writeFile() écrivent du contenu dans un fichier.

void writeFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Writing file: %s\r\n", path);

  File file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("- failed to open file for writing");
    return;
  }
  if(file.print(message)){
    Serial.println("- file written");
  } else {
    Serial.println("- frite failed");
  }
}

initWiFi()

La fonction initWiFi() renvoie une valeur booléenne (vraie ou fausse) indiquant si la carte ESP s’est connectée avec succès à un réseau.

Tout d’abord, il vérifie si les variables ssid et ip sont vides. Si c’est le cas, il ne pourra pas se connecter à un réseau, il renvoie donc false.

if(ssid=="" || ip==""){
  Serial.println("Undefined SSID or IP address.");
  return false;
}

Si ce n’est pas le cas, nous essaierons de nous connecter au réseau en utilisant le SSID et le mot de passe enregistrés sur les variables SSID et pass et de définir l’adresse IP.

WiFi.mode(WIFI_STA);
localIP.fromString(ip.c_str());

if (!WiFi.config(localIP, gateway, subnet)){
  Serial.println("STA Failed to configure");
  return false;
}
WiFi.begin(ssid.c_str(), pass.c_str());
Serial.println("Connecting to WiFi...");

Si au bout de 10 secondes (variable d’intervalle), il n’arrive pas à se connecter au Wi-Fi, il renverra faux.

unsigned long currentMillis = millis();
previousMillis = currentMillis;

while(WiFi.status() != WL_CONNECTED) {
  currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    Serial.println("Failed to connect.");
    return false;
  }
}

Serial.println(WiFi.localIP());

Si aucune des conditions précédentes n’est remplie, cela signifie que l’ESP s’est connecté avec succès au réseau en mode station (renvoie vrai).

return true;

installation()

Dans setup(), initialisez le Serial Monitor.

Serial.begin(115200);

Initialisez les rangées de LED RVB adressables (bandes) :

// Initialize strips
strip1.begin();
strip2.begin();

Réglez la luminosité des bandes. Vous pouvez modifier la luminosité sur la variable BRIGTHNESS.

// Set brightness 
strip1.setBrightness(BRIGHTNESS);
strip2.setBrightness(BRIGHTNESS);

Appelez la fonction initBME() pour initialiser le capteur :

// Init BME280 senspr
initBME();

Initialisez le système de fichiers :

// Init SPIFFS
initSPIFFS();

Lisez les fichiers pour obtenir le SSID, le mot de passe et l’adresse IP précédemment enregistrés.

// Load values saved in SPIFFS
ssid = readFile(SPIFFS, ssidPath);
pass = readFile(SPIFFS, passPath);
ip = readFile(SPIFFS, ipPath);

Si l’ESP se connecte avec succès en mode station (la fonction initWiFi() renvoie true) :

if(initWiFi()) {

Allumez toutes les LED de couleur bleu sarcelle, afin que nous sachions que l’ESP32 s’est connecté avec succès à un réseau Wi-Fi :

// If ESP32 inits successfully in station mode light up all pixels in a teal color
for(int i=0; i<LED_COUNT; i++) { // For each pixel...
  strip1.setPixelColor(i, strip1.Color(0, 255, 128));
  strip2.setPixelColor(i, strip2.Color(0, 255, 128));

  strip1.show();   // Send the updated pixel colors to the hardware.
  strip2.show();   // Send the updated pixel colors to the hardware.
}

Ensuite, nous pouvons définir les commandes pour gérer les requêtes du serveur Web. Envoyez le fichier index.html, lorsque vous accédez à l’URL root :

//Handle the Web Server in Station Mode
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
  request->send(SPIFFS, "/index.html", "text/html");
});

Envoyez les fichiers CSS et JavaScript demandés par le fichier HTML (qui sont également enregistrés dans SPIFFS) :

server.serveStatic("/", SPIFFS, "/");

Lorsque vous accédez à la page du serveur Web pour la première fois, il fait une demande au serveur sur l’URL /lectures demandant les dernières lectures du capteur. Lorsque cela se produit, envoyez la chaîne JSON avec les lectures :

// Request for the latest sensor readings
server.on("/readings", HTTP_GET, [](AsyncWebServerRequest *request){
  getSensorReadings();
  String json = getJSONReadings();
  request->send(200, "application/json", json);
  json = String();
});

Configurez les événements envoyés par le serveur sur le serveur :

events.onConnect([](AsyncEventSourceClient *client){
  if(client->lastId()){
    Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
  }
});
server.addHandler(&events);

Enfin, démarrez le serveur :

server.begin();

Si l’ESP32 ne peut pas se connecter à un réseau Wi-Fi, la fonction initWiFi() renvoie false. Dans ce cas, allumez toutes les LED en rouge, pour que l’on sache que l’ESP32 sera en mode point d’accès :

for(int i=0; i<LED_COUNT; i++) { // For each pixel...
  strip1.setPixelColor(i, strip1.Color(128, 0, 21));
  strip2.setPixelColor(i, strip2.Color(128, 0, 21));

  strip1.show();   // Send the updated pixel colors to the hardware.
  strip2.show();   // Send the updated pixel colors to the hardware.
}

Configurez l’ESP comme point d’accès :

// Set Access Point
Serial.println("Setting AP (Access Point)");
// NULL sets an open Access Point
WiFi.softAP("ESP-WIFI-MANAGER", NULL);

IPAddress IP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(IP); 

Pour définir un point d’accès, on utilise la méthode softAP() et on passe en argument le nom du point d’accès et le mot de passe. Nous voulons que le point d’accès soit ouvert, nous définissons donc le mot de passe sur NULL. Vous pouvez ajouter un mot de passe si vous le souhaitez. Pour en savoir plus sur la configuration d’un point d’accès, lisez le didacticiel suivant :

Lorsque vous accédez au point d’accès, il affiche la page Web pour saisir les informations d’identification du réseau sur le formulaire. Ainsi, l’ESP doit envoyer le fichier wifimanager.html lorsqu’il reçoit une requête sur la root/URL.

// Web Server Root URL For WiFi Manager Web Page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send(SPIFFS, "/wifimanager.html", "text/html");
});

Nous devons également gérer ce qui se passe lorsque le formulaire est soumis via une requête HTTP POST.

Les lignes suivantes enregistrent les valeurs soumises sur les variables ssid, pass et ip et enregistrent ces variables sur les fichiers correspondants.

// Get the parameters submited on the form 
server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
  int params = request->params();
  for(int i=0;i<params;i++){
    AsyncWebParameter* p = request->getParam(i);
    if(p->isPost()){
      // HTTP POST ssid value
      if (p->name() == PARAM_INPUT_1) {
        ssid = p->value().c_str();
        Serial.print("SSID set to: ");
        Serial.println(ssid);
        // Write file to save value
        writeFile(SPIFFS, ssidPath, ssid.c_str());
      }
      // HTTP POST pass value
      if (p->name() == PARAM_INPUT_2) {
        pass = p->value().c_str();
        Serial.print("Password set to: ");
        Serial.println(pass);
        // Write file to save value
        writeFile(SPIFFS, passPath, pass.c_str());
      }
      // HTTP POST ip value
      if (p->name() == PARAM_INPUT_3) {
        ip = p->value().c_str();
        Serial.print("IP Address set to: ");
        Serial.println(ip);
        // Write file to save value
        writeFile(SPIFFS, ipPath, ip.c_str());
      }
      //Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
    }
  }

Après avoir soumis le formulaire, envoyez une réponse avec du texte, afin que nous sachions que l’ESP a reçu les détails du formulaire :

request->send(200, "text/plain", "Done. ESP will restart, connect to your router and go to IP address: " + ip);

Après trois secondes, redémarrez la carte ESP avec ESP.restart() :

delay(3000);
// After saving the parameters, restart the ESP32
ESP.restart();

Après le redémarrage, la carte aura le SSID et le mot de passe enregistrés sur les fichiers, et elle s’initialisera avec succès en mode station.

boucle()

Dans la boucle (), vérifiez si l’ESP32 est correctement connecté à une station Wi-Fi :

if (WiFi.status() == WL_CONNECTED) {

Si c’est le cas, procédez comme suit toutes les 30 secondes (variable timerDelay) :

  • obtenir les dernières lectures de capteur : appelez la fonction getSensorReadings() ;
  • mettez à jour les couleurs des LED RVB pour qu’elles correspondent aux valeurs de température et d’humidité : appelez les fonctions updateColors() ;
  • envoyer un événement au navigateur avec les dernières lectures de capteur au format JSON.
if (millis() - lastTime > timerDelay) {
  getSensorReadings();
  updateColors();
      
  String message = getJSONReadings();
  events.send(message.c_str(),"new_readings" ,millis());
  lastTime = millis();
}

Manifestation

Après avoir téléchargé avec succès tous les fichiers, vous pouvez ouvrir le moniteur série. S’il exécute le code pour la première fois, il essaiera de lire les fichiers ssid.txt, pass.txt et ip.txt et il ne réussira pas car ces fichiers n’ont pas encore été créés. Ainsi, il démarrera un point d’accès.

Moniteur série Mode point d'accès ESP32

Toutes les LED du shield s’allumeront en rouge, indiquant que la carte est configurée comme point d’accès.

Indicateur d'état ESP32 Capteur PCB Bouclier Mode Point d'accès

Sur votre ordinateur ou votre smartphone, rendez-vous dans vos paramètres réseau et connectez-vous au point d’accès ESP-WIFI-MANAGER.

Carte ESP32 Wi-Fi Manager Point d'accès serveur web SSID mot de passe

Ensuite, ouvrez votre navigateur et accédez à 192.168.4.1. La page Web du gestionnaire Wi-Fi devrait s’ouvrir.

Serveur Web de la page Web ESP32 Wi-Fi Manager

Entrez vos identifiants réseau : SSID et mot de passe et une adresse IP disponible sur votre réseau local. Après cela, vous serez redirigé vers la page suivante :

ESP32 connecté au succès de la station Wi-Fi Manager

En même temps, l’ESP devrait imprimer ce qui suit dans le Serial Monitor indiquant que les paramètres que vous avez insérés ont été enregistrés avec succès sur les fichiers correspondants :

Serveur Web ESP32 Wi-Fi Manager Web Page Démonstration du moniteur série Arduino IDE

Après quelques secondes, l’ESP redémarrera. Et si vous avez inséré le bon SSID et le bon mot de passe, il démarrera en mode station :

Serveur Web ESP32 Wi-Fi Manager Web Page Démonstration du moniteur série Arduino IDE

Toutes les LED sur le bouclier seront allumées en bleu sarcelle pendant 30 secondes.

Indicateur d'état ESP32 Capteur PCB Shield Mode Station

Cette fois, ouvrez un navigateur sur votre réseau local et insérez l’adresse IP ESP. Vous devriez avoir accès à la page Web qui affiche les lectures du capteur :

Tableau du serveur Web des lectures du capteur ESP32 BME280

Les LED sur le bouclier s’allumeront en fonction de la plage de température et d’humidité.

Indicateur d'état ESP32 capteur PCB Shield Station Mode température humidité

Remarque : la photo précédente et l’écran d’impression du serveur Web ont été prises à des moments différents (c’est pourquoi les valeurs du tableau ne correspondent pas au nombre de voyants allumés). Vous pouvez aussi regarder la vidéo de démonstration.

Conclusion

Dans ce didacticiel, vous avez appris à créer un bouclier pour l’ESP32 avec un capteur BME280, deux rangées de LED RVB adressables et un bouton-poussoir. Vous avez également appris à configurer un gestionnaire Wi-Fi pour vos projets de serveur Web. Avec le Wi-Fi Manager, vous pouvez facilement connecter vos serveurs Web ESP à différents réseaux sans avoir à coder en dur les informations d’identification du réseau. Vous pouvez appliquer le Wi-Fi Manager à n’importe quel projet de serveur Web.

Si vous aimez ce tutoriel, nous avons d’autres projets similaires qui incluent la construction et la conception de PCB :

En savoir plus sur l’ESP32 avec nos ressources :

[Update] le cadeau PCB nu a pris fin et les gagnants sont: Hai, Hasse Lorentzon, Tuan Hazeem, Paul Smulders et Sudhir Gupta.

Cette vidéo vous emmène dans l’histoire de Raspberry Pi :

YouTube video

  • ESP32-S3 Contrôle Industriel, Intégrées RS485 et Can Interfaces pour Connecter des Périphériques RS485 et Can Externes, Support 2.4GHz Wi-FI/Bluetooth 5, Circuits de Protection Multiples
  • ELEGOO 3PCS Carte de Développement ESP32 Type-C, 2,4 GHz WiFi + Bluetooth Dual Core Carte de Contrôle pour Arduino, Support MicroPython, NodeMCU, AP/STA/AP+STA, Puce CP2102