1. Apa Itu OTA Update?
OTA (Over-The-Air) adalah metode untuk mengupdate firmware atau software pada perangkat embedded secara wireless, tanpa perlu menghubungkan kabel USB atau mengakses fisik perangkat. Teknologi ini sangat penting dalam ekosistem IoT di mana perangkat sering dipasang di lokasi yang sulit dijangkau â seperti atap gedung, gudang, area pertanian, atau bahkan di dalam dinding.
Bayangkan Anda memiliki 50 unit ESP32 yang tersebar di berbagai lokasi untuk memantau suhu gudang. Tanpa OTA, setiap kali ada bug atau fitur baru, Anda harus mendatangi setiap perangkat satu per satu dengan laptop dan kabel USB. Dengan OTA, semua bisa diupdate dari satu lokasi pusat melalui jaringan WiFi.
OTA bukan sekadar kenyamanan â untuk banyak proyek IoT produksi, OTA adalah kebutuhan wajib. Tanpa OTA, biaya maintenance perangkat yang tersebar bisa sangat mahal dan tidak praktis.
Jenis-Jenis OTA pada ESP32
ESP32 mendukung beberapa metode OTA yang bisa dipilih sesuai kebutuhan:
| Metode OTA | Cara Kerja | Kompleksitas | Cocok Untuk |
|---|---|---|---|
| ArduinoOTA | Update via jaringan lokal menggunakan Arduino IDE | Mudah | Development & testing |
| Web-Based OTA | Upload firmware via browser ke web server di ESP32 | Sedang | Prototyping & demo |
| HTTP OTA | ESP32 mengunduh firmware dari server HTTP/HTTPS | Lanjut | Produksi & fleet update |
Skema Partisi OTA ESP32
Untuk mendukung OTA, ESP32 menggunakan skema partisi khusus yang membagi flash memory menjadi beberapa bagian. Paling tidak, diperlukan dua partisi aplikasi â satu yang sedang berjalan (aktif) dan satu lagi untuk menampung firmware baru yang diupload.
Pastikan ukuran firmware Anda tidak melebihi kapasitas partisi. Dengan skema default "Default 4MB with spiffs", masing-masing partisi app0 dan app1 berukuran sekitar 1.5 MB. Jika firmware Anda terlalu besar, Anda perlu membuat custom partition scheme.
2. Setup ArduinoOTA
ArduinoOTA adalah metode OTA paling sederhana yang tersedia di ekosistem Arduino. Dengan ArduinoOTA, Anda bisa mengupload firmware baru langsung dari Arduino IDE tanpa perlu kabel USB, asalkan ESP32 dan komputer Anda berada di jaringan WiFi yang sama.
Langkah 1: Instal Library ArduinoOTA
Library ArduinoOTA sudah termasuk dalam package ESP32 untuk Arduino IDE, jadi jika Anda sudah menginstal board ESP32 (seperti di tutorial ESP32 Fundamentals), Anda tidak perlu menginstal library tambahan.
Langkah 2: Program ESP32 dengan ArduinoOTA
Berikut adalah kode dasar yang mengaktifkan ArduinoOTA pada ESP32:
ESP32
Device
Boot
Loader
HTTPS GET
â Web Server
â (GitHub/
firmware.bin S3/custom)
â
1. Cek versi terbaru
dari server
2. Jika ada update,
download firmware.bin
3. Tulis ke partisi OTA
4. Set flag & restart
âŧ
â bootloader memilih
partisi baru
Program HTTP OTA dengan Version Check
// ============================================
// HTTP OTA Update - ESP32
// BeebaneLabs - https://beebanelabs.pages.dev
// ============================================
#include <WiFi.h>
#include <HTTPClient.h>
#include <HTTPUpdate.h>
#include <WiFiClientSecure.h>
const char* ssid = "WIFI_KAMU";
const char* password = "PASSWORD_WIFI";
// URL firmware di server (bisa GitHub raw, S3, server sendiri)
const char* firmwareURL =
"http://yourserver.com/esp32/firmware.bin";
// URL file versi (untuk cek update terbaru)
const char* versionURL =
"http://yourserver.com/esp32/version.txt";
// Versi firmware saat ini â naikkan setiap kali ada update
#define FIRMWARE_VERSION "1.0.0"
void setup() {
Serial.begin(115200);
Serial.println("Firmware v" + String(FIRMWARE_VERSION));
// Koneksi WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected!");
// Cek dan jalankan update jika tersedia
checkForUpdate();
}
void loop() {
// Cek update setiap 60 detik
static unsigned long lastCheck = 0;
if (millis() - lastCheck > 60000) {
checkForUpdate();
lastCheck = millis();
}
// Program utama...
}
void checkForUpdate() {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient http;
http.begin(versionURL);
int httpCode = http.GET();
if (httpCode == 200) {
String newVersion = http.getString();
newVersion.trim();
Serial.println("Versi server: " + newVersion);
Serial.println("Versi lokal: " + String(FIRMWARE_VERSION));
if (newVersion != String(FIRMWARE_VERSION)) {
Serial.println("Update tersedia! Memulai download...");
performOTA(firmwareURL);
} else {
Serial.println("Firmware sudah versi terbaru.");
}
} else {
Serial.println("Gagal cek versi: " + String(httpCode));
}
http.end();
}
void performOTA(const char* url) {
WiFiClient client;
Serial.println("Downloading firmware dari: " + String(url));
t_httpUpdate_return ret = httpUpdate.update(client, url);
switch (ret) {
case HTTP_UPDATE_FAILED:
Serial.printf("Update GAGAL! Error(%d): %s\n",
httpUpdate.getLastError(),
httpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println("Tidak ada update.");
break;
case HTTP_UPDATE_OK:
Serial.println("Update berhasil! Restart...");
// ESP akan restart otomatis
break;
}
}
Menyimpan Firmware di GitHub
Salah satu cara termudah untuk mendistribusikan firmware adalah menggunakan GitHub Releases. Upload file .bin sebagai release asset, lalu gunakan URL raw dari file tersebut di kode ESP32:
// URL firmware dari GitHub Release
const char* firmwareURL =
"https://github.com/user/repo/releases/latest/"
"download/firmware.bin";
// Untuk HTTPS, gunakan WiFiClientSecure:
WiFiClientSecure client;
client.setInsecure(); // Skip SSL verification (dev only!)
httpUpdate.update(client, firmwareURL);
Untuk koneksi HTTPS yang aman, gunakan sertifikat CA server yang valid, bukan setInsecure(). setInsecure() hanya untuk development â di produksi, ini rentan terhadap man-in-the-middle attack. Simpan root CA certificate di SPIFFS dan muat saat inisialisasi.
5. Pertimbangan Keamanan OTA
OTA adalah pedang bermata dua â memudahkan update, tetapi juga membuka potensi keamanan. Jika seseorang bisa mengintersep proses OTA dan mengirim firmware berbahaya, mereka bisa mengambil alih seluruh jaringan perangkat IoT Anda. Berikut adalah langkah-langkah keamanan yang wajib diterapkan:
- â Firmware injection oleh attacker
- â Intercept & modifikasi firmware
- â Upload malware ke semua device
- â Brick perangkat dengan firmware corrupt
- â Pencurian data konfigurasi WiFi
- â Firmware terenkripsi (AES-256)
- â Signature verification (RSA/ECDSA)
- â HTTPS dengan certificate pinning
- â Rollback otomatis jika boot gagal
- â Version downgrade protection
Best Practices Keamanan OTA
| Langkah | Deskripsi | Tingkat |
|---|---|---|
| Gunakan HTTPS | Enkripsi channel komunikasi untuk mencegah intercept | Wajib |
| Verifikasi Signature | Tanda tangani firmware dengan private key, verifikasi di ESP32 | Sangat Disarankan |
| Firmware Encryption | Enkripsi file firmware agar tidak bisa dibaca/dimodifikasi | Disarankan |
| Version Check | Pastikan versi baru > versi lama (cegah downgrade) | Wajib |
| Secure Boot | ESP32 hanya menjalankan firmware yang ditandatangani Espressif | Produksi |
| Flash Encryption | Enkripsi seluruh flash memory, firmware tidak bisa dibaca via JTAG | Produksi |
Jangan pernah menyimpan password WiFi atau API key secara plain text di firmware yang dikirim via OTA. Gunakan NVS (Non-Volatile Storage) ESP32 untuk menyimpan kredensial secara terpisah dari firmware, sehingga update firmware tidak menghapus atau mengekspos data sensitif.
Implementasi Rollback Otomatis
ESP32 memiliki fitur OTA rollback built-in yang mencegah boot loop jika firmware baru bermasalah. Jika ESP32 tidak bisa boot dengan firmware baru setelah N kali restart, bootloader akan otomatis kembali ke firmware lama:
#include <esp_ota_ops.h>
void setup() {
Serial.begin(115200);
// Cek apakah ini boot pertama setelah OTA
const esp_partition_t* running =
esp_ota_get_running_partition();
esp_ota_img_states_t state;
if (esp_ota_get_state_partition(running, &state) == ESP_OK) {
if (state == ESP_OTA_IMG_PENDING_VERIFY) {
// Firmware baru berjalan pertama kali
// Lakukan self-test di sini:
bool selfTestOK = runSelfTest();
if (selfTestOK) {
// Konfirmasi firmware valid
esp_ota_mark_app_valid_cancel_rollback();
Serial.println("Firmware baru dikonfirmasi!");
} else {
// Firmware bermasalah, rollback ke versi lama
Serial.println("Self-test gagal! Rollback...");
esp_ota_mark_app_invalid_and_rollback();
ESP.restart();
}
}
}
}
bool runSelfTest() {
// Test koneksi WiFi
// Test koneksi server
// Test sensor aktif
// Return true jika semua OK
return true;
}
6. Proyek Praktis: Remote Update Sensor Node
Sekarang kita akan menggabungkan semua yang telah dipelajari ke dalam satu proyek lengkap: sensor node yang bisa di-update dari jarak jauh. Proyek ini menggunakan ESP32 yang membaca sensor suhu DHT11, mengirim data ke MQTT broker, dan mendukung update firmware via HTTP OTA dari server.
Fitur Proyek
- Monitoring suhu dan kelembaban via MQTT
- Web dashboard untuk status perangkat
- HTTP OTA dengan version checking otomatis
- LED status: hijau (normal), kuning (updating), merah (error)
- Auto-reconnect WiFi dan MQTT
- Rollback otomatis jika firmware baru gagal
Kode Lengkap Proyek
// ============================================
// Proyek: Remote Update Sensor Node
// ESP32 + DHT11 + MQTT + HTTP OTA
// BeebaneLabs - https://beebanelabs.pages.dev
// ============================================
#include <WiFi.h>
#include <PubSubClient.h>
#include <HTTPClient.h>
#include <HTTPUpdate.h>
#include <DHT.h>
#include <esp_ota_ops.h>
// ====== KONFIGURASI ======
#define FIRMWARE_VERSION "1.2.0"
#define LED_STATUS_PIN 2
#define DHT_PIN 4
#define DHT_TYPE DHT11
#define OTA_CHECK_INTERVAL 300000 // 5 menit
const char* ssid = "WIFI_KAMU";
const char* password = "PASSWORD_WIFI";
const char* mqtt_server = "192.168.1.100";
const int mqtt_port = 1883;
const char* mqtt_topic = "iot/sensornode/data";
const char* mqtt_cmd_topic= "iot/sensornode/cmd";
const char* ota_version_url =
"http://yourserver.com/ota/version.txt";
const char* ota_firmware_url =
"http://yourserver.com/ota/firmware.bin";
// ====== OBJEK GLOBAL ======
WiFiClient espClient;
PubSubClient mqtt(espClient);
DHT dht(DHT_PIN, DHT_TYPE);
unsigned long lastOTA = 0;
unsigned long lastRead = 0;
// ====== LED STATUS ======
void setLedStatus(const char* mode) {
// Dipanggil dengan "ok", "ota", "error"
// Implementasi LED blink pattern bisa ditambah
Serial.printf("Status: %s\n", mode);
}
// ====== WIFI ======
void setupWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Menghubungkan WiFi");
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 30) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi OK! IP: " + WiFi.localIP().toString());
} else {
Serial.println("\nWiFi gagal! Restart...");
ESP.restart();
}
}
// ====== MQTT ======
void mqttCallback(char* topic, byte* payload, unsigned int length) {
String msg;
for (int i = 0; i < length; i++) {
msg += (char)payload[i];
}
Serial.printf("MQTT [%s]: %s\n", topic, msg.c_str());
if (msg == "check_update") {
checkForOTAUpdate();
} else if (msg == "restart") {
ESP.restart();
} else if (msg == "status") {
publishStatus();
}
}
void connectMQTT() {
while (!mqtt.connected()) {
Serial.print("MQTT connecting...");
if (mqtt.connect("esp32-sensor-node")) {
Serial.println("connected!");
mqtt.subscribe(mqtt_cmd_topic);
} else {
Serial.printf("failed (%d). Retry...\n", mqtt.state());
delay(3000);
}
}
}
void publishStatus() {
String status = "{";
status += "\"version\":\"" + String(FIRMWARE_VERSION) + "\",";
status += "\"ip\":\"" + WiFi.localIP().toString() + "\",";
status += "\"rssi\":" + String(WiFi.RSSI()) + ",";
status += "\"uptime\":" + String(millis() / 1000);
status += "}";
mqtt.publish(mqtt_topic, status.c_str());
}
// ====== OTA UPDATE ======
void checkForOTAUpdate() {
if (WiFi.status() != WL_CONNECTED) return;
Serial.println("Mengecek update OTA...");
setLedStatus("ota");
HTTPClient http;
http.begin(ota_version_url);
int code = http.GET();
if (code == 200) {
String serverVersion = http.getString();
serverVersion.trim();
if (serverVersion != String(FIRMWARE_VERSION)) {
Serial.println("Update tersedia: " + serverVersion);
performOTAUpdate();
} else {
Serial.println("Sudah versi terbaru.");
setLedStatus("ok");
}
} else {
Serial.println("Gagal cek versi: " + String(code));
setLedStatus("error");
}
http.end();
}
void performOTAUpdate() {
WiFiClient client;
t_httpUpdate_return ret =
httpUpdate.update(client, ota_firmware_url);
switch (ret) {
case HTTP_UPDATE_OK:
Serial.println("OTA berhasil! Restart...");
break;
case HTTP_UPDATE_FAILED:
Serial.printf("OTA gagal: %s\n",
httpUpdate.getLastErrorString().c_str());
setLedStatus("error");
break;
default:
break;
}
}
// ====== SETUP ======
void setup() {
Serial.begin(115200);
pinMode(LED_STATUS_PIN, OUTPUT);
dht.begin();
setupWiFi();
mqtt.setServer(mqtt_server, mqtt_port);
mqtt.setCallback(mqttCallback);
connectMQTT();
Serial.println("Sensor Node siap! v" + String(FIRMWARE_VERSION));
setLedStatus("ok");
}
// ====== LOOP ======
void loop() {
// Maintain connections
if (WiFi.status() != WL_CONNECTED) setupWiFi();
if (!mqtt.connected()) connectMQTT();
mqtt.loop();
// Baca sensor setiap 15 detik
if (millis() - lastRead > 15000) {
float suhu = dht.readTemperature();
float hum = dht.readHumidity();
if (!isnan(suhu) && !isnan(hum)) {
String payload = "{";
payload += "\"suhu\":" + String(suhu, 1) + ",";
payload += "\"kelembaban\":" + String(hum, 1) + ",";
payload += "\"versi\":\"" + String(FIRMWARE_VERSION) + "\"";
payload += "}";
mqtt.publish(mqtt_topic, payload.c_str());
Serial.printf("Suhu: %.1f°C, Humidity: %.1f%%\n",
suhu, hum);
}
lastRead = millis();
}
// Cek OTA setiap interval
if (millis() - lastOTA > OTA_CHECK_INTERVAL) {
checkForOTAUpdate();
lastOTA = millis();
}
}
1. Upload kode pertama kali via kabel USB.
2. Sensor suhu mulai dikirim ke MQTT setiap 15 detik.
3. Untuk update remote: naikkan versi di FIRMWARE_VERSION, compile, upload file .bin ke server, dan buat file version.txt berisi versi baru.
4. ESP32 akan otomatis mendeteksi update baru setiap 5 menit.
5. Atau kirim perintah check_update ke topik MQTT iot/sensornode/cmd untuk trigger manual.
7. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang OTA Update pada ESP32: