Ligne 1 379 : | Ligne 1 379 : | ||
d'ailleurs si même une seule carte à un endroit, id unique utile (MQTT par exemple). Introduire cette notion plus haut ? | d'ailleurs si même une seule carte à un endroit, id unique utile (MQTT par exemple). Introduire cette notion plus haut ? | ||
}} | }} | ||
− | {{Notes | + | {{Notes}} |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | }} | ||
{{Tuto Status | {{Tuto Status | ||
|Complete=Draft | |Complete=Draft | ||
}} | }} |
Auteur Philippe Blusseau | Dernière modification 6/02/2023 par Philby
Wi-Fi, HTTP, MQTT, JSON Code_minimal_des_fonctions_r_seau_WiKi_Reseau.png
Cette expérience regroupe différentes manières de bénéficier des capacités de communication des cartes compatibles Arduino possédant une puce Wi-Fi. On suppose (Cf. "Expériences ré-requises" ci-après) que vous avez déjà manipulé une carte Arduino et son environnement de développement. Toutes les étapes décrites ici sont en fait indépendantes :
Dans la même philosophie que les expériences "Code minimal des capteurs pour Arduino" et "Code minimal des actionneurs pour Arduino", nous fournirons ici uniquement le code relatif à nos besoins de connexion, sans mettre au point une quelconque application. Donc, ici, pas besoin de connecter une led ou un capteur, donc pas de schéma de montage : vous branchez simplement votre carte en USB sur votre ordinateur, et les résultats seront visibles en mode texte dans le moniteur série de l'environnement de développement Arduino.
Il existe bien sûr déjà un tas de tutoriels avec des exemples similaires, sans compter bien sûr les exemples fournis avec les bibliothèques que l'on va utiliser (2). La modeste contribution de de cette page est de tenter de regrouper les cas de figures les plus importants. S'il en manque, n'hésitez pas à mettre un commentaire, voire à ajouter une étape !
(1) Pas d'inquiétude sur les "JSON "et autre "MQTT", on explique tout dans les étapes correspondantes
Cette première étape permet à un Wemos D1 mini (ou autre carte compatible Arduino avec puce Wi-Fi) de se connecter au Wi-Fi dans un environnement connu, et qui ne change pas ; C'est-à-dire que l'on à accès à une borne Wi-Fi, on connait son mot de passe - aka "clé de sécurité réseau", et a priori la carte va rester dans cet environnement.
Ces bibliothèques sont pré-chargées dans l'environnement Arduino, il n'est pas nécessaire d'aller les chercher dans le gestionnaire de bibliothèques.
Connexion Wi-Fi de base | ||
Avant le Setup | Importation de la bibliothèque | #include <ESP8266WiFi.h> // Pour le Wemos D1 Mini, ou ...
#include <WiFi.h> // ... Pour l'ESP32 |
Création de l’objet | ||
Dans le Setup | Démarrage de la connexion | WiFi.begin(SSID, SecKey) ; // Où SSID est le nom du point d'accès Wi-Fi, et SecKey son mot de passe |
Test de la connexion | if (WiFi.Status() == WL_CONNECTED) { (...) } | |
Récupération de l'adresse IP | WiFi.localIP() ; | |
Dans le Loop | Utilisation | Le test de la connexion, et la récupération de l'adresse IP peuvent aussi être utilisés dans le loop(). |
Pour connaître toutes les autres possibilités de ces bibliothèques, voir leurs références, respectivement ici (D1 Mini) et ici (ESP32).
1 /* =========================================================================================================
2 *
3 * CODE MINIMAL RESEAU - ETAPE 1 : connexion basique au Wi-Fi
4 *
5 * ---------------------------------------------------------------------------------------------------------
6 * Les petits Débrouillards - décembre 2022 - CC-By-Sa http://creativecommons.org/licenses/by-nc-sa/3.0/
7 * ========================================================================================================= */
8
9 // Bibliothèques WiFi : UNE SEULE EST NECESSAIRE, choisir celle correspondant à votre matériel.
10 // ATTENTION AUX MAJUSCULES & MINUSCULES ! Sinon d'autres bibliothèques, plus ou moins valides, seraient utilisées.
11
12 #include <ESP8266WiFi.h> // A utiliser pour le D1 Mini
13 //#include <WiFi.h> // A utiliser pour l'ESP32
14
15 // Définition du point d'accès Wi-Fi et de son mot de passe ("clé de sécurité")
16 // A REMPLACER PAR LES VERITABLES VALEURS CORRESPONDANT A VOTRE EMPLACEMENT
17
18 const char* mySSID = "MA_BOX_INTERNET";
19 const char* mySecKey = "MA_CLE_DE_SECURITE";
20
21 /* --------------------------------------------------------------------------------------------------------
22 * SETUP : Initialisation
23 * -------------------------------------------------------------------------------------------------------- */
24 void setup() {
25
26 // Initialisation de la liaison série, affichage 1er message
27
28 Serial.begin(115200);
29 delay(100) ;
30 Serial.println();
31 Serial.println("----------------------------------") ;
32 Serial.println("Exemple de connexion Wi-Fi basique") ;
33 Serial.println("----------------------------------") ;
34
35 // Démarrage de la tentative de connexion, avec le nom du point d'accès Wi-Fi et son mot de passe
36
37 WiFi.begin(mySSID, mySecKey) ;
38
39 // Attente de la connexion pendant 10 secondes (20 x 500 ms)
40
41 Serial.print("Connexion à "); Serial.print(mySSID) ; Serial.print(" ") ;
42 int tryNumber = 1 ;
43 while (WiFi.status() != WL_CONNECTED)
44 {
45 delay(500);
46 Serial.print(".");
47 if (++tryNumber > 20) {
48 Serial.println() ; Serial.println("Pas de connexion, abandon") ;
49 return ;
50 }
51 }
52
53 // La connexion a réussi ! On affiche l'adresse IP obtenue.
54
55 Serial.println(); Serial.print("Connecté ! Adresse IP : ");
56 Serial.println(WiFi.localIP());
57
58 }
59
60 /* --------------------------------------------------------------------------------------------------------------
61 * LOOP : fonction appelée régulièrement par le système
62 * ------------------------------------------------------------------------------------------------------------- */
63 void loop() {
64 /* On ne fait rien de particulier sur cet exemple */
65 }
Dans l'étape précédente on supposait que le Wi-Fi était permanent (cas où les cartes ne quittent pas notre labo, par exemple). Mais si on souhaite faire voyager nos cartes (démos dans des écoles, etc ...), on a trois possibilités :
En effet, cette bibliothèque permet d'enregistrer de façon pérenne (même si on débranche la carte) le dernier Point d'Accès Wi-Fi sur lequel la carte a réussi à se connecter. La bibliothèque va d'abord chercher à se connecter sur ce Point d'Accès "connu". Et si ça ne fonctionne pas (on a changé de lieu, par exemple), alors elle va se positionner elle-même en mode "Point d'Accès", et va proposer sur l'adresse 192.168.4.1 une interface web permettant d'afficher les Points d'Accès Wi-Fi environnants, et d'en sélectionner un. Le nouveau Point d'Accès choisi sera sauvegardé pour les fois suivantes.
Interface web du WiFi Manager :
Bibliothèque
La bibliothèque doit être rajoutée à l'environnement Arduino dans le gestionnaire de Bibliothèques (voir ici pour le mode d'emploi) :
Wifimanager | ||
Avant le Setup | Importation de la bibliothèque | #include <WiFiManager.h> |
Création de l’objet | WiFiManager myWiFiManager; | |
Dans le Setup | Déclaration du mode bloquant | myWiFiManager.setConfigPortalBlocking(true); // ... ou rien (mode par défaut) |
Déclaration du mode non bloquant | myWiFiManager.setConfigPortalBlocking(false); | |
Tentative de connexion à un PA Wi-Fi | if (myWiFiManager.autoConnect(Nom_AP, MotDePasse_AP)) { (... connexion OK !) } | |
Dans le Loop | Activation régulière pour le mode non bloquant | myWiFiManager.process() ; // Obligatoire en mode non bloquant |
Pour connaître toutes les autres possibilités de cette bibliothèque, voir sa référence, ici.
Code minimal : mode bloquant (par défaut)
1 /* =========================================================================================================
2 *
3 * CODE MINIMAL RESEAU - ETAPE 2 : Connexion à un point d'accès choisi par l'utilisateur
4 *
5 * CAS A : MODE BLOQUANT - On attend tant que l'utilisateur n'a pas choisi son Point d'Accès Wi-Fi
6 *
7 * ---------------------------------------------------------------------------------------------------------
8 * Les petits Débrouillards - décembre 2022 - CC-By-Sa http://creativecommons.org/licenses/by-nc-sa/3.0/
9 * ========================================================================================================= */
10
11 // Bibliothèque WiFiManager. Un seule bibibliothèque suffit ici, quelque soit la carte (ESP32 ou Wemos D1 Mini)
12
13 #include <WiFiManager.h> // Gestion de la connexion Wi-Fi (recherche de points d'accès)
14 WiFiManager myWiFiManager; // Création de mon instance de WiFiManager.
15
16 // Définition de la carte lorsqu'elle se positionne en mode "Point d'Accès".
17
18 const char* mySSID = "AP_PetitDeb" ; // Nom du point d'accès
19 const char* mySecKey = "PSWD1234" ; // Mot de passe, 8 caractères au minimum
20
21 /* --------------------------------------------------------------------------------------------------------
22 * SETUP : Initialisation
23 * -------------------------------------------------------------------------------------------------------- */
24 void setup() {
25
26 // Initialisation de la liaison série, affichage 1er message
27
28 Serial.begin(115200);
29 delay(100) ;
30 Serial.println();
31 Serial.println("----------------------------------") ;
32 Serial.println("Exemple de connexion Wi-Fi évoluée") ;
33 Serial.println("----------------------------------") ;
34
35 // Tentative de connexion au Wi-Fi. Si la carte n'a pas réussi se connecter au dernier Point d'Accès connu,
36 // alors elle va se positionner en mode Point d'Accès, demandera sur l'adresse 192.168.4.1 quel nouveau
37 // Point d'Accès choisir. Par défaut, on restera bloqué tant que l'utilisateur n'aura pas fait de choix.
38
39 Serial.println("Connexion au Wi-Fi ...");
40 if (myWiFiManager.autoConnect(mySSID, mySecKey)) {
41
42 // Wi-Fi en mode standard ok --> On affiche l'adresse IP obtenue.
43
44 Serial.println(); Serial.print("Connecté ! Adresse IP : ");
45 Serial.println(WiFi.localIP());
46
47 }
48 else {
49 Serial.println("Connexion Wi-Fi KO :-(");
50 }
51
52 }
53
54 /* --------------------------------------------------------------------------------------------------------------
55 * LOOP : fonction appelée régulièrement par le système
56 * ------------------------------------------------------------------------------------------------------------- */
57 void loop() {
58 /* On ne fait rien de particulier sur cet exemple */
59 }
1 /* =========================================================================================================
2 *
3 * CODE MINIMAL RESEAU - ETAPE 2 : Connexion à un point d'accès choisi par l'utilisateur
4 *
5 * CAS B : MODE NON BLOQUANT - On peut faire autre chose en attendant que l'utilisateur ait choisi
6 * son Point d'Accès Wi-Fi
7 *
8 * ---------------------------------------------------------------------------------------------------------
9 * Les petits Débrouillards - décembre 2022 - CC-By-Sa http://creativecommons.org/licenses/by-nc-sa/3.0/
10 * ========================================================================================================= */
11
12 // Bibliothèque WiFiManager. Un seule bibibliothèque suffit ici, quelque soit la carte (ESP32 ou Wemos D1 Mini)
13
14 #include <WiFiManager.h> // Gestion de la connexion Wi-Fi (recherche de points d'accès)
15 WiFiManager myWiFiManager; // Création de mon instance de WiFiManager.
16
17 // Définition de la carte lorsqu'elle se positionne en mode "Point d'Accès".
18
19 const char* mySSID = "AP_PetitDeb" ; // Nom du point d'accès
20 const char* mySecKey = "PSWD1234" ; // Mot de passe, 8 caractères au minimum
21
22 // Pour les besoins de l'exemple (traces)
23
24 bool IAmNotConnected = true ;
25
26 /* --------------------------------------------------------------------------------------------------------
27 * SETUP : Initialisation
28 * -------------------------------------------------------------------------------------------------------- */
29 void setup() {
30
31 // Initialisation de la liaison série, affichage 1er message
32
33 Serial.begin(115200);
34 delay(100) ;
35 Serial.println();
36 Serial.println("----------------------------------") ;
37 Serial.println("Exemple de connexion Wi-Fi évoluée") ;
38 Serial.println("----------------------------------") ;
39
40 // Déclaration du mode "non bloquant".
41 // Bonus : suppression des traces fournies par le WiFiManager (il est très bavard)
42
43 myWiFiManager.setConfigPortalBlocking(false);
44 myWiFiManager.setDebugOutput(false);
45
46 // Tentative de connexion au Wi-Fi. Si la carte n'a pas réussi se connecter au dernier Point d'Accès connu,
47 // alors elle va se positionner en mode Point d'Accès, demandera sur l'adresse 192.168.4.1 quel nouveau
48 // Point d'Accès choisir. On ne reste pas bloqué, la suite du setup() va se dérouler, et le WiFiManager
49 // traitera les demandes ultérieurement, dans la fonction loop().
50
51 Serial.println("Connexion au Wi-Fi ...");
52 if (myWiFiManager.autoConnect(mySSID, mySecKey)) {
53
54 // Wi-Fi en mode standard ok --> On affiche l'adresse IP obtenue.
55
56 Serial.println(); Serial.print("Connecté ! Adresse IP : ");
57 Serial.println(WiFi.localIP());
58
59 }
60 else {
61
62 // Wi-Fi standard KO, on est passé en mode AP, qui sera traité dans le loop().
63
64 Serial.println("Pas de point Wi-Fi connu, passage en mode AP (identifiant \"" + String(mySSID) + "\")");
65 }
66
67 }
68
69 /* --------------------------------------------------------------------------------------------------------------
70 * LOOP : fonction appelée régulièrement par le système
71 * ------------------------------------------------------------------------------------------------------------- */
72 void loop() {
73
74 // Obligatoire en mode non bloquant, pour que le WiFiManager continue sa tâche.
75
76 myWiFiManager.process() ;
77
78 // Test pour savoir si on est enfin connecté - on ne l'affiche qu'une fois pour limiter les traces
79
80 if (IAmNotConnected) {
81 if (WiFi.status() == WL_CONNECTED) {
82 Serial.print("Connecté au point d'accès " + String(WiFi.SSID()) + ", Adresse IP : ") ;
83 Serial.println(WiFi.localIP());
84 IAmNotConnected = false ;
85 }
86 }
87
88 }
Il existe des cas particuliers où une application n'a en fait pas besoin du Wi-Fi pour aller envoyer ou recevoir des données d'Internet, mais souhaite être juste être considérée comme un Point d'Accès Wi-Fi. Ce mode est suffisant si l'on souhaite commander notre carte depuis un système proche. Par exemple pour commander un système domotique en mode web depuis notre mobile ... petit "spoiler" de l'étape 4 :-)
Pour utiliser le mode "Point d'Accès", on garde les librairies de base, vues à l'étape 1, en utilisant d'autres fonctions.
Connexion Wi-Fi de base | ||
Avant le Setup | Importation de la bibliothèque | #include <ESP8266WiFi.h> // Pour le Wemos D1 Mini, ou ...
#include <WiFi.h> // ... Pour l'ESP32 |
Création de l’objet | ||
Dans le Setup | Lancement du mode AP
avec mot de passe | if (WiFi.softAP(SSID, SecKey)) { (... succès ... } ; // Où SSID est le nom du point d'accès Wi-Fi, et SecKey son mot de passe |
Lancement du mode AP
sans mot de passe | if (WiFi.softAP(SSID)) { (... succès ... } ; // Où SSID est le nom du point d'accès Wi-Fi | |
Récupération de l'adresse IP de base | WiFi.softAPIP() ; | |
Dans le Loop | Utilisation | La récupération de l'adresse IP peut aussi être utilisée dans le loop(). |
Pour connaître toutes les autres possibilités de ces bibliothèques, voir leurs références, respectivement ici (D1 Mini) et ici (ESP32).
1 /* =========================================================================================================
2 *
3 * CODE MINIMAL RESEAU - ETAPE 3 : Configuration en mode Point d'Accès
4 *
5 * ---------------------------------------------------------------------------------------------------------
6 * Les petits Débrouillards - décembre 2022 - CC-By-Sa http://creativecommons.org/licenses/by-nc-sa/3.0/
7 * ========================================================================================================= */
8
9 // Bibliothèques WiFi : UNE SEULE EST NECESSAIRE, choisir celle correspondant à votre matériel.
10 // ATTENTION AUX MAJUSCULES & MINUSCULES ! Sinon d'autres bibliothèques, plus ou moins valides, seraient utilisées.
11
12 #include <ESP8266WiFi.h> // A utiliser pour le D1 Mini
13 //#include <WiFi.h> // A utiliser pour l'ESP32
14
15 const char* mySSID = "AP_PetitDeb" ;
16 const char* mySecKey = "PSWD1234" ;
17
18 /* --------------------------------------------------------------------------------------------------------
19 * SETUP : Initialisation
20 * -------------------------------------------------------------------------------------------------------- */
21 void setup() {
22
23 // Initialisation de la liaison série, affichage 1er message
24
25 Serial.begin(115200);
26 delay(100) ;
27 Serial.println();
28 Serial.println("-----------------------------") ;
29 Serial.println("Exemple en mode Point d'Accès") ;
30 Serial.println("-----------------------------") ;
31
32 // Déclaration du mode "Point d'Accès"
33
34 Serial.println("Déclaration Mode AP, SSID \"" + String(mySSID) + "\"") ;
35
36 if (WiFi.softAP(mySSID,mySecKey)) {
37
38 // Voilà, nous somme en mode "Point d'Accès", notre carte sera visible des systèmes Wi-Fi environnants,
39 // au même titre que les autres box Wi-Fi du voisinage. Par contre, ça s'arrête là, et si une fois
40 // connecté sur ce Point d'Accès "AP_PetitDeb" on cherche à joindre notre carte sur l'adresse IP obtenue
41 // ci-dessous par WiFi.softAPIP(), on aura droit à un beau "ERR_CONNECTION_REFUSED". Normal, on n'a pas
42 // précisé dans l'application ce qu'il faut faire : voir exemple suivant Code_Minimal_Etape4.
43
44 Serial.print("Mode AP OK, IP Address : ") ;
45 Serial.println(WiFi.softAPIP()) ;
46 }
47 else {
48 Serial.println("Mode AP KO ... :-(") ;
49 }
50
51 }
52
53 /* --------------------------------------------------------------------------------------------------------------
54 * LOOP : fonction appelée régulièrement par le système
55 * ------------------------------------------------------------------------------------------------------------- */
56 void loop() {
57
58 // Rien de spécial dans cet exemple
59
60 }
Une première véritable utilisation du Wi-Fi sur nos cartes, est d'y définir un mini-serveur web , qui nous permettra d'afficher voire de modifier des données gérées par la carte, sur n'importe quel navigateur.
On peut trouver quelques exemples d'applications de ce type, réalisée par des Petits Débrouillards, en particulier le Petit Bot, petit robot commandable, ou encore Commander un D1 mini avec une interface web, permettant d'animer des leds, de gérer un moteur, et de récupérer des données du D1 mini sur une interface web.
Site web | ||
Avant le Setup | Importation de la bibliothèque | #include <ESP8266WebServer.h> // Pour le D1 Mini, ou ...
#include <WebServer.h> // ... pour l'ESP32 |
Création du serveur web (sur le port 80) | ESP8266WebServer myWeb(80); // Pour le D1 Mini , ou ...
// WebServer myWeb(80) ; // ... pour l'ESP32 | |
Dans le Setup | Déclaration de la fonction qui s'occupera
de la génération de la page web | myWeb.on ( "/", runPage01 ); |
Démarrage du serveur web | myWeb.begin(); | |
Dans le Loop | Traitement des requêtes web | myWeb.handleClient(); |
La page web hébergée sur notre carte doit être codée en HTML. La page peut être assez évoluée, intégrer du code javascript, être formatée en mode CSS, etc ... Dans l'exemple "minimal" ci-dessous, on se contente d'une page HTML basique.
Une fois le code téléversé sur votre carte, pour voir le résultat, connectez-vous (avec un ordinateur ou un mobile) sur le point d'accès "AP_PetitDeb" (mot de passe "PSWD1234"), puis lancez votre navigateur préféré et tapez 192.168.4.1.
1 /* =========================================================================================================
2 *
3 * CODE MINIMAL RESEAU - ETAPE 4 : site WEB
4 *
5 * CAS A : Page HTML Basique, consultation d'une variable de la carte
6 *
7 * ---------------------------------------------------------------------------------------------------------
8 * Les petits Débrouillards - décembre 2022 - CC-By-Sa http://creativecommons.org/licenses/by-nc-sa/3.0/
9 * ========================================================================================================= */
10
11 // Bibliothèques WiFi et WebServer: ATTENTION, choisir celles correspondant à votre matériel.
12 // ATTENTION AUX MAJUSCULES & MINUSCULES ! Sinon d'autres bibliothèques, plus ou moins valides, seraient utilisées.
13
14 #include <ESP8266WiFi.h> // A utiliser pour le D1 Mini
15 #include <ESP8266WebServer.h> // A utiliser pour le D1 Mini
16 //#include <WiFi.h> // A utiliser pour l'ESP32
17 //#include <WebServer.h> // A utiliser pour l'ESP32
18
19 const char* mySSID = "AP_PetitDeb" ; // On va utiliser le mode "Access Point" pour cet exemple
20 const char* mySecKey = "PSWD1234" ;
21
22 // Déclaration de notre serveur web interne.
23
24 ESP8266WebServer myWeb(80); // A utiliser pour le D1 Mini
25 // WebServer myWeb(80) ; // A utiliser pour l'ESP32
26
27 /* --------------------------------------------------------------------------------------------------------
28 * webPage01 : formattage HTML de la page web.
29 * - En fait cette fonction doit rendre une chaîne (String) contenant l'intégralité du code HTML qui sera
30 * envoyé au navigateur de l'utilisateur.
31 * - On peut y insérer des informations de la carte, comme ici par exemple, le nom du Point d'accès (mySSID).
32 * Dans une véritable application, ça pourrait être la valeur d'un capteur de température.
33 * - Pour pouvoir débugger facilement le code HTML/Javascript sur un browser (par exemple Firefox / Outils
34 * supplémentaires / Outils de développement Web), il est préférable d'indenter le code à l'intérieur de la chaîne
35 * de caractère, et de mettre des sauts de ligne ("\n") à la fin de chaque ligne de code HTML.
36 * -------------------------------------------------------------------------------------------------------- */
37 String webPage01() {
38
39 String p;
40 p = "<html lang=fr-FR><head><title>ETAPE 4 (Mini-Web)</title></head>\n" ;
41 p += "<body>\n" ;
42 p += " <br><br><br><center><font size=\"12\">\n" ;
43 p += " Bonjour, je suis " + String(mySSID) + "...\n" ; // C'est ici qu'on place l'information SSID.
44 p += " <br>... très heureux de te rencontrer !\n" ;
45 p += " </center>\n" ;
46 p += "</body></html>\n" ;
47 return p;
48
49 }
50
51 /* --------------------------------------------------------------------------------------------------------
52 * runPage01 : gestion de la page web
53 * -------------------------------------------------------------------------------------------------------- */
54 void runPage01() {
55
56 // Affichage de la page Web.
57 myWeb.send ( 200, "text/html", webPage01() );
58 }
59
60 /* --------------------------------------------------------------------------------------------------------
61 * SETUP : Initialisation
62 * -------------------------------------------------------------------------------------------------------- */
63 void setup() {
64
65 // Initialisation de la liaison série, affichage 1er message
66
67 Serial.begin(115200);
68 delay(100) ;
69 Serial.println();
70 Serial.println("----------------------") ;
71 Serial.println("Exemple de serveur WEB") ;
72 Serial.println("----------------------") ;
73
74 // Déclaration du mode "Point d'Accès". On s'arrête là si échec.
75
76 Serial.println("Déclaration Mode AP, SSID \"" + String(mySSID) + "\"") ;
77 if (!WiFi.softAP(mySSID,mySecKey)) {
78 Serial.println("Mode AP KO ... :-(") ;
79 return ;
80 }
81
82 // Affichage de l'adresse IP principale du Point d'Accès.
83
84 Serial.print("Mode AP OK, IP Address : ") ;
85 Serial.println(WiFi.softAPIP()) ;
86
87 // Définition des points d'entrée du serveur Web (un seul ici), et démarrage du serveur.
88
89 myWeb.on ( "/", runPage01 );
90 myWeb.begin();
91
92 }
93
94 /* --------------------------------------------------------------------------------------------------------------
95 * LOOP : fonction appelée régulièrement par le système
96 * ------------------------------------------------------------------------------------------------------------- */
97 void loop() {
98
99 // Traitement des requêtes web.
100 myWeb.handleClient();
101
102 }
Dans l'exemple précédent, on se contente de récupérer un paramètre de la carte. Mais il est également possible de modifier un paramètre (par exemple l'état d'une des sorties de la carte, et donc d'agir sur un de ses périphériques : led, moteur, ...).
Le code ci-dessous présente donc un code "moins minimal", permettant d'afficher et de modifier une variable du programme Arduino. Dans une application réelle, il suffira alors d'utiliser cette variable pour afficher et agir sur sur l'état d'une des entrées/sorties de la carte.
La partie HTML est un peu plus complexe, car on va y définir une fonction javascript, qui permettra de faire passer des informations du navigateur au serveur web hébergé. Voir les explications complémentaires dans le code lui-même.
1 /* =========================================================================================================
2 *
3 * CODE MINIMAL RESEAU - ETAPE 4 : site WEB
4 *
5 * CAS B : Page HTML plus évoluéee, et modification d'une variable de la carte
6 *
7 * ---------------------------------------------------------------------------------------------------------
8 * Les petits Débrouillards - décembre 2022 - CC-By-Sa http://creativecommons.org/licenses/by-nc-sa/3.0/
9 * ========================================================================================================= */
10
11 // Bibliothèques WiFi et WebServer: ATTENTION, choisir celles correspondant à votre matériel.
12 // ATTENTION AUX MAJUSCULES & MINUSCULES ! Sinon d'autres bibliothèques, plus ou moins valides, seraient utilisées.
13
14 #include <ESP8266WiFi.h> // A utiliser pour le D1 Mini
15 #include <ESP8266WebServer.h> // A utiliser pour le D1 Mini
16 //#include <WiFi.h> // A utiliser pour l'ESP32
17 //#include <WebServer.h> // A utiliser pour l'ESP32
18
19 const char* mySSID = "AP_PetitDeb" ; // On va utiliser le mode "Access Point" pour cet exemple
20 const char* mySecKey = "PSWD1234" ;
21
22 // Déclaration de notre serveur web interne, qui écoutera sur le port 80.
23
24 ESP8266WebServer myWeb(80); // A utiliser pour le D1 Mini
25 // WebServer myWeb(80) ; // A utiliser pour l'ESP32
26
27 // Variable qui sera affichée et modifiée depuis notre interface web.
28
29 int myValue = 0 ;
30
31 /* --------------------------------------------------------------------------------------------------------
32 * webPage01 : formattage HTML de la page web.
33 * - En fait cette fonction doit rendre une chaîne (String) contenant l'intégralité du code HTML qui sera
34 * envoyé au navigateur de l'utilisateur.
35 * - Comme dans l'exemple précédent (Exemple_4A), on insère dans cette chaîne une information de la carte,
36 * ici la valeur de notre variable 'my value'. Mais on va aussi ajouter des boutons permettant de modifier
37 * cette valeur sur la carte.
38 * - Idem Exemple_4A : pour pouvoir débugger facilement le code HTML/Javascript sur un browser (par exemple
39 * Firefox / Outils supplémentaires / Outils de développement Web), il est préférable d'indenter le code à
40 * l'intérieur de la chaîne de caractère, et de mettre des sauts de ligne ("\n") à la fin de chaque ligne
41 * de code HTML.
42 * -------------------------------------------------------------------------------------------------------- */
43 String webPage01() {
44
45 String p;
46
47 // Début de construction de la page web (entête, titre, paramètres)
48
49 p = "<html lang=fr-FR><head>\n" ;
50 p += "<title>ETAPE 4B</title>\n" ; // Titre de la page
51 p += " <meta charset='UTF-8'>\n" ; // Codage des caractères, UTF-8 est fortement recommandé
52 p += "</head>\n" ;
53
54 // Définitions CSS (), qui permettent de décrire le format des objets sur la page web.
55 // Si vous voulez tout savoir sur CSS, on peut trouver une bonne introduction ici : https://developer.mozilla.org/fr/docs/Learn/CSS
56 // et une référence complète ici : https://developer.mozilla.org/fr/docs/Web/CSS/Reference
57
58 p += "<style>\n" ;
59 p += " body { background-color: #000088; color: white; font-size: 25px; }\n"; // couleur fond écran (bleu foncé) et textes (blanc).
60 p += " input { width:25%; margin:10px; font-size:20px; border-radius: 5px; }\n"; // format des boutons (taille, coins arrondis, ...).
61 p += "</style>\n" ;
62
63 // Début du code javascript. Javascript est le langage utilisé au niveau des navigateurs web (Firefox, Microsoft Edge, Google Chrome, ...)
64 // pour introduire un peu de dynamisme et d'intelligence dans les pages web. Cela peut permettre, par exemple, de réaliser une action
65 // locale et immediate, telle que l'agrandissement d'une image, le changement d'un texte, etc ... sans avoir à réinterroger le serveur web.
66 //
67 // Dans notre cas, la fonction 'addition(val)' ci-dessous va ajouter le paramètres 'val' à l'adresse du serveur web, et va ensuite appeler
68 // la page web de notre carte, avec ce paramètre. Par exemple, si l'adresse du site web de notre carte est 192.168.4.1, l'appel à la fonction
69 // addition(-1) va demander la page '192.168.4.1?add=-1'. Le paramètre 'add' de valeur '-1' sera alors exploité par la carte dans la
70 // fonction runPage01() définie plus bas.
71 //
72 // Dans un exemple réel on pourrait bien sûr définir plusieurs paramètres, du style '192.168.4.1?voyant=vert&servo1=90&servo2=0'
73
74 p += "<script>\n" ;
75 p += "function addition(val) {\n";
76 p += " window.location = window.location.pathname + '?add=' + val ;\n";
77 p += "}\n";
78 p += "</script>\n" ;
79
80 // Corps de la page web : affichage de la valeur récupérée sur la carte, et de deux boutons 'ajouter 1' et 'enlever 1'.
81 // La fonction addition() définie dans le code javascript ci-dessus, sera appelée lorsqu'on appuie sur ces boutons.
82
83 p += "<body><center>\n" ;
84 p += " </br></br>Valeur actuelle : " + String(myValue) + "</br></br>\n";
85 p += " <form>\n";
86 p += " <input type='submit' value='ajouter 1' formaction='javascript:addition(1);' formmethod=post>\n" ;
87 p += " <input type='submit' value='enlever 1' formaction='javascript:addition(-1);' formmethod=post>\n" ;
88 p += " </form>\n";
89 p += "</center></body></html>" ;
90
91 // ça y est, la page web est complètement constituée !
92
93 return p;
94
95 }
96
97 /* --------------------------------------------------------------------------------------------------------
98 * runPage01 : gestion de la page web
99 * -------------------------------------------------------------------------------------------------------- */
100 void runPage01() {
101
102 // Si la page a un paramètre 'add', alors on récupère sa valeur, et on l'ajoute à notre variable 'myValue'.
103
104 if ( myWeb.hasArg("add") ) {
105 Serial.println("Traitement pge web, arg = '" + String(myWeb.arg("add")) + "'") ;
106 int myArg = myWeb.arg("add").toInt() ;
107 myValue = myValue + myArg ;
108 Serial.println("Traitement page web, arg = '" + String(myWeb.arg("add")) + "' --> Nouvelle valeur : " + String(myValue)) ;
109 }
110
111 // On renvoie la page Web.
112 myWeb.send ( 200, "text/html", webPage01() );
113 }
114
115 /* --------------------------------------------------------------------------------------------------------
116 * SETUP : Initialisation
117 * -------------------------------------------------------------------------------------------------------- */
118 void setup() {
119
120 // Initialisation de la liaison série, affichage 1er message
121
122 Serial.begin(115200);
123 delay(100) ;
124 Serial.println();
125 Serial.println("----------------------") ;
126 Serial.println("Exemple de serveur WEB") ;
127 Serial.println("----------------------") ;
128
129 // Déclaration du mode "Point d'Accès". On s'arrête là si échec.
130
131 Serial.println("Déclaration Mode AP, SSID \"" + String(mySSID) + "\"") ;
132 if (!WiFi.softAP(mySSID,mySecKey)) {
133 Serial.println("Mode AP KO ... :-(") ;
134 return ;
135 }
136
137 // Affichage de l'adresse IP principale du Point d'Accès.
138
139 Serial.print("Mode AP OK, IP Address : ") ;
140 Serial.println(WiFi.softAPIP()) ;
141
142 // Définition des points d'entrée du serveur Web (un seul ici),
143 // et démarrage du serveur.
144
145 myWeb.on ( "/", runPage01 );
146 myWeb.begin();
147
148 }
149
150 /* --------------------------------------------------------------------------------------------------------------
151 * LOOP : fonction appelée régulièrement par le système
152 * ------------------------------------------------------------------------------------------------------------- */
153 void loop() {
154
155 // Traitement des requêtes web.
156 myWeb.handleClient();
157
158 }
JSON, c'est quoi ?
Nous allons maintenant nous intéresser à la récupération de données sur Internet (informations sur la météo, sur la pollution, sur les derniers recensements, ...). De nombreux serveurs de données, et en particulier les serveurs "Open Data" (offrant des données libres de droit), sont accessibles en mode web. C'est-à-dire qu'une simple requête dans la barre d'adresse de votre navigateur, permet de récupérer les informations souhaitées.
Et, encore mieux, dans la plupart des cas, la réponse revient sous une forme standardisée de type JSON (JavaScript Objet Notation), que les navigateurs récents sont capables de décoder. A titre d'exemple, ouvrez un nouvel onglet dans votre navigateur, et recopiez dans la barre d'adresse ce qui suit ...
https://data.rennesmetropole.fr//api/records/1.0/search/?dataset=etat-du-trafic-en-temps-reel&q=rocade
... et vous devriez avoir en retour un texte de ce type :
{"nhits": 63, "parameters": {"dataset": "etat-du-trafic-en-temps-reel", "q": "rocade", "rows": 10, "start": 0, "format": "json", "timezone": "UTC"}, "records": [{"datasetid": "etat-du-trafic-en-temps-reel", "recordid": "c8cd4fc9d2a9f1840170322c834f827fc100cc75", "fields": {"traveltimereliability": 100, "traveltime": 55, "predefinedlocationreference": "30023", "averagevehiclespeed": 91, "datetime": "2022-11-29T15:11:00+01:00", "gml_id": "v_rva_troncon_fcd.fid-722fb9f8_184c264cda5_453f", "trafficstatus": "freeFlow", "func_class": 666, "geo_point_2d": [48.14130932076887, -1.6781068587055177], (...)
... mais que votre navigateur va quasi-immédiatement immédiatement reconnaître comme un format JSON, et afficher sous une forme plus structurée :
Nous avons fait ici appel au serveur Open Data de la ville de Rennes, et avons fait une requête demandant l'état du trafic sur la rocade principale. Ce même serveur propose un tas d'autres données libres, et on peut trouver sur Internet une multitude d'autres serveurs "Open Data" en mode JSON.
Oui, mais mon D1 mini n'a pas de navigateur ?
C'est là où deux autres bibliothèques vont nous être utiles :
Les possibilités sont multiples, et l'exploitation des données JSON par les cartes D1 mini ou ESP32, peut prendre des formes très sympathiques : voir par exemple les réalisations "Voir Demain" et "Hawaiiiii" issues d'un hackathon organisé en décembre 2021 par Les Petits Débrouillards Grand Ouest et L'Edulab de l'Université de Rennes 2.
{
MQTT c'est quoi ?
MQTT (Message Queuing Telemetry Transport) permet l'envoi et la réception de messages de petite taille. MQTT s'appuie sur un "broker MQTT", serveur externe, qui va recevoir les données d'un système, et les redistribuer à d'autres systèmes.
MQTT est basé sur un principe d'abonnement : le système émetteur doit préciser à quel sujet ("topic") se rattache son message, et tous les systèmes qui s'étaient préalablement abonnés à ce "topic" recevront alors le message. Principe proche de Twitter ou Instagram et leurs "hashtags", donc.
On peut implémenter son propre broker MQTT (le code est libre d'usage), ou s'appuyer sur des brokers gérés par des associations ou des entreprises. Nous nous intéressons ici uniquement à la partie "client", c'est à dire ce qu'il faut mettre en œuvre sur nos cartes D1 mini ou ESP.
MQTT est souvent utilisé pour collecter des données en provenance de petits capteurs (par exemple, capteurs de température dans un système domotique, capteurs de pollution au niveau d'une région voire d'un pays), car il a aussi comme avantage d'être peu consommateur de ressources.
Mise en œuvre sur nos petites cartes :
Il existe plusieurs bibliothèques Arduino permettent de gérer des messages MQTT. Pour notre part, on utilise celle-ci (à aller chercher dans le gestionnaire de bibliothèque) :
Gestion du MQTT | ||
Avant le Setup | Importation de la bibliothèque | #include <MQTT.h> |
Création de l’objet | MQTTClient myMQTTClient; | |
Dans le Setup (ou le loop) | Initialisation | myMQTTClient.begin(@IP Broker, Port Broker, Client Wifi) ; |
Se préparer à la réception de messages | myMQTTClient.onMessage(référence de la fonction à appeler sur réception d'un message) ; | |
Connexion au broker MQTT | myMQTTClient.connect(ID unique) | |
Souscrire à un "topic" particulier | myMQTTClient.subscribe(topic) ; | |
Publier un message | myMQTTClient.publish(topic, message) ; | |
Dans le Loop | Activation régulière | obligatoire : myMQTTClient.loop() ; |
Pour connaître toutes les autres possibilités de cette bibliothèque, voir sa référence, ici.
Code minimal :
1 /* =========================================================================================================
2 *
3 * CODE MINIMAL RESEAU - ETAPE 6 : Messages MQTT
4 *
5 * ---------------------------------------------------------------------------------------------------------
6 * Les petits Débrouillards - décembre 2022 - CC-By-Sa http://creativecommons.org/licenses/by-nc-sa/3.0/
7 * ========================================================================================================= */
8
9 // Bibliothèques requises
10 // ATTENTION AUX MAJUSCULES & MINUSCULES ! Sinon d'autres bibliothèques, plus ou moins valides, seraient utilisées.
11
12 #include <WiFiManager.h> // Gestion de la connexion Wi-Fi (recherche de points d'accès)
13 #include <WiFiClientSecure.h> // Gestion de la connexion à un serveur de données
14 #include <MQTT.h> // Gestion des requêtes MQTT
15
16
17 // Variables globales
18
19 WiFiManager myWiFiManager; // Manager Wi-Fi
20 WiFiClient myWiFiClient ; // Client WiFi
21 const char* mySSID = "AP_PetitDeb" ; // Nom de la carte en mode Point d'Accès.
22 const char* mySecKey = "PSWD1234" ; // Mot de passe associé, 8 caractères au minimum.
23
24
25 #define MQTT_BROKER_IP "debrouillards.ddns.net" // Serveur sur lequel est installé le Broker MQTT.
26 #define MQTT_BROKER_PORT 1883 // Port sur lequel écoute le broker MQTT
27
28 char MY_MQTT_ID[20] ; // Id unique de notre objet, basé sur ESP.getChipId()
29 const char MY_MQTT_TOPIC[] = "PING_PONG" ; // Nom de notre topic (sujet) MQTT
30
31 MQTTClient myMQTTClient; // Client MQTT
32
33 bool IHaveToAnswer = false ; // Passe à 'true' si on doit répondre.
34
35 #define TEN_SECONDS 10000 // On enverra un message au broker toutes les 10000 ms = 10 secondes.
36 unsigned long myWakeUp ; // Timer mis en place pour limiter le nombre d'envois au broker.
37
38 /* --------------------------------------------------------------------------------------------------------------
39 * MQTT_Received : réception d'un message MQTT
40 * ------------------------------------------------------------------------------------------------------------- */
41 void MQTT_Received(String &topic, String &payload) {
42
43 char myTrace[80] ;
44
45 sprintf(myTrace, "Réception sur le topic \"%s\" du message MQTT \"%s\".", topic, payload) ;
46 Serial.println(myTrace) ;
47
48 // Comme indiqué dans la documentation, il ne faut pas renvoyer de messages dans cette fonction,
49 // ça risque de mal se passer (blocages, ...). Si on souhaite répondre au message reçu, il vaut
50 // mieux mettre à jour une variable globale, qui sera vérifiée dans la partie loop().
51
52 if (payload == String("Ping")) {
53 IHaveToAnswer = true ;
54 }
55
56 }
57
58 /* --------------------------------------------------------------------------------------------------------------
59 * MQTT_Connect : Connexion - ou reconnexion - au broker MQTT.
60 * ------------------------------------------------------------------------------------------------------------- */
61 void MQTT_Connect() {
62
63 // Vérification WiFi OK.
64
65 int nbTries = 0 ;
66 while (WiFi.status() != WL_CONNECTED) {
67 if (nbTries++ > 10) {
68 Serial.println("Connexion WiFi KO :-(") ;
69 return ;
70 }
71 delay(500);
72 }
73
74 // Connexion au broker.
75
76 Serial.println("--- Connexion MQTT, Id unique \"" + String(MY_MQTT_ID) + "\" ") ;
77 nbTries = 0 ;
78 while (!myMQTTClient.connect(MY_MQTT_ID)) {
79 Serial.print(".") ;
80 if (nbTries++ > 10) {
81 Serial.println(" KO :-(") ;
82 return ;
83 }
84 delay(500);
85 }
86
87 // Abonnement au topic.
88
89 Serial.println("--- Abonnement au sujet \"" + String(MY_MQTT_TOPIC) + "\"") ;
90 myMQTTClient.subscribe(MY_MQTT_TOPIC);
91
92 }
93 /* --------------------------------------------------------------------------------------------------------
94 * SETUP : Initialisation
95 * -------------------------------------------------------------------------------------------------------- */
96 void setup() {
97
98 // Initialisation de la liaison série, affichage 1er message
99
100 Serial.begin(115200);
101 delay(100) ;
102 Serial.println();
103 Serial.println("---------------------") ;
104 Serial.println("Exemple messages MQTT") ;
105 Serial.println("---------------------") ;
106
107 // Tentative de connexion au Wi-Fi. Si la carte n'a pas réussi se connecter au dernier Point d'Accès connu,
108 // alors elle va se positionner en mode Point d'Accès, demandera sur l'adresse 192.168.4.1 quel nouveau
109 // Point d'Accès choisir. Par défaut, on restera bloqué tant que l'utilisateur n'aura pas fait de choix.
110
111 Serial.println("Connexion au Wi-Fi ...");
112 if (myWiFiManager.autoConnect(mySSID, mySecKey)) {
113 Serial.println(); Serial.print("Connecté ! Adresse IP : ");
114 Serial.println(WiFi.localIP());
115 }
116 else {
117 Serial.println("Connexion Wi-Fi KO :-(");
118 }
119
120 // Initialisation du MQTT
121
122 Serial.println("Initialisation MQTT ...");
123 myMQTTClient.begin(MQTT_BROKER_IP, MQTT_BROKER_PORT, myWiFiClient); // lancement du client MQTT ...
124 myMQTTClient.onMessage(MQTT_Received); // ... qui appelera la fonction MQTT_Received si un message est reçu.
125
126 strncpy(MY_MQTT_ID, String(ESP.getChipId()).c_str(),sizeof(MY_MQTT_ID)) ; // Fabrication de mon ID unique, sur la base du n° de puce
127 MY_MQTT_ID[sizeof(MY_MQTT_ID)-1] = '\0' ;
128
129 // Connexion au broker
130
131 MQTT_Connect() ;
132
133 // Initialisation du timer qui sera testé dans loop() - pour faire appel au serveur seulement toutes les 10 secondes
134 // millis() est une fonction système donnant le nombre de ms depuis le lancement ou la réinitialisation de la carte.
135
136 unsigned long myWakeUp = millis() + TEN_SECONDS ;
137
138 }
139
140 /* --------------------------------------------------------------------------------------------------------------
141 * LOOP : fonction appelée régulièrement par le système
142 * ------------------------------------------------------------------------------------------------------------- */
143 void loop() {
144
145 // Réactivation du client MQTT
146
147 myMQTTClient.loop() ;
148 delay(10) ; // Problèmes de stabilité Wi-Fi ? (Cf. doc MQTT)
149
150 // Reconnexion au broker MQTT si nécessaire ...
151
152 if (!myMQTTClient.connected()) {
153 MQTT_Connect();
154 }
155
156 // Si on a précédemment reçu un 'Ping', on va répondre 'Pong'
157
158 if (IHaveToAnswer) {
159 IHaveToAnswer = false ;
160 Serial.println("Envoi de la réponse \"Pong\" sur le topic \"" + String(MY_MQTT_TOPIC) + "\".") ;
161 myMQTTClient.publish(MY_MQTT_TOPIC, "Pong") ;
162 }
163
164 // Envoi d'un message toutes les 10 secondew.
165
166 unsigned long myNow = millis() ;
167 if (myNow >= myWakeUp) {
168 Serial.println("Wake Up ! envoi du message \"Ping\" sur le topic \"" + String(MY_MQTT_TOPIC) + "\".") ;
169 myMQTTClient.publish(MY_MQTT_TOPIC, "Ping") ;
170 myWakeUp = myNow + TEN_SECONDS ;
171 }
172
173
174 }
Identifiant unique (D1 min vs ESP ?) proposer code utilisant l'id unique de la pucey
d'ailleurs si même une seule carte à un endroit, id unique utile (MQTT par exemple). Introduire cette notion plus haut ?
Dernière modification 6/02/2023 par user:Philby.
Draft
Vous avez entré un nom de page invalide, avec un ou plusieurs caractères suivants :
< > @ ~ : * € £ ` + = / \ | [ ] { } ; ? #