1. Pengenalan Sensor DHT11 & DHT22
Family sensor DHT (Digital Humidity Temperature) merupakan salah satu sensor digital paling populer untuk proyek IoT. Sensor ini mampu mengukur suhu dan kelembaban udara secara bersamaan dalam satu modul kecil yang sangat terjangkau. Dua varian utama yang banyak digunakan adalah DHT11 dan DHT22 (dikenal juga sebagai AM2302).
Sensor DHT bekerja dengan memanfaatkan komponen kapasitif untuk mengukur kelembaban dan termistor NTC untuk mengukur suhu. Data dikirim secara digital melalui satu jalur data (single-wire interface), sehingga sangat hemat pin GPIO pada mikrokontroler seperti ESP32.
Spesifikasi DHT11
| Parameter | Nilai |
|---|---|
| Rentang Suhu | 0ยฐC โ 50ยฐC |
| Akurasi Suhu | ยฑ2ยฐC |
| Rentang Kelembaban | 20% โ 80% RH |
| Akurasi Kelembaban | ยฑ5% RH |
| Resolusi | 1 bit (8 bit per pembacaan) |
| Tegangan Operasi | 3.3V โ 5.5V DC |
| Arus Kerja | 2.5 mA (rata-rata) |
| Sampling Rate | 1 Hz (1 pembacaan per detik) |
| Ukuran Fisik | 12 ร 15.5 ร 5.5 mm |
| Harga (rata-rata) | Rp 10.000 โ Rp 20.000 |
Spesifikasi DHT22 (AM2302)
| Parameter | Nilai |
|---|---|
| Rentang Suhu | -40ยฐC โ 80ยฐC |
| Akurasi Suhu | ยฑ0.5ยฐC |
| Rentang Kelembaban | 0% โ 100% RH |
| Akurasi Kelembaban | ยฑ2% RH |
| Resolusi | 0.1ยฐC / 0.1% RH (16 bit) |
| Tegangan Operasi | 3.3V โ 6V DC |
| Arus Kerja | 1.5 mA (rata-rata) |
| Sampling Rate | 0.5 Hz (1 pembacaan per 2 detik) |
| Ukuran Fisik | 15 ร 25 ร 7.7 mm |
| Harga (rata-rata) | Rp 25.000 โ Rp 45.000 |
Pilih DHT11 untuk proyek pemula, sekadar belajar, atau monitoring kasar (misal: indikator ruangan). Pilih DHT22 jika membutuhkan akurasi lebih baik, rentang suhu lebih lebar, atau untuk data logging jangka panjang. Perbedaan harga sekitar Rp 15.000โ25.000 sangat worth it untuk presisi yang jauh lebih baik.
2. Perbandingan DHT11 vs DHT22 vs BME280
Jika DHT11 dan DHT22 populer karena harganya yang murah, sensor BME280 (buatan Bosch) hadir sebagai alternatif premium dengan fitur lebih lengkap, termasuk pengukuran tekanan udara (barometrik). Berikut tabel perbandingan lengkap:
DHT11
Murah & Mudah- Jenis: Digital
- Suhu: 0โ50ยฐC (ยฑ2ยฐC)
- Kelembaban: 20โ80% (ยฑ5%)
- Tekanan Udara: โ
- Protokol: Single-wire
- Tegangan: 3.3โ5.5V
- Arus Kerja: 2.5 mA
- Sampling Rate: 1 Hz
- Antarmuka: 1 GPIO
- Kesulitan: โญ Mudah
- Harga: Rp 10โ20rb
- Cocok Untuk: Pemula, proyek sederhana
DHT22
Akurat & Andal- Jenis: Digital
- Suhu: -40โ80ยฐC (ยฑ0.5ยฐC)
- Kelembaban: 0โ100% (ยฑ2%)
- Tekanan Udara: โ
- Protokol: Single-wire
- Tegangan: 3.3โ6V
- Arus Kerja: 1.5 mA
- Sampling Rate: 0.5 Hz
- Antarmuka: 1 GPIO
- Kesulitan: โญ Mudah
- Harga: Rp 25โ45rb
- Cocok Untuk: Monitoring akurat
BME280
Premium & Lengkap- Jenis: Digital (MEMS)
- Suhu: -40โ85ยฐC (ยฑ1ยฐC)
- Kelembaban: 0โ100% (ยฑ3%)
- Tekanan Udara: โ (300โ1100 hPa)
- Protokol: I2C / SPI
- Tegangan: 1.71โ3.6V
- Arus Kerja: 3.6 ยตA @ 1Hz
- Sampling Rate: Hingga 100 Hz
- Antarmuka: 4+ pin (I2C/SPI)
- Kesulitan: โญโญ Sedang
- Harga: Rp 40โ80rb
- Cocok Untuk: Weather station, IoT lanjut
Pemula: Mulai dengan DHT11 (murah, mudah). Sedang: Gunakan DHT22 untuk akurasi lebih baik tanpa kompleksitas wiring. Lanjut: Pilih BME280 jika butuh data tekanan udara untuk aplikasi weather station atau prediksi cuaca. Ketiga sensor kompatibel dengan ESP32 tanpa masalah.
DHT11
12 ร 15.5 mmDHT22
15 ร 25 mmBME280
Modul Kecil (I2C)3. Wiring & Koneksi ke ESP32
Koneksi sensor DHT11/DHT22 ke ESP32 sangat sederhana karena hanya membutuhkan 3 kabel: VCC (power), DATA (sinyal), dan GND (ground). Pin DATA membutuhkan resistor pull-up 10kฮฉ untuk menjaga stabilitas sinyal komunikasi.
Kebutuhan Komponen
- 1x ESP32 DevKit v1
- 1x Sensor DHT11 atau DHT22
- 1x Resistor 10kฮฉ (pull-up)
- Kabel jumper (jantan-jantan)
- 1x Breadboard (opsional, untuk prototipe)
Resistor 10kฮฉ dipasang antara pin DATA (2) dan VCC (1) sebagai pull-up resistor. Beberapa modul DHT sudah memiliki resistor internal โ periksa modul Anda sebelum memasang.
Wiring Multi-Sensor (DHT11 + DHT22)
Jika ingin menggunakan dua sensor sekaligus untuk komparasi, masing-masing sensor terhubung ke GPIO berbeda:
- ESP32 beroperasi pada tegangan 3.3V. Jangan hubungkan pin GPIO langsung ke tegangan 5V tanpa level shifter.
- Beberapa modul DHT11/DHT22 sudah memiliki resistor pull-up internal (modul breakout board). Periksa datasheet modul Anda sebelum memasang resistor eksternal.
- Panjang kabel jumper idealnya kurang dari 20 cm untuk menghindari gangguan noise pada sinyal data.
4. Setup Library Arduino IDE
Untuk menggunakan sensor DHT11/DHT22 di Arduino IDE, kita membutuhkan library dari Adafruit. Adafruit menyediakan library DHT yang sudah sangat stabil dan banyak digunakan komunitas maker di seluruh dunia.
Langkah 1: Instalasi Library DHT
- Buka Arduino IDE
- Buka menu Sketch โ Include Library โ Manage Libraries
- Pada kolom pencarian, ketik "DHT sensor library"
- Pilih "DHT sensor library" oleh Adafruit
- Klik tombol Install
- Jika muncul prompt instalasi dependency, klik "Install All"
Library ini akan otomatis menginstal Adafruit Unified Sensor sebagai dependency, yang merupakan library dasar untuk semua sensor digital Adafruit.
Langkah 2: Verifikasi Instalasi
Setelah instalasi selesai, pastikan library berhasil dimuat dengan cara:
- Buka menu Sketch โ Include Library
- Scroll ke bawah, cari "DHT sensor library" di bagian Contributed Libraries
- Jika sudah muncul, berarti instalasi berhasil
Struktur Include di Kode
// Library utama untuk sensor DHT #include "DHT.h" // Definisi pin dan tipe sensor #define DHT_PIN 4 // GPIO4 terhubung ke pin DATA sensor #define DHT_TYPE DHT11 // Ganti ke DHT22 jika pakai DHT22 // Inisialisasi objek sensor DHT sensorSuhu(DHT_PIN, DHT_TYPE);
Jika menggunakan DHT22, cukup ganti baris #define DHT_TYPE DHT11 menjadi #define DHT_TYPE DHT22. Kode lainnya tetap sama โ library akan otomatis menyesuaikan protokol pembacaan.
5. Program Membaca Suhu & Kelembaban
Sekarang kita akan membuat program Arduino untuk membaca data suhu dan kelembaban dari sensor DHT. Program ini termasuk penanganan error jika sensor gagal membaca, serta perhitungan Heat Index (indec panas) yang sangat berguna untuk monitoring kenyamanan ruangan.
Program Dasar Pembacaan DHT
// =============================================
// Program Membaca Suhu & Kelembaban DHT11/DHT22
// BeebaneLabs - https://beebanelabs.pages.dev
// =============================================
#include "DHT.h"
// === Konfigurasi Sensor ===
#define DHT_PIN 4 // GPIO4 terhubung ke pin DATA
#define DHT_TYPE DHT11 // Ganti ke DHT22 jika diperlukan
#define LED_PIN 2 // LED internal ESP32 (GPIO2)
// === Interval Pembacaan ===
const unsigned long INTERVAL_BACA = 5000; // Baca setiap 5 detik
// === Objek Sensor ===
DHT sensorDHT(DHT_PIN, DHT_TYPE);
// === Variabel Penyimpanan ===
float suhuTerkini = 0.0;
float kelembabanTerkini = 0.0;
float heatIndex = 0.0;
unsigned long totalPembacaan = 0;
unsigned long totalError = 0;
// === Fungsi Pembacaan dengan Validasi ===
bool bacaSensor() {
float s = sensorDHT.readTemperature(); // Celsius
float h = sensorDHT.readHumidity(); // Persen
float f = sensorDHT.readTemperature(true); // Fahrenheit
// Validasi: cek apakah pembacaan valid
if (isnan(s) || isnan(h)) {
totalError++;
Serial.println("[ERROR] Gagal membaca sensor DHT!");
Serial.println(" Penyebab: koneksi longgar, resistor belum dipasang, atau sensor rusak.");
return false;
}
suhuTerkini = s;
kelembabanTerkini = h;
heatIndex = sensorDHT.computeHeatIndex(s, h, false);
totalPembacaan++;
return true;
}
// === Fungsi Tampilkan Data ke Serial ===
void tampilkanData() {
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
Serial.println("โ Pembacaan Sensor DHT โ");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค");
Serial.print("โ Suhu : ");
Serial.print(suhuTerkini, 1);
Serial.println(" ยฐC โ");
Serial.print("โ Kelembaban : ");
Serial.print(kelembabanTerkini, 1);
Serial.println(" % โ");
Serial.print("โ Heat Index : ");
Serial.print(heatIndex, 1);
Serial.println(" ยฐC โ");
Serial.print("โ Pembacaan # : ");
Serial.print(totalPembacaan);
Serial.println(" โ");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
Serial.println("โ Sensor DHT11/DHT22 + ESP32 โ");
Serial.println("โ BeebaneLabs - https://beebanelabs.pages.dev โ");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
// Mulai sensor
sensorDHT.begin();
delay(2000); // Waktu stabilisasi sensor
Serial.println("Sensor dimulai. Menunggu pembacaan pertama...");
}
void loop() {
static unsigned long lastBaca = 0;
unsigned long sekarang = millis();
if (sekarang - lastBaca >= INTERVAL_BACA) {
lastBaca = sekarang;
if (bacaSensor()) {
tampilkanData();
// Kedipkan LED saat pembacaan berhasil
digitalWrite(LED_PIN, HIGH);
delay(100);
digitalWrite(LED_PIN, LOW);
}
}
}
Heat Index (indeks panas) adalah suhu yang "terasa" oleh tubuh manusia, menggabungkan efek suhu aktual dan kelembaban. Semakin tinggi kelembaban, semakin panas suhu terasa. Contoh: suhu 30ยฐC dengan kelembaban 80% terasa seperti 36ยฐC! Heat Index sangat berguna untuk monitoring kenyamanan ruangan atau sistem pendingin otomatis.
6. Kalibrasi & Error Handling
Sensor DHT11/DHT22, seperti semua sensor, memiliki toleransi pembacaan tertentu. Untuk proyek yang membutuhkan akurasi lebih tinggi, diperlukan proses kalibrasi. Selain itu, implementasi error handling yang baik akan memastikan sistem tetap stabil meskipun sensor mengalami gangguan sementara.
Teknik Kalibrasi Dasar
Metode kalibrasi paling sederhana adalah perbandingan dengan referensi. Gunakan termometer digital akurat (misal: termometer laboratorium atau sensor BME280 sebagai referensi) untuk menentukan offset sensor DHT Anda.
// =============================================
// Kalibrasi & Error Handling Sensor DHT
// BeebaneLabs - https://beebanelabs.pages.dev
// =============================================
#include "DHT.h"
#define DHT_PIN 4
#define DHT_TYPE DHT11
DHT sensorDHT(DHT_PIN, DHT_TYPE);
// === Faktor Kalibrasi ===
// Nilai ini didapatkan dari perbandingan dengan sensor referensi
// Contoh: jika DHT11 membaca 30.5ยฐC tapi referensi menunjuk 29.8ยฐC
// maka offset_suhu = 29.8 - 30.5 = -0.7
const float OFFSET_SUHU = -0.7; // Koreksi suhu (ยฐC)
const float OFFSET_KELEMBABAN = 2.0; // Koreksi kelembaban (%)
const float BATAS_SUHU_MIN = -10.0; // Batas bawah suhu valid
const float BATAS_SUHU_MAX = 60.0; // Batas atas suhu valid
const float BATAS_RH_MIN = 0.0; // Batas bawah kelembaban
const float BATAS_RH_MAX = 100.0; // Batas atas kelembaban
const int MAX_ERROR_BERUNTUN = 5; // Max error berturut sebelum reset
// === Counter Error ===
int errorBeruntun = 0;
// === Fungsi Kalibrasi ===
float kalibrasiSuhu(float raw) {
return raw + OFFSET_SUHU;
}
float kalibrasiKelembaban(float raw) {
float calibrated = raw + OFFSET_KELEMBABAN;
// Clamp ke rentang valid
if (calibrated < BATAS_RH_MIN) calibrated = BATAS_RH_MIN;
if (calibrated > BATAS_RH_MAX) calibrated = BATAS_RH_MAX;
return calibrated;
}
// === Fungsi Pembacaan dengan Error Handling Lanjut ===
bool bacaSensorLanjut(float* suhu, float* kelembaban) {
float rawSuhu = sensorDHT.readTemperature();
float rawRH = sensorDHT.readHumidity();
// Error 1: Pembacaan NaN
if (isnan(rawSuhu) || isnan(rawRH)) {
errorBeruntun++;
Serial.printf("[ERROR #%d/%d] NaN diterima dari sensor!\n",
errorBeruntun, MAX_ERROR_BERUNTUN);
if (errorBeruntun >= MAX_ERROR_BERUNTUN) {
Serial.println("[CRITICAL] Terlalu banyak error berturut. Mencoba reset...");
sensorDHT.begin();
delay(3000);
errorBeruntun = 0;
}
return false;
}
// Error 2: Nilai di luar rentang fisik
float calibratedSuhu = kalibrasiSuhu(rawSuhu);
float calibratedRH = kalibrasiKelembaban(rawRH);
if (calibratedSuhu < BATAS_SUHU_MIN || calibratedSuhu > BATAS_SUHU_MAX) {
errorBeruntun++;
Serial.printf("[WARN] Suhu %.1fยฐC di luar rentang valid (%.0fโ%.0fยฐC)\n",
calibratedSuhu, BATAS_SUHU_MIN, BATAS_SUHU_MAX);
return false;
}
// Error 3: Kelembaban di luar rentang
if (calibratedRH < BATAS_RH_MIN || calibratedRH > BATAS_RH_MAX) {
errorBeruntun++;
Serial.printf("[WARN] Kelembaban %.1f%% di luar rentang valid\n", calibratedRH);
return false;
}
// Error 4: Perubahan mendadak (sensor terlepas?)
static float lastSuhu = 0;
if (lastSuhu != 0 && abs(calibratedSuhu - lastSuhu) > 10.0) {
Serial.printf("[WARN] Lompatan suhu ekstrem: %.1f โ %.1fยฐC\n",
lastSuhu, calibratedSuhu);
// Tidak return false, tapi catat warning
}
lastSuhu = calibratedSuhu;
// Semua valid
*suhu = calibratedSuhu;
*kelembaban = calibratedRH;
errorBeruntun = 0;
return true;
}
void setup() {
Serial.begin(115200);
Serial.println("=== Sistem Kalibrasi DHT ===");
sensorDHT.begin();
delay(2000);
Serial.printf("Offset Suhu : %.1fยฐC\n", OFFSET_SUHU);
Serial.printf("Offset Kelembaban : %.1f%%\n", OFFSET_KELEMBABAN);
Serial.printf("Rentang Suhu : %.0f ~ %.0fยฐC\n", BATAS_SUHU_MIN, BATAS_SUHU_MAX);
}
void loop() {
static unsigned long lastBaca = 0;
if (millis() - lastBaca > 5000) {
lastBaca = millis();
float suhu, kelembaban;
if (bacaSensorLanjut(&suhu, &kelembaban)) {
Serial.printf("[OK] Suhu: %.1fยฐC | RH: %.1f%%\n", suhu, kelembaban);
}
}
}
Panduan Kalibrasi Manual
- Siapkan referensi: Gunakan termometer akurat dan hygrometer kalibrasi. Tempatkan bersama DHT di lokasi yang sama.
- Rekam pembacaan: Catat 10-20 pembacaan dari DHT dan referensi pada kondisi stabil.
- Hitung rata-rata selisih: offset = (rata-rata referensi) โ (rata-rata DHT)
- Masukkan offset ke kode: Ubah nilai
OFFSET_SUHUdanOFFSET_KELEMBABAN. - Uji ulang: Verifikasi bahwa pembacaan koreksi sesuai referensi dalam toleransi ยฑ0.5ยฐC.
7. Menyimpan Data ke EEPROM/SD Card
ESP32 memiliki memori EEPROM (Electrically Erasable Programmable Read-Only Memory) virtual sebesar 4096 bytes yang bisa digunakan untuk menyimpan data. Namun untuk logging data sensor dalam jumlah besar, SD Card merupakan pilihan yang jauh lebih praktis.
Opsi 1: Menyimpan ke EEPROM (Data Terbatas)
// =============================================
// Menyimpan Data Sensor ke EEPROM ESP32
// BeebaneLabs - https://beebanelabs.pages.dev
// =============================================
#include "DHT.h"
#include <EEPROM.h>
#define DHT_PIN 4
#define DHT_TYPE DHT11
DHT sensorDHT(DHT_PIN, DHT_TYPE);
// === Struktur Data untuk Disimpan ===
struct DataSensor {
float suhu;
float kelembaban;
unsigned long timestamp; // millis() sebagai timestamp
bool valid; // Flag validitas data
};
// === Konfigurasi Penyimpanan ===
const int EEPROM_SIZE = 4096;
const int ALAMAT_AWAL = 0; // Alamat awal penyimpanan
const int MAX_RECORDS = 40; // Max record (4096 / sizeof(DataSensor))
const int ALAMAT_COUNTER = 4000; // Alamat counter record
int jumlahRecord = 0;
void setup() {
Serial.begin(115200);
EEPROM.begin(EEPROM_SIZE);
Serial.println("=== Data Logging ke EEPROM ===");
sensorDHT.begin();
delay(2000);
// Baca jumlah record yang tersimpan
jumlahRecord = EEPROM.read(ALAMAT_COUNTER);
if (jumlahRecord > MAX_RECORDS) {
Serial.println("[INFO] EEPROM penuh. Menimpa dari awal.");
jumlahRecord = 0;
}
Serial.printf("Record tersimpan: %d / %d\n", jumlahRecord, MAX_RECORDS);
}
// === Simpan Data ke EEPROM ===
void simpanData(float suhu, float kelembaban) {
if (jumlahRecord >= MAX_RECORDS) {
Serial.println("[WARN] EEPROM penuh! Data baru tidak disimpan.");
return;
}
DataSensor data;
data.suhu = suhu;
data.kelembaban = kelembaban;
data.timestamp = millis();
data.valid = true;
// Hitung alamat penyimpanan
int alamat = ALAMAT_AWAL + (jumlahRecord * sizeof(DataSensor));
// Tulis data ke EEPROM
EEPROM.put(alamat, data);
EEPROM.write(ALAMAT_COUNTER, jumlahRecord + 1);
EEPROM.commit(); // Wajib untuk ESP32!
jumlahRecord++;
Serial.printf("[EEPROM] Data #%d disimpan di alamat %d\n", jumlahRecord, alamat);
}
// === Baca Data dari EEPROM ===
void bacaSemuaData() {
Serial.printf("\n=== Total %d Record di EEPROM ===\n", jumlahRecord);
for (int i = 0; i < jumlahRecord; i++) {
DataSensor data;
int alamat = ALAMAT_AWAL + (i * sizeof(DataSensor));
EEPROM.get(alamat, data);
if (data.valid) {
Serial.printf("#%d | %.1fยฐC | %.1f%% | %lu ms\n",
i + 1, data.suhu, data.kelembaban, data.timestamp);
}
}
}
void loop() {
static unsigned long lastSimpan = 0;
if (millis() - lastSimpan > 10000) { // Simpan setiap 10 detik
lastSimpan = millis();
float suhu = sensorDHT.readTemperature();
float kelembaban = sensorDHT.readHumidity();
if (!isnan(suhu) && !isnan(kelembaban)) {
simpanData(suhu, kelembaban);
// Setiap 5 record, tampilkan semua data
if (jumlahRecord % 5 == 0) {
bacaSemuaData();
}
}
}
}
EEPROM ESP32 hanya 4096 bytes. Setiap DataSensor menempati 12 bytes (2 float + 1 unsigned long + 1 bool), sehingga maksimal sekitar 340 record. Untuk logging data 10 detik sekali, EEPROM hanya cukup ~56 menit. Untuk logging jangka panjang, gunakan SD Card.
Opsi 2: Menyimpan ke SD Card (Data Besar)
// =============================================
// Menyimpan Data Sensor ke SD Card sebagai CSV
// BeebaneLabs - https://beebanelabs.pages.dev
// =============================================
#include "DHT.h"
#include <SPI.h>
#include <SD.h>
#define DHT_PIN 4
#define DHT_TYPE DHT11
#define SD_CS_PIN 5 // GPIO5 sebagai Chip Select
DHT sensorDHT(DHT_PIN, DHT_TYPE);
const char* NAMA_FILE = "/sensor_log.csv";
// === Inisialisasi SD Card ===
bool mulaiSDCard() {
if (!SD.begin(SD_CS_PIN)) {
Serial.println("[ERROR] SD Card gagal dimulai!");
return false;
}
Serial.printf("SD Card: Tipe=%d, Kapasitas=%llu bytes\n",
SD.cardType(), SD.cardSize());
return true;
}
// === Tulis Header CSV ===
void tulisHeader() {
File file = SD.open(NAMA_FILE, FILE_APPEND);
if (file) {
// Tulis header hanya jika file baru
if (file.size() == 0) {
file.println("nomor,suhu_c,kelembaban_persen,heat_index,millis,uptime_detik");
Serial.println("[SD] Header CSV ditulis.");
}
file.close();
}
}
// === Tulis Data Baru ===
void tulisDataCSV(float suhu, float kelembaban, float heatIndex) {
File file = SD.open(NAMA_FILE, FILE_APPEND);
if (file) {
// Hitung nomor baris berdasarkan ukuran file
int nomorBaris = file.size() / 50; // Estimasi kasar
// Format CSV: nomor,suhu,kelembaban,heat_index,millis,uptime
file.printf("%d,%.2f,%.2f,%.2f,%lu,%lu\n",
nomorBaris + 1, suhu, kelembaban, heatIndex,
millis(), millis() / 1000);
file.close();
Serial.printf("[SD] Baris #%d ditulis: %.1fยฐC, %.1f%%\n",
nomorBaris + 1, suhu, kelembaban);
} else {
Serial.println("[ERROR] Gagal menulis ke SD Card!");
}
}
void setup() {
Serial.begin(115200);
sensorDHT.begin();
Serial.println("=== Data Logging ke SD Card ===");
delay(2000);
if (mulaiSDCard()) {
tulisHeader();
Serial.println("[OK] SD Card siap untuk logging.");
}
}
void loop() {
static unsigned long lastTulis = 0;
if (millis() - lastTulis > 15000) { // Tulis setiap 15 detik
lastTulis = millis();
float suhu = sensorDHT.readTemperature();
float kelembaban = sensorDHT.readHumidity();
if (!isnan(suhu) && !isnan(kelembaban)) {
float heatIndex = sensorDHT.computeHeatIndex(suhu, kelembaban, false);
tulisDataCSV(suhu, kelembaban, heatIndex);
}
}
}
Format SD Card sebagai FAT32 atau exFAT sebelum digunakan. Gunakan file CSV supaya data mudah dibuka di Excel atau Google Sheets. Jangan lupa lepaskan SD Card sebelum mencabutnya dari module untuk menghindari kerusakan data. Kapasitas 16GB SD Card cukup untuk menyimpan data logging bertahun-tahun!
8. Proyek: Sensor + MQTT + Web Dashboard
Di bagian ini, kita akan menggabungkan semua materi ke dalam satu proyek utuh: ESP32 membaca sensor DHT, mengirim data ke MQTT broker, dan data ditampilkan secara real-time di web dashboard sederhana yang dibangun dengan HTML/JavaScript.
Arsitektur Sistem
Kode ESP32: Publisher MQTT
// =============================================
// Proyek: DHT Sensor + MQTT + Web Dashboard
// BeebaneLabs - https://beebanelabs.pages.dev
// =============================================
#include "WiFi.h"
#include "PubSubClient.h"
#include "DHT.h"
// === Konfigurasi WiFi ===
const char* WIFI_SSID = "NamaWiFiAnda";
const char* WIFI_PASS = "PasswordWiFi";
// === Konfigurasi MQTT ===
const char* MQTT_SERVER = "test.mosquitto.org";
const int MQTT_PORT = 1883;
const char* TOPIC_DATA = "iothub/project/dht/data";
const char* TOPIC_STATUS = "iothub/project/dht/status";
const char* CLIENT_ID = "esp32_dht_dashboard_01";
// === Konfigurasi Sensor ===
#define DHT_PIN 4
#define DHT_TYPE DHT11
#define LED_PIN 2
// === Objek ===
DHT sensorDHT(DHT_PIN, DHT_TYPE);
WiFiClient espClient;
PubSubClient mqtt(espClient);
// === Interval ===
const unsigned long INTERVAL_KIRIM = 10000; // 10 detik
unsigned long lastKirim = 0;
int msgCount = 0;
// === Koneksi WiFi ===
void setupWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
Serial.print("WiFi: Menghubungkan");
int attempt = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if (++attempt > 40) {
Serial.println(" GAGAL! Restart...");
ESP.restart();
}
}
Serial.printf(" OK! IP: %s\n", WiFi.localIP().toString().c_str());
}
// === Koneksi MQTT ===
void hubungkanMQTT() {
while (!mqtt.connected()) {
Serial.print("MQTT: Menghubungkan...");
if (mqtt.connect(CLIENT_ID)) {
Serial.println(" OK!");
mqtt.publish(TOPIC_STATUS, "{\"status\":\"online\"}", true);
} else {
Serial.printf(" GAGAL (rc=%d). Coba lagi 3s...\n", mqtt.state());
delay(3000);
}
}
}
// === Kirim Data sebagai JSON ===
void kirimData() {
float suhu = sensorDHT.readTemperature();
float kelembaban = sensorDHT.readHumidity();
if (isnan(suhu) || isnan(kelembaban)) {
Serial.println("[ERROR] Sensor gagal membaca!");
return;
}
float heatIndex = sensorDHT.computeHeatIndex(suhu, kelembaban, false);
// Format JSON
char payload[256];
snprintf(payload, sizeof(payload),
"{"
"\"suhu\":%.1f,"
"\"kelembaban\":%.1f,"
"\"heat_index\":%.1f,"
"\"rssi\":%d,"
"\"uptime\":%lu,"
"\"msg_count\":%d,"
"\"timestamp\":%lu"
"}",
suhu, kelembaban, heatIndex,
WiFi.RSSI(),
millis() / 1000,
msgCount + 1,
millis()
);
if (mqtt.publish(TOPIC_DATA, payload)) {
msgCount++;
Serial.printf("[%d] Suhu: %.1fยฐC | RH: %.1f%% | HI: %.1fยฐC\n",
msgCount, suhu, kelembaban, heatIndex);
digitalWrite(LED_PIN, HIGH);
delay(50);
digitalWrite(LED_PIN, LOW);
} else {
Serial.println("[ERROR] Gagal publish ke MQTT!");
}
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
Serial.println("โ DHT + MQTT + Dashboard v1.0 โ");
Serial.println("โ BeebaneLabs - https://beebanelabs.pages.dev โ");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
sensorDHT.begin();
delay(2000);
setupWiFi();
mqtt.setServer(MQTT_SERVER, MQTT_PORT);
mqtt.setBufferSize(512);
hubungkanMQTT();
}
void loop() {
if (!mqtt.connected()) {
hubungkanMQTT();
}
mqtt.loop();
if (millis() - lastKirim >= INTERVAL_KIRIM) {
lastKirim = millis();
kirimData();
}
}
Web Dashboard (HTML + JavaScript)
Simpan kode berikut sebagai file dashboard.html dan buka di browser. Dashboard ini menggunakan MQTT over WebSocket untuk menerima data real-time dari broker MQTT.
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>IoT Dashboard - Monitoring Suhu</title>
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', sans-serif; background: #0f172a; color: #e2e8f0; padding: 20px; }
h1 { text-align: center; margin-bottom: 20px; color: #38bdf8; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; max-width: 800px; margin: 0 auto; }
.card { background: #1e293b; border-radius: 12px; padding: 24px; text-align: center; border: 1px solid #334155; }
.card .label { font-size: 0.85rem; color: #94a3b8; margin-bottom: 8px; }
.card .value { font-size: 2.5rem; font-weight: 700; }
.card .unit { font-size: 0.9rem; color: #64748b; }
.card.suhu .value { color: #f97316; }
.card.rh .value { color: #38bdf8; }
.card.hi .value { color: #ef4444; }
.card.rssi .value { color: #22c55e; font-size: 1.5rem; }
#status { text-align: center; margin: 16px 0; font-size: 0.9rem; }
#status.connected { color: #22c55e; }
#status.disconnected { color: #ef4444; }
#log { max-width: 800px; margin: 20px auto; background: #1e293b; border-radius: 8px; padding: 16px; font-family: monospace; font-size: 0.8rem; max-height: 200px; overflow-y: auto; }
</style>
</head>
<body>
<h1>๐ก๏ธ IoT Dashboard - Real-time Monitoring</h1>
<p id="status" class="disconnected">๐ด Menunggu koneksi MQTT...</p>
<div class="grid">
<div class="card suhu">
<div class="label">Suhu</div>
<div class="value" id="suhu">--</div>
<div class="unit">ยฐC</div>
</div>
<div class="card rh">
<div class="label">Kelembaban</div>
<div class="value" id="rh">--</div>
<div class="unit">%</div>
</div>
<div class="card hi">
<div class="label">Heat Index</div>
<div class="value" id="hi">--</div>
<div class="unit">ยฐC</div>
</div>
<div class="card rssi">
<div class="label">WiFi Signal</div>
<div class="value" id="rssi">--</div>
<div class="unit">dBm</div>
</div>
</div>
<div id="log"><div>โณ Menunggu data...</div></div>
<script>
const broker = "wss://test.mosquitto.org:8081/mqtt";
const topic = "iothub/project/dht/data";
const client = mqtt.connect(broker);
const logEl = document.getElementById("log");
client.on("connect", () => {
document.getElementById("status").textContent = "๐ข Terhubung ke MQTT Broker";
document.getElementById("status").className = "connected";
client.subscribe(topic);
});
client.on("message", (t, msg) => {
const data = JSON.parse(msg.toString());
document.getElementById("suhu").textContent = data.suhu.toFixed(1);
document.getElementById("rh").textContent = data.kelembaban.toFixed(1);
document.getElementById("hi").textContent = data.heat_index.toFixed(1);
document.getElementById("rssi").textContent = data.rssi;
const line = document.createElement("div");
line.textContent = `[${new Date().toLocaleTimeString()}] Suhu: ${data.suhu}ยฐC | RH: ${data.kelembaban}%`;
logEl.appendChild(line);
logEl.scrollTop = logEl.scrollHeight;
});
client.on("error", (err) => {
document.getElementById("status").textContent = "๐ด Error: " + err.message;
document.getElementById("status").className = "disconnected";
});
</script>
</body>
</html>
- Simpan kode HTML di atas sebagai file
dashboard.html - Upload program ESP32 ke board Anda
- Buka file
dashboard.htmldi browser (Chrome/Edge/Firefox) - Pastikan ESP32 dan komputer terhubung ke internet
- Dashboard akan menampilkan data suhu secara real-time!
Kustomisasi Lanjutan
- Ganti broker: Ganti URL WebSocket sesuai broker yang Anda gunakan (HiveMQ, EMQX, dll)
- Ganti topik: Ubah variabel
topicsesuai konfigurasi di kode ESP32 - Tambah grafik: Integrasikan Chart.js atau D3.js untuk visualisasi data historis
- Tambah kontrol: Subscribe ke topik perintah untuk mengontrol LED atau aktuator dari dashboard
9. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang sensor DHT dan ESP32: