Arduino OTA – Sketch Upload per WLAN ohne Kabel

Wenn du dein DIY-Projekt mit WiFi fertiggestellt hast, es eventuell sogar schon in einem Gehäuse verbaut ist, jedoch nicht einfach per Kabel auf eine neue Version deines Sketches aktualisiert werden kann, dann kann die „Arduino-OTA“ Bibliothek (over the air) einen bequemen WLAN-Upload über Funk ermöglichen.
Die Installation über die OTA-Schnittstelle in der Arduino-IDE setzt WiFi-fähige Boards, ausreichend Flash-Speicher und die Integration der benötigten OTA-Bibliothek voraus.

Vorbereitung:

Richte zuerst unter Entwicklungsboard das zu verwendende Board deiner Wahl ein. Schließe es per USB Kabel an deinem PC mit der Arduino-IDE an und wähle den korrekten Com-Port.

Prüfe nun unter Sketsche/Beispiel ob dort OTA Beispiel-Sketche aus wählbar sind.


Bibliothek nachträglich installieren:
Gehen dazu in der Arduino-IDE zu Menüpunkt „Sketch“ > „Bibliotheken einbinden“ > „Bibliotheken verwalten…“
In dem sich öffnenden Fenster kann nun nach den benötigten Bibliothek „ArduinoOTA“ gesucht werden.
Diese nun installieren.

Funktion von OTA:
Nach der Installation findet man wie immer Beispiele für die installierte Bibliothek.
Bei näherer Betrachtung kann man jeden bereits erstellten Sketch wie folgt mit OTA erweitern.
Es erfordert lediglich, wenn nicht schon geschehen, das includen dieser 4 Bibliotheken, ArduinoOTA.begin in der Setup und ArduinoOTA.handle in der Loop.
Ob ihr jetzt den Hostnamen betitelt oder ein Passwort verwendet ist optional:

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

const char* ssid = "Ihr_WLAN_SSID";
const char* password = "Ihr_WLAN_Passwort";

void setup() {
  // Verbindung zum WLAN herstellen
  WiFi.begin(ssid, password);
  
  // Initialisiere OTA

  // Setzen Sie den Hostnamen für OTA
     ArduinoOTA.setHostname(OTAHostname);

  // Setzen Sie das Passwort für OTA-Updates (optional)
     ArduinoOTA.setPassword("geheimesPasswort");

     ArduinoOTA.begin();

  // Dein bestehender Setup-Code...
}

void loop() {
  // Dein bestehender Setup-Code...

  // Fügen Sie diese Zeile hinzu, um OTA-Updates zu ermöglichen
  ArduinoOTA.handle();
}

Sketch der Upgedatet werden soll:
Um es übersichtlich zu machen verwende ich hier als Beispiel nur den Blink – Sketch (ESP32 mit LED an Pin 19):

#define LED_PIN 19

void setup() {
  pinMode(LED_PIN, OUTPUT); // Setzt den LED-Pin als Ausgang
}

void loop() {
  digitalWrite(LED_PIN, HIGH); // Schaltet die LED ein
  delay(1000); // Wartet für eine Sekunde
  digitalWrite(LED_PIN, LOW); // Schaltet die LED aus
  delay(1000); // Wartet für eine Sekunde
}

Kombiniert man nun diese beiden Sketche sieht das Ergebnis so aus:

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

const char* ssid = "Accesspoint  Name";
const char* password = "geheim123";

#define LED_PIN 19

void setup() {
  pinMode(LED_PIN, OUTPUT); // Setzt den LED-Pin als Ausgang
  WiFi.begin(ssid, password);
  
  // Hostname defaults to esp3232-[MAC]
 ArduinoOTA.setHostname("myesp32");

  // No authentication by default
 ArduinoOTA.setPassword("admin");

  ArduinoOTA.begin();

}

void loop() {
  ArduinoOTA.handle();
  digitalWrite(LED_PIN, HIGH); // Schaltet die LED ein
  delay(1000); // Wartet für eine Sekunde
  digitalWrite(LED_PIN, LOW); // Schaltet die LED aus
  delay(1000); // Wartet für eine Sekunde
}

Somit sind die Vorbereitungen abgeschlossen. Gerät kann nun getestet werden.

Späteres Update per WLAN:

Wird nun etwas am Sketch verändert, kann das Board nun ohne Kabel ausgewählt werden:

Sollte ein Passwort gesetzt worden sein, dann wird vorab geprüft:

Finaler Test:

Im abschließenden Test habe ich die Blinkfrequenz im Delay verändert um zu sehen ob das update funktioniert.
Bei mir hat es ohne Probleme die neue Version übertragen und automatisch mit dieser gestartet. Inzwischen gibt es immer mehr Entwicklungsboards mit Wifi. Ich könnte mir vorstellen das es auch bei den ein oder anderen funktionieren könnte. Probiert das doch mal aus.

Fazit:
In IoT-Anwendungen bieten OTA-Updates klare Vorteile. Sie ermöglichen die Fernaktualisierung von Firmware, bieten Fehlerbehebung und Funktionserweiterungen, sparen Zeit, minimieren Ausfallzeiten und verbessern die Skalierbarkeit und die Langlebigkeit von IoT-Geräten.


Der Vollständigkeit halber hier auch die erweiterte Sketch Version mit weiteren Optionen und für Analyseausgabe im Seriellen Monitor:

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

const char* ssid = "Accesspoint  Name";
const char* password = "geheim123";

#define LED_PIN 19

void setup() {
  pinMode(LED_PIN, OUTPUT); // Setzt den LED-Pin als Ausgang
  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("myesp32");

  // 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();
  digitalWrite(LED_PIN, HIGH); // Schaltet die LED ein
  delay(1000); // Wartet für eine Sekunde
  digitalWrite(LED_PIN, LOW); // Schaltet die LED aus
  delay(1000); // Wartet für eine Sekunde
}
, , ,