Skip to content

Instantly share code, notes, and snippets.

@SebastianBitsch
Created April 12, 2025 01:14
Show Gist options
  • Save SebastianBitsch/567e03edc98bc6ccd1bfec8419d0b30e to your computer and use it in GitHub Desktop.
Save SebastianBitsch/567e03edc98bc6ccd1bfec8419d0b30e to your computer and use it in GitHub Desktop.
Update ESP boards over-the-air
/*
* ESP32 HTTP OTA Update Example
* This sketch demonstrates how to check for and download firmware updates
* from an HTTP server.
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <HTTPUpdate.h>
#define LED_BUILTIN 2
// WiFi credentials
const char* ssid = "...";
const char* password = "...";
// Device information
const char* DEVICE_TYPE = "esp32";
const char* FIRMWARE_VERSION = "1.0.1";
// Update server details
const char* API_SERVER = "http://...:5001";
const char* API_KEY = "...";
const unsigned long CHECK_INTERVAL = 24 * 60 * 60 * 1000; // Once per day, ms
unsigned long lastCheckTime = 0;
void setup() {
Serial.begin(115200);
Serial.println("\n\n--------------------------");
Serial.println("ESP32 OTA Update Client");
Serial.println("--------------------------");
Serial.print("Current firmware version: ");
Serial.println(FIRMWARE_VERSION);
// Connect to WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("Connected to WiFi. IP address: ");
Serial.println(WiFi.localIP());
// Check for updates on startup
checkForUpdates();
// Your regular setup code here
// ..
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
// Periodically check for updates
if (millis() - lastCheckTime > CHECK_INTERVAL || lastCheckTime == 0) {
if (WiFi.status() == WL_CONNECTED) {
checkForUpdates();
}
lastCheckTime = millis();
}
// Your regular code here
// ..
// Print status periodically
static unsigned long lastMsg = 0;
if (millis() - lastMsg > 10000) { // Every 10 seconds
lastMsg = millis();
Serial.printf("Device running firmware v%s, IP: %s\n", FIRMWARE_VERSION, WiFi.localIP().toString().c_str());
}
}
void checkForUpdates() {
Serial.println("Checking for firmware updates...");
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi not connected. Skipping update check.");
return;
}
HTTPClient http;
// Prepare URL with query parameters
String url = String(API_SERVER) + "/firmware/version?device_type=" + DEVICE_TYPE + "&current_version=" + FIRMWARE_VERSION;
Serial.print("Connecting to: ");
Serial.println(url);
http.begin(url);
http.addHeader("X-API-Key", API_KEY);
// Send GET request
int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println("Response: " + payload);
// Manual JSON parsing to avoid dependency on ArduinoJson
// Looking for "update_available":true
bool updateAvailable = (payload.indexOf("\"update_available\":true") > -1);
if (updateAvailable) {
// Extract version - simple method, assumes format like "latest_version":"1.0.1"
int verStart = payload.indexOf("\"latest_version\":\"") + 18; // Length of "latest_version":"
int verEnd = payload.indexOf("\"", verStart);
String latestVersion = "";
if (verStart > 18 && verEnd > verStart) {
latestVersion = payload.substring(verStart, verEnd);
Serial.println("New version available: " + latestVersion);
Serial.println("Current version: " + String(FIRMWARE_VERSION));
// Download and install update
updateFirmware(latestVersion);
} else {
Serial.println("Found update but couldn't parse version");
}
} else {
Serial.println("Firmware is up to date!");
}
} else {
Serial.print("Failed to check version, HTTP error code: ");
Serial.println(httpCode);
Serial.println(http.errorToString(httpCode));
}
http.end();
}
// Custom function to handle firmware updates with the API key properly included
void updateFirmware(String version) {
Serial.println("Starting firmware update...");
// Prepare URL for firmware download
String url = String(API_SERVER) + "/firmware/download?device_type=" + DEVICE_TYPE + "&version=" + version;
Serial.print("Downloading from: ");
Serial.println(url);
// Create HTTP client
HTTPClient http;
http.begin(url);
// Add API key header
http.addHeader("X-API-Key", API_KEY);
// Start the request
int httpCode = http.GET();
if (httpCode != HTTP_CODE_OK) {
Serial.printf("HTTP GET failed, error: %d, %s\n", httpCode, http.errorToString(httpCode).c_str());
http.end();
return;
}
// Get content length for progress tracking
int contentLength = http.getSize();
if (contentLength <= 0) {
Serial.println("Error: Content length is invalid");
http.end();
return;
}
Serial.printf("Update size: %d bytes\n", contentLength);
// Check if we have enough space
if (!Update.begin(contentLength)) {
Serial.println("Error: Not enough space for update");
http.end();
return;
}
// Create buffer for reading data
uint8_t buff[1024] = { 0 };
size_t bytesRead = 0;
size_t totalRead = 0;
// Get tcp stream
WiFiClient * stream = http.getStreamPtr();
// Read all data from server and write it to the update partition
Serial.println("Downloading firmware...");
// Turn on LED to indicate update in progress
digitalWrite(LED_BUILTIN, HIGH);
// Read data and write it to the Update object
while (http.connected() && (totalRead < contentLength)) {
// Read data from HTTP stream
size_t avail = stream->available();
if (avail) {
bytesRead = stream->readBytes(buff, min(avail, sizeof(buff)));
// Write data to the update partition
if (Update.write(buff, bytesRead) != bytesRead) {
Serial.println("Error: Update write failed");
http.end();
Update.abort();
return;
}
totalRead += bytesRead;
// Print progress
int progress = (totalRead * 100) / contentLength;
static int lastProgress = 0;
if (progress % 10 == 0 && progress != lastProgress) {
Serial.printf("Progress: %d%%\n", progress);
lastProgress = progress;
// Blink LED for visual feedback
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
}
delay(1); // Small delay to prevent WDT issues
}
// Check if we got all data
if (totalRead != contentLength) {
Serial.println("Error: Size mismatch");
http.end();
Update.abort();
return;
}
// End the update
if (!Update.end()) {
Serial.printf("Error: Update end failed! (%d)\n", Update.getError());
http.end();
return;
}
// Cleanup
http.end();
Serial.println("Update successful!");
Serial.println("Rebooting...");
delay(1000);
ESP.restart();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment