Modul Praktik V.2.0 SMA Kristen Barana

Internet of Things
Masterclass.

Sistem Smart Home: Monitoring Suhu & Kontrol Relay Web

NodeMCU ESP8266 + Firebase RTDB + Google Apps Script

1

PENDAHULUAN

1.1 Tujuan Pembelajaran

Setelah menyelesaikan modul ini, peserta didik diharapkan mampu:

  1. Memahami konsep dasar arsitektur IoT berbasis Cloud.
  2. Merangkai sensor (DHT11) dan aktuator (Relay) pada NodeMCU ESP8266.
  3. Mengkonfigurasi Firebase Realtime Database sebagai broker dan penyimpan data.
  4. Membuat antarmuka Web Dashboard yang responsif menggunakan layanan gratis Google Apps Script (GAS).
  5. 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 ESP8266

Bertugas membaca sensor DHT11 dan mengirimkannya ke Firebase. Di saat bersamaan, selalu mengecek status perintah di Firebase. Jika ada perintah "ON", NodeMCU menyalakan Relay.

Google Apps Script (GAS)

Digunakan sebagai Web Server gratis untuk menampilkan Dashboard. Mengakses Firebase langsung, sehingga pengguna bisa melihat suhu & menekan tombol dari mana saja.

2

ALAT DAN BAHAN

A. Hardware

  • NodeMCU ESP8266 / ESP32
  • Sensor DHT11
  • Modul Relay 1-Channel (5V)
  • Kabel Jumper
  • Kabel Micro USB

B. Software

  • Arduino IDE
  • Akun Google
  • Web Browser
  • Koneksi Internet
3

PERSIAPAN CLOUD

3.1 Konfigurasi Firebase Realtime Database

Untuk menghubungkan perangkat IoT Anda dengan database, kita membutuhkan dua kunci utama: Firebase Host (URL) dan Firebase Auth (Database Secret).

A. Mendapatkan Firebase Host (URL Database)

  1. Buka console.firebase.google.com dan login dengan akun Google.
  2. Klik Tambahkan Proyek (Add Project), beri nama "IoT Smart Home".
  3. Di menu kiri, pilih Build > Realtime Database > Klik Create Database.
  4. Pilih lokasi server terdekat, lalu pilih Start in Test Mode (Mode pengujian agar perangkat bisa baca-tulis tanpa otentikasi rumit). Klik Enable.
  5. Salin dan simpan URL Database Anda.
    Penting: Saat di-paste ke Arduino IDE, hapus https:// dan / di akhir.
    Contoh: iot-smarthome-123.firebaseio.com

B. Mendapatkan Firebase Auth (Database Secret)

  1. Klik ikon Gir (Settings) di menu sebelah kiri atas, lalu pilih Project settings.
  2. Pindah ke tab Service accounts.
  3. Pada menu sebelah kiri, klik Database secrets.
  4. Anda akan melihat baris rahasia yang disensor. Klik tombol Show (Tampilkan).
  5. Copy (Salin) kode teks panjang yang muncul.
  6. Paste (Tempel) kode tersebut ke dalam variabel FIREBASE_AUTH di Arduino IDE Anda nanti.

    Catatan Penting: Simpan baik-baik kode rahasia yang baru saja Anda copy. Kita akan mem-paste kode ini ke aplikasi Arduino IDE saat masuk ke Bab 5: Pemrograman NodeMCU nanti.

3.2 Pembuatan Dashboard Web di GAS

  1. Buka script.google.com dan buat Proyek Baru.
  2. Ganti nama proyek di kiri atas menjadi "Dashboard IoT".
  3. 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');
}
  1. Buat file baru: Klik ikon + (Tambahkan file) di sebelah kiri > pilih HTML > beri nama Index (Huruf kapital I).
  2. Masukkan kode antarmuka HTML super keren di bawah ini ke dalam file Index.html Anda.

    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>IoT Smart Dashboard</title>
    <!-- Tailwind CSS -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- FontAwesome -->
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
    <!-- Google Fonts -->
    <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
    <style>
        body { font-family: 'Poppins', sans-serif; background-color: #0f172a; background-image: radial-gradient(circle at top right, #1e1b4b, #0f172a, #020617); color: white; min-height: 100vh; }
        .glass-card { background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border: 1px solid rgba(255, 255, 255, 0.1); }
        .toggle-checkbox:checked { right: 0; border-color: #10b981; }
        .toggle-checkbox:checked + .toggle-label { background-color: #10b981; }
        .toggle-checkbox { right: 28px; z-index: 1; border-color: #475569; transition: all 0.3s; }
        .toggle-label { background-color: #475569; transition: all 0.3s; }
        .float-anim { animation: floating 3s ease-in-out infinite; }
        @keyframes floating { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-8px); } }
    </style>
</head>
<body class="antialiased pb-12">

    <!-- Navbar Glass -->
    <nav class="glass-card sticky top-0 z-50 shadow-lg">
        <div class="max-w-6xl mx-auto px-4 py-4 flex justify-between items-center">
            <div class="text-xl md:text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-emerald-400 flex items-center gap-3">
                <div class="bg-white/10 p-2 rounded-lg"><i class="fa-solid fa-microchip text-blue-400"></i></div> 
                Smart IoT
            </div>
            <div class="glass-card px-3 md:px-4 py-1.5 md:py-2 rounded-full flex items-center gap-2 text-xs md:text-sm border-white/20">
                <span class="w-2 h-2 rounded-full bg-yellow-400 animate-pulse shadow-[0_0_8px_#facc15]" id="status-dot"></span>
                <span id="status-text" class="font-medium text-slate-200">Menghubungkan ESP8266...</span>
            </div>
        </div>
    </nav>

    <!-- Main Content -->
    <main class="max-w-6xl mx-auto px-4 py-8">
        <!-- Header -->
        <div class="mb-8">
            <h1 class="text-3xl md:text-4xl font-bold mb-2">Welcome Home 👋</h1>
            <p class="text-slate-400">Pantau dan kontrol perangkat IoT Anda secara real-time.</p>
        </div>

        <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">

            <!-- Card Suhu -->
            <div class="glass-card rounded-3xl p-6 relative overflow-hidden group hover:bg-white/10 transition-all duration-300 shadow-xl">
                <div class="absolute -right-4 -top-4 text-8xl text-red-500/10 group-hover:scale-110 transition-transform"><i class="fa-solid fa-temperature-half"></i></div>
                <div class="flex items-center gap-4 mb-6 relative z-10">
                    <div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-red-500 to-orange-400 flex items-center justify-center text-2xl shadow-lg shadow-red-500/30 float-anim">
                        <i class="fa-solid fa-temperature-half text-white"></i>
                    </div>
                    <h2 class="text-lg font-semibold text-slate-300 tracking-wide">Suhu Ruangan</h2>
                </div>
                <div class="flex items-baseline gap-2 relative z-10">
                    <span id="suhu-value" class="text-5xl md:text-6xl font-bold tracking-tight">--</span>
                    <span class="text-2xl text-red-400 font-medium">°C</span>
                </div>
            </div>

            <!-- Card Kelembapan -->
            <div class="glass-card rounded-3xl p-6 relative overflow-hidden group hover:bg-white/10 transition-all duration-300 shadow-xl">
                <div class="absolute -right-4 -top-4 text-8xl text-blue-500/10 group-hover:scale-110 transition-transform"><i class="fa-solid fa-droplet"></i></div>
                <div class="flex items-center gap-4 mb-6 relative z-10">
                    <div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-blue-500 to-cyan-400 flex items-center justify-center text-2xl shadow-lg shadow-blue-500/30 float-anim" style="animation-delay: 0.5s;">
                        <i class="fa-solid fa-droplet text-white"></i>
                    </div>
                    <h2 class="text-lg font-semibold text-slate-300 tracking-wide">Kelembapan</h2>
                </div>
                <div class="flex items-baseline gap-2 relative z-10">
                    <span id="kelembapan-value" class="text-5xl md:text-6xl font-bold tracking-tight">--</span>
                    <span class="text-2xl text-blue-400 font-medium">%</span>
                </div>
            </div>

            <!-- Card Kontrol Relay -->
            <div class="glass-card rounded-3xl p-6 relative overflow-hidden group hover:bg-white/10 transition-all duration-300 shadow-xl sm:col-span-2 lg:col-span-1 flex flex-col justify-between">
                <div class="absolute -right-4 -top-4 text-8xl text-yellow-500/5 group-hover:scale-110 transition-transform"><i class="fa-solid fa-bolt"></i></div>
                <div class="flex justify-between items-start mb-6 relative z-10">
                    <div class="flex items-center gap-4">
                        <div id="relay-icon-bg" class="w-14 h-14 rounded-2xl bg-slate-700/50 border border-white/10 flex items-center justify-center text-2xl shadow-lg transition-all duration-500">
                            <i class="fa-solid fa-power-off text-slate-400" id="relay-icon"></i>
                        </div>
                        <div>
                            <h2 class="text-lg font-semibold text-slate-300 tracking-wide">Smart Relay</h2>
                            <div id="relay-status-text" class="text-sm font-bold text-slate-500 mt-1">STATUS: OFF</div>
                        </div>
                    </div>
                </div>
                
                <div class="mt-auto bg-black/20 p-4 rounded-2xl flex justify-between items-center border border-white/5 relative z-10">
                    <span class="font-medium text-slate-300">Power Switch</span>
                    <div class="relative inline-block w-14 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-7 h-7 rounded-full bg-white border-4 appearance-none cursor-pointer outline-none"/>
                        <label for="relay-toggle" class="toggle-label block overflow-hidden h-7 rounded-full bg-slate-600 cursor-pointer"></label>
                    </div>
                </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');
        const relayIcon = document.getElementById('relay-icon');

        // Fungsi Set Offline
        let espDisconnectTimer;
        function setEspOffline() {
            statusDot.className = 'w-2 h-2 rounded-full bg-red-500 shadow-[0_0_8px_#ef4444] animate-pulse';
            statusText.innerText = "ESP8266 Terputus";
            statusText.className = "font-medium text-red-400";
        }

        // Deteksi Koneksi Web ke Server Firebase
        firebase.database().ref(".info/connected").on("value", (snap) => {
            if (snap.val() !== true) {
                setEspOffline();
            }
        });

        // Deteksi Sinyal Kehidupan (Heartbeat) dari ESP8266
        db.ref('/status/uptime').on('value', (snap) => {
            if(snap.val() !== null) {
                // ESP mengirim data baru, berarti perangkat Online!
                statusDot.className = 'w-2 h-2 rounded-full bg-emerald-400 shadow-[0_0_8px_#34d399]';
                statusText.innerText = "ESP8266 Terhubung";
                statusText.className = "font-medium text-emerald-400";
                
                // Jika 12 detik ESP berhenti mengirim data, anggap terputus
                clearTimeout(espDisconnectTimer);
                espDisconnectTimer = setTimeout(setEspOffline, 12000);
            }
        });

        // 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 = "STATUS: ON";
                relayStatusText.className = "text-sm font-bold text-emerald-400 mt-1";
                relayIconBg.className = "w-14 h-14 rounded-2xl bg-gradient-to-br from-emerald-400 to-teal-500 flex items-center justify-center text-2xl shadow-lg shadow-emerald-500/40 float-anim border border-white/20";
                relayIcon.className = "fa-solid fa-power-off text-white";
            } else {
                relayStatusText.innerText = "STATUS: OFF";
                relayStatusText.className = "text-sm font-bold text-slate-500 mt-1";
                relayIconBg.className = "w-14 h-14 rounded-2xl bg-slate-700/50 border border-white/10 flex items-center justify-center text-2xl shadow-lg transition-all duration-500";
                relayIcon.className = "fa-solid fa-power-off text-slate-400";
            }
        }
    </script>
</body>
</html>
  1. Klik tombol Terapkan (Deploy) > Deployment Baru.
  2. Pilih jenis Aplikasi Web. Atur akses ke Siapa saja (Anyone).
  3. 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

  • Pin VCC
    Pin 3V3
  • Pin GND
    Pin GND
  • Pin DATA
    Pin D2 (GPIO4)

2. Relay 5V

  • 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:

  • 1
    DHT sensor library oleh Adafruit
  • 2
    Firebase ESP8266 Client oleh 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;
FirebaseAuth auth;     // Objek autentikasi versi terbaru
FirebaseConfig config; // Objek konfigurasi versi terbaru

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!");

  // --- KONFIGURASI FIREBASE TERBARU ---
  config.host = FIREBASE_HOST;
  config.signer.tokens.legacy_token = FIREBASE_AUTH;

  Firebase.begin(&config, &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);
      
      // Kirim sinyal kehidupan (uptime) ke web
      Firebase.setInt(firebaseData, "/status/uptime", waktuSekarang / 1000);
      
      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 secara langsung.

6

PENGUJIAN & EVALUASI

6.1 Langkah Pengujian

  • Verifikasi Hardware: Serial Monitor menampilkan "Terhubung ke WiFi!".
  • Verifikasi Cloud: Buka Firebase. Pastikan folder /sensor dan /kontrol muncul.
  • 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 LOW menjadi HIGH (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!"

Halaman 1 dari 6