Pendahuluan — Dari Sensor ke Gambar

Seri 2 sudah mengajarkan telemetry: DHT22 (#5), MQTT (#7), bahkan LoRa jarak jauh (#26). Tapi kadang kamu butuh visual — cek kondisi kebun, pantau gerbang, atau dokumentasi lapangan.

ESP32-CAM menggabungkan ESP32 + kamera OV2640 dalam satu modul murah. Artikel Jalur D ini fokus pada streaming MJPEG ke browser dan capture foto JPEG via WiFi — pola mirip web server ESP32 (#6), tapi payload-nya frame gambar, bukan angka sensor.

Prasyarat: Sudah paham WiFi ESP32 (#4) dan idealnya pernah buat WebServer (#6). Video streaming bukan pengganti MQTT — lihat REST vs MQTT (#20).

Apa Itu ESP32-CAM?

ESP32-CAM adalah modul AI-Thinker (dan clone) berisi:

  • Chip ESP32 (WiFi + dual-core)
  • Kamera OV2640 (2 MP, JPEG built-in)
  • Slot microSD (opsional, untuk simpan foto)
  • LED flash putih + LED indikator merah

Modul ini hemat biaya (~Rp 40–60rb) tapi punya keterbatasan: butuh 5V stabil, panas saat stream lama, dan bandwidth WiFi tinggi dibanding sensor telemetry.

ESP32-CAM vs DevKit vs LoRa/ESP-NOW

ModulCocok untukDataCatatan
ESP32 DevKit + DHT22Telemetry angkaSuhu, RH, MQTTHemat bandwidth (#5, #7)
ESP-NOW (#25)Node dekat, tanpa routerPaket kecilBukan video
LoRa (#26)Sensor sangat jauhBytes jarangTidak untuk video
ESP32-CAM (artikel ini)Visual monitoringMJPEG / JPEGButuh WiFi stabil

Yang Kamu Butuhkan

  • 1× ESP32-CAM (AI-Thinker atau clone kompatibel)
  • USB-to-TTL adapter (FTDI/CP2102) untuk flash — jangan colok USB langsung ke modul tanpa regulator
  • Kabel jumper · breadboard (opsional)
  • Router WiFi 2.4 GHz
  • Library esp32-camera (biasanya sudah di board package)

Estimasi biaya: modul ESP32-CAM ~Rp 50rb + USB-TTL ~Rp 25rb → lab ~Rp 75–100rb.

Arsitektur Streaming MJPEG

KomponenPeran
OV2640Capture frame → kompres JPEG di chip kamera
ESP32WiFi + WebServer serve stream HTTP
Browser / HPBuka http://IP_ESP32/stream atau /capture
  [ OV2640 ] --> JPEG frame --> [ ESP32 WebServer :80 ]
                                        |
                                        |  WiFi LAN
                                        v
                              [ Browser / HP di jaringan sama ]

Untuk telemetry paralel (suhu + gambar), kamu bisa gabungkan dengan MQTT (#7) di board terpisah — jangan paksa video lewat broker MQTT.

Power & Flashing — Penting!

ESP32-CAM tidak punya USB onboard. Wiring umum ke USB-TTL:

ESP32-CAMUSB-TTL
5V5V (supply stabil ≥500 mA)
GNDGND
U0R (GPIO 3)TX
U0T (GPIO 1)RX
GPIO 0GND saat flash (boot mode)

Pro tip: Lepas jumper GPIO 0 → GND setelah upload. Tekan tombol RESET sebelum buka stream. Undervoltage = gambar corrupt atau reboot loop.

Instalasi Board & Library

  1. Arduino IDE → Board Manager → esp32 by Espressif
  2. Pilih board: AI Thinker ESP32-CAM
  3. Partition Scheme: Huge APP (3MB No OTA) — streaming butuh flash besar
  4. Library esp_camera ikut board package (tidak perlu install terpisah)

Sketch — Inisialisasi Kamera

#include "esp_camera.h"
#include <WiFi.h>
#include <WebServer.h>

#define CAMERA_MODEL_AI_THINKER

const char* ssid = "GANTI_NAMA_WIFI";
const char* password = "GANTI_PASSWORD_WIFI";

WebServer server(80);

void setup() {
  Serial.begin(115200);
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = 5;
  config.pin_d1 = 18;
  config.pin_d2 = 19;
  config.pin_d3 = 21;
  config.pin_d4 = 36;
  config.pin_d5 = 39;
  config.pin_d6 = 34;
  config.pin_d7 = 35;
  config.pin_xclk = 0;
  config.pin_pclk = 22;
  config.pin_vsync = 25;
  config.pin_href = 23;
  config.pin_sccb_sda = 26;
  config.pin_sccb_scl = 27;
  config.pin_pwdn = 32;
  config.pin_reset = -1;
  config.xclk_freq_hz = 20000000;
  config.frame_size = FRAMESIZE_VGA;
  config.pixel_format = PIXFORMAT_JPEG;
  config.grab_mode = CAMERA_GRAB_LATEST;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = 12;
  config.fb_count = 2;

  if (esp_camera_init(&config) != ESP_OK) {
    Serial.println("Camera init gagal");
    return;
  }

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
  Serial.println(WiFi.localIP());
}

Endpoint MJPEG Stream

Pola standar: boundary multipart HTTP. Browser menampilkan sebagai video live di jaringan lokal.

void handleStream() {
  WiFiClient client = server.client();
  String response = "HTTP/1.1 200 OK\r\n";
  response += "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n";
  server.sendContent(response);

  while (client.connected()) {
    camera_fb_t* fb = esp_camera_fb_get();
    if (!fb) continue;
    client.printf("--frame\r\nContent-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n", fb->len);
    client.write(fb->buf, fb->len);
    client.print("\r\n");
    esp_camera_fb_return(fb);
    delay(30);
  }
}

Endpoint Capture Foto

void handleCapture() {
  camera_fb_t* fb = esp_camera_fb_get();
  if (!fb) {
    server.send(500, "text/plain", "Capture gagal");
    return;
  }
  server.sendHeader("Content-Disposition", "inline; filename=capture.jpg");
  server.send_P(200, "image/jpeg", (const char*)fb->buf, fb->len);
  esp_camera_fb_return(fb);
}

void setupRoutes() {
  server.on("/stream", HTTP_GET, handleStream);
  server.on("/capture", HTTP_GET, handleCapture);
  server.on("/", HTTP_GET, []() {
    server.send(200, "text/html",
      "<h1>ESP32-CAM</h1><p><a href='/stream'>Live stream</a> · "
      "<a href='/capture'>Capture foto</a></p>");
  });
  server.begin();
}

void loop() {
  server.handleClient();
}

Resolusi & Kualitas JPEG

  • FRAMESIZE_QVGA (320×240) — paling ringan, cocok WiFi lemah
  • FRAMESIZE_VGA (640×480) — sweet spot lab
  • FRAMESIZE_SVGA / UXGA — lebih tajam, lag lebih besar
  • jpeg_quality 10–15 — angka lebih rendah = kualitas lebih baik (counter-intuitive di esp_camera)

Contoh metadata log (konsisten timestamp Seri 2 untuk proyek hybrid):

{"event":"capture","unix":1782977400,"iso":"2026-07-02T14:30:00","framesize":"VGA"}

Bandwidth & Latency

MJPEG di VGA bisa menghabiskan 1–3 Mbps — jauh di atas paket MQTT sensor. Pastikan:

  • Klien dan ESP32-CAM di WiFi yang sama (2.4 GHz)
  • Jangan stream 24/7 tanpa heatsink — modul panas
  • Untuk monitoring jarang, pakai /capture periodik, bukan stream terus

MicroSD (Opsional) — Simpan Foto di Lapangan

Banyak modul ESP32-CAM punya slot microSD. Kamu bisa simpan hasil /capture ke kartu untuk audit lapangan tanpa koneksi terus-menerus — pola mirip logging offline SD Card (#37).

  • Format kartu FAT32 · kapasitas ≤32 GB untuk kompatibilitas terbaik
  • Gunakan library SD_MMC atau FS dari board package
  • Nama file contoh: /sdcard/cap_1782977400.jpg — selaraskan dengan timestamp NTP (#34)
  • Jangan stream MJPEG dan write SD bersamaan di sketch pertama — debug satu fitur dulu

Integrasi dengan Stack MQTT (Hybrid)

Polanya: ESP32-CAM untuk visual lokal, ESP32 DevKit terpisah untuk telemetry MQTT ke kodingindonesia/esp32/dht22/data via broker 192.168.1.50. Jangan kirim frame video lewat MQTT — bandwidth broker tidak dirancang untuk itu.

Event ringan yang masuk MQTT: {"event":"motion","unix":1782977400} atau trigger capture saat PIR (#23) terdeteksi — metadata saja, bukan binary JPEG.

WiFiManager untuk Deploy Lapangan

Ganti hardcode SSID dengan NVS + WiFiManager (#12) — portal konfigurasi saat pertama nyala, sama seperti node sensor produksi.

LED Flash & Kondisi Cahaya

ESP32-CAM punya LED flash putih di GPIO 4 (umum di AI-Thinker). Untuk foto malam di kebun:

  • Aktifkan LED sebelum esp_camera_fb_get() — matikan setelah capture untuk hemat arus
  • Exposure otomatis OV2640 butuh ~100–300 ms setelah LED nyala
  • Stream siang hari tanpa LED — hindari backlight langsung ke lensa
  • Gabungkan dengan sensor cahaya LDR (#35) untuk auto-flash

Untuk proyek greenhouse capstone (#39), kamera + suhu MQTT + pompa relay adalah tiga jalur terpisah yang saling melengkapi — visual tidak menggantikan angka sensor.

Checklist: Kapan Pakai ESP32-CAM?

  1. Butuh lihat kondisi visual real-time di LAN? → ESP32-CAM stream
  2. Butuh foto sesekali (audit kebun, bukti lapangan)? → /capture
  3. Butuh angka sensor ke dashboard MQTT? → DHT22/BME280 + MQTT (#7)
  4. Butuh jarak kilometer tanpa WiFi? → LoRa (#26), bukan kamera
  5. Butuh akses dari internet publik? → VPN / reverse proxy — jangan port-forward mentah

Uji Coba (Lab)

# Setelah flash & Serial menampilkan IP (mis. 192.168.1.88):
# Browser: http://192.168.1.88/
# Live:    http://192.168.1.88/stream
# Foto:    http://192.168.1.88/capture

# Cek MQTT sensor paralel (board terpisah) — topic Seri 2:
mosquitto_sub -h 192.168.1.50 -u kindo_esp32 -P GANTI_PASSWORD_MQTT \
  -t kodingindonesia/esp32/dht22/data -v
  1. Flash sketch, buka Serial Monitor 115200 — catat IP
  2. Buka /stream di browser HP/laptop jaringan sama
  3. Klik /capture — harus muncul JPEG
  4. Ubah FRAMESIZE_QVGA jika lag — bandingkan smoothness
  5. Matikan stream 5 menit — cek suhu modul tidak overheat

FAQ Singkat

Bisa streaming ke Grafana?
Grafana untuk time-series angka (#19). Video butuh stack lain (RTSP/WebRTC) — di luar scope tutorial ini.
Bisa kirim frame lewat MQTT?
Secara teknis bisa base64, tapi tidak efisien. MQTT untuk metadata/event; gambar simpan SD atau HTTP.
ESP32-CAM vs CCTV IP camera?
CCTV lebih matang untuk 24/7. ESP32-CAM cocok prototipe & belajar embedded vision murah.

Tips & Troubleshooting

  • Camera init gagal: Cek model board AI-Thinker, partition Huge APP, power 5V cukup
  • Gambar hijau/pink: Kabel kamera longgar atau PSRAM tidak aktif
  • Stream putus-putus: Turunkan resolusi atau dekatkan ke router
  • Tidak bisa flash: GPIO 0 harus ke GND saat boot flash
  • IP tidak muncul: SSID/password salah — uji dengan #4 dulu

Keamanan & Produksi

  • Jangan expose port 80 ESP32-CAM langsung ke internet — risiko bot scan kamera
  • Ganti GANTI_NAMA_WIFI / GANTI_PASSWORD_WIFI — jangan commit ke GitHub
  • Pertimbangkan MQTT TLS (#17) untuk channel kontrol terpisah
  • Label modul & lokasi fisik — kamera di area privat perlu consent

Langkah Selanjutnya (Jalur D)

ESP32-CAM menambah dimensi visual ke toolkit IoT kamu — tetap di LAN untuk lab, dan pisahkan dari pipeline telemetry MQTT. Lanjutkan Seri 2 di halaman artikel Koding Indonesia.