LOCODUINO

Forum de discussion
Dépôt GIT Locoduino
Flux RSS

jeudi 26 mai 2022

41 visiteurs en ce moment

Éclairer le réseau (3)

Over The Air

. Par : Jean-Luc

DIFFICULTÉ :

Nous avons maintenant un ESP32 qui se connecte au WiFi de manière aussi fiable que possible compte tenu de l’application et qui répond au doux nom d’Eclairage.local sur le réseau local. Occupons nous maintenant de l’OTA.

L’OTA

OTA est l’acronyme de Over The Air. Il s’agit d’un service permettant de téléverser un sketch via le réseau WiFi et donc de ne pas avoir à ramper ou à grimper jusqu’à l’ESP32, une fois que celui-ci sera installé à son emplacement final, pour y brancher un câble USB. C’est évidemment extrêmement pratique et, en réalité, quasiment indispensable.

Il est possible de faire une mise en place minimum avec très peu de code et une mise en place un peu plus élaborée qui sera pratique pour débugger. Commençons par la mise en place minimum.

Il faut d’abord inclure la bibliothèque comme ceci :

  1. #include <ArduinoOTA.h>

Il faut ensuite initialiser l’OTA en :

  1. Spécifiant un nom pour la machine. À ma connaissance l’OTA repose sur mDNS. Ce nom est celui sous lequel l’ESP apparaîtra dans le menu de l’IDE, nous y reviendrons. Pour cela, on utilise la fonction ArduinoOTA.setHostname(...) ;
  2. Démarrer le service OTA avec la fonction ArduinoOTA.begin()

Pour cela nous allons ajouter une méthode de classe (c’est à dire qualifiée de static) privée à la classe Connection, méthode que nous appellerons initOTA() et dont l’implémentation est la suivante :

  1. void Connection::initOTA()
  2. {
  3. DP("Demarrage OTA sous le nom ");
  4. DPLN(sName);
  5. ArduinoOTA.setHostname(sName);
  6. ArduinoOTA.begin();
  7. }

Afin d’appeler initOTA() au bon moment, c’est à dire après avoir effectué la connection au WiFi et lancé le service mDNS [1], nous allons ajouter un état OTA_OK à notre automate et le remanier en conséquence.

Figure 1 : La machine à état de connexion intégrant l'OTA.
Figure 1 : La machine à état de connexion intégrant l’OTA.

Deux case sont modifiés en conséquence :

  1. case MDNS_OK:
  2. if (WiFi.status() == WL_CONNECTED) {
  3. initOTA();
  4. sState = OTA_OK;
  5. } else {
  6. DPLN("Perte de connexion");
  7. sState = OFFLINE;
  8. }
  9. break;
  10.  
  11. case OTA_OK:
  12. if (WiFi.status() != WL_CONNECTED) {
  13. DPLN("Perte de connexion");
  14. ArduinoOTA.end();
  15. sState = OFFLINE;
  16. }
  17. break;

Et isOnline() l’est également :

  1. bool Connection::isOnline()
  2. {
  3. return (sState == OTA_OK);
  4. }

Enfin, il faut appeler le plus souvent possible la fonction ArduinoOTA.handle() pour que le service puisse répondre aux sollicitations de téléversement que l’IDE lui envoie. Nous modifions donc Connection::loop() à cette fin.

  1. void Connection::loop()
  2. {
  3. const uint32_t currentDate = millis();
  4. if ((currentDate - sLastDate) >= sPeriod) {
  5. update();
  6. sLastDate = currentDate;
  7. }
  8. ArduinoOTA.handle();
  9. }

Le code est chargé sur l’ESP32 de manière classique, via l’USB, mais désormais un nouveau port devrait apparaître dans le menu Outils, sous menu Ports de l’IDE, dans la section Ports réseau, comme montré à la figure 2.

Figure 2 : Après chargement du sketch comprenant le service OTA, un nouveau port réseau apparaît, <i>Eclairage</i>.
Figure 2 : Après chargement du sketch comprenant le service OTA, un nouveau port réseau apparaît, Eclairage.

Si ce n’est pas le cas, quitter et relancer l’IDE règlera le problème. Nous voilà prêts à tester le téléversement via le WiFi. Le port réseau est sélectionné puis on presse le bouton Téléverser. l’IDE compile le sketch et le téléverse comme montré à la figure 3. L’OTA est fonctionnel.

L’ESP32 peut désormais être déconnecté de l’ordinateur que vous utilisez pour programmer. Pourvu qu’il soit alimenté et connecté au même réseau WiFi que votre ordinateur, vous pourrez le programmer à distance grâce à l’OTA.

Figure 3 : Téléversement du sketch en OTA. L'IDE indique l'adresse IP puis affiche une barre de progression.
Figure 3 : Téléversement du sketch en OTA. L’IDE indique l’adresse IP puis affiche une barre de progression.
Bien évidemment, si vous chargez de cette manière un sketch dépourvu du service OTA ou une nouvelle version d’un sketch qui ne fonctionne pas correctement, ou qui plante, vous perdrez le service OTA et devrez donc aller chercher l’ESP là où vous l’avez installé pour le reprogrammer via l’USB. Il faut donc être prudent et tester systématiquement toute nouvelle version sur un ESP de développement avant de la déployer en OTA.

Sécurisons un peu

Il ne s’agit pas ici de blinder le téléversement en OTA contre des cyberattaques mais plutôt d’éviter des méprises. En effet, quand le nombre d’ESP32 dédiés à des tâches diverses commencent à pulluler sur le réseau du domicile et que la liste des ports réseau s’allonge dans l’IDE, il est aisé de se tromper de port et de flasher le mauvais ESP. En associant un mot de passe différent à chaque logiciel, le risque d’erreur est plus limité.

Une donnée de classe est ajoutée à Connection pour garder un pointeur sur le mot de passe OTA :

  1. static char *sOTAPass;

Il suffit d’ajouter un appel à ArduinoOTA.setPassword(...) dans la méthode initOTA et le tour est joué.

  1. if (sOTAPass != NULL) {
  2. ArduinoOTA.setPassword(sOTAPass);
  3. }

Enfin, un argument supplémentaire est ajouté à Connection::setup(...) :

  1. void Connection::setup(const char *inSsid,
  2. const char *inPass,
  3. const char *inName,
  4. const char *inOTAPass,
  5. const uint32_t inPeriod)

L’appel à setup est fait avec le mot de passe désiré, dans l’exemple suivant locoduino :

  1. Connection::setup(ssid, pass, "Eclairage", "locoduino");

Lors du téléversement, le mot de passe est désormais demandé comme montré à la figure 4.

Figure 4 : Fenêtre d'authentification pour autoriser un téléversement via OTA.
Figure 4 : Fenêtre d’authentification pour autoriser un téléversement via OTA.

On peut également ne pas vouloir mettre ce mot de passe en clair dans le sketch et lui substituer un mot de passe chiffré. Dans ce cas, il faut chiffrer le mot de passe désiré avec MD5. On appelle le résultat un hash MD5. Avec un Mac, on ouvre un terminal et on tape :

  1. jlb@Arrakis ~ % md5 -s locoduino
  2. MD5 ("locoduino") = 35789343f9ea974b8742c8367e43f8a1
  3. jlb@Arrakis ~ %

Avec Linux, c’est un peu différent :

  1. pi@raspberrypi:~ $ echo -n 'locoduino' | md5sum
  2. 35789343f9ea974b8742c8367e43f8a1 -
  3. pi@raspberrypi:~ $

Il est également possible d’utiliser un générateur de hash MD5 en ligne.

Il suffit ensuite de copier-coller le hash MD5 dans votre sketch et d’utiliser la fonction ArduinoOTA.setPasswordHash(...) en lieu et place de ArduinoOTA.setPassword(...). Il va de soi qu’en cas d’oubli du mot de passe vous êtes fichu et que vous devrez ramper ou grimper pour brancher un câble USB sur votre ESP pour téléverser un nouveau sketch.

Debugger l’OTA

Il est possible d’accrocher des fonctions à soi aux endroits critiques du service OTA pour être notifié de la progression des opérations. L’intérêt est limité lorsque l’ESP est placé à son endroit définitif car, en l’absence de connexion série, les affichages que l’on effectueraient partiraient dans le vide.

En revanche, ça peut être pratique pour régler des problèmes pendants les tests alors que l’ESP est au bout du câble USB. Pour accrocher ces fonctions, l’objet ArduinoOTA propose les méthodes suivantes dont l’unique argument est la fonction à appeler :

  • ArduinoOTA.onStart(...) permet d’accrocher une fonction sans argument qui sera appelée une fois au début du processus de téléversement ;
  • ArduinoOTA.onProgress(...) permet d’accrocher une fonction avec deux arguments. Le premier est un entier non signé donnant la progression courante, progress, et le second est un entier non signé sonnant la progression totale, total. L’expression 100 * progress / total donne la progression en pourcentage ;
  • ArduinoOTA.onEnd(...) permet d’accrocher une fonction sans argument qui sera appelée une fois à la fin du processus de téléversement, et donc juste avant le redémarrage de l’ESP ;
  • ArduinoOTA.onError(...) permet d’accrocher une fonction avec un unique argument de type ota_error_t qui sera appelée si une erreur survient pendant les opérations.

Ajoutons l’affichage de ces informations de debug dans le sketch. Tout d’abord la déclaration des 4 fonctions que nous allons accrocher :

  1. #ifdef DEBUG
  2. static void startingOTA();
  3. static void OTAInProgress(unsigned int inProgress, unsigned int inTotal);
  4. static void endingOTA();
  5. static void OTAError(ota_error_t error);
  6. #endif

Ensuite leur implémentation :

  1. #ifdef DEBUG
  2. void Connection::startingOTA()
  3. {
  4. const int command = ArduinoOTA.getCommand();
  5. if (command == U_FLASH) {
  6. DPLN("Téléversement du firmware");
  7. } else {
  8. DP("Commande inattendue ");
  9. DPLN(command);
  10. }
  11. }
  12.  
  13. void Connection::OTAInProgress(unsigned int inProgress, unsigned int inTotal)
  14. {
  15. static uint32_t previousNumberOfDots = 0;
  16. const uint32_t numberOfDots = 50 * inProgress / inTotal;
  17. for (uint32_t dot = previousNumberOfDots; dot < numberOfDots; dot++) {
  18. DP('.');
  19. }
  20. if (inTotal == inProgress) {
  21. DPLN();
  22. }
  23. previousNumberOfDots = numberOfDots;
  24. }
  25.  
  26. void Connection::endingOTA()
  27. {
  28. DPLN("Téléversement terminé");
  29. }
  30.  
  31. void Connection::OTAError(ota_error_t error)
  32. {
  33. DP("Erreur[");
  34. DP(error);
  35. DP("] : ");
  36. switch (error) {
  37. case OTA_AUTH_ERROR: DPLN("L'authentification a échoué"); break;
  38. case OTA_BEGIN_ERROR: DPLN("Échec au début"); break;
  39. case OTA_CONNECT_ERROR: DPLN("Échec à la connexion"); break;
  40. case OTA_RECEIVE_ERROR: DPLN("Échec à la réception"); break;
  41. case OTA_END_ERROR: DPLN("Échec à la fermeture"); break;
  42. }
  43. }
  44. #endif

Et enfin, la mise en place de ces fonctions dans initOTA :

  1. void Connection::initOTA()
  2. {
  3. DP("Demarrage OTA sous le nom ");
  4. DPLN(sName);
  5. ArduinoOTA.setHostname(sName);
  6. if (sOTAPass != NULL) {
  7. ArduinoOTA.setPassword(sOTAPass);
  8. }
  9.  
  10. #ifdef DEBUG
  11. ArduinoOTA.onStart(startingOTA);
  12. ArduinoOTA.onProgress(OTAInProgress);
  13. ArduinoOTA.onEnd(endingOTA);
  14. ArduinoOTA.onError(OTAError);
  15. #endif
  16.  
  17. ArduinoOTA.begin();
  18. }

Lors du téléchargement, le moniteur série affiche les informations sur le téléversement en cours.

Figure 5 : Affichage de la progression de l'OTA dans le moniteur série.
Figure 5 : Affichage de la progression de l’OTA dans le moniteur série.
Les numéros de ligne indiqués correspondent aux lignes du sketch final que l’on peut télécharger à la fin de l’article.

Voici le sketch, correspondant à cette étape, à télécharger.

Sketch comprenant la connexion au WiFi, mDNS et l’OTA

Le prochain article traitera de la mise en œuvre de MQTT

[1L’ESP32 plantera vigoureusement si l’OTA est initialisé alors que la connexion WiFi ne l’est pas.

2 Messages

Réagissez à « Éclairer le réseau (3) »

Qui êtes-vous ?
Votre message

Pour créer des paragraphes, laissez simplement des lignes vides.

Lien hypertexte

(Si votre message se réfère à un article publié sur le Web, ou à une page fournissant plus d’informations, vous pouvez indiquer ci-après le titre de la page et son adresse.)

Rubrique « Projets »

Un chenillard de DEL

Enseigne de magasin

Feux tricolores

Multi-animations lumineuses

L’Arduino et le système de commande numérique DCC

Un décodeur d’accessoire DCC versatile basé sur Arduino

Un moniteur de signaux DCC

Une barrière infrarouge

Un capteur RFID

Un TCO xpressnet

Une animation sonore

L’Arduino au coeur des systèmes de pilotage analogiques ou numériques

Calcul de la vitesse d’un train miniature avec l’Arduino

La génèse d’un réseau 100% Arduino

Une horloge à échelle H0

Simulateur de soudure à arc

Un automatisme de Passage à Niveau

Automatisation du pont FLEISCHMANN 6152 (HO) avec un ESP32 (1)

Identifier et localiser vos trains avec le RFID/NFC et un bus CAN.

Etude d’un passage à niveau multivoies

La rétro-signalisation sur Arduino

Décodeur pour aiguillage à solénoïdes sur Arduino

Un décodeur DCC pour les signaux à deux ou trois feux sur Arduino NANO/UNO

Etude d’un passage à niveau universel

Réalisation pratique d’un système de mesure de vitesse à l’échelle N

Une Passerelle entre le bus S88 et le bus CAN pour la rétro signalisation

Un décodeur DCC pour 16 feux tricolores

Block Automatique Lumineux avec la carte shield "Arduino 4 relays"

Réalisation d’un affichage de gare ARRIVEE DEPART

Ménage à trois (Ordinateur, Arduino, réseau)

Réalisation d’un va-et-vient automatique et réaliste

Souris et centrale sans fil

Communications entre JMRI et Arduino

Annonces en gare avec la RFID

Une croix de pharmacie animée avec Arduino UNO

Réalisation d’un wagon de mesure (distance et vitesse)

Une manette simple et autonome pour LaBox

Block Automatique Lumineux à 8 cantons analogiques

JMRI pour Ma première centrale DCC

Rocrail pour Ma première centrale DCC

CDM-Rail pour Ma première centrale DCC (1)

CDM-Rail pour Ma première centrale DCC (2)

Ma première manette pour les aiguillages DCC

Mon premier décodeur pour les aiguillages DCC

Mise en boitier de la station DCC minimale

Comment piloter trains et accessoires en DCC avec un Arduino (1)

Comment piloter trains et accessoires en DCC avec un Arduino (2)

Comment piloter trains et accessoires en DCC avec un Arduino (3)

Comment piloter trains et accessoires en DCC avec un Arduino (4)

SGDD : Système de Gestion DD (1)

SGDD : Système de Gestion DD (2)

SGDD : Système de Gestion DD (3)

La PWM : Qu’est-ce que c’est ? (1)

La PWM : Qu’est-ce que c’est ? (2)

La PWM : Qu’est ce que c’est ? (3)

La PWM : Qu’est ce que c’est ? (4)

Mise en oeuvre du Bus CAN entre modules Arduino (1)

Mise en oeuvre du Bus CAN entre modules Arduino (2)

Un gestionnaire en C++ pour votre réseau (1)

Un gestionnaire en C++ pour votre réseau (2)

Un gestionnaire en C++ pour votre réseau (3)

Un gestionnaire en C++ pour votre réseau (4)

Réalisation de centrales DCC avec le logiciel libre DCC++ (1)

Réalisation de centrales DCC avec le logiciel libre DCC++ (2)

Réalisation de centrales DCC avec le logiciel libre DCC++ (3)

Contrôleur à télécommande infrarouge pour centrale DCC++

Gestion d’une gare cachée (1)

Gestion d’une gare cachée (2)

Gestion d’une gare cachée (3)

La carte Satellite V1

La carte Satellite V1

La carte Satellite V1

La carte Satellite V1

La carte Satellite V1

Les derniers articles

Mise en boitier de la station DCC minimale


msport

Mon premier décodeur pour les aiguillages DCC


msport

Ma première manette pour les aiguillages DCC


msport

Éclairer le réseau (5)


Jean-Luc

CDM-Rail pour Ma première centrale DCC (2)


msport

Éclairer le réseau (4)


Jean-Luc

CDM-Rail pour Ma première centrale DCC (1)


msport

Rocrail pour Ma première centrale DCC


msport

Éclairer le réseau (3)


Jean-Luc

JMRI pour Ma première centrale DCC


msport

Les articles les plus lus

Réalisation de centrales DCC avec le logiciel libre DCC++ (3)

La PWM : Qu’est-ce que c’est ? (1)

Une croix de pharmacie animée avec Arduino UNO

Comment piloter trains et accessoires en DCC avec un Arduino (3)

Un chenillard de DEL

Réalisation de centrales DCC avec le logiciel libre DCC++ (1)

Mise en oeuvre du Bus CAN entre modules Arduino (2)

L’Arduino au coeur des systèmes de pilotage analogiques ou numériques

Une barrière infrarouge

Feux tricolores