â˜€ī¸Siang
ESP32 & ESP8266

OTA Update ESP32: Update Firmware Tanpa Kabel

TOKEN

Panduan lengkap mengupdate firmware ESP32 secara wireless menggunakan ArduinoOTA, Web-Based OTA, dan HTTP OTA — tanpa perlu kabel USB lagi

Artikel: Esp32 Ota Update Artikel: Esp32 Ota Update


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.

💡 Tips

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
ArduinoOTAUpdate via jaringan lokal menggunakan Arduino IDEMudahDevelopment & testing
Web-Based OTAUpload firmware via browser ke web server di ESP32SedangPrototyping & demo
HTTP OTAESP32 mengunduh firmware dari server HTTP/HTTPSLanjutProduksi & fleet update
Perbandingan Arsitektur Metode OTA
đŸ’ģ
ArduinoOTA
Arduino IDE → WiFi → ESP32
🌐
Web OTA
Browser → WiFi → ESP32
â˜ī¸
HTTP OTA
Server → WiFi → ESP32
↓
💾
Flash Memory
Firmware ditulis ke partisi OTA
🔄
Swap Partition
Boot dari partisi baru
✅
Validasi
Rollback jika gagal boot

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.

Diagram: Skema Partisi OTA pada Flash 4 MB

Flash 4 MB

Saat OTA: firmware baru ditulis ke partisi yang...

lalu bootloader mengarahkan boot ke partisi bar...

âš ī¸ Peringatan

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:

Diagram: Arsitektur HTTP OTA
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

C++ — http_ota_update.ino

// ============================================
// 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:

Contoh URL GitHub

// 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);
âš ī¸ Peringatan HTTPS

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:

🔴
Risiko Tanpa Keamanan
  • ❌ Firmware injection oleh attacker
  • ❌ Intercept & modifikasi firmware
  • ❌ Upload malware ke semua device
  • ❌ Brick perangkat dengan firmware corrupt
  • ❌ Pencurian data konfigurasi WiFi
đŸŸĸ
Dengan Keamanan OTA
  • ✅ 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
🔴 Keamanan Kritis

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:

C++ — Rollback pada loop() pertama

#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
Diagram

OTA Server (version + firmware)

MQTT Broker (Mosquitto)

DHT11 WiFi ← HTTP GET

LED firmware.bin

Kode Lengkap Proyek

C++ — ota_sensor_node.ino (klik untuk expand)

// ============================================
// 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();
  }
}
â„šī¸ Cara Menggunakan Proyek

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:

Pertanyaan 1: Apa kepanjangan dari OTA dalam konteks update firmware?

a) On The Application
b) Over-The-Air
c) Open Terminal Access
d) One Time Authentication

Pertanyaan 2: Fungsi apa yang WAJIB dipanggil di loop() agar ArduinoOTA berfungsi?

a) ArduinoOTA.start()
b) ArduinoOTA.handle()
c) ArduinoOTA.update()
d) ArduinoOTA.listen()

Pertanyaan 3: Mengapa ESP32 memerlukan skema partisi khusus untuk OTA?

a) Agar firmware lebih cepat dijalankan
b) Agar ada dua partisi: satu aktif dan satu untuk menampung firmware baru
c) Untuk menghemat penggunaan RAM
d) Untuk memisahkan kode WiFi dari kode sensor

Pertanyaan 4: Keamanan mana yang SANGAT DISARANKAN untuk OTA di lingkungan produksi?

a) Menggunakan password sederhana di ArduinoOTA
b) Menggunakan HTTPS dengan verifikasi signature firmware
c) Mengganti nama SSID WiFi
d) Menggunakan kabel USB yang lebih panjang

Pertanyaan 5: Apa yang terjadi jika firmware baru gagal boot saat rollback diaktifkan?

a) ESP32 akan mati permanen dan harus diganti
b) ESP32 akan otomatis kembali ke firmware versi lama
c) ESP32 akan masuk mode AP dan menunggu konfigurasi
d) ESP32 akan menghapus semua data di flash

← Sebelumnya Panduan Lengkap ESP32 Selanjutnya → Artikel Lainnya
🔍 Zoom
100%
🎨 Tema