Une fonctionnalité très pratique dans le domaine des IoT est la possibilité de programmer un microcontrôleur connecté , comme un ESP8266, via Wifi. Cette technique est appelée Transmission aérienne ou Over-The-Air (OTA) Programming.
Matériel
- NodeMCU ESP8266
- Câble USB A Mâle/Micro B Mâle
- Ordinateur
- Réseau WiFi
Principe de fonctionnement
En principe, le NodeMCU ESP8266 se programme via le port USB. L’ordinateur communique le programme au microcontrôleur. Lorsque deux appareils sont connectés au même réseau Wifi, ils peuvent communiquer ensemble. On peut donc téléverser un code grâce au réseau Wifi sans avoir à se connecter à chaque microcontrôleur.
Il est aussi possible de téleverser un code sur le NodeMCU lorsqu’il est configuré comme Point d’Accès Wifi. Dans ce cas, l’ordinateur, utilisé pour la programmation, doit être connecté au réseau du NodeMCU.
Ajouter le firmware ArduinoOTA
La librairie ArduinoOTA est disponible à l’installation du gestionnaire d’ESP8266. Pour pourvoir mettre en place la programmation OTA, vous devez installer le firmware. Pour cela, vous pouvez utiliser l’exemple BasicOTA.ino disponible dans l’IDE Arduino.
Veillez à remplacer ssid et password par les identifiants de votre réseau WiFi.
#include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h> #ifndef STASSID #define STASSID "your-ssid" #define STAPSK "your-password" #endif const char* ssid = STASSID; const char* password = STAPSK; void setup() { Serial.begin(115200); Serial.println("Booting"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } // Port defaults to 8266 // ArduinoOTA.setPort(8266); // Hostname defaults to esp8266-[ChipID] // ArduinoOTA.setHostname("myesp8266"); // No authentication by default // ArduinoOTA.setPassword("admin"); // Password can be set with it's md5 value as well // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) { type = "sketch"; } else { // U_FS type = "filesystem"; } // NOTE: if updating FS this would be the place to unmount FS using FS.end() Serial.println("Start updating " + type); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) { Serial.println("Auth Failed"); } else if (error == OTA_BEGIN_ERROR) { Serial.println("Begin Failed"); } else if (error == OTA_CONNECT_ERROR) { Serial.println("Connect Failed"); } else if (error == OTA_RECEIVE_ERROR) { Serial.println("Receive Failed"); } else if (error == OTA_END_ERROR) { Serial.println("End Failed"); } }); ArduinoOTA.begin(); Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } void loop() { ArduinoOTA.handle(); }
Veillez à noter l’adresse IP local de l’appareil (ici: 192.168.1.78).
Une fois ce code téléverser par voie série, vous serez en capacité de téléverser un code via Wifi. Appuyer sur le bouton RST ou EN de votre ESP et redémarrer l’IDE Arduino.
Modifier votre programme avant de le téléverser
Nous plaçons le code d’initialisation dans la fonction initOTA(). Il sera ensuite facile de la copier pour d’autre projet. Et nous allons rajouter un affichage sur le port série pour vérifier que le code a bien été modifié.
ATTENTION: Le code relatif à l’initialisation de ArduinoOTA doit être présent dans tous les codes que vous téléversez ou vous perdrez la possibilité de faire de la transmission aérienne.
#include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h> const char* ssid = "*******"; const char* password = "********"; unsigned long previousMillis; void setup() { Serial.begin(115200); Serial.println("Booting"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } initOTA(); Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } void loop() { ArduinoOTA.handle(); if (millis() - previousMillis >= 500) { previousMillis = millis(); Serial.println(F("Code has been update")); } } void initOTA() { // Port defaults to 8266 // ArduinoOTA.setPort(8266); // Hostname defaults to esp8266-[ChipID] // ArduinoOTA.setHostname("myesp8266"); // No authentication by default // ArduinoOTA.setPassword("admin"); // Password can be set with it's md5 value as well // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) { type = "sketch"; } else { // U_FS type = "filesystem"; } // NOTE: if updating FS this would be the place to unmount FS using FS.end() Serial.println("Start updating " + type); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) { Serial.println("Auth Failed"); } else if (error == OTA_BEGIN_ERROR) { Serial.println("Begin Failed"); } else if (error == OTA_CONNECT_ERROR) { Serial.println("Connect Failed"); } else if (error == OTA_RECEIVE_ERROR) { Serial.println("Receive Failed"); } else if (error == OTA_END_ERROR) { Serial.println("End Failed"); } }); ArduinoOTA.begin(); }
Un fois votre code modifié, sous « Outil> Port », sélectionnez votre carte dans les ports réseau. (si le port réseau ne s’affiche pas voir chapitre suivant ci-dessous)
Vous pouvez alors téléverser votre code comme vous le feriez avec la communication série.
Sélectionnez à nouveau le port série, puis ouvrez le moniteur série pour vérifier que le code a bien été modifié.
Si le Port Réseau ne s’affiche pas dans l’IDE Arduino
Si le port réseau n’est pas présent dans les options de l’IDE Arduino, il vous faudra effectué une petite manipulation. Vous devez vous rendre dans le Centre Réseau et Partage
Puis aller dans « Modifier les paramètres de la carte »
Cliquez droit sur votre réseau puis aller dans propriétés
Vous pouvez ensuite décocher l’option « Protocole Internet version 6 (TCP/IPv6) ».
Si vous retourner sur l’IDE Arduino, dans « Outil > Port » vous devriez l’option port réseau s’afficher.
Vous pouvez de nouveau cocher le protocole IPv6 un fois que votre port réseau est reconnu.
Bonus: Affichage de message série en OTA
La possibilité de téléverser un programme par Wifi est très appréciable mais, il est bon de noter, que l’on perd la capacité de debugger avec le moniteur série. Il est possible de créer une interface Web sur laquelle on peut afficher des informations provenant du NodeMCU ESP8266.
Nous allons voir ici l’utilisation de la librairie RemoteDebug qui va nous permettre de nous connecter en telnet au microcontrôleur et récupérer les messages envoyés.
- Commencez par installer la librairie en téléchargeant le ZIP ou via le gestionnaire de bibliothèque.
- Créez un objet RemoteDebug Debug; après avoir inclus la librairie
- Initialisez le debug avec Debug.begin(« ESP8266 »);
- Puis remplacer tout les Serial.print par Debug.print
#include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h> #include <RemoteDebug.h> const char* ssid = "******"; const char* password = "*******"; RemoteDebug Debug; unsigned long previousMillis; void setup() { Serial.begin(115200); Serial.println("Booting"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } // init remote debug Debug.begin("ESP8266"); initOTA(); Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } void loop() { ArduinoOTA.handle(); Debug.handle(); if (millis() - previousMillis >= 500) { previousMillis = millis(); Debug.println(F("Code has been update")); } } void initOTA() { // Port defaults to 8266 // ArduinoOTA.setPort(8266); // Hostname defaults to esp8266-[ChipID] //ArduinoOTA.setHostname("ESP8266"); // No authentication by default // ArduinoOTA.setPassword("admin"); // Password can be set with it's md5 value as well // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) { type = "sketch"; } else { // U_FS type = "filesystem"; } // NOTE: if updating FS this would be the place to unmount FS using FS.end() Serial.println("Start updating " + type); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) { Serial.println("Auth Failed"); } else if (error == OTA_BEGIN_ERROR) { Serial.println("Begin Failed"); } else if (error == OTA_CONNECT_ERROR) { Serial.println("Connect Failed"); } else if (error == OTA_RECEIVE_ERROR) { Serial.println("Receive Failed"); } else if (error == OTA_END_ERROR) { Serial.println("End Failed"); } }); ArduinoOTA.begin(); }
Pour visualiser les messages envoyer via RemoteDebug, nous allons utiliser le logciel PuTTy que nous avons vu plusieurs fois déjà. Pour cette application, nous allons configurer PuTTy en telnet en utilisant l’adresse IP récupérée sur le moniteur série.