Data suhu dan kelembapan dicatat setiap menit ke kartu micro SD sebagai file CSV, satu file per hari, sambil tetap tampil di Klenik. File CSV bisa dibuka di Excel atau Google Sheets untuk dibuat grafik bulanan, dan datanya tetap tercatat walaupun internet putus.
Klenik bagus untuk melihat data sekarang, tetapi untuk menyimpan data berbulan-bulan dibutuhkan penyimpanan sendiri. Modul micro SD terhubung lewat SPI (seperti RFID di proyek 111), dan pustaka SD bawaan ESP32 bisa membuat, menulis, dan menambah isi file.
Setiap menit, satu baris jam,suhu,lembap ditambahkan (mode FILE_APPEND) ke file bernama tanggal hari itu, misalnya 2026-10-27.csv. Jamnya dari NTP. File baru otomatis diberi baris judul kolom. File ditutup setiap selesai menulis, jadi kalau listrik padam, paling banyak satu baris yang hilang.
CSV (comma separated values) adalah format tabel paling sederhana: setiap baris satu catatan, dan koma memisahkan kolom. Hampir semua program lembar kerja bisa membukanya.
Komponen
| Komponen | Qty | Harga |
|---|---|---|
| ESP32 DOIT DevKit V1 30 pin | 1 | Rp75.000 |
| Modul Micro SD Card SPI Interface TF Card Reader | 1 | Rp9.800 |
| Modul sensor DHT11 | 1 | Rp12.000 |
| Kabel jumper female-female 10 cm (isi 10)isi 10, terpakai 9 | 1 | Rp3.500 |
| Kabel micro USB data 30 cmopsional, kalau belum punya kabel micro USB data | 1 | Rp11.700 |
| Total (tanpa opsional) | Rp100.300 |
Langkah 1: Rangkai komponen
Sambungkan kabel sesuai gambar di atas. Kalau gambar dan tabel terlihat berbeda, ikuti tabel.
| Dari | Ke | Kabel | |
|---|---|---|---|
| Modul micro SD (SPI) GND | → | GND | hitam |
| Modul micro SD (SPI) VCC | → | VIN | merah |
| Modul micro SD (SPI) MISO | → | D19 GPIO19 | ungu |
| Modul micro SD (SPI) MOSI | → | D23 GPIO23 | biru |
| Modul micro SD (SPI) SCK | → | D18 GPIO18 | hijau |
| Modul micro SD (SPI) CS | → | D5 GPIO5 | kuning |
| DHT11 VCC | → | 3V3 | merah |
| DHT11 DATA | → | D4 GPIO4 | oranye |
| DHT11 GND | → | GND | hitam |
Langkah 2: Siapkan dashboard Klenik
Cara cepat: unduh p149.json, ganti budi1234 dengan KODE-mu, lalu import di Klenik (menu titik tiga → Export / Import → Import → Ganti total). Langkah lengkapnya ada di Panduan Klenik.
| Widget | Topic | Setting |
|---|---|---|
| Gauge Suhu | ichibot/KODE/p149/suhu | 15–40 °C |
| Gauge Kelembapan | ichibot/KODE/p149/lembap | 0–100 % |
| Indikator Boolean Kartu SD | ichibot/KODE/p149/kartu | ON = 1 “MENCATAT”, OFF = 0 |
| Gauge Baris Tercatat | ichibot/KODE/p149/baris | 0–1440 |
Langkah 3: Upload kode
Library: PubSubClient (Nick O'Leary), DHT sensor library (Adafruit), Adafruit Unified Sensor. Board di Arduino IDE: ESP32 Dev Module.
Isi dulu nama WiFi dan password di bagian ISI DULU, lalu ganti budi1234 di baris topic dengan KODE-mu, lalu upload dan buka Serial Monitor (115200).
// Proyek 149 - Data Logger SD Card + Dashboard
// Board: ESP32 DOIT DevKit V1 | Dashboard: klenik.ichibot.id
#include <WiFi.h>
#include <PubSubClient.h>
#include <SPI.h>
#include <SD.h>
#include <DHT.h>
#include <time.h>
// ===== ISI DULU =====
const char* WIFI_NAMA = "nama-wifi-kamu";
const char* WIFI_PASS = "password-wifi-kamu";
// topic MQTT: ganti budi1234 dengan KODE-mu (sama dengan di dashboard Klenik)
const char* TOPIK_SUHU = "ichibot/budi1234/p149/suhu";
const char* TOPIK_LEMBAP = "ichibot/budi1234/p149/lembap";
const char* TOPIK_KARTU = "ichibot/budi1234/p149/kartu";
const char* TOPIK_BARIS = "ichibot/budi1234/p149/baris";
const unsigned long JEDA_CATAT = 60000; // catat setiap 1 menit
const char* BROKER = "mqtt.ichibot.id";
WiFiClient wifi;
PubSubClient mqtt(wifi);
DHT dht(4, DHT11);
const int PIN_CS = 5; // SCK 18, MOSI 23, MISO 19
bool kartuSiap = false;
long jumlahBaris = 0;
unsigned long terakhir = 0;
bool catat(String baris) {
time_t t = time(nullptr);
char nama[20];
strftime(nama, sizeof(nama), "/%Y-%m-%d.csv", localtime(&t)); // satu file per hari
bool baru = !SD.exists(nama);
File f = SD.open(nama, FILE_APPEND);
if (!f) return false;
if (baru) f.println("jam,suhu,lembap"); // judul kolom
f.println(baris);
f.close(); // tutup supaya data benar-benar tertulis
return true;
}
void langganan() {}
sambungWiFi() dan sambungMQTT(): sama di semua proyek (klik untuk lihat)
void sambungWiFi() {
WiFi.begin(WIFI_NAMA, WIFI_PASS);
Serial.print("WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" OK, IP " + WiFi.localIP().toString());
}
void sambungMQTT() {
while (!mqtt.connected()) {
if (mqtt.connect(WiFi.macAddress().c_str())) {
Serial.println("Terhubung ke Klenik");
langganan();
} else {
Serial.println("Broker gagal, coba lagi 3 detik");
delay(3000);
}
}
}
void setup() {
Serial.begin(115200);
dht.begin();
kartuSiap = SD.begin(PIN_CS);
Serial.println(kartuSiap ? "Kartu SD siap" : "Kartu SD tidak terbaca");
sambungWiFi();
configTime(7 * 3600, 0, "pool.ntp.org");
mqtt.setServer(BROKER, 1883);
}
void loop() {
if (!mqtt.connected()) sambungMQTT();
mqtt.loop();
if (millis() - terakhir < JEDA_CATAT || time(nullptr) < 1700000000) return;
terakhir = millis();
float suhu = dht.readTemperature(), lembap = dht.readHumidity();
if (isnan(suhu)) return;
time_t t = time(nullptr);
char jam[9];
strftime(jam, sizeof(jam), "%H:%M:%S", localtime(&t));
String baris = String(jam) + "," + String(suhu, 1) + "," + String(lembap, 0);
bool ok = kartuSiap && catat(baris);
if (ok) jumlahBaris++;
mqtt.publish(TOPIK_SUHU, String(suhu, 1).c_str());
mqtt.publish(TOPIK_LEMBAP, String(lembap, 0).c_str());
mqtt.publish(TOPIK_KARTU, ok ? "1" : "0");
mqtt.publish(TOPIK_BARIS, String(jumlahBaris).c_str());
}Langkah 4: Pahami kodenya
- Nama file dari tanggal, jadi file baru otomatis dibuat setiap hari dan mudah dicari.
FILE_APPENDmenambah di akhir file tanpa menghapus isi lama.FILE_WRITEdi ESP32 akan menimpa file.- Data baru benar-benar tersimpan di kartu setelah
close(). File yang tidak ditutup bisa kosong saat dibuka di laptop.