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
| Mode | Konsumsi (typ.) | CPU | WiFi/BLE | RTC Mem | Digital Mem | Wake Source |
|---|---|---|---|---|---|---|
| Active | 80-240 mA | ON | ON | ON | ON | - |
| Modem Sleep | 20 mA | ON (80MHz) | OFF | ON | ON | WiFi |
| Light Sleep | 0.8 mA | Paused | OFF | ON | ON | Timer, GPIO, Touch, ULP |
| Deep Sleep | 10 ยตA | OFF | OFF | ON | OFF | Timer, GPIO, Touch, ULP |
| Hibernation | 5 ยตA | OFF | OFF | OFF* | OFF | Timer, GPIO (RTC only) |
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:
| Kondisi | Konsumsi (typ.) | Detail |
|---|---|---|
| WiFi TX (20 dBm) | 160-240 mA | Saat mengirim data WiFi |
| WiFi RX | 80-100 mA | Saat menerima data WiFi |
| WiFi Idle | 60-80 mA | WiFi ON, tidak TX/RX |
| BLE Active | 50-80 mA | BLE advertising atau connected |
| CPU 240 MHz | 30-40 mA | Tanpa WiFi/BLE, CPU aktif |
| CPU 80 MHz | 15-20 mA | Tanpa WiFi/BLE, CPU clock rendah |
| CPU 40 MHz | 10-15 mA | Tanpa WiFi/BLE, CPU clock minimum |
Tips Mengurangi Konsumsi di Active Mode
#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.
#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.
#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.
#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 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.
#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
// 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
// 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)
| Method | Jumlah GPIO | Kondisi | Mode Sleep |
|---|---|---|---|
| ext0 | 1 pin RTC | Level HIGH/LOW | Deep, Light |
| ext1 | Multiple RTC pins | ANY_HIGH/ANY_LOW/ALL_LOW | Deep, Light |
| GPIO (ESP32-S2/S3) | Any GPIO | Level HIGH/LOW | Deep, 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.
#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 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.
// 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());
}
| Metode | Kapasitas | Survive Deep Sleep? | Survive Reset? |
|---|---|---|---|
| RTC_DATA_ATTR | 8 KB | โ Ya | โ Tidak (normal reset) |
| NVS (Preferences) | ~20 KB (partition) | โ Ya | โ Ya |
| SPIFFS/LittleFS | Custom partition | โ Ya | โ Ya |
| RTC_NOINIT_ATTR | 8 KB | โ Ya | โ Ya (software reset) |