Voici un exemple pour expliquer comment présenter à l'utilisateur une page web qui permet de rentrer des paramètres pour son application ESP32 avec WiFiManager et de les sauvegarder en mémoire Flash en utilisant l'API Preferences de Espressif
L'idée est de créer un portail captif qui affiche automatiquement une page de configuration quand on se connecte sur le réseau ouvert de l'ESP32.
WiFiManager est généralement utilisé pour choisir un Wi-Fi et fournir le mot de passe afin de configurer un ESP32 dans un environnement particulier, mais WiFiManager ne se limite pas qu'à cela et on peut ne pas demander le Wi-Fi et juste fonctionner en portail local pour fournir des paramètres de configuration / calibration d'un appareil.
C'est ce que je fais dans l'exemple qui suit, avec 3 paramètres "longueur", "largeur", et "hauteur" :
Quand vous lancez le code vous voyez dans le moniteur série (à 115200 bauds)
Système prêt. Accédez au réseau Wi-Fi AirPressure
---------------
Configuration Enregistrée:
longueur -> "10" -> 10
largeur -> "20" -> 20
hauteur -> "30" -> 30
une fois que vous rejoignez le réseau Wi-Fi AirPressure défini dans le code par
const char * wifiSSID = "AirPressure";
Vous verrez cela sur votre téléphone :
C'est mon code qui créé ce portail et rajoute un menu Setup qui donne accès aux paramètres, un séparateur et les boutons Restart Exit avec cette ligne de code:
std::vector<const char *> menu = {"param", "sep", "restart", "exit"};
wm.setMenu(menu);
En cliquant sur Setup vous accédez aux paramètres que j'ai défini dans un tableau
const char* parametresDesc[] = {"longueur", "largeur", "hauteur"};
la valeur par défaut (textuelle) des paramètres est stockée dans
char parametresTxt[nbParams][tailleMaxTexte] = {"10", "20", "30"};
donc ici on a bien les 3 paramètres "longueur", "largeur", et "hauteur"
vous pouvez éditer le contenu dans les champs textuels, par exemple ici je rajoute un 0 à chaque variable.
le code essaye d'être un peu intelligent et de faire une analyse de ce qui a été saisi pour extraire le nombre. Si vous tapez "coucou" à la place d'un nombre, ce sera ignoré (et il y aura un message dans le moniteur série).
Quand vous cliquez sur Save, ça déclenche l'appel du callback callbackParametres ()
dans le code qui se charge de relire la valeur de chacun des champs de la page web, et d'affecter sa conversion en long
dans le tableau
long parametres[nbParams];
et de les stocker en mémoire permanente (Flash) de l'ESP32 en utilisant l'API Preferences de Espressif.
vous verrez dans le moniteur série que c'est bien extrait avec l'affichage
---------------
Configuration Enregistrée:
longueur -> "100" -> 100
largeur -> "200" -> 200
hauteur -> "300" -> 300
Vous pouvez donc utiliser ensuite ce tableau de paramètres dans votre programme, il correspond aux préférences de l'utilisateur et si vous coupez le courant de votre ESP32 et le remettez, vous verrez dans la console
Système prêt. Accédez au réseau Wi-Fi AirPressure
---------------
Configuration Enregistrée:
longueur -> "100" -> 100
largeur -> "200" -> 200
hauteur -> "300" -> 300
➜ on voit que les valeurs ont bien été sauvegardées.
voilà il ne reste plus qu'à intégrer cela à votre code, la seule dépendance c'est que la loop() soit non bloquante et que la première ligne soit l'appel à la gestion du wifimanager
void loop() {
wm.process();
// ici le reste du code en non bloquant
}
Simple et efficace.
le code
/* ============================================
code is placed under the MIT license
Copyright (c) 2024 J-M-L
For the Arduino Forum : https://forum.arduino.cc/u/j-m-l
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
#include <Preferences.h>
Preferences preferences;
const char * wifiSSID = "AirPressure";
constexpr size_t tailleMaxTexte = 10;
const char* parametresDesc[] = {"longueur", "largeur", "hauteur"};
const size_t nbParams = sizeof parametresDesc / sizeof * parametresDesc;
char parametresTxt[nbParams][tailleMaxTexte] = {"10", "20", "30"};
long parametres[nbParams];
WiFiManager wm; // global wm instance
WiFiManagerParameter wmParameters[nbParams];
// ----------------------------------------------------------------
// WiFi Manager et Préférences
// ----------------------------------------------------------------
void printConfig() {
Serial.println("\n---------------\nConfiguration Enregistrée:");
for (size_t i = 0; i < nbParams; i++) {
Serial.print(parametresDesc[i]); Serial.print(" -> \""); Serial.print(parametresTxt[i]); Serial.print("\" -> "); Serial.println(parametres[i]);
}
Serial.println();
}
void callbackParametres () {
if (preferences.begin("parametres", false)) {
for (size_t i = 0; i < nbParams; i++) {
const char * vTxt = wmParameters[i].getValue();
char * ptr = nullptr;
long v = strtol(vTxt, &ptr, 10); // base 10
if (ptr && *ptr == '\0') {
// le parsing s'est bien passé on définit la valeur textuelle et numérique
parametres[i] = v;
snprintf(parametresTxt[i], tailleMaxTexte, "%s", vTxt);
preferences.putString(parametresDesc[i], parametresTxt[i]); // on sauve pour la prochaine fois
} else {
// ça s'est mal passsé on ne modifie pas
Serial.print("erreur format pour ");
Serial.println(parametresTxt[i]);
}
}
preferences.end();
} else {
Serial.println("Error writing Prefernces");
}
printConfig();
}
// ----------------------------------------------------------------
void setup() {
Serial.begin(115200); Serial.println();
// on lit les valeurs de configuration
if (preferences.begin("parametres", false)) {
for (size_t i = 0; i < nbParams; i++) {
char * ptr = nullptr;
char vTxt[tailleMaxTexte];
snprintf(vTxt, tailleMaxTexte, "%s", preferences.getString(parametresDesc[i], parametresTxt[i]).c_str());
long v = strtol(vTxt, &ptr, 10); // base 10
if (ptr && *ptr == '\0') {
// le parsing s'est bien passé on définit la valeur textuelle et numérique
parametres[i] = v;
snprintf(parametresTxt[i], tailleMaxTexte, "%s", vTxt);
} else {
// ça s'est mal passsé
Serial.println("erreur parsing");
parametres[i] = atoi(parametresTxt[i]); // on prend la valeur par défaut
preferences.putString(parametresDesc[i], parametresTxt[i]); // on sauve pour la prochaine fois
}
}
preferences.end();
} else {
Serial.println("Erreur Preferences");
}
// gestion portail config
WiFi.mode(WIFI_STA); // esp par défaut sur STA+AP (ou mettre WIFI_AP)
wm.setDebugOutput(false);
for (size_t i = 0; i < nbParams; i++) { // on créee les champs spécifiques
new (&(wmParameters[i])) WiFiManagerParameter(parametresDesc[i], parametresDesc[i], parametresTxt[i], tailleMaxTexte);
wm.addParameter(&(wmParameters[i]));
}
wm.setConfigPortalBlocking(false);
wm.setSaveParamsCallback(callbackParametres);
std::vector<const char *> menu = {"param", "sep", "restart", "exit"};
wm.setMenu(menu);
wm.startConfigPortal(wifiSSID);
Serial.print("\nSystème prêt. Accédez au réseau Wi-Fi "); Serial.println(wifiSSID);
printConfig();
}
void loop() {
wm.process();
// ici le reste du code en non bloquant
}