Pendahuluan — Data Tetap Tersimpan Tanpa WiFi
Seri 2 sudah mengajarkan kirim sensor ke broker MQTT (#7), histori di MySQL (#18), dan grafik Grafana (#19). Semua itu mengasumsikan WiFi atau jaringan tersedia.
Di lapangan — kebun, greenhouse, atau titik monitoring jauh dari router — koneksi bisa putus berjam-jam. Node deep sleep (#11) bangun sebentar, baca sensor, lalu tidur lagi; tanpa penyimpanan lokal, sampel hilang selamanya.
Artikel Tier 2 ini mengajarkan SD Card microSD lewat bus SPI (bukan I2C): tulis log CSV offline, lalu sinkron ke MQTT saat WiFi kembali — melengkapi arsitektur hybrid capstone #10, ESP8266 vs ESP32 (#36), dan persiapan capstone greenhouse (#39).
Prasyarat: Paham GPIO (#3), WiFi (#4), DHT22 (#5), dan idealnya sudah pakai NTP (#34) untuk timestamp akurat di setiap baris log.
Mengapa SD Card, Bukan Hanya Cloud?
| Skenario | MQTT / cloud saja | SD Card + MQTT hybrid |
|---|---|---|
| WiFi mati 6 jam | Data hilang | CSV tetap terisi |
| Deep sleep node baterai | Reconnect lambat | Log dulu, upload nanti |
| Audit lapangan | Butuh laptop + broker | Cabut kartu → baca di PC |
| Debugging firmware | Sulit trace event lokal | File teks mudah dibuka |
SPI vs I2C — Jangan Campur
Di artikel I2C (#13), sensor BME280 dan OLED #14 pakai dua wire (SDA/SCL) + alamat perangkat. SD Card memakai SPI — protokol berbeda:
| Bus | Wire | Cocok untuk | Artikel Seri 2 |
|---|---|---|---|
| I2C | SDA, SCL | Sensor kecil, OLED | #13 BME280 |
| SPI | MOSI, MISO, SCK, CS | SD Card, display cepat, LoRa | #37 (ini), #26 LoRa |
SPI lebih cepat untuk burst data ke kartu memori — tepat untuk append ribuan baris CSV.
Dasar SPI — Empat Sinyal Utama
- MOSI (Master Out Slave In) — ESP32 kirim data ke SD
- MISO (Master In Slave Out) — SD kirim balik ke ESP32
- SCK (Clock) — tick sinkron
- CS / SS (Chip Select) — pilih perangkat di bus yang sama
Pro tip: Satu bus SPI bisa dipakai beberapa perangkat — asalkan masing-masing punya CS pin terpisah. Jangan dua perangkat aktif CS bersamaan.
Hardware — Modul SD Card microSD
- Modul SD Card (holder microSD + level shifter 3,3 V)
- ESP32 DevKit
- microSD 4–32 GB (FAT32)
- DHT22 untuk demo log suhu/kelembaban (#5)
- Kabel jumper · breadboard
Wiring SPI — ESP32 ke Modul SD
Pin HSPI default yang umum di tutorial ESP32 (hindari bentrok dengan flash internal):
| SD Module | ESP32 GPIO | Fungsi SPI |
|---|---|---|
| CS | GPIO 5 | Chip Select |
| SCK / CLK | GPIO 18 | Clock |
| MOSI | GPIO 23 | Data ke SD |
| MISO | GPIO 19 | Data dari SD |
| VCC | 3,3 V | Jangan 5 V langsung ke GPIO |
| GND | GND | Common ground |
| DHT22 data | GPIO 4 | Digital — tidak bentrok SPI |
Konflik Pin — Cek Sebelum Wiring
| Fungsi lain | GPIO | Bentrok SPI? |
|---|---|---|
| DHT22 (#5) | 4 | Tidak |
| Relay (#8) | 26 | Tidak |
| Soil ADC (#35) | 34, 35 | Tidak |
| Servo (#33) | 27 | Tidak |
| SD CS | 5 | Hindari jika board pakai flash pada GPIO 6–11 |
Format File CSV di Kartu
Satu file /sensor.csv dengan header — mudah diimpor ke Excel atau script Python (#18):
timestamp_iso,unix,temp_c,hum_pct
2026-07-02T14:30:00,1782977400,28.5,62.1
Timestamp ISO dan unix mengikuti konvensi NTP (#34) — contoh unix 1782977400 agar konsisten di seluruh seri.
Library & Include
Di Arduino IDE untuk ESP32, cukup:
SPI.h— bus SPI bawaanSD.h— filesystem FAT di kartuDHT sensor library— sama seperti #5
Sketch — Init SD & Tulis Baris Pertama
#include <SPI.h>
#include <SD.h>
#include <DHT.h>
#include <time.h>
#define SD_CS 5
#define SD_SCK 18
#define SD_MISO 19
#define SD_MOSI 23
#define DHT_PIN 4
#define DHT_TYPE DHT22
#define LOG_FILE "/sensor.csv"
DHT dht(DHT_PIN, DHT_TYPE);
bool initSD() {
SPI.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS, SPI)) {
Serial.println("SD init gagal");
return false;
}
if (!SD.exists(LOG_FILE)) {
File f = SD.open(LOG_FILE, FILE_WRITE);
if (f) {
f.println("timestamp_iso,unix,temp_c,hum_pct");
f.close();
}
}
return true;
}
void appendLog(float t, float h, time_t unixNow) {
struct tm ti;
localtime_r(&unixNow, &ti);
char iso[25];
strftime(iso, sizeof(iso), "%Y-%m-%dT%H:%M:%S", &ti);
File f = SD.open(LOG_FILE, FILE_APPEND);
if (!f) return;
f.printf("%s,%ld,%.1f,%.1f\n", iso, (long)unixNow, t, h);
f.close();
}
void setup() {
Serial.begin(115200);
dht.begin();
delay(2000);
initSD();
}
void loop() {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (!isnan(t) && !isnan(h)) {
time_t now = 1782977400; // ganti dengan NTP (#34) di produksi
appendLog(t, h, now);
Serial.println("Baris ditulis ke SD");
}
delay(60000);
}
Sinkron ke MQTT Saat WiFi Kembali
Pola hybrid — log selalu ke SD; jika WiFi connect, baca baris terakhir (atau seluruh file) dan publish ke broker Mosquitto (#16):
// Setelah WiFi + mqtt.connected()
// Topic konsisten Seri 1: kodingindonesia/esp32/dht22/data
const char* TOPIC = "kodingindonesia/esp32/dht22/data";
void publishLastSample(float t, float h, long unixTs) {
char payload[160];
snprintf(payload, sizeof(payload),
"{\"unix\":%ld,\"temp\":%.1f,\"hum\":%.1f,\"source\":\"sd_sync\"}",
unixTs, t, h);
mqtt.publish(TOPIC, payload);
}
Subscriber Python (#18) dan Grafana (#19) tidak perlu diubah — field JSON sama dengan node MQTT langsung.
Deep Sleep + Log Satu Sampel
Gabung dengan deep sleep (#11): di setiap wake, baca DHT → appendLog() → tidur lagi. Kartu SD tetap terisi meski WiFi tidak pernah aktif selama seminggu.
Baca Kartu di PC
- Cabut microSD dengan aman (unmount tidak ada di bare metal — minimal stop write dengan delay setelah
f.close()) - Colok ke reader USB di laptop
- Buka
sensor.csvdi Excel/LibreOffice - Opsional: impor ke MySQL dengan script Python mirip #18 — baca CSV bukan MQTT
PlatformIO — Dependency
Di PlatformIO (#29):
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
adafruit/DHT sensor library@^1.4
Library SD dan SPI sudah bundled framework Arduino ESP32.
SD vs SPIFFS vs LittleFS
| Media | Kapasitas | Cocok untuk |
|---|---|---|
| SD Card (SPI) | GB | Log bulanan, cabut & baca di PC |
| SPIFFS / LittleFS | MB (flash chip) | Config kecil, web asset OTA (#15) |
| MQTT → DB | Unlimited (server) | Dashboard real-time #19 |
Keamanan & Best Practice
- Jangan cabut kartu saat
SD.open(..., FILE_APPEND)aktif — selaluclose() - Kartu FAT32 — hindari power loss saat menulis (kapasitor kecil membantu)
- Jangan simpan password WiFi di file teks di SD — pakai
GANTI_*placeholder di firmware - Produksi: enkripsi kartu atau fisik secure enclosure
Estimasi Biaya (Indonesia)
| Komponen | Harga (Rp) |
|---|---|
| ESP32 DevKit | 35.000 – 55.000 |
| Modul SD Card + holder | 15.000 – 30.000 |
| microSD 8 GB | 25.000 – 45.000 |
| DHT22 | 35.000 – 55.000 |
| Total | ~110.000 – 185.000 |
Checklist Sebelum Demo
- ☐ Kartu diformat FAT32
- ☐ Serial:
SD init gagaltidak muncul - ☐ File
/sensor.csvada + header benar - ☐ Baris baru setiap interval baca DHT
- ☐ Cabut kartu → buka CSV di PC → data terbaca
- ☐ Opsional: WiFi sync publish ke
kodingindonesia/esp32/dht22/data
FAQ Singkat
- Bisa pakai I2C untuk SD Card?
- Modul SD standar di pasaran pakai SPI — I2C jarang dan lambat untuk log intensif.
- SD init gagal terus?
- Cek wiring CS/SCK/MOSI/MISO, format FAT32, dan supply 3,3 V stabil.
- Bentrok dengan BME280 I2C?
- Tidak — I2C GPIO 21/22, SPI pakai 18/19/23/5 di sketch ini.
- Perlu NTP?
- Sangat disarankan — tanpa NTP, timestamp placeholder tidak akurat di lapangan (#34).
- ESP8266 bisa logging SD?
- Bisa terbatas — lihat perbandingan #36; ESP32 lebih nyaman untuk SPI + WiFi + MQTT.
Tips & Troubleshooting
- File corrupt: Gunakan kartu berkualitas · hindari cabut saat write · coba
SD.end()sebelum sleep panjang - 0 byte file: Pastikan
FILE_APPENDdanflush/closedipanggil - DHT NaN di log: Sama seperti #5 — pull-up 10kΩ,
delay(2000)setelahdht.begin() - MQTT sync dobel: Tandai baris sudah di-upload (kolom
synced=1) atau simpan offset di NVS (#12) - Kartu penuh: Rotasi file harian
/2026-07-02.csvatau hapus baris lama
MQTT Credentials Saat Sync
Saat node kembali online dan mengirim backlog, gunakan pola kredensial yang sama dengan artikel MQTT Seri 1:
- Broker:
192.168.1.50(Mosquitto #16) - User:
kindo_esp32 - Password:
GANTI_PASSWORD_MQTT— jangan hardcode di repo - WiFi:
GANTI_NAMA_WIFI/GANTI_PASSWORD_WIFI
Placeholder ini konsisten di seluruh seri — ganti saat flash firmware ke lapangan.
FreeRTOS & SD Write
Jika firmware memakai task terpisah (FreeRTOS #31), jangan tulis SD dari dua task bersamaan tanpa mutex. Pola aman: satu task loggerTask yang dequeue sample dari queue dan append ke kartu — hindari korupsi FAT saat WiFi task dan logger task bentrok.
Perbandingan dengan ESP-NOW & LoRa
ESP-NOW (#25) dan LoRa (#26) mengirim data ke gateway — tetap butuh penyimpanan jika gateway offline. SD di node sensor adalah buffer lokal pertama sebelum data mencapai gateway LoRa → MQTT (#28).
Rotasi File Harian
Untuk deployment jangka panjang, jangan biarkan satu sensor.csv membengkak tanpa batas. Pola umum:
/log/2026-07-02.csv— satu file per hari (butuh NTP #34 untuk nama file)- Hapus file >30 hari saat kartu >80% penuh
- Simpan offset baris terakhir yang sudah di-MQTT-kan di NVS (#12)
Rotasi ini mencegah kartu 8 GB penuh di musim hujan saat node tidak pernah di-flash ulang.
Gabung Multi-Sensor di Satu Baris
Setelah paham DHT22, tambahkan kolom dari ADC soil & LDR (#35):
timestamp_iso,unix,temp_c,hum_pct,soil_pct,light_pct
Satu baris CSV = snapshot lengkap greenhouse — siap diimpor ke MySQL (#18) tanpa ubah skema MQTT.
Node-RED & Home Assistant
Setelah sync MQTT, flow Node-RED (#23) dan entitas Home Assistant (#21) membaca topic yang sama seperti node tanpa SD — field source: sd_sync membantu debug data yang tertunda.
Langkah Selanjutnya — Tier 2 Seri 2
Logging offline melengkapi pipeline MQTT — data aman di lapangan dan di cloud. Lanjut:
- Keamanan HTTPS & sertifikat (#38) — amankan HTTP client ESP32 ke API eksternal
- ADC (#35) — tambah kolom soil/LDR di CSV yang sama
- Grafana (#19) — visualisasi setelah CSV diimpor atau MQTT sync
- Capstone greenhouse (#39) — multi-sensor + SD backup + dashboard
SPI dan SD Card membuka jalur data offline — lanjutkan di halaman artikel Koding Indonesia.