1 PENDAHULUAN
1.1 Tujuan Pembelajaran
Setelah menyelesaikan modul ini, peserta didik diharapkan mampu:
- Memahami konsep dasar arsitektur IoT berbasis Cloud.
- Merangkai sensor (DHT11) dan aktuator (Relay) pada NodeMCU ESP8266.
- Mengkonfigurasi Firebase Realtime Database sebagai broker dan penyimpan data.
- Membuat antarmuka Web Dashboard yang responsif menggunakan layanan gratis Google Apps Script (GAS).
- Memprogram NodeMCU untuk mengirim dan menerima data secara real-time.
1.2 Konsep Kerja Sistem
Sistem ini menggunakan Firebase Realtime Database sebagai pusat data.
- NodeMCU bertugas membaca sensor DHT11 dan mengirimkannya ke Firebase. Di saat bersamaan, ia selalu mengecek status perintah di Firebase. Jika ada perintah "ON", NodeMCU akan menyalakan Relay.
- Google Apps Script (GAS) digunakan sebagai Web Server gratis untuk menampilkan Dashboard HTML/CSS/JS. Dashboard ini akan mengakses Firebase secara langsung, sehingga pengguna bisa melihat suhu dan menekan tombol relay melalui HP atau Laptop dari mana saja.
2 ALAT DAN BAHAN
A. Hardware
- NodeMCU ESP8266 (atau ESP32)
- Sensor Suhu & Kelembapan DHT11
- Modul Relay 1-Channel (5V)
- Kabel Jumper (Secukupnya)
- Kabel Micro USB
B. Software
- Arduino IDE (versi terbaru)
- Akun Google (Firebase & GAS)
- Web Browser (Chrome/Firefox)
- Koneksi Internet / WiFi
3 PERSIAPAN CLOUD
3.1 Konfigurasi Firebase Realtime Database
- Buka console.firebase.google.com dan login dengan akun Google.
- Klik Tambahkan Proyek (Add Project), beri nama "IoT Smart Home".
- Di menu kiri, pilih Build > Realtime Database > Klik Create Database.
- Pilih lokasi server terdekat, lalu pilih Start in Test Mode (Mode pengujian agar perangkat bisa baca-tulis tanpa otentikasi rumit). Klik Enable.
- Salin dan simpan URL Database Anda (tanpa
https://dan tanpa/di akhir). Contoh:iot-smarthome-123.firebaseio.com.
3.2 Pembuatan Dashboard Web di GAS
- Buka script.google.com dan buat Proyek Baru.
- Ganti nama proyek di kiri atas menjadi "Dashboard IoT".
- Pada tab
Code.gs, hapus semua kode dan masukkan kode Javascript backend ini:
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index')
.setTitle('Dashboard IoT Pintar')
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
- Buat file baru: Klik ikon + (Tambahkan file) di sebelah kiri > pilih HTML > beri nama Index (Huruf kapital I).
- Masukkan kode antarmuka HTML super keren di bawah ini ke dalam file
Index.htmlAnda.Langkah Super Penting!
Cari bagian
databaseURL: "https://..."di dalam baris kode di bawah, lalu ganti dengan URL Firebase Anda sendiri.
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard IoT Pintar</title>
<!-- Menggunakan Tailwind CSS untuk desain responsif yang modern -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- FontAwesome untuk Ikon -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<style>
.fade-in { animation: fadeIn 0.5s ease-in-out; }
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.toggle-checkbox:checked { right: 0; border-color: #3b82f6; }
.toggle-checkbox:checked + .toggle-label { background-color: #3b82f6; }
.toggle-checkbox { right: 0; z-index: 1; border-color: #e5e7eb; transition: all 0.3s; }
.toggle-label { background-color: #e5e7eb; transition: all 0.3s; }
</style>
</head>
<body class="bg-slate-100 font-sans min-h-screen text-slate-800">
<!-- Navbar -->
<nav class="bg-blue-600 text-white shadow-lg">
<div class="max-w-6xl mx-auto px-4 py-4 flex justify-between items-center">
<div class="text-xl font-bold flex items-center gap-2">
<i class="fa-solid fa-house-signal"></i> Smart Home IoT
</div>
<div id="connection-status" class="text-sm bg-blue-700 px-3 py-1 rounded-full flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-yellow-400 animate-pulse" id="status-dot"></span>
<span id="status-text">Menghubungkan...</span>
</div>
</div>
</nav>
<!-- Main Content -->
<main class="max-w-6xl mx-auto px-4 py-8">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Card Suhu -->
<div class="bg-white rounded-2xl shadow-sm p-6 flex flex-col items-center justify-center fade-in border border-slate-100 hover:shadow-md transition-shadow">
<div class="w-16 h-16 rounded-full bg-red-100 text-red-500 flex items-center justify-center text-2xl mb-4">
<i class="fa-solid fa-temperature-half"></i>
</div>
<h2 class="text-slate-500 font-medium mb-1">Suhu Ruangan</h2>
<div class="text-4xl font-bold text-slate-800 flex items-baseline gap-1">
<span id="suhu-value">--</span>
<span class="text-xl font-normal text-slate-400">°C</span>
</div>
</div>
<!-- Card Kelembapan -->
<div class="bg-white rounded-2xl shadow-sm p-6 flex flex-col items-center justify-center fade-in border border-slate-100 hover:shadow-md transition-shadow" style="animation-delay: 0.1s;">
<div class="w-16 h-16 rounded-full bg-blue-100 text-blue-500 flex items-center justify-center text-2xl mb-4">
<i class="fa-solid fa-droplet"></i>
</div>
<h2 class="text-slate-500 font-medium mb-1">Kelembapan</h2>
<div class="text-4xl font-bold text-slate-800 flex items-baseline gap-1">
<span id="kelembapan-value">--</span>
<span class="text-xl font-normal text-slate-400">%</span>
</div>
</div>
<!-- Card Kontrol Relay -->
<div class="bg-white rounded-2xl shadow-sm p-6 flex flex-col items-center justify-center fade-in border border-slate-100 hover:shadow-md transition-shadow" style="animation-delay: 0.2s;">
<div class="w-16 h-16 rounded-full bg-yellow-100 text-yellow-500 flex items-center justify-center text-2xl mb-4" id="relay-icon-bg">
<i class="fa-solid fa-lightbulb" id="relay-icon"></i>
</div>
<h2 class="text-slate-500 font-medium mb-3">Kontrol Perangkat (Relay)</h2>
<div class="relative inline-block w-16 mr-2 align-middle select-none transition duration-200 ease-in">
<input type="checkbox" name="toggle" id="relay-toggle" class="toggle-checkbox absolute block w-8 h-8 rounded-full bg-white border-4 appearance-none cursor-pointer"/>
<label for="relay-toggle" class="toggle-label block overflow-hidden h-8 rounded-full bg-gray-300 cursor-pointer"></label>
</div>
<div id="relay-status-text" class="mt-2 font-bold text-slate-400">OFF</div>
</div>
</div>
</main>
<!-- Firebase App (v8 Compat) -->
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-database.js"></script>
<script>
// PENTING: GANTI URL DI BAWAH DENGAN URL FIREBASE ANDA
const firebaseConfig = {
databaseURL: "https://GANTI_DENGAN_URL_FIREBASE_ANDA.firebaseio.com"
};
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
}
const db = firebase.database();
// DOM Elements
const statusDot = document.getElementById('status-dot');
const statusText = document.getElementById('status-text');
const suhuEl = document.getElementById('suhu-value');
const kelembapanEl = document.getElementById('kelembapan-value');
const relayToggle = document.getElementById('relay-toggle');
const relayStatusText = document.getElementById('relay-status-text');
const relayIconBg = document.getElementById('relay-icon-bg');
// Deteksi Koneksi
firebase.database().ref(".info/connected").on("value", (snap) => {
if (snap.val() === true) {
statusDot.className = 'w-2 h-2 rounded-full bg-green-400';
statusText.innerText = "Terhubung";
} else {
statusDot.className = 'w-2 h-2 rounded-full bg-red-500';
statusText.innerText = "Terputus";
}
});
// Baca Sensor
db.ref('/sensor/suhu').on('value', (s) => { if(s.val() !== null) suhuEl.innerText = s.val(); });
db.ref('/sensor/kelembapan').on('value', (s) => { if(s.val() !== null) kelembapanEl.innerText = s.val(); });
// Kontrol Relay
let isCodeClick = false;
db.ref('/kontrol/relay').on('value', (s) => {
isCodeClick = true;
const state = s.val() === "ON";
relayToggle.checked = state;
updateUI(state);
setTimeout(() => { isCodeClick = false; }, 100);
});
relayToggle.addEventListener('change', (e) => {
if (isCodeClick) return;
updateUI(e.target.checked);
db.ref('/kontrol/relay').set(e.target.checked ? "ON" : "OFF");
});
function updateUI(isOn) {
if(isOn) {
relayStatusText.innerText = "ON";
relayStatusText.className = "mt-2 font-bold text-blue-500";
relayIconBg.className = "w-16 h-16 rounded-full bg-blue-100 text-blue-500 flex items-center justify-center text-2xl mb-4";
} else {
relayStatusText.innerText = "OFF";
relayStatusText.className = "mt-2 font-bold text-slate-400";
relayIconBg.className = "w-16 h-16 rounded-full bg-yellow-100 text-yellow-500 flex items-center justify-center text-2xl mb-4";
}
}
</script>
</body>
</html>
- Klik tombol Terapkan (Deploy) > Deployment Baru.
- Pilih jenis Aplikasi Web. Atur akses ke Siapa saja (Anyone).
- Klik Terapkan. Salin URL Web App yang dihasilkan. Buka link tersebut di HP Anda.
4 PERAKITAN HARDWARE
Pastikan kabel USB belum terpasang ke komputer saat merakit!
1. Sensor DHT11 NodeMCU
- Pin VCC Pin 3V3
- Pin GND Pin GND
- Pin DATA Pin D2 (GPIO4)
2. Relay 5V NodeMCU
- Pin VCC Pin VU / VIN
- Pin GND Pin GND
- Pin IN Pin D1 (GPIO5)
5 PEMROGRAMAN NODEMCU
5.1 Instalasi Library
Buka Arduino IDE, masuk ke menu Sketch > Include Library > Manage Libraries. Cari dan instal:
DHT sensor libraryoleh Adafruit.Firebase ESP8266 Clientoleh Mobizt.
5.2 Upload Kode Program
Salin kode C++ berikut ke Arduino IDE. Jangan lupa ubah pengaturan WiFi dan Firebase.
#include <ESP8266WiFi.h>
#include <FirebaseESP8266.h>
#include "DHT.h"
// 1. PENGATURAN WIFI
#define WIFI_SSID "NAMA_WIFI_ANDA"
#define WIFI_PASSWORD "PASSWORD_WIFI_ANDA"
// 2. PENGATURAN FIREBASE
// Masukkan URL Firebase (Tanpa https:// dan tanpa / di akhir)
#define FIREBASE_HOST "URL_FIREBASE_ANDA.firebaseio.com"
// (Opsional) Masukkan rahasia database, kosongkan "" jika masih test mode
#define FIREBASE_AUTH ""
// 3. PENGATURAN HARDWARE
#define DHTPIN 4 // Pin D2
#define DHTTYPE DHT11
#define RELAY_PIN 5 // Pin D1
DHT dht(DHTPIN, DHTTYPE);
FirebaseData firebaseData;
unsigned long waktuTerakhir = 0;
void setup() {
Serial.begin(115200);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH); // Relay OFF (Active Low)
dht.begin();
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("\nMenghubungkan WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nTerhubung ke WiFi!");
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
Firebase.reconnectWiFi(true);
}
void loop() {
unsigned long waktuSekarang = millis();
// A. MEMBACA PERINTAH DARI WEB (REAL-TIME)
if (Firebase.getString(firebaseData, "/kontrol/relay")) {
String status = firebaseData.stringData();
if (status == "ON") {
digitalWrite(RELAY_PIN, LOW); // Relay menyala
} else if (status == "OFF") {
digitalWrite(RELAY_PIN, HIGH); // Relay mati
}
}
// B. MENGIRIM DATA SENSOR (SETIAP 5 DETIK)
if (waktuSekarang - waktuTerakhir > 5000) {
waktuTerakhir = waktuSekarang;
float h = dht.readHumidity();
float t = dht.readTemperature();
if (!isnan(h) && !isnan(t)) {
Firebase.setFloat(firebaseData, "/sensor/suhu", t);
Firebase.setFloat(firebaseData, "/sensor/kelembapan", h);
Serial.println("Suhu: " + String(t) + "C, Kelembapan: " + String(h) + "%");
} else {
Serial.println("Gagal membaca sensor!");
}
}
}
Klik tombol Upload pada Arduino IDE. Buka Serial Monitor (Baudrate 115200) untuk melihat log data.
6 PENGUJIAN DAN EVALUASI
6.1 Langkah Pengujian
- Verifikasi Hardware: Serial Monitor menampilkan "Terhubung ke WiFi!".
- Verifikasi Cloud: Buka Firebase. Pastikan folder
/sensordan/kontrolmuncul. - Verifikasi Web Dashboard: Buka URL Web App di HP Anda. Coba tekan tombol Toggle Relay. Relay fisik harus berbunyi "klik".
6.2 Pemecahan Masalah (Troubleshooting)
- Status WiFi terus "...": Pastikan WiFi Anda menggunakan frekuensi 2.4 GHz. NodeMCU tidak mendukung 5 GHz.
- Sensor "NaN": Kabel data DHT terbalik atau kurang rapat.
- Relay logika terbalik: Jika relay Anda bertipe Active High, ubah
LOWmenjadiHIGH(dan sebaliknya) pada fungsi digitalWrite di Arduino IDE.
Tantangan Ekstra!
Modifikasi tampilan HTML di GAS! Coba ubah warna tema, atau tambahkan logika otomatis di Arduino: "Jika suhu > 30°C, maka relay kipas menyala otomatis!"