LOCODUINO

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

vendredi 26 avril 2024

Visiteurs connectés : 84

É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 :

#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 :

void Connection::initOTA()
{
  DP("Demarrage OTA sous le nom ");
  DPLN(sName);
  ArduinoOTA.setHostname(sName);
  ArduinoOTA.begin();
}

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 :

    case MDNS_OK:
      if (WiFi.status() == WL_CONNECTED) {
        initOTA();
        sState = OTA_OK;
      } else {
        DPLN("Perte de connexion");
        sState = OFFLINE;
      }
      break;

    case OTA_OK:
      if (WiFi.status() != WL_CONNECTED) {
        DPLN("Perte de connexion");
        ArduinoOTA.end();
        sState = OFFLINE;
      }
      break;

Et isOnline() l’est également :

bool Connection::isOnline()
{ 
  return (sState == OTA_OK);
}

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.

void Connection::loop()
{
  const uint32_t currentDate = millis();
  if ((currentDate - sLastDate) >= sPeriod) {
    update();
    sLastDate = currentDate;
  }
  ArduinoOTA.handle();
}

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, « Eclairage ».
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 :

  static char *sOTAPass;

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

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

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

void Connection::setup(const char *inSsid,
                       const char *inPass,
                       const char *inName,
                       const char *inOTAPass,
                       const uint32_t inPeriod)

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

  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 :

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

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

pi@raspberrypi:~ $ echo -n 'locoduino' | md5sum
35789343f9ea974b8742c8367e43f8a1  -
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 :

#ifdef DEBUG
  static void startingOTA();
  static void OTAInProgress(unsigned int inProgress, unsigned int inTotal);
  static void endingOTA();
  static void OTAError(ota_error_t error);
#endif

Ensuite leur implémentation :

#ifdef DEBUG
void Connection::startingOTA()
{
  const int command = ArduinoOTA.getCommand();
  if (command == U_FLASH) {
    DPLN("Téléversement du firmware");
  } else {
    DP("Commande inattendue ");
    DPLN(command);
  }
}

void Connection::OTAInProgress(unsigned int inProgress, unsigned int inTotal)
{
  static uint32_t previousNumberOfDots = 0;
  const uint32_t numberOfDots = 50 * inProgress / inTotal;
  for (uint32_t dot = previousNumberOfDots; dot < numberOfDots; dot++) {
    DP('.');
  }
  if (inTotal == inProgress) {
    DPLN();
  }
  previousNumberOfDots = numberOfDots;
}

void Connection::endingOTA()
{
  DPLN("Téléversement terminé");
}

void Connection::OTAError(ota_error_t error)
{
  DP("Erreur[");
  DP(error);
  DP("] : ");
  switch (error) {
    case OTA_AUTH_ERROR:    DPLN("L'authentification a échoué"); break;
    case OTA_BEGIN_ERROR:   DPLN("Échec au début");              break;
    case OTA_CONNECT_ERROR: DPLN("Échec à la connexion");        break;
    case OTA_RECEIVE_ERROR: DPLN("Échec à la réception");        break;
    case OTA_END_ERROR:     DPLN("Échec à la fermeture");        break;
  }
}
#endif

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

void Connection::initOTA()
{
  DP("Demarrage OTA sous le nom ");
  DPLN(sName);
  ArduinoOTA.setHostname(sName);
  if (sOTAPass != NULL) {
    ArduinoOTA.setPassword(sOTAPass);
  }
  
#ifdef DEBUG
  ArduinoOTA.onStart(startingOTA);
  ArduinoOTA.onProgress(OTAInProgress);
  ArduinoOTA.onEnd(endingOTA);
  ArduinoOTA.onError(OTAError);
#endif

  ArduinoOTA.begin();
}

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 »

LaBox, Une Centrale DCC polyvalente et abordable (1)

LaBox, Une Centrale DCC polyvalente et abordable (2)

LaBox, Une Centrale DCC polyvalente et abordable (3)

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 (1)

La carte Satellite V1 (2)

La carte Satellite V1 (3)

La carte Satellite V1 (4)

La carte Satellite V1 (5)

Un décodeur DCC pour les plaques tournantes Fleischmann et Roco

Communications entre JMRI et Arduino

Une croix de pharmacie animée avec Arduino UNO

Enseigne de magasin

Feux tricolores

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

TCO Web interactif avec des ESP32 et des ESP8266 (5)

Multi-animations lumineuses

Passage à niveau géré par Arduino (1)

Passage à niveau géré par Arduino (2)

Passage à niveau géré par Arduino (3)

Passage à niveau géré par Arduino (4)

Passage à niveau géré par Arduino (5)

Une manette simple et autonome pour LaBox

Block Automatique Lumineux à 8 cantons analogiques

TCO Web interactif avec des ESP32 et des ESP8266 (4)

Affichage publicitaire avec Arduino (2)

JMRI pour Ma première centrale DCC

Rocrail pour Ma première centrale DCC

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

TCO Web interactif avec des ESP32 et des ESP8266 (3)

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

Banc de test pour les décodeurs DCC

Ma première manette pour les aiguillages DCC

Mon premier décodeur pour les aiguillages DCC

Boitier 3D pour la station DCC minimale

Va-et-vient pour deux trains

TCO Web interactif avec des ESP32 et des ESP8266 (2)

Un programme pour régler facilement les servos moteurs avec un ESP32

TCO Web interactif avec des ESP32 et des ESP8266 (1)

Affichage publicitaire avec Arduino (1)

Etude d’un passage à niveau universel

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

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

Simulateur de soudure à arc

Une horloge à échelle H0

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

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

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

Etude d’un passage à niveau multivoies

La rétro-signalisation sur Arduino

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

Une animation sonore

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

Un TCO xpressnet

Un capteur RFID

Annonces en gare avec la RFID

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

Une barrière infrarouge

Un moniteur de signaux DCC

Chenillard de DEL

Un décodeur DCC pour 16 feux tricolores

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

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

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

Un automatisme de Passage à Niveau

Les derniers articles

LaBox, Une Centrale DCC polyvalente et abordable (3)


Thierry

LaBox, Une Centrale DCC polyvalente et abordable (1)


Thierry

LaBox, Une Centrale DCC polyvalente et abordable (2)


Dominique, msport, Thierry

Un programme pour régler facilement les servos moteurs avec un ESP32


bobyAndCo

TCO Web interactif avec des ESP32 et des ESP8266 (5)


utpeca

TCO Web interactif avec des ESP32 et des ESP8266 (4)


utpeca

TCO Web interactif avec des ESP32 et des ESP8266 (3)


utpeca

TCO Web interactif avec des ESP32 et des ESP8266 (2)


utpeca

TCO Web interactif avec des ESP32 et des ESP8266 (1)


utpeca

Affichage publicitaire avec Arduino (2)


catplus, Christian

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 Passerelle entre le bus S88 et le bus CAN pour la rétro signalisation

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

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

La rétro-signalisation sur Arduino

Etude d’un passage à niveau multivoies

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

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

Chenillard de DEL