Site icon AranaCorp

Programmer un ESP32 via WiFi avec l’IDE Arduino (OTA)

Une fonctionnalité très pratique dans le domaine des IoT est la possibilité de programmer un microcontrôleur connecté , comme un ESP32, via Wifi. Cette technique est appelée Transmission aérienne ou Over-The-Air (OTA) Programming.

Matériel

Principe de fonctionnement

En principe, un programme est téléversé sur le NodeMCU ESP32 par une connexion série avec 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. Le code complet est donné à la fin de ce tutoriel.

Ajouter le firmware ArduinoOTA

La librairie ArduinoOTA est disponible à l’installation du gestionnaire d’ESP32. 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 <WiFi.h>
#include <ESPmDNS.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();
  }
  
    // Port defaults to 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  //ArduinoOTA.setHostname("esp3232");

  // 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_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .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.33).

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 <WiFi.h>
#include <ESPmDNS.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 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  ArduinoOTA.setHostname("ESP32");

  // 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_SPIFFS
      type = "filesystem";

    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    Serial.println("Start updating " + type);
  })
  .onEnd([]() {
    Serial.println("\nEnd");
  })
  .onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  })
  .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 après l’avoir redémarré, dans « Outil > Port » vous devriez voir 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 ESP32.

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.

#include <WiFi.h>
#include <ESPmDNS.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("ESP32");  
  
  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 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  ArduinoOTA.setHostname("ESP32");

  // 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_SPIFFS
      type = "filesystem";

    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    Serial.println("Start updating " + type);
  })
  .onEnd([]() {
    Serial.println("\nEnd");
  })
  .onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  })
  .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.

Bonus 2: Programmation OTA en mode Access Point

Il est possible d’utiliser le réseau créer par le NodeMCU ESP32 en mode Access Point. Pour cela vous pouvez télecharger le code suivant via le port série. Vous devrez ensuite connecter votre ordinateur au réseau du NodeMCU pour pouvoir téleverser un nouveau code par Wifi.

#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

const char *ssid = "AC-ESP32";
const char *passphrase = "123456789";

IPAddress local_IP(192,168,4,22);
IPAddress gateway(192,168,4,9);
IPAddress subnet(255,255,255,0);

unsigned long previousMillis;
void setup() {
 Serial.begin(115200);
 Serial.println("Booting");

 //AP config
 Serial.print("Setting soft-AP configuration ... ");
 Serial.println(WiFi.softAPConfig(local_IP, gateway, subnet) ? "Ready" : "Failed!");
 Serial.print("Setting soft-AP ... ");
 Serial.println(WiFi.softAP(ssid,passphrase) ? "Ready" : "Failed!");
   
 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 via Wifi"));
 }
}
void initOTA() {
 // Port defaults to 3232
 // ArduinoOTA.setPort(3232);
 // Hostname defaults to esp3232-[MAC]
 ArduinoOTA.setHostname("ESP32");
 // 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_SPIFFS
     type = "filesystem";
   // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
   Serial.println("Start updating " + type);
 })
 .onEnd([]() {
   Serial.println("\nEnd");
 })
 .onProgress([](unsigned int progress, unsigned int total) {
   Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
 })
 .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();
}

Sources

Quitter la version mobile