Ratgeber · 13 Min. Lesezeit

ESP32 OTA Update: Code kabellos hochladen mit ArduinoOTA

ESP32 OTA: Sketch per WLAN ohne USB-Kabel hochladen. ArduinoOTA-Netzwerkport, ElegantOTA-Webseite, Passwort, Partitionsschema und abgebrochene Uploads.

ESP32 OTA (Over-The-Air-Update) bedeutet, neuen Code per WLAN auf dein Board zu laden, statt ein USB-Kabel anzuschließen. Stell dir einen Sensor an der Zimmerdecke vor, eine Bewässerungssteuerung im Garten oder eine Relaisplatine im Schaltschrank: Statt für jede kleine Korrektur die Leiter zu holen, das Board auszubauen und an den Rechner zu hängen, schickst du die neue Version in wenigen Sekunden aus der Arduino IDE oder dem Browser. Das Board schreibt das neue Programm im Hintergrund in seinen Speicher, prüft es und startet sich selbst neu.

In dieser Anleitung lernst du Schritt für Schritt, wie OTA im ESP32 funktioniert, drei verschiedene Methoden (ArduinoOTA für die Arduino IDE, ElegantOTA für den Browser und HTTPUpdate zum Abholen von einem Server), die Wahl des richtigen Partitionsschemas, den Passwortschutz, was bei einem abgebrochenen Upload passiert und wie du OTA im nächsten Sketch nicht verlierst. Der gesamte Code wurde mit dem ESP32-Arduino-Core kompiliert und getestet.

ESP32-Entwicklungsboard mit kabellosem OTA-Upload
ESP32-Entwicklungsboard: Nachdem du den ersten OTA-Sketch einmal per USB hochgeladen hast, kannst du alle weiteren Updates per WLAN senden.

Was ist ESP32 OTA und wie funktioniert es?

Der Flash-Speicher des ESP32 ist kein einziger Block; er wird durch eine Karte namens Partitionstabelle in Bereiche aufgeteilt. Eine OTA-fähige Partitionstabelle enthält zwei gleich große Programmbereiche: app0 (ota_0) und app1 (ota_1). Während das Board aus einem davon läuft, wird das neue Programm in den anderen geschrieben. Eine kleine otadata-Partition merkt sich, welcher Bereich beim nächsten Start ausgeführt wird. So wird das laufende Programm während des Uploads nie angefasst, und das Board gibt das alte Programm erst auf, wenn der neue Code vollständig geschrieben und geprüft ist.

  1. Das neue Programm (die kompilierte .bin-Datei) kommt Stück für Stück per WLAN am Board an.
  2. Der ESP32 schreibt jedes Stück in die Programmpartition, die gerade nicht benutzt wird; der laufende Code arbeitet währenddessen weiter.
  3. Sobald die ganze Datei da ist, werden Image-Header und Prüfsumme kontrolliert; eine beschädigte oder unvollständige Datei wird abgelehnt.
  4. Ist die Prüfung erfolgreich, wird otadata aktualisiert: Beim nächsten Start läuft die neue Partition.
  5. Das Board startet neu und kommt mit dem neuen Programm hoch. Das nächste Update landet dann in der anderen Partition; beide Bereiche werden abwechselnd genutzt.
MethodeVon wo sendest du den Code?Am besten geeignet fürZusätzliche Bibliothek
ArduinoOTAÜber den Netzwerkport in der Arduino IDEEntwicklung am Schreibtisch im selben NetzKeine (im Core enthalten)
ElegantOTAAuswahl einer .bin auf der Seite /update im BrowserUpdates durch Leute ohne IDE, Upload vom HandyElegantOTA
HTTPUpdateDas Board lädt eine .bin-Datei selbst von einem ServerViele Geräte, entfernte Geräte, automatische UpdatesKeine (im Core enthalten)

Partitionsschema und Flash-Größe

Das ist die am häufigsten übersehene Voraussetzung für OTA: Es muss einen zweiten freien Bereich geben, in den das neue Programm geschrieben wird. Deshalb ist das größte Programm, das du per OTA hochladen kannst, kleiner als die Hälfte des Flashs. Die Partitionstabelle wählst du in der Arduino IDE unter Werkzeuge > Partition Scheme. Bei den verbreiteten ESP32-DevKit-Boards mit 4 MB Flash (ESP32 Dev Module) gibt es diese Optionen:

Partition SchemeProgrammbereichOTADateisystem (SPIFFS/LittleFS)
Default 4MB with spiffs2 × 1,25 MB (1.310.720 Byte)Ja1,375 MB
Minimal SPIFFS (1.9MB APP with OTA)2 × 1,875 MB (1.966.080 Byte)Ja128 KB
No OTA (2MB APP/2MB SPIFFS)1 × 2 MBNein1,875 MB
Huge APP (3MB No OTA/1MB SPIFFS)1 × 3 MBNein896 KB
Minimal (1.3MB APP/700KB SPIFFS)1 × 1,25 MB (für Boards mit 2 MB Flash)Nein640 KB
Wenn ein großes Programm mit Bluetooth und WLAN gleichzeitig "Sketch too big" meldet, wählen die meisten Huge APP. Dieses Schema hat keinen zweiten Programmbereich: Per USB lässt sich der Code problemlos hochladen, aber OTA startet nicht und bricht mit "Not Enough Space" oder "Begin Failed" ab. Wenn du OTA willst, wähle Minimal SPIFFS (1.9MB APP with OTA).

Wie viel Platz dein Programm belegt, siehst du in der Kompilierausgabe: Unser erstes Beispiel mit WLAN und ArduinoOTA meldet "Sketch uses 758685 bytes (57%) ... Maximum is 1310720 bytes". Das Maximum ist die Größe eines einzelnen Programmbereichs im gewählten Schema. Liegt die Auslastung über 90 %, wirst du bald auf Minimal SPIFFS umsteigen müssen. Noch eine wichtige Regel: Die Partitionstabelle lässt sich nicht per OTA ändern. Hast du das Schema geändert, muss dieser Upload per USB erfolgen; spätere OTA-Updates laufen dann mit der neuen Tabelle. Auf Boards mit 8 MB oder 16 MB Flash (wie viele ESP32-S3-Modelle) bekommst du deutlich größere OTA-Bereiche, wenn du im Menü Flash Size die richtige Größe wählst.

Wenn du sehen willst, aus welcher Partition dein Board gerade läuft und wie viel Platz für OTA bleibt, lade den kleinen Sketch unten hoch. Er braucht keine Bibliothek und nutzt direkt die OTA-Funktionen von ESP-IDF:

C++ (Arduino IDE)
1#include <esp_ota_ops.h>
2
3void setup() {
4  Serial.begin(115200);
5  delay(1000);
6  const esp_partition_t* running = esp_ota_get_running_partition();
7  const esp_partition_t* next = esp_ota_get_next_update_partition(NULL);
8
9  Serial.printf("Flash boyutu / Flash size: %u KB\n", ESP.getFlashChipSize() / 1024);
10  Serial.printf("Program boyutu / Sketch size: %u KB\n", ESP.getSketchSize() / 1024);
11  Serial.printf("OTA icin bos alan / Free space for OTA: %u KB\n", ESP.getFreeSketchSpace() / 1024);
12  Serial.printf("Calisan bolum / Running partition: %s (0x%06x)\n", running->label, running->address);
13  if (next != NULL) {
14    Serial.printf("Siradaki OTA bolumu / Next OTA partition: %s (0x%06x)\n", next->label, next->address);
15  } else {
16    Serial.println("OTA bolumu yok: bolum tablosunu degistir / No OTA partition: change the partition scheme");
17  }
18}
19
20void loop() {
21}

Mit dem Standardschema zeigt die Ausgabe nach dem ersten USB-Upload "Running partition: app0 (0x010000)" und "Next OTA partition: app1 (0x150000)". Führst du den Code nach einem OTA-Update erneut aus, siehst du, dass er jetzt aus app1 läuft. Der Wert von ESP.getFreeSketchSpace() ist die Größe des größten Programms, das du per OTA hochladen kannst; ist deine neue .bin-Datei größer, startet das Update nicht.

Methode 1: kabelloser Upload aus der Arduino IDE mit ArduinoOTA

Die Bibliothek ArduinoOTA ist im ESP32-Core enthalten, du musst also nichts installieren. Sobald das Board im Netz ist, meldet es sich per mDNS; die Arduino IDE erkennt das und fügt dem Port-Menü einen Netzwerkport hinzu. Drückst du auf Hochladen, schickt die IDE das Programm über diesen Netzwerkport statt über USB. Auf dem ESP32 lauscht der OTA-Dienst standardmäßig auf Port 3232. Der folgende Sketch verbindet sich mit dem WLAN, startet OTA mit Passwort und lässt als Beweis die Onboard-LED blinken:

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <ArduinoOTA.h>
3
4const char* WIFI_SSID = "AgAdi";          // Wi-Fi adın / your Wi-Fi name
5const char* WIFI_PASS = "AgSifresi";      // Wi-Fi şifren / your Wi-Fi password
6const int LED_PIN = 2;                    // çoğu DevKit'te dahili LED / onboard LED on most DevKits
7
8unsigned long lastBlink = 0;
9
10void setup() {
11  Serial.begin(115200);
12  pinMode(LED_PIN, OUTPUT);
13
14  WiFi.mode(WIFI_STA);
15  WiFi.begin(WIFI_SSID, WIFI_PASS);
16  while (WiFi.status() != WL_CONNECTED) {   // bağlanana kadar bekle / wait until connected
17    delay(500);
18    Serial.print(".");
19  }
20  Serial.println();
21  Serial.print("IP: ");
22  Serial.println(WiFi.localIP());
23
24  ArduinoOTA.setHostname("bluegrays-esp32");  // IDE'de görünen ad / name shown in the IDE
25  ArduinoOTA.setPassword("ota1234");          // yükleme parolası / upload password
26
27  ArduinoOTA.onStart([]() {
28    // Güncelleme başlıyor: motorları, röleleri güvenli konuma al / update starting: put motors and relays in a safe state
29    String type = (ArduinoOTA.getCommand() == U_FLASH) ? "program" : "dosya sistemi / filesystem";
30    Serial.println("OTA basladi / started: " + type);
31  });
32  ArduinoOTA.onEnd([]() {
33    Serial.println("\nOTA bitti, yeniden baslatiliyor / done, rebooting");
34  });
35  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
36    Serial.printf("Ilerleme / Progress: %u%%\r", progress * 100 / total);
37  });
38  ArduinoOTA.onError([](ota_error_t error) {
39    Serial.printf("Hata / Error[%u]: ", error);
40    if (error == OTA_AUTH_ERROR) Serial.println("parola / auth failed");
41    else if (error == OTA_BEGIN_ERROR) Serial.println("baslatilamadi, yer yok / begin failed, no space");
42    else if (error == OTA_CONNECT_ERROR) Serial.println("baglanti / connect failed");
43    else if (error == OTA_RECEIVE_ERROR) Serial.println("veri alinamadi / receive failed");
44    else if (error == OTA_END_ERROR) Serial.println("bitirilemedi / end failed");
45  });
46
47  ArduinoOTA.begin();                         // OTA hizmetini başlat / start the OTA service
48}
49
50void loop() {
51  ArduinoOTA.handle();                        // her turda çağır, unutma / call on every pass, never forget
52
53  // delay() yerine millis(): OTA isteklerini kaçırmamak için / millis() instead of delay() so OTA requests aren't missed
54  if (millis() - lastBlink >= 500) {
55    lastBlink = millis();
56    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
57  }
58}
ZeileWozu dient sie?
ArduinoOTA.setHostname("bluegrays-esp32")Der Name in der Port-Liste der IDE und im Netzwerk. Hast du mehrere Boards, gib jedem einen eigenen Namen.
ArduinoOTA.setPassword("ota1234")Ohne Passwort kann jeder in deinem Netz Code auf dein Board laden. Die IDE fragt vor dem Upload nach diesem Passwort.
onStart / onEndLaufen zu Beginn und am Ende des Updates. Der ideale Ort, um Motoren zu stoppen, Relais auszuschalten oder "Update läuft" anzuzeigen.
onProgressLiefert den Prozentwert; du kannst damit einen Fortschrittsbalken auf einem LCD oder OLED zeichnen.
onErrorNennt die Fehlerart: Passwort, kein Platz, Verbindung, Empfang oder Abschluss.
ArduinoOTA.handle()Prüft auf eingehende OTA-Anfragen. Wird die Funktion in loop() nicht oft genug aufgerufen, kann das Board der IDE nicht antworten.

Schritt für Schritt: dein erster OTA-Upload

  1. Passe WIFI_SSID und WIFI_PASS im Code an dein Netz an. Der ESP32 verbindet sich nur mit 2,4-GHz-Netzen.
  2. Wähle im Menü Werkzeuge dein Board (z. B. ESP32 Dev Module) und ein Partition Scheme mit OTA (Default oder Minimal SPIFFS).
  3. Den ersten Upload machst du per USB-Kabel. Das ist nötig, weil auf dem Board noch kein OTA-Code läuft.
  4. Öffne den Seriellen Monitor mit 115200 Baud und notiere die IP-Adresse, die das Board ausgibt.
  5. Zieh das USB-Kabel ab und versorge das Board, wenn du willst, über ein anderes Netzteil. Nach 10–20 Sekunden erscheint unter Werkzeuge > Port bei den Netzwerkports eine Zeile wie "bluegrays-esp32 at 192.168.1.x"; wähle sie aus.
  6. Ändere die LED-Zeit im Code von 500 auf 100 und klicke auf Hochladen. Wenn die IDE nach dem Passwort fragt, gib "ota1234" ein.
  7. Im Ausgabefenster siehst du den Fortschritt in Prozent und am Ende eine Zeile wie "Done" oder "Result: OK". Das Board startet neu und die LED blinkt jetzt schnell.
Taucht der Netzwerkport nicht auf, prüfe zuerst, ob Rechner und ESP32 im selben Netz sind; Gastnetze und manche Mesh-Systeme verhindern, dass sich Geräte gegenseitig sehen. Die IDE neu starten, das Board neu starten oder einfach ein paar Sekunden warten reicht meistens. Auf Mac und Linux nutzt die IDE für den Upload das Skript espota.py, daher muss Python 3 auf deinem Rechner installiert sein.

Eine Einschränkung solltest du kennen: Der Netzwerkport ist nur zum Hochladen da, der Serielle Monitor funktioniert nicht kabellos. Um die Meldungen des Boards zu sehen, steckst du entweder USB wieder ein oder zeigst den Status auf einer Webseite, einem Display oder per MQTT an. Beim Entwickeln am Schreibtisch kannst du das Board auch am USB lassen und trotzdem übers Netz hochladen; so hast du schnelle Uploads und den Seriellen Monitor gleichzeitig.

Passwortschutz und Sicherheit

Ein Board mit offenem OTA-Dienst ist eine Tür, durch die jeder in deinem Netz Code hochladen kann. Bei ArduinoOTA steht das Passwort mit setPassword() im Klartext im Code; willst du den Code weitergeben, kannst du mit setPasswordHash() den MD5-Hash des Passworts übergeben, sodass das Passwort selbst nicht im Quelltext steht. ElegantOTA schützt die Seite /update mit Benutzername und Passwort (HTTP Basic Auth).

  • Gib jedem Gerät ein eigenes, schwer zu erratendes Passwort: Werte wie "1234" oder "admin" probiert jeder zuerst.
  • Mach das Board nicht aus dem Internet erreichbar: OTA oder die Seite /update per Portweiterleitung am Router nach außen zu öffnen, ist ein ernstes Risiko; diese Methoden laufen über unverschlüsseltes HTTP.
  • Nutze HTTPUpdate für entfernte Geräte: Weil das Board das Update selbst anfordert, genügt eine ausgehende Verbindung; holst du es übers Internet, nimm HTTPS mit WiFiClientSecure.
  • Geh während des Updates in einen sicheren Zustand: Stoppe in onStart die Motoren und schalte Heizungs- und Pumpenrelais aus. Der Neustart dauert ein paar Sekunden, und die Pins können in dieser Zeit undefiniert sein.

Methode 2: .bin im Browser hochladen mit ElegantOTA

ElegantOTA ergänzt den Webserver auf dem ESP32 um eine schicke Seite /update. Du öffnest sie vom Handy oder von jedem Rechner ohne Arduino IDE, wählst die kompilierte .bin-Datei und lädst sie hoch; der Fortschrittsbalken erscheint im Browser. Das ist die praktischste Methode, wenn du das Gerät an jemand anderen übergibst oder vor Ort aktualisierst.

  1. Öffne in der Arduino IDE den Bibliotheksverwalter, suche nach ElegantOTA (Ayush Sharma) und installiere die Bibliothek.
  2. Passe den Code unten an und lade ihn beim ersten Mal per USB hoch.
  3. Öffne die im Seriellen Monitor angezeigte Adresse (z. B. http://192.168.1.42/update) im Browser und melde dich mit dem Benutzernamen "admin" und dem Passwort "ota1234" an.
  4. Lass als Modus Firmware ausgewählt und zieh die .bin-Datei hinein; nach dem Upload startet das Board von selbst neu.
C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WebServer.h>
3#include <ElegantOTA.h>
4
5const char* WIFI_SSID = "AgAdi";          // Wi-Fi adın / your Wi-Fi name
6const char* WIFI_PASS = "AgSifresi";      // Wi-Fi şifren / your Wi-Fi password
7
8WebServer server(80);
9unsigned long otaProgressMillis = 0;
10
11void onOTAStart() {
12  Serial.println("OTA basladi / OTA started");     // röleleri kapat / switch relays off
13}
14
15void onOTAProgress(size_t current, size_t final) {
16  if (millis() - otaProgressMillis > 1000) {        // saniyede bir yaz / print once per second
17    otaProgressMillis = millis();
18    Serial.printf("%u / %u bayt / bytes\n", current, final);
19  }
20}
21
22void onOTAEnd(bool success) {
23  Serial.println(success ? "OTA basarili / OTA successful" : "OTA hatasi / OTA failed");
24}
25
26void setup() {
27  Serial.begin(115200);
28  WiFi.mode(WIFI_STA);
29  WiFi.begin(WIFI_SSID, WIFI_PASS);
30  while (WiFi.status() != WL_CONNECTED) {
31    delay(500);
32    Serial.print(".");
33  }
34  Serial.println();
35  Serial.print("Adres / Address: http://");
36  Serial.print(WiFi.localIP());
37  Serial.println("/update");
38
39  server.on("/", []() {
40    server.send(200, "text/plain", "BlueGrays ESP32 - surum / version 1.0");
41  });
42
43  ElegantOTA.begin(&server, "admin", "ota1234");   // /update sayfası + kullanıcı/parola / /update page + user/password
44  ElegantOTA.onStart(onOTAStart);
45  ElegantOTA.onProgress(onOTAProgress);
46  ElegantOTA.onEnd(onOTAEnd);
47
48  server.begin();
49}
50
51void loop() {
52  server.handleClient();     // web isteklerini işle / handle web requests
53  ElegantOTA.loop();         // başarılı yüklemeden sonra yeniden başlatır / reboots after a successful upload
54}

Standardmäßig arbeitet ElegantOTA mit der synchronen Klasse WebServer aus dem Core, deshalb sind die Aufrufe server.handleClient() und ElegantOTA.loop() in loop() Pflicht. Nutzt dein Projekt bereits ESPAsyncWebServer, kannst du die Option ELEGANTOTA_USE_ASYNC_WEBSERVER der Bibliothek auf 1 setzen und sie mit dem asynchronen Server verwenden; die Einrichtung des asynchronen Servers erklären wir im Beitrag ESP32 Async Webserver und WebSocket. Der Modus Filesystem auf der Seite aktualisiert statt des Programms das LittleFS- oder SPIFFS-Abbild (Webseitendateien, Einstellungsdateien).

Die .bin-Datei bekommen: kompilierte Binärdatei exportieren

Für ElegantOTA und HTTPUpdate brauchst du die kompilierte Programmdatei. Wähle in der Arduino IDE Sketch > Kompilierte Binärdatei exportieren (Export Compiled Binary). Die IDE kompiliert das Programm und legt mehrere Dateien im Ordner build innerhalb deines Sketch-Ordners ab. Nur eine davon eignet sich für OTA:

DateiInhaltFür OTA geeignet?
meinprojekt.ino.binNur die Anwendung (dein Programm)Ja, diese Datei lädst du hoch
meinprojekt.ino.bootloader.binBootloaderNein
meinprojekt.ino.partitions.binPartitionstabelleNein
meinprojekt.ino.merged.bin (Core 3.x)Bootloader, Tabelle und Programm zusammenNein, wird nur per USB an Adresse 0x0 geschrieben
Achte darauf, dass du das Programm für den Chip auf deinem Board kompiliert hast. Lädst du eine für den ESP32 kompilierte .bin auf einen ESP32-S3 oder ESP32-C3, wird sie bei der abschließenden Prüfung abgelehnt und das Board läuft mit dem alten Programm weiter. Wählst du versehentlich merged.bin oder bootloader.bin, bricht das Update mit "Wrong Magic Byte", Platzmangel oder einem Aktivierungsfehler ab.

Methode 3: automatische Updates vom Server mit HTTPUpdate

Stell dir vor, du hast fünf Sensorboards im Haus verteilt. Statt jedes einzeln aus der IDE zu bespielen, legst du die neue .bin-Datei auf einen Server und die Boards laden sie selbst herunter. Die Bibliothek HTTPUpdate aus dem ESP32-Core erledigt das mit einer einzigen Zeile. Im Beispiel unten startet das Update, wenn du die BOOT-Taste (GPIO 0) auf dem Board drückst:

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <HTTPUpdate.h>
3
4const char* WIFI_SSID = "AgAdi";
5const char* WIFI_PASS = "AgSifresi";
6// Bilgisayarındaki ya da sunucundaki .bin dosyası / the .bin file on your computer or server
7const char* FIRMWARE_URL = "http://192.168.1.50:8000/firmware.bin";
8const int BUTTON_PIN = 0;               // karttaki BOOT butonu / the BOOT button on the board
9
10void setup() {
11  Serial.begin(115200);
12  pinMode(BUTTON_PIN, INPUT_PULLUP);
13  WiFi.begin(WIFI_SSID, WIFI_PASS);
14  while (WiFi.status() != WL_CONNECTED) delay(500);
15  Serial.println("Hazir: guncellemek icin BOOT'a bas / Ready: press BOOT to update");
16}
17
18void loop() {
19  if (digitalRead(BUTTON_PIN) == LOW) {      // butona basıldı / button pressed
20    WiFiClient client;
21    httpUpdate.rebootOnUpdate(true);          // başarılıysa yeniden başlat / reboot on success
22    t_httpUpdate_return ret = httpUpdate.update(client, FIRMWARE_URL);
23
24    switch (ret) {
25      case HTTP_UPDATE_FAILED:
26        Serial.printf("Hata / Error (%d): %s\n", httpUpdate.getLastError(),
27                      httpUpdate.getLastErrorString().c_str());
28        break;
29      case HTTP_UPDATE_NO_UPDATES:
30        Serial.println("Guncelleme yok / No update");
31        break;
32      case HTTP_UPDATE_OK:
33        Serial.println("Tamam / OK");        // buraya genelde gelinmez, kart yeniden başlar / usually not reached, the board reboots
34        break;
35    }
36    delay(1000);
37  }
38}

Zum Ausprobieren legst du die .bin-Datei als firmware.bin in einen Ordner auf deinem Rechner und startest dort python3 -m http.server 8000; die IP-Adresse im Code ersetzt du durch die lokale IP deines Rechners. Im echten Einsatz ersetzt du die Taste durch einen Timer: Das Board liest zum Beispiel stündlich eine kleine Datei "version.txt", und ist die Versionsnummer auf dem Server höher als die eigene, startet es das Update. So hängt es auch nicht in einer Schleife fest, in der es dieselbe Datei immer wieder lädt und neu startet.

Was passiert, wenn die Verbindung während des OTA-Updates abbricht?

Kurze Antwort: Dein Board wird nicht unbrauchbar. Weil das neue Programm in die unbenutzte Partition geschrieben und die Boot-Partition erst nach der Prüfung der kompletten Datei umgestellt wird, läuft das Board nach einem abgebrochenen Upload mit dem alten Programm weiter. Du siehst "Error Uploading" in der IDE, OTA_RECEIVE_ERROR bei ArduinoOTA oder ein Fehlschlagen bei ElegantOTA; behebe das Problem und wiederhole den Upload. Fällt mitten im Upload der Strom aus, gilt dasselbe: Das Board startet das alte Programm. Das einzige echte Risiko ist ein fehlerhaftes neues Programm: Lädst du ein Programm hoch, das sich nicht mit dem WLAN verbindet oder keinen OTA-Code enthält, brauchst du für das nächste Update wieder das Kabel.

  • Schwaches WLAN-Signal: Bleibt der Upload bei 30–60 % hängen, bring das Board näher an den Router oder nimm ein Modul mit externer Antenne. Ist WiFi.RSSI() im Seriellen Monitor schlechter als -75 dBm, sind Abbrüche zu erwarten; Details findest du in ESP32 verbindet sich nicht mit dem WLAN.
  • Zu wenig Strom: Flash-Schreiben und WLAN-Senden ziehen gleichzeitig Strom. Ein schwacher USB-Port oder ein dünnes Kabel kann das Board während des Uploads zurücksetzen; das zeigt sich als Brownout-Fehler. Nutze ein solides 5-V-Netzteil, das mindestens 500 mA liefert.
  • Lange Wartezeiten in loop(): Pausen wie delay(5000) verzögern den Aufruf von handle(), und die IDE meldet "No response from the ESP". Erledige das Timing mit millis().
  • Firewall: Bei ArduinoOTA verbindet sich der ESP32 beim Start des Uploads zurück zu deinem Rechner. Blockiert die Windows-Firewall oder ein Virenscanner diese eingehende Verbindung, scheitert der Upload sofort; erlaube im Dialog beim ersten Versuch den Zugriff in privaten Netzwerken.

OTA in jedem neuen Sketch behalten

Die häufigste OTA-Enttäuschung läuft so ab: Du lädst per OTA ein völlig anderes Projekt hoch, dieses Projekt enthält keinen ArduinoOTA-Code, und das Board taucht nicht mehr als Netzwerkport auf. Das neu hochgeladene Programm ersetzt das alte vollständig; OTA ist nichts, was "auf dem Board bleibt", jedes Programm muss es selbst mitbringen. Damit du nicht wieder auf die Leiter zum Deckengerät steigen musst, mach diese Regeln zur Gewohnheit:

  • Nutze eine Vorlage: Pack die WLAN-Verbindung und die ArduinoOTA-Einstellungen in eine eigene Funktion (z. B. setupOTA()) und beginne jedes neue Projekt mit dieser Datei.
  • Setz den Aufruf von handle() ganz an den Anfang von loop() und lass in loop() niemals eine lange blockierende Schleife.
  • Bei WLAN-Abbruch neu verbinden: Nutze WiFi.setAutoReconnect(true) oder prüfe die Verbindung regelmäßig; ein Board ohne Verbindung bekommt keine Updates.
  • Gib Deep-Sleep-Projekten ein Wartungsfenster: Ein schlafendes Board hört die OTA-Anfrage nicht. Schreib einen Modus, der vor dem Schlafen 60 Sekunden auf OTA wartet, wenn beim Start eine Taste gedrückt ist oder ein MQTT-Flag gekommen ist. Zu den Schlafmodi siehe den Beitrag ESP32 Deep Sleep.
  • Teste zuerst auf einem zweiten Board am Schreibtisch: Bevor du an das Gerät im Einsatz sendest, lass denselben Code auf einem Board neben dir laufen; verbindet es sich mit dem WLAN und erscheint als Netzwerkport, kannst du sicher senden.
  • Gib eine Versionsnummer aus: Halte oben im Code eine Konstante FW_VERSION und zeige sie auf der Webseite oder dem Display; so weißt du immer, welche Version auf welchem Board läuft.

OTA auf ESP8266 und Raspberry Pi Pico W

Der ArduinoOTA- und ElegantOTA-Code aus dieser Anleitung läuft mit kleinen Änderungen auch auf ESP8266-Boards (NodeMCU, Wemos D1 Mini): Statt WiFi.h nimmst du ESP8266WiFi.h, statt WebServer ESP8266WebServer, und der OTA-Port ist 8266. Auf ESP8266-Boards mit 4 MB Flash musst du im Menü Flash Size eine Option wählen, die genug Programmspeicher für OTA übrig lässt. Beim Raspberry Pi Pico W bietet der Core arduino-pico Unterstützung für ArduinoOTA; dort wird das neue Programm zuerst ins LittleFS-Dateisystem geladen und beim Start an seinen Platz kopiert. Deshalb musst du beim Pico W im Menü Flash Size einen Dateisystembereich reservieren, der größer als dein Programm ist. MicroPython hat kein fertiges OTA-Werkzeug; man kann kleine Skripte schreiben, die .py-Dateien übers Netz laden und ersetzen, aber das ist kein geprüftes Update mit zwei Partitionen wie beim ESP32.

Projektideen mit OTA

  • Decken- oder Wandsensor: Ändere die Schwellwerte eines Boards, das Temperatur, Luftfeuchte und Bewegung misst, ohne ein Kabel anzufassen.
  • Smart-Home-Relais: Aktualisiere die Zeitregeln der Relais-Platine im Verteilerkasten per OTA; schalte die Relais in onStart in einen sicheren Zustand.
  • Home-Assistant-Geräte: Ergänze Sensoren, die per MQTT mit Home Assistant verbunden sind, übers Netz um neue Funktionen.
  • Gartenbewässerung: Ändere Gießzeiten und den Bodenfeuchte-Schwellwert, ohne das wasserdichte Gehäuse zu öffnen.
  • Fortschrittsbalken auf dem LCD: Zeige den onProgress-Wert als Prozent und Balken auf einem 16x2-LCD; genau das macht das ESP32-OTA-Projekt in BlueGrays.
  • Flotten-Update: Lass mehrere Boards jede Nacht per HTTPUpdate beim selben Server nach einer neuen Version fragen.

Häufige Fehler und Lösungen

SymptomWahrscheinliche UrsacheLösung
Kein Netzwerkport im Port-MenüBoard in anderem Netz, mDNS blockiert, Code ruft ArduinoOTA.begin() nicht aufGleiches 2,4-GHz-Netz nutzen, IDE neu starten, prüfen, ob die IP im Seriellen Monitor erscheint
"No response from the ESP"Langes delay() in loop(), Board beschäftigt oder Firewallmillis() statt delay() nutzen, die IDE in der Firewall zulassen
"Authentication Failed"Falsches OTA-PasswortDen setPassword-Wert aus dem Code eingeben; bei vergessenem Passwort einmal per USB hochladen
"Not Enough Space" / Begin FailedSchema Huge APP oder No OTA, Programm passt nicht in den zweiten BereichMinimal SPIFFS wählen und einmal per USB hochladen; Programm verkleinern
Upload bricht mittendrin abSchwaches Signal, Spannungseinbruch, VerbindungsabbruchBoard näher an den Router, solides 5-V-Netzteil, erneut versuchen; das alte Programm läuft weiter
Board kommt nach dem Upload nicht ins NetzNeuer Code ohne WLAN oder OTA, falsche SSIDPer USB korrigieren; künftig jedes Projekt mit der OTA-Vorlage beginnen
"Wrong Magic Byte" oder Aktivierungsfehler bei ElegantOTAmerged.bin, bootloader.bin oder eine für einen anderen Chip kompilierte Datei gewähltNur die Datei meinprojekt.ino.bin hochladen
Wenn du OTA zum ersten Mal einrichtest, lass das Board am USB und den Seriellen Monitor offen; die Ausgabe von onError sagt dir in einer Zeile, ob Passwort, Platz oder Verbindung das Problem ist. Sobald alles läuft, kannst du das Kabel abziehen.

OTA ist der Schlüssel, um ESP32-Projekte vom Schreibtisch an einen echten Einsatzort zu bringen: Ist es einmal richtig eingerichtet, kommen Korrekturen, neue Funktionen und geänderte Schwellwerte in Sekunden kabellos an. In der BlueGrays-App findest du das Projekt ESP32 OTA Update (mit IP- und Fortschrittsanzeige auf dem LCD) zusammen mit den Projekten zu WLAN-Verbindung, Async Webserver, mDNS und NTP, jeweils Schritt für Schritt mit Schaltplan und Code.

Häufige Fragen

Was ist ESP32 OTA?

OTA (Over-The-Air) bedeutet, ein neues Programm per WLAN statt per USB-Kabel auf den ESP32 zu laden. Das Board schreibt den neuen Code in eine unbenutzte Programmpartition, prüft ihn und startet mit der neuen Version neu. Den ersten OTA-fähigen Sketch musst du einmal per USB hochladen.

Warum erscheint der ESP32-Netzwerkport nicht in der Arduino IDE?

Die häufigsten Gründe sind, dass Rechner und Board in verschiedenen Netzen sind, ein Gastnetz die Geräte trennt oder der Aufruf ArduinoOTA.begin() im Code nie ausgeführt wird. Prüfe im Seriellen Monitor, ob das Board eine IP bekommen hat, starte die IDE neu und warte ein paar Sekunden.

Welches Partitionsschema brauche ich für ESP32 OTA?

Auf Boards mit 4 MB Flash wählst du Default (2 × 1,25 MB Programmbereich) oder bei großen Programmen Minimal SPIFFS (2 × 1,875 MB). Huge APP und No OTA haben keinen zweiten Programmbereich, daher funktioniert OTA damit nicht. Der erste Upload nach einem Schemawechsel muss per USB erfolgen.

Kann ein abgebrochenes OTA-Update den ESP32 unbrauchbar machen?

Nein. Das neue Programm wird in eine leere Partition geschrieben, und die Boot-Partition wird erst umgestellt, wenn die komplette Datei geprüft ist. Fallen Verbindung oder Strom aus, startet das Board das alte Programm und du kannst den Upload einfach wiederholen.

Kann ich beim OTA-Upload den Seriellen Monitor nutzen?

Der Netzwerkport dient nur zum Hochladen von Code; der Serielle Monitor funktioniert nicht kabellos. Um Meldungen zu sehen, kannst du das Board am USB lassen oder die Informationen auf einer Webseite, einem Display oder per MQTT anzeigen.

Wie setze ich ein ESP32-OTA-Passwort?

Bei ArduinoOTA rufst du vor begin() ArduinoOTA.setPassword("passwort") auf; die IDE fragt vor dem Upload nach diesem Passwort. Soll das Passwort nicht im Code stehen, übergibst du mit setPasswordHash() seinen MD5-Hash. Bei ElegantOTA schützt du die Seite mit begin(&server, "benutzer", "passwort").

Alle Projekte ansehen
ESP32-OTA-Update – Drahtlose Firmware-Installation (mit LCD-Display)
#132Fortgeschritten
Premium

ESP32-OTA-Update – Drahtlose Firmware-Installation (mit LCD-Display)

In diesem Projekt lernst du, wie du auf dem ESP32 ohne USB-Kabel über WLAN neue Firmware installieren kannst. Mit der ArduinoOTA-Bibliothek wird der ESP32 im Netzwerk sichtbar und wird im Reiter „Network port“ der Arduino-IDE automatisch als bluegrays-ota aufgelistet. Die erste Installation erfolgt über USB, alle nachfolgenden Updates erfolgen drahtlos – eine äußerst wichtige Funktion für Feldgeräte. Auf dem I2C-LCD-Display werden der WLAN-Status, die IP-Adresse, der Hostname, der Fortschrit

4.6(14)
22
ESP32-WLAN-STA-Verbindung (mit LCD-Display)
#127Fortgeschritten

ESP32-WLAN-STA-Verbindung (mit LCD-Display)

In diesem Projekt verbinden wir den ESP32 im Station-Modus (STA) sicher und fehlertolerant mit dem heimischen WLAN. Wir lagern SSID und Passwort in eine separate secrets.h-Datei aus, um Leaks zu Git zu verhindern, richten einen Auto-Reconnect-Mechanismus ein und zeigen RSSI-Signalpegel und IP-Adresse auf einem I2C-LCD-Display an. Die interne LED dient als Statusanzeige. Ein Verbindungsmanager auf Produktionsniveau.

4.4(21)
34
ESP32 Async-Webserver (mit IP-Anzeige auf dem LCD)
#129Fortgeschritten

ESP32 Async-Webserver (mit IP-Anzeige auf dem LCD)

In diesem Projekt verwandeln wir den ESP32 in einen asynchronen Webserver, den Sie über Ihr Smartphone oder Ihren Computer im selben WLAN-Netzwerk steuern können. Dank der ESPAsyncWebServer-Bibliothek kann der Server mehrere Anfragen gleichzeitig bearbeiten (im Gegensatz zum klassischen WebServer.h, der bei einer einzigen Anfrage blockiert). Sie können über den Browser die IP-Adresse des ESP32 öffnen und durch Drücken der ON/OFF-Schaltflächen (Routen /on und /off) die an GPIO 5 anges

4.8(16)
26
ESP32 mDNS: Zugriff auf das Gerät über „bluegrays-esp.local“ (mit LCD-Display)
#131Fortgeschritten
Premium

ESP32 mDNS: Zugriff auf das Gerät über „bluegrays-esp.local“ (mit LCD-Display)

In diesem Projekt fügen wir dem ESP32 einen mDNS-Dienst (Multicast DNS) hinzu, um den Zugriff nicht über eine IP-Adresse, sondern über einen lesbaren Hostnamen wie bluegrays-esp.local zu ermöglichen. Selbst wenn sich die vom DHCP zugewiesene IP-Adresse ändert, können Sie das Gerät immer unter demselben Namen erreichen. Indem wir zusätzlich einen kleinen Webserver darauf betreiben, senden wir über den Browser unter der Adresse http://bluegrays-esp.local/ Befehle zur LED-Steuerung. Auf dem I2C

4.8(14)
23
ESP32-WebSocket-Zähler (2 Tasten + LCD + Web-Echtzeit)
#130Fortgeschritten
Premium

ESP32-WebSocket-Zähler (2 Tasten + LCD + Web-Echtzeit)

In diesem Projekt ändern zwei am ESP32 angeschlossene Taster (GPIO 5 zählt hoch, GPIO 4 zählt herunter) einen Zähler. Der Wert wird sofort auf einem 16x2-I2C-LCD und über die WebSocket-Unterstützung von ESPAsyncWebServer in allen verbundenen Browsern aktualisiert, ohne die Seite neu zu laden. Statt HTTP-Polling wird eine einzige dauerhafte Verbindung genutzt; der ESP32 sendet den neuen Wert mit ws.textAll() an alle.

4.5(14)
23
ESP32: Echtzeit aus dem Internet per NTP
#128Fortgeschritten
Premium

ESP32: Echtzeit aus dem Internet per NTP

Der ESP32 verbindet sich mit dem WLAN und ruft die Echtzeit mit Millisekunden-Genauigkeit von NTP-Servern (Network Time Protocol) ab. Dank configTzTime() wird die türkische Zeitzone (TRT, UTC+3) automatisch angewendet, und der DST-Wechsel wird per POSIX-TZ-String verwaltet. Die Uhrzeit wird auf dem Serial Monitor und einem optionalen I2C-LCD ausgegeben. configTzTime() startet den SNTP-Dienst; bei verfügbarem Netzwerkzugang erfolgt regelmäßig eine erneute Synchronisierung, und zwischen den Sy

4.5(13)
21
ESP32 HTTPClient + Wetter-API (mit LCD-Display)
#133Fortgeschritten
Premium

ESP32 HTTPClient + Wetter-API (mit LCD-Display)

In diesem Projekt führen wir mit dem ESP32 über das Internet mithilfe von HTTPClient.h einen REST-API-Aufruf an die Wetter-API (wttr.in) durch. Mit ArduinoJson v7 analysieren wir die zurückgegebenen JSON-Daten und zeigen Informationen zu Stadt, Temperatur, Luftfeuchtigkeit, Wetter und Wind sowohl auf Türkisch als auch auf Englisch auf einem I2C-LCD-Display an. wttr.in ist kostenlos und erfordert keinen API-Schlüssel – Sie können den aktuellen Wetterbericht einer beliebigen Stadt abrufen, indem

4.7(13)
20
ESP32 Deep Sleep – Batteriesparmodus (OLED + RTC-RAM-Zähler)
#135Fortgeschritten
Premium

ESP32 Deep Sleep – Batteriesparmodus (OLED + RTC-RAM-Zähler)

Der Deep-Sleep-Modus des ESP32 senkt den Stromverbrauch auf etwa 10 µA, indem er die CPU und die meisten Peripheriegeräte abschaltet, und ist für batteriebetriebene IoT-Geräte von entscheidender Bedeutung. In diesem Projekt verwenden wir drei verschiedene Weckquellen: den Timer (15 s), einen externen Pin (EXT0 – Taste GPIO 33) und die Berührungserkennung (T0/GPIO 4). Mit RTC_DATA_ATTR markierte Variablen bleiben während des Deep-Sleep-Modus erhalten – der Boot-Zähler, der Timer-Wake-Zähler und

4.3(10)
16