IoT

ESP32 Deep Sleep & Power Management: Hemat Energi Maksimal

TOKEN

Pelajari semua mode tidur ESP32 โ€” dari light sleep hingga hibernation โ€” untuk proyek IoT berbaterai yang bisa bertahan berbulan-bulan

1. Overview Power Management ESP32

ESP32 memiliki fitur power management yang sangat lengkap, memungkinkan pengembang mengoptimalkan konsumsi daya sesuai kebutuhan aplikasi. Dengan menggabungkan mode tidur yang tepat dan wake source yang sesuai, ESP32 bisa bertahan berbulan-bulan dengan satu baterai.

ESP32 memiliki dua domain power utama: domain utama (CPU, WiFi, BLE, SRAM) dan RTC domain (RTC controller, RTC memory, ULP coprocessor, RTC peripherals). Saat masuk mode tidur, domain utama bisa dimatikan sementara RTC domain tetap aktif.

Perbandingan Mode Tidur ESP32

ModeKonsumsi (typ.)CPUWiFi/BLERTC MemDigital MemWake Source
Active80-240 mAONONONON-
Modem Sleep20 mAON (80MHz)OFFONONWiFi
Light Sleep0.8 mAPausedOFFONONTimer, GPIO, Touch, ULP
Deep Sleep10 ยตAOFFOFFONOFFTimer, GPIO, Touch, ULP
Hibernation5 ยตAOFFOFFOFF*OFFTimer, GPIO (RTC only)
๐Ÿ’ก Estimasi Battery Life

Dengan baterai 18650 (3000 mAh) dan ESP32 dalam deep sleep (10 ยตA) dengan wake-up setiap 5 menit (active 5 detik, ~100 mA rata-rata), baterai bisa bertahan ~3-6 bulan. Dengan hibernation, bisa mencapai 1+ tahun.

2. Active Mode & Konsumsi Daya

Active mode adalah mode default di mana semua komponen ESP32 aktif. Konsumsi daya sangat bervariasi tergantung aktivitas:

KondisiKonsumsi (typ.)Detail
WiFi TX (20 dBm)160-240 mASaat mengirim data WiFi
WiFi RX80-100 mASaat menerima data WiFi
WiFi Idle60-80 mAWiFi ON, tidak TX/RX
BLE Active50-80 mABLE advertising atau connected
CPU 240 MHz30-40 mATanpa WiFi/BLE, CPU aktif
CPU 80 MHz15-20 mATanpa WiFi/BLE, CPU clock rendah
CPU 40 MHz10-15 mATanpa WiFi/BLE, CPU clock minimum

Tips Mengurangi Konsumsi di Active Mode

C++ (Arduino)
#include <WiFi.h>
#include "driver/adc.h"
#include "esp_wifi.h"

void optimizeActiveMode() {
  // 1. Kurangi CPU clock
  setCpuFrequencyMhz(80);  // Turunkan dari 240 ke 80 MHz
  Serial.printf("CPU: %d MHz\n", getCpuFrequencyMhz());

  // 2. Reduce WiFi TX power
  WiFi.setTxPower(WIFI_POWER_8_5dBm);  // Turunkan dari default 20dBm

  // 3. Matikan ADC jika tidak dipakai
  adc_power_off();

  // 4. Matikan Brownout detector jika tidak kritis
  // disableBrownoutDetector();  // Hati-hati: berisiko

  // 5. Gunakan WiFi DTIM untuk mengurangi wake frequency
  esp_wifi_set_ps(WIFI_PS_MODEM);  // Modem power save

  // 6. Matikan Bluetooth jika tidak dipakai
  // btStop();  // Matikan BT classic
  // esp_bluedroid_disable();

  // 7. Matikan peripheral yang tidak dipakai
  // esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE);  // Fix channel
}

3. Modem Sleep & Automatic Light Sleep

Modem Sleep adalah mode otomatis yang aktif ketika ESP32 dalam keadaan idle (CPU aktif tapi WiFi/BLE tidak mengirim/menerima). WiFi radio dimatikan sementara CPU tetap berjalan.

C++ (Arduino)
#include <WiFi.h>
#include "esp_wifi.h"

void setupModemSleep() {
  // Modem Sleep: otomatis saat WiFi idle
  // WiFi stack akan mematikan radio saat tidak ada traffic
  WiFi.mode(WIFI_STA);
  WiFi.begin("SSID", "PASS");

  // Atur Power Save mode
  esp_wifi_set_ps(WIFI_PS_MODEM);      // Modem Sleep (~20 mA idle)
  // esp_wifi_set_ps(WIFI_PS_NONE);     // No power save (~80 mA)
  // esp_wifi_set_ps(WIFI_PS_MIN_MODEM); // Minimum modem sleep

  // Automatic Light Sleep: CPU pause saat WiFi tidur
  // Lebih hemat dari Modem Sleep saja
  esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
}

void setupAutomaticLightSleep() {
  // Automatic Light Sleep: CPU paused saat semua thread blocked
  // Konsumsi: ~0.8 mA

  // Configure WiFi with Automatic Light Sleep
  wifi_config_t wifi_config = {};
  strcpy((char *)wifi_config.sta.ssid, "SSID");
  strcpy((char *)wifi_config.sta.password, "PASS");

  // Set WiFi sleep type
  esp_wifi_set_ps(WIFI_PS_MIN_MODEM);

  // Configure PM (Power Management)
  esp_pm_configure(&pm_config);
}

// Power management configuration
esp_pm_config_esp32_t pm_config = {
  .max_freq_mhz = 240,       // Max frequency saat aktif
  .min_freq_mhz = 40,        // Min frequency saat idle
  .light_sleep_enable = true  // Aktifkan automatic light sleep
};

4. Light Sleep Mode

Light Sleep mematikan CPU dan digital peripherals, tetapi RTC domain dan SRAM tetap powered. Saat bangun, eksekusi dilanjutkan dari titik terakhir โ€” tidak perlu restart.

C++ (Arduino)
#include <WiFi.h>
#include "esp_sleep.h"
#include "driver/rtc_io.h"

void setupLightSleep() {
  Serial.begin(115200);
  delay(1000);

  // Setup GPIO 0 sebagai wake source (tombol)
  // GPIO harus RTC-capable: 0,2,4,12-15,25-27,32-39
  rtc_gpio_pulldown_en(GPIO_NUM_0);
  rtc_gpio_pullup_dis(GPIO_NUM_0);

  // Setup Touch pin sebagai wake source
  touchAttachInterrupt(T3, touchCallback, 40);

  // Konfigurasi ext0 wakeup (single GPIO)
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0);  // Wake saat LOW

  // Atau ext1 wakeup (multiple GPIO, bitmask)
  // esp_sleep_enable_ext1_wakeup(
  //   (1ULL << GPIO_NUM_0) | (1ULL << GPIO_NUM_2),
  //   ESP_EXT1_WAKEUP_ANY_LOW
  // );

  // Timer wakeup: 10 detik
  esp_sleep_enable_timer_wakeup(10 * 1000000);  // microseconds

  // Touch wakeup
  esp_sleep_enable_touchpad_wakeup();

  Serial.println("Masuk Light Sleep dalam 3 detik...");
  delay(3000);

  // Masuk light sleep โ€” kode di sini tidak berjalan
  esp_light_sleep_start();

  // === Kode dilanjutkan di sini setelah wake ===
  esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();

  switch (cause) {
    case ESP_SLEEP_WAKEUP_EXT0:
      Serial.println("Bangun dari GPIO 0!");
      break;
    case ESP_SLEEP_WAKEUP_EXT1:
      Serial.println("Bangun dari GPIO (ext1)!");
      break;
    case ESP_SLEEP_WAKEUP_TIMER:
      Serial.println("Bangun dari Timer!");
      break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD:
      Serial.println("Bangun dari Touch!");
      break;
    case ESP_SLEEP_WAKEUP_UNDEFINED:
      Serial.println("Bangun pertama kali (boot)");
      break;
    default:
      Serial.printf("Wake cause: %d\n", cause);
  }
}

void touchCallback() {
  // Callback saat touch terdeteksi
  // Hanya logging, tidak ada action saat sleep
}

5. Deep Sleep Mode

Deep Sleep adalah mode hemat daya paling populer. Semua komponen dimatikan kecuali RTC controller, RTC memory, RTC peripherals, dan ULP coprocessor. Konsumsi hanya ~10 ยตA.

C++ (Arduino โ€” Deep Sleep)
#include "esp_sleep.h"
#include "driver/rtc_io.h"
#include "driver/adc.h"

// RTC memory: data yang survive deep sleep
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR float lastTemp = 0.0;
RTC_DATA_ATTR unsigned long lastWakeTime = 0;

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

  bootCount++;
  Serial.printf("\n=== Boot #%d ===\n", bootCount);
  Serial.printf("Waktu sejak boot pertama: %lu ms\n", millis());

  // Cek wake cause
  esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
  if (cause == ESP_SLEEP_WAKEUP_EXT0) {
    Serial.println("Bangun karena tombol GPIO 0");
  } else if (cause == ESP_SLEEP_WAKEUP_TIMER) {
    Serial.printf("Bangun karena timer (data: %.1fยฐC)\n", lastTemp);
  }

  // Simpan data ke RTC memory sebelum sleep
  lastTemp = readTemperature();  // Fungsi baca sensor
  lastWakeTime = millis();

  // === Konfigurasi Wake Sources ===

  // 1. Timer wakeup: 30 detik
  esp_sleep_enable_timer_wakeup(30 * 1000000ULL);

  // 2. GPIO wakeup (hanya pin RTC-capable)
  rtc_gpio_pulldown_en(GPIO_NUM_0);
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0);  // Wake saat LOW

  // 3. Touch wakeup
  // touchAttachInterrupt(T3, NULL, 40);
  // esp_sleep_enable_touchpad_wakeup();

  // === Matikan ADC dan WiFi sebelum sleep ===
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  btStop();
  adc_power_off();

  Serial.println("Masuk Deep Sleep...");
  Serial.flush();  // Pastikan semua output terkirim

  // Masuk deep sleep โ€” RESET saat bangun
  esp_deep_sleep_start();

  // Kode di bawah ini TIDAK PERNAH dijalankan
  // karena ESP32 akan restart dari setup()
}

void loop() {
  // Tidak pernah dipanggil dalam deep sleep pattern
  // Karena ESP32 restart dari setup() setiap wake
}

float readTemperature() {
  // Contoh membaca sensor
  return 25.0 + random(-50, 50) / 10.0;
}
โš ๏ธ Deep Sleep vs Light Sleep

Deep Sleep menyebabkan restart (program mulai dari setup() lagi). Gunakan RTC_DATA_ATTR untuk mempertahankan data antar wake cycle. Light Sleep melanjutkan eksekusi dari titik terakhir tanpa restart.

6. Hibernation Mode

Hibernation adalah mode dengan konsumsi paling rendah (~5 ยตA). Semua dimatikan termasuk sebagian besar RTC domain โ€” bahkan RTC memory juga hilang.

C++ (Arduino โ€” Hibernation)
#include "esp_sleep.h"
#include "driver/rtc_io.h"

void enterHibernation() {
  // Hibernation: hanya RTC timer yang aktif (~5 ยตA)
  // RTC memory TIDAK disimpan!

  // Atur GPIO ke kondisi hemat daya
  // Tarik semua pin ke HIGH atau LOW (tidak floating)
  for (int pin = 0; pin < 40; pin++) {
    if (pin == 0 || pin == 2 || pin == 12 ||
        pin == 15 || pin == 25 || pin == 26 ||
        pin == 27 || pin == 32 || pin == 33 ||
        pin == 34 || pin == 35 || pin == 36 ||
        pin == 39) {
      // RTC-capable pins: bisa diatur sebelum hibernation
      rtc_gpio_isolate(GPIO_NUM_0);
    } else {
      // Pin non-RTC: pull-down
      gpio_pullup_dis((gpio_num_t)pin);
      gpio_pulldown_en((gpio_num_t)pin);
    }
  }

  // Timer wakeup (satu-satunya yang tersisa)
  esp_sleep_enable_timer_wakeup(60 * 1000000ULL);  // 60 detik

  // GPIO wakeup (hanya RTC GPIO: 0, 2, 4, 12-15, 25-27, 32-39)
  // esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0);

  Serial.println("Masuk Hibernation...");
  Serial.flush();

  // Masuk hibernation
  esp_deep_sleep_start();

  // Atau gunakan fungsi eksplisit:
  // esp_sleep_start();  // dengan RTC_CNTL_DEEPSLEEP_ON
}

7. Wake Sources Lengkap

ESP32 mendukung berbagai sumber wake-up yang bisa dikombinasikan:

Timer Wakeup

C++
// Timer wakeup dengan presisi tinggi
#define uS_TO_S_FACTOR 1000000ULL
#define TIME_TO_SLEEP  300  // 5 menit dalam detik

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

// Periksa waktu yang tersisa sebelum bangun
int64_t remaining = esp_sleep_get_wakeup_time_remainder();
Serial.printf("Sisa waktu tidur: %lld ยตs\n", remaining);

Touch Wakeup

C++
// Touch pin yang tersisa: T0(GPIO4), T2(GPIO2), T3(GPIO15),
// T4(GPIO13), T5(GPIO12), T6(GPIO14), T7(GPIO27),
// T8(GPIO33), T9(GPIO32)

touchAttachInterrupt(T3, NULL, 40);  // Threshold = 40
esp_sleep_enable_touchpad_wakeup();

// Setelah bangun, identifikasi touch pad
touch_pad_t touchPin = esp_sleep_get_touchpad_wakeup_status();
Serial.printf("Touch pad: %d\n", touchPin);

GPIO Wakeup (ext0 & ext1)

MethodJumlah GPIOKondisiMode Sleep
ext01 pin RTCLevel HIGH/LOWDeep, Light
ext1Multiple RTC pinsANY_HIGH/ANY_LOW/ALL_LOWDeep, Light
GPIO (ESP32-S2/S3)Any GPIOLevel HIGH/LOWDeep, Light

8. ULP Coprocessor

ULP (Ultra Low Power) coprocessor adalah prosesor kecil yang berjalan saat ESP32 dalam deep sleep. ULP bisa membaca ADC, melakukan perhitungan sederhana, dan membangunkan ESP32 berdasarkan kondisi tertentu โ€” sangat berguna untuk sensor monitoring tanpa mengorbankan daya.

C++ (ULP Program)
#include "ulp_main.h"
#include "esp_sleep.h"
#include "driver/adc.h"
#include "esp32/ulp.h"

// ULP program dalam assembly
const ulp_insn_t ulp_program[] = {
  // Konfigurasi ADC channel 0 (GPIO 36)
  I_ADC(R0, 0, 4),          // ADC1 channel 4, 12-bit

  // Simpan ke RTC memory
  I_ST(R0, R1, 0),          // Store R0 ke addr[R1]

  // Bandingkan dengan threshold
  I_LD(R2, R1, 1),          // Load threshold
  I_SUBR(R3, R0, R2),       // R3 = ADC - threshold
  M_BGE(ULP_WAKE, 32768),   // Branch jika ADC >= threshold

  // Tidak melebihi threshold, tidur lagi
  I_HALT(),

  // Label: WAKE โ€” bangunkan ESP32
  M_LABEL(ULP_WAKE),
  I_WAKE(),                  // Bangunkan ESP32
};

// Simpan threshold di RTC memory
RTC_DATA_ATTR uint32_t rtc_threshold = 2048;  // 12-bit ADC mid-point

void setupULP() {
  // Inisialisasi ADC
  adc1_config_width(ADC_WIDTH_BIT_12);
  adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_DB_11);

  // Load ULP program
  size_t size = sizeof(ulp_program) / sizeof(ulp_insn_t);
  ulp_load_binary(0, ulp_program, size);

  // Set threshold di RTC memory
  RTC_SLOW_MEM[1] = rtc_threshold;

  // Set period ULP: baca setiap 1 detik
  ulp_set_wakeup_period(0, 1000000);  // 1 second

  // Mulai ULP
  ulp_run(0);

  Serial.println("ULP coprocessor aktif! Masuk deep sleep...");
  Serial.flush();

  // Masuk deep sleep, ULP tetap berjalan
  esp_deep_sleep_start();
}
โ„น๏ธ ULP Limitations

ULP coprocessor memiliki instruksi yang sangat terbatas โ€” hanya bisa operasi aritmatika sederhana, load/store, dan branching. Tidak bisa menjalankan floating point, library, atau WiFi. Program ULP ditulis dalam assembly atau dikompilasi dari C menggunakan toolchain khusus.

9. RTC Memory & Data Persistence

RTC memory adalah satu-satunya RAM yang tetap powered selama deep sleep. Di ESP32, tersedia 8 KB RTC slow memory dan 8 KB RTC fast memory.

C++
// Data yang survive deep sleep
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR struct {
  float lastTemperature;
  float lastHumidity;
  unsigned long timestamp;
  char lastMessage[64];
} sensorData;

// Alternatif: NVS (Non-Volatile Storage)
#include <Preferences.h>

Preferences prefs;

void saveToNVS() {
  prefs.begin("sensor", false);
  prefs.putFloat("temp", 25.5);
  prefs.putFloat("humid", 60.0);
  prefs.putUInt("count", bootCount);
  prefs.putString("msg", "Hello from ESP32");
  prefs.end();
}

void loadFromNVS() {
  prefs.begin("sensor", true);  // Read-only
  float temp = prefs.getFloat("temp", 0.0);
  float humid = prefs.getFloat("humid", 0.0);
  unsigned int count = prefs.getUInt("count", 0);
  String msg = prefs.getString("msg", "default");
  prefs.end();

  Serial.printf("NVS: T=%.1f, H=%.1f, Count=%u, Msg=%s\n",
    temp, humid, count, msg.c_str());
}
MetodeKapasitasSurvive Deep Sleep?Survive Reset?
RTC_DATA_ATTR8 KBโœ… YaโŒ Tidak (normal reset)
NVS (Preferences)~20 KB (partition)โœ… Yaโœ… Ya
SPIFFS/LittleFSCustom partitionโœ… Yaโœ… Ya
RTC_NOINIT_ATTR8 KBโœ… Yaโœ… Ya (software reset)

10. Quiz Pemahaman

Pertanyaan 1: Konsumsi daya ESP32 dalam deep sleep adalah sekitar?

a) 20 mA
b) 0.8 mA
c) 10 ยตA
d) 80 mA

Pertanyaan 2: Apa perbedaan utama deep sleep dan light sleep?

a) Deep sleep lebih boros dari light sleep
b) Deep sleep menyebabkan restart, light sleep melanjutkan eksekusi
c) Light sleep tidak bisa pakai timer
d) Deep sleep tidak bisa pakai GPIO

Pertanyaan 3: Keyword apa yang digunakan untuk data yang survive deep sleep?

a) PROGMEM
b) volatile
c) RTC_DATA_ATTR
d) static

Pertanyaan 4: ULP coprocessor bisa digunakan untuk?

a) Menjalankan WiFi selama deep sleep
b) Membaca ADC dan membangunkan ESP32 berdasarkan threshold
c) Menjalankan JavaScript
d) Mengirim data BLE

Pertanyaan 5: Mode tidur apa yang memiliki konsumsi terendah (~5 ยตA)?

a) Modem Sleep
b) Light Sleep
c) Deep Sleep
d) Hibernation
โ† Sebelumnya ESP32-CAM Streaming Selanjutnya โ†’ ESP32 Matter
๐Ÿ” Zoom
100%
๐ŸŽจ Tema