Pendahuluan — Seri 2 ESP32/IoT

Selamat datang di artikel pembuka Seri 2 Koding Indonesia! Ini adalah lanjutan langsung dari janji deep sleep di roadmap artikel #10. Di capstone Seri 1 kamu sudah membangun dashboard hybrid Web + MQTT yang terus menyala. Itu cocok untuk proyek bertenaga adaptor USB di meja kerja.

Tapi bagaimana jika sensor harus dipasang di kebun, gudang, atau sudut rumah tanpa stop kontak? Node yang terus hidup akan menghabiskan baterai dalam hitungan jam. Solusinya: deep sleep — ESP32 tidur nyaris total, bangun sebentar untuk kirim data, lalu tidur lagi.

Dalam tutorial ini kita bangun node sensor DHT22 hemat baterai yang setiap beberapa menit:

  1. Bangun dari deep sleep
  2. Hubungkan WiFi
  3. Baca suhu & kelembaban
  4. Publish JSON ke MQTT (topic sama seperti Seri 1)
  5. Matikan radio WiFi dan tidur lagi

Prasyarat: Sudah paham WiFi ESP32, sensor DHT22, dan publish MQTT. Familiar dengan JSON MQTT dari proyek gabungan atau dashboard capstone akan membantu.

Light Sleep vs Deep Sleep

ModeCPU & WiFiKonsumsi arusCocok untuk
Light sleepCPU pause, RAM tetapLebih tinggi dari deep sleepBangun cepat, koneksi WiFi tetap hidup
Deep sleepHampir mati total; hanya RTC~10 µA (ideal) pada chipNode baterai kirim data periodik

Pada deep sleep, ESP32 reset penuh saat bangun — program dimulai lagi dari setup(). Itu normal dan justru disederhanakan: tidak perlu khawatir state lama di RAM.

Wake-up timer vs GPIO: Tutorial ini memakai esp_sleep_enable_timer_wakeup() (bangun tiap N detik). Alternatif lanjutan: bangun dari pin eksternal (mis. tombol atau sensor) dengan esp_sleep_enable_ext0_wakeup() — berguna jika event jarang terjadi.

Install Library

Install lewat Arduino IDE → Sketch → Include Library → Manage Libraries:

  1. DHT sensor library — Adafruit (+ Adafruit Unified Sensor)
  2. PubSubClient — Nick O'Leary

Board ESP32 via Board Manager sudah menyertakan esp_sleep.h — tidak perlu library tambahan untuk deep sleep.

Yang Kamu Butuhkan

  • ESP32 DevKit + sensor DHT22 (GPIO 4, pull-up 10kΩ ke 3.3V)
  • Kabel jumper & breadboard
  • Power: USB untuk uji awal; opsional LiPo 3.7V + modul TP4056 untuk simulasi baterai
  • Library: DHT sensor library, PubSubClient
  • WiFi 2.4 GHz + MQTT Explorer (subscribe topic)

Catatan daya: Saat WiFi connect, arus bisa melonjak >100 mA meski sebentar. Itulah mengapa kita matikan WiFi sebelum tidur — bukan hanya deep sleep chip, tapi juga radio WiFi yang harus off.

Wiring DHT22

Sama seperti Seri 1 — jangan ubah pin tanpa alasan:

  • VCC DHT22 → 3.3V
  • GND → GND
  • DATA → GPIO 4 + resistor pull-up 10kΩ ke 3.3V

Pin strapping: Hindari GPIO yang dipakai saat boot (mis. beberapa board sensitif di GPIO 0, 2, 12, 15). GPIO 4 aman untuk DHT22 di kebanyakan DevKit.

Arsitektur Node Sensor

TahapDurasi tipikalCatatan
Deep sleep10 menit (konfigurasi)Hanya RTC timer hidup
Bangun + baca DHT22~2–3 detikdelay(2000) setelah dht.begin()
WiFi + MQTT publish~3–10 detikSekali publish per siklus
Matikan WiFi → deep sleep<1 detikWiFi.mode(WIFI_OFF)

Broker latihan: test.mosquitto.org:1883 (sama Seri 1). Topic: kodingindonesia/esp32/dht22/data — payload JSON {"suhu":28.5,"kelembaban":65.2}.

Broker bukan website: test.mosquitto.org tidak dibuka di browser. Pakai MQTT Explorer atau mosquitto_sub. Detail di artikel MQTT.

Pro tip: Ganti segmen topic dengan nama unik, misalnya kodingindonesia/anton/esp32/dht22/data, agar tidak bentrok dengan peserta tutorial lain di broker publik.

Kode Lengkap: Deep Sleep + DHT22 + MQTT

Ganti ssid dan password, lalu upload. Setelah upload, buka Serial Monitor 115200 — kamu akan melihat satu siklus lalu ESP32 tidur (Serial berhenti sampai bangun lagi).

#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include "esp_sleep.h"

// Durasi tidur (detik) — ubah sesuai kebutuhan
const uint64_t DURASI_TIDUR_DETIK = 600; // 10 menit

const char* ssid     = "NamaWiFiKamu";
const char* password = "PasswordWiFiKamu";

const char* mqttServer  = "test.mosquitto.org";
const int   mqttPort    = 1883;
const char* topicSensor = "kodingindonesia/esp32/dht22/data";

#define DHT_PIN  4
#define DHT_TYPE DHT22

DHT dht(DHT_PIN, DHT_TYPE);
WiFiClient espClient;
PubSubClient mqttClient(espClient);

void cetakAlasanBangun() {
  esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
  switch (cause) {
    case ESP_SLEEP_WAKEUP_TIMER:
      Serial.println("Bangun: timer deep sleep");
      break;
    case ESP_SLEEP_WAKEUP_UNDEFINED:
    default:
      Serial.println("Bangun: boot / reset (upload atau tombol EN)");
      break;
  }
}

void matikanWiFi() {
  mqttClient.disconnect();
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
}

bool koneksiWiFi() {
  Serial.print("WiFi");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  unsigned long mulai = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - mulai < 15000) {
    delay(500);
    Serial.print(".");
  }

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("\nWiFi gagal (timeout 15 detik)");
    return false;
  }

  Serial.println("\nWiFi terhubung");
  return true;
}

bool koneksiMQTT() {
  mqttClient.setServer(mqttServer, mqttPort);
  mqttClient.setBufferSize(512);

  String clientId = "ESP32-Sleep-" + String(random(0xffff), HEX);
  if (mqttClient.connect(clientId.c_str())) {
    Serial.println("MQTT terhubung");
    return true;
  }

  Serial.print("MQTT gagal, rc=");
  Serial.println(mqttClient.state());
  return false;
}

bool publishSensor() {
  float kelembaban = dht.readHumidity();
  float suhu       = dht.readTemperature();

  if (isnan(kelembaban) || isnan(suhu)) {
    Serial.println("DHT22 gagal (NaN) — lewati publish");
    return false;
  }

  String payload = "{\"suhu\":" + String(suhu, 1);
  payload += ",\"kelembaban\":" + String(kelembaban, 1) + "}";

  mqttClient.loop();
  if (mqttClient.publish(topicSensor, payload.c_str())) {
    Serial.print("Publish ");
    Serial.print(topicSensor);
    Serial.print(": ");
    Serial.println(payload);
    return true;
  }

  Serial.println("Publish gagal");
  return false;
}

void masukDeepSleep() {
  Serial.print("Deep sleep ");
  Serial.print((unsigned long)DURASI_TIDUR_DETIK);
  Serial.println(" detik...");
  Serial.flush();

  esp_sleep_enable_timer_wakeup(DURASI_TIDUR_DETIK * 1000000ULL);
  esp_deep_sleep_start();
  // tidak pernah sampai di sini
}

void setup() {
  Serial.begin(115200);
  delay(100);

  cetakAlasanBangun();

  // Hemat daya saat aktif (opsional, trade-off kecepatan)
  setCpuFrequencyMhz(80);

  randomSeed(micros());
  dht.begin();
  delay(2000); // stabilkan DHT22 setelah bangun

  if (!koneksiWiFi()) {
    matikanWiFi();
    masukDeepSleep();
    return;
  }

  if (!koneksiMQTT()) {
    matikanWiFi();
    masukDeepSleep();
    return;
  }

  publishSensor();
  matikanWiFi();
  masukDeepSleep();
}

void loop() {
  // Deep sleep: loop tidak dipakai — semua logika di setup() tiap bangun
}

Alur Program (Tiap Siklus Bangun)

  1. setup() jalan dari awal (reset setelah deep sleep)
  2. Cetak alasan bangun (timer atau boot pertama)
  3. Inisialisasi DHT22 + jeda 2 detik
  4. Connect WiFi (timeout 15 detik)
  5. Connect MQTT + setBufferSize(512)
  6. Publish satu payload JSON
  7. Disconnect MQTT & matikan WiFi
  8. esp_deep_sleep_start() — tidur DURASI_TIDUR_DETIK

Uji Coba

  1. Upload sketch, buka Serial Monitor 115200
  2. Catat log: WiFi OK → MQTT → publish JSON → "Deep sleep 600 detik..."
  3. Serial berhenti — ESP32 tidur (normal)
  4. Di MQTT Explorer, connect ke test.mosquitto.org, subscribe kodingindonesia/esp32/dht22/data
  5. Tunggu ~10 menit (atau ubah DURASI_TIDUR_DETIK jadi 60 untuk uji cepat) — pesan baru muncul periodik
mosquitto_sub -h test.mosquitto.org -t "kodingindonesia/esp32/dht22/data" -v

Uji cepat: Set DURASI_TIDUR_DETIK = 60 saat development, kembalikan ke 600 (10 menit) untuk deploy baterai.

Optimasi Hemat Daya

  • setCpuFrequencyMhz(80) — kurangi konsumsi saat aktif (boleh 160 jika connect WiFi sering gagal)
  • WiFi.mode(WIFI_OFF) — wajib sebelum sleep; jangan biarkan radio idle
  • Satu publish per bangun — hindari loop panjang di loop()
  • Timeout WiFi — jangan infinite loop; gagal → tidur lagi agar baterai tidak habis di jaringan WiFi rumah yang lemah
  • DHT22 — selalu delay(2000) setelah begin() pasca deep sleep
  • Multimeter — ukur arus di jalur 3.3V saat bangun vs saat tidur untuk validasi optimasi (harapkan lonjakan singkat saat WiFi connect)

Tips & Troubleshooting

  • DHT22 NaN setelah bangun: Perpanjang delay; cek wiring & pull-up; hindari kabel panjang tanpa shield
  • Boot loop tanpa tidur: Pastikan tidak ada kode setelah esp_deep_sleep_start() yang mengharapkan lanjut; cek brownout jika pakai baterai lemah (gunakan supply stabil)
  • Tidak ada pesan MQTT: Topic case-sensitive; cek setBufferSize(512); lihat artikel MQTT
  • Baterai cepat habis: Kurangi frekuensi bangun; pastikan WiFi benar-benar off; ukur arus dengan multimeter untuk baseline
  • Upload gagal setelah sleep: Tekan tombol BOOT saat upload, atau colok USB lalu reset sebelum ESP32 sempat tidur

Langkah Selanjutnya (Seri 2)

Keamanan: Jangan hardcode password WiFi di repo publik. Untuk proyek lapangan, gunakan NVS + WiFiManager atau simpan kredensial di file terpisah yang tidak di-commit.

Ini langkah pertama menuju node IoT yang benar-benar wireless — sensor di mana adaptor listrik tidak tersedia. Lanjutkan Seri 2 di halaman artikel Koding Indonesia.