← Web Server OTA Firmware Updates on an ESP32 PLC
Textile monitoring (weaving)ESP32 PLCHTTPResilience / OTA
Web Server OTA Firmware Updates on an ESP32 PLC — full example
Embedded web server with OTA firmware updates on an ESP32 PLC: status page, JSON endpoint and browser .bin upload — no USB cable on the factory floor.
Complete, runnable program for the ESP32 PLC (webserver-ota-firmware.ino): wiring header, requirements and integration notes included.
Download the full project pack — freeThis example + the related ones + bill of materials
Read-only preview.
/*
* COMPLETE EXAMPLE — Embedded web server with OTA firmware update
*
* Hardware: ESP32 PLC (Industrial Shields, any model with WiFi)
* Based on: textile monitoring project, modul_WebServer_v2.h
*
* Network:
* The PLCs are spread across the plant, next to each knitting machine:
* reflashing over USB means climbing a ladder. With OTA the update is
* done from the browser: http:///
*
* Endpoints:
* GET / HTML status page with a firmware upload form
* GET /status JSON with digital inputs, uptime and free heap
* POST /update Receives the compiled .bin, flashes it and reboots
*
* Works together with other catalog examples:
* - nonblocking-wifi-reconnection.ino (the server only responds with network)
* - rtc-ntp-synchronization.ino (timestamp in /status)
* - mqtt-remote-commands.ino (complementary diagnostics without a browser)
*/
#include
#include
#include
const char *WIFI_SSID = "WIFI_SSID";
const char *WIFI_PASS = "WIFI_PASS";
const int PLC_ID = 1;
WebServer server(80);
const int pins[] = {I0_0, I0_1, I0_2, I0_3, I0_4, I0_5};
const int NPINS = 6;
// ------------------------------------------------- Pages
void handleRoot() {
String html =
"PLC " + String(PLC_ID) + " "
"ESP32 PLC " + String(PLC_ID) + " — Textile monitoring
"
"Uptime: " + String(millis() / 1000) + " s | "
"Free heap: " + String(ESP.getFreeHeap()) + " bytes
"
""
"Update firmware (OTA)
"
""
"";
server.send(200, "text/html", html);
}
void handleStatus() {
String json = "{\"id\":" + String(PLC_ID) +
",\"uptime_s\":" + String(millis() / 1000) +
",\"heap\":" + String(ESP.getFreeHeap()) + ",\"inputs\":{";
for (int i = 0; i < NPINS; i++)
json += "\"I0_" + String(i) + "\":" + String(digitalRead(pins[i])) +
(i < NPINS - 1 ? "," : "");
json += "}}";
server.send(200, "application/json", json);
}
// ------------------------------------------------- OTA over HTTP POST
// First callback: final response + reboot. Second: chunks of the .bin
void setupOTA() {
server.on("/update", HTTP_POST, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/plain", Update.hasError() ? "FAIL" : "OK - rebooting");
delay(1000);
ESP.restart(); // boots with the new firmware
}, []() {
HTTPUpload &up = server.upload();
if (up.status == UPLOAD_FILE_START) {
Serial.println("OTA: receiving " + up.filename);
if (!Update.begin(UPDATE_SIZE_UNKNOWN)) Update.printError(Serial);
} else if (up.status == UPLOAD_FILE_WRITE) {
if (Update.write(up.buf, up.currentSize) != up.currentSize)
Update.printError(Serial);
} else if (up.status == UPLOAD_FILE_END) {
if (Update.end(true))
Serial.println("OTA OK: " + String(up.totalSize) + " bytes");
else
Update.printError(Serial);
}
});
}
void setup() {
Serial.begin(115200);
for (int i = 0; i < NPINS; i++) pinMode(pins[i], INPUT);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
uint32_t t0 = millis();
while (WiFi.status() != WL_CONNECTED && millis() - t0 < 15000) delay(500);
Serial.println("IP: " + WiFi.localIP().toString());
server.on("/", HTTP_GET, handleRoot);
server.on("/status", HTTP_GET, handleStatus);
setupOTA();
server.begin();
Serial.println("OTA web server ready on port 80");
}
void loop() {
server.handleClient(); // serve web requests
// ... the normal PLC work continues here (pulses, MQTT, SD):
// the web server only adds a few microseconds per loop iteration
delay(5);
}
Download the full project pack — freeThis example + the related ones + bill of materials