☀️Siang
Dashboard & Cloud

Firebase Auth & Firestore untuk Aplikasi IoT

TOKEN

Tutorial komprehensif menggunakan Firebase Authentication dan Cloud Firestore untuk membangun backend aplikasi IoT — dari autentikasi user, database real-time, hingga security rules

Artikel: Firebase Auth Firestore Artikel: Firebase Auth Firestore


1. Overview: Mengapa Firebase untuk IoT?

Firebase adalah platform Backend-as-a-Service (BaaS) dari Google yang menyediakan berbagai layanan cloud tanpa perlu mengelola server sendiri. Untuk proyek IoT, Firebase sangat menarik karena menyediakan autentikasi user, database real-time, dan hosting dalam satu platform terintegrasi.

Bayangkan kamu punya proyek Smart Home — kamu tidak perlu membuat server API dari nol, mengelola database, atau membangun sistem login. Firebase menyediakan semuanya tinggal pakai.

Layanan Firebase yang Relevan untuk IoT

Layanan Fungsi Contoh Penggunaan IoT
AuthenticationManajemen user & loginLogin ke dashboard monitoring IoT
Cloud FirestoreNoSQL database real-timeMenyimpan data sensor, konfigurasi device
Realtime DatabaseDatabase JSON real-timeStatus device, kontrol relay real-time
Cloud FunctionsServerless functionsProses data sensor, kirim notifikasi
Cloud Messaging (FCM)Push notificationsAlert suhu tinggi ke HP user
HostingWeb hosting statisDeploy dashboard web IoT

Firestore vs Realtime Database

Firebase menyediakan dua database. Untuk kebanyakan proyek IoT modern, Cloud Firestore lebih direkomendasikan karena:

  • Struktur data lebih baik — Koleksi dan dokumen, bukan JSON tree besar
  • Query lebih kuat — Filter, sorting, dan pagination yang fleksibel
  • Scalability lebih baik — Sharding otomatis untuk data besar
  • Offline support — Sinkronisasi offline otomatis untuk mobile app
  • Composite index — Query dengan multiple filter dan sorting
💡 Contoh Use Case IoT

Smart Greenhouse: ESP32 mengirim data suhu dan kelembaban ke Cloud Functions via HTTP. Data disimpan di Firestore. User login ke dashboard web menggunakan Firebase Auth (Google Sign-In) dan melihat grafik real-time dari Firestore. Saat suhu melebihi threshold, Cloud Function mengirim push notification ke HP via FCM.

Diagram: Arsitektur Firebase untuk IoT
Arsitektur Firebase untuk IoT

FCM Push Notification

Web/Mobile Dashboard ▼ (Real-time sync) ← Fireb...

Firestore Database ▼ ▼



2. Setup Firebase Authentication

Firebase Authentication menyediakan sistem login yang aman tanpa perlu membuat backend autentikasi dari nol. Mendukung email/password, Google, GitHub, Facebook, dan metode login lainnya.

Langkah 1: Buat Project Firebase

  1. Buka https://console.firebase.google.com
  2. Klik "Add project"
  3. Masukkan nama project (misal: "iot-smart-home")
  4. Aktifkan/nonaktifkan Google Analytics sesuai kebutuhan
  5. Klik "Create project"

Langkah 2: Register Web App

Collection: 'devices'

Document: 'device-001'

name: 'Sensor Suhu Ruang Server'

type: 'temperature'

location: 'Lantai 2, Ruang Server'

owner_uid: 'abc123'

Sub-collection: 'readings'

Doc: '2026-06-25T10:00:00'

suhu: 28.5

kelembaban: 72.0

Doc: '2026-06-25T10:05:00'

suhu: 28.7

kelembaban: 71.5

Document: 'device-002'

name: 'Sensor Kelembaban Tanah'

type: 'soil_moisture'

location: 'Kebun Belakang'

Document: 'device-003'

name: 'Relay Lampu Teras'

type: 'relay'

Perbedaan utama dengan database relasional:

Aspek SQL (MySQL) Firestore (NoSQL)
StrukturTabel dengan baris dan kolomKoleksi dengan dokumen
SchemaTetap, harus didefinisikanFleksibel, bisa berbeda per dokumen
RelasiJOIN antar tabelSub-collection atau referensi
QuerySQLSDK dengan filter, sort, limit
SkalabilitasVertikal (tambah resource)Horizontal (otomatis)
Real-timePolling / externalBuilt-in real-time listener


6. CRUD Operations di Firestore

CRUD (Create, Read, Update, Delete) adalah operasi dasar database. Berikut implementasi lengkap dengan Cloud Firestore:

Create — Menambah Data

JavaScript — Create Data di Firestore
import { collection, doc, setDoc, addDoc, serverTimestamp } from "firebase/firestore";
import { db, auth } from "./firebase-config.js";

// === Metode 1: addDoc() — ID dokumen otomatis ===
async function addDevice(deviceData) {
  try {
    const docRef = await addDoc(collection(db, "devices"), {
      name: deviceData.name,
      type: deviceData.type,
      location: deviceData.location,
      owner_uid: auth.currentUser.uid,
      status: "online",
      created_at: serverTimestamp(),
      updated_at: serverTimestamp()
    });
    console.log("Device ditambahkan dengan ID:", docRef.id);
    return docRef.id;
  } catch (error) {
    console.error("Error menambah device:", error);
    throw error;
  }
}

// === Metode 2: setDoc() — ID manual ===
async function addReading(deviceId, readingData) {
  try {
    const readingId = new Date().toISOString(); // ID berdasarkan timestamp
    const readingRef = doc(db, "devices", deviceId, "readings", readingId);

    await setDoc(readingRef, {
      suhu: readingData.suhu,
      kelembaban: readingData.kelembaban,
      timestamp: serverTimestamp()
    });
    console.log("Data sensor ditambahkan:", readingId);
  } catch (error) {
    console.error("Error menambah data:", error);
    throw error;
  }
}

// Contoh penggunaan
await addDevice({
  name: "Sensor Suhu Gudang",
  type: "temperature",
  location: "Gudang Utama"
});

await addReading("device-001", {
  suhu: 28.5,
  kelembaban: 72.0
});

Read — Membaca Data

JavaScript — Read Data dari Firestore
import { collection, doc, getDoc, getDocs, query, where, orderBy, limit } from "firebase/firestore";
import { db } from "./firebase-config.js";

// === Baca satu dokumen berdasarkan ID ===
async function getDevice(deviceId) {
  const docRef = doc(db, "devices", deviceId);
  const docSnap = await getDoc(docRef);

  if (docSnap.exists()) {
    console.log("Data device:", docSnap.data());
    return { id: docSnap.id, ...docSnap.data() };
  } else {
    console.log("Device tidak ditemukan!");
    return null;
  }
}

// === Baca semua device milik user yang sedang login ===
async function getUserDevices() {
  const q = query(
    collection(db, "devices"),
    where("owner_uid", "==", auth.currentUser.uid),
    orderBy("created_at", "desc"),
    limit(50)
  );

  const querySnapshot = await getDocs(q);
  const devices = [];

  querySnapshot.forEach((doc) => {
    devices.push({ id: doc.id, ...doc.data() });
  });

  console.log(`Ditemukan ${devices.length} device`);
  return devices;
}

// === Baca data sensor dengan filter ===
async function getHighTempReadings(deviceId, minTemp) {
  const q = query(
    collection(db, "devices", deviceId, "readings"),
    where("suhu", ">", minTemp),
    orderBy("suhu", "desc"),
    limit(10)
  );

  const snapshot = await getDocs(q);
  return snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
}

Update & Delete

JavaScript — Update & Delete Data
import { doc, updateDoc, deleteDoc, serverTimestamp } from "firebase/firestore";
import { db } from "./firebase-config.js";

// === Update data device ===
async function updateDevice(deviceId, newData) {
  const deviceRef = doc(db, "devices", deviceId);

  await updateDoc(deviceRef, {
    ...newData,
    updated_at: serverTimestamp()
  });

  console.log("Device berhasil diupdate");
}

// Contoh: update status dan lokasi device
await updateDevice("device-001", {
  status: "offline",
  location: "Lantai 3, Ruang Lab"
});

// === Hapus device (termasuk sub-collection) ===
async function deleteDevice(deviceId) {
  // PERINGATAN: Sub-collection tidak otomatis terhapus!
  // Hapus sub-collection "readings" terlebih dahulu
  const readings = await getDocs(collection(db, "devices", deviceId, "readings"));
  const deletePromises = readings.docs.map(d => deleteDoc(d.ref));
  await Promise.all(deletePromises);

  // Hapus dokumen device
  await deleteDoc(doc(db, "devices", deviceId));
  console.log("Device dan semua data sensornya berhasil dihapus");
}

// === Batch write: operasi sekaligus ===
import { writeBatch } from "firebase/firestore";

async function batchUpdateStatus(deviceIds, status) {
  const batch = writeBatch(db);

  deviceIds.forEach(id => {
    const deviceRef = doc(db, "devices", id);
    batch.update(deviceRef, { status, updated_at: serverTimestamp() });
  });

  await batch.commit(); // Commit semua sekaligus
  console.log(`${deviceIds.length} device diupdate sekaligus`);
}


7. Firestore Security Rules

Security Rules menentukan siapa yang boleh membaca, menulis, atau menghapus data. Tanpa rules yang benar, siapa saja bisa mengakses data sensor IoT kamu. Ini adalah lapisan keamanan paling penting di Firebase.

⚠️ Security Rules Bukan Opsional!

API key Firebase bersifat publik — siapa saja yang melihat source code web kamu bisa mengetahui API key-nya. Security Rules adalah satu-satunya pertahanan untuk melindungi data kamu. Jangan pernah menggunakan "test mode" di produksi!

Firestore — firestore.rules
rules_version = "2";
service cloud.firestore {
  match /databases/{database}/documents {

    // Helper function: cek apakah user sudah login
    function isAuth() {
      return request.auth != null;
    }

    // Helper function: cek apakah user adalah pemilik dokumen
    function isOwner(userId) {
      return request.auth.uid == userId;
    }

    // === Collection: devices ===
    match /devices/{deviceId} {
      // Baca: hanya pemilik device yang bisa melihat
      allow read: if isAuth() && isOwner(resource.data.owner_uid);

      // Buat: user yang login, owner_uid harus miliknya, wajib ada field tertentu
      allow create: if isAuth()
        && request.resource.data.owner_uid == request.auth.uid
        && request.resource.data.keys().hasAll(["name", "type", "owner_uid"])
        && request.resource.data.name is string
        && request.resource.data.name.size() > 0;

      // Update: hanya pemilik, owner_uid tidak bisa diubah
      allow update: if isAuth()
        && isOwner(resource.data.owner_uid)
        && request.resource.data.owner_uid == resource.data.owner_uid;

      // Hapus: hanya pemilik
      allow delete: if isAuth() && isOwner(resource.data.owner_uid);

      // Sub-collection: readings (data sensor)
      match /readings/{readingId} {
        // Baca: hanya pemilik parent device
        allow read: if isAuth() && isOwner(
          get(/databases/$(database)/documents/devices/$(deviceId)).data.owner_uid
        );

        // Tulis data baru: hanya pemilik, validasi tipe data
        allow create: if isAuth()
          && isOwner(get(/databases/$(database)/documents/devices/$(deviceId)).data.owner_uid)
          && request.resource.data.suhu is number
          && request.resource.data.kelembaban is number;

        // Data sensor TIDAK BOLEH diubah atau dihapus (integritas data)
        allow update, delete: if false;
      }
    }
  }
}

Testing Security Rules

Terminal — Test Security Rules
# Instalasi Firebase CLI
npm install -g firebase-tools

# Login ke Firebase
firebase login

# Jalankan emulator untuk test security rules secara lokal
firebase emulators:start --only firestore

# Deploy security rules ke production
firebase deploy --only firestore:rules


8. Real-Time Listeners

Fitur terbaik Firestore untuk IoT adalah real-time listener. Data yang berubah di database akan otomatis ter-update di semua client yang mendengarkan. Tidak perlu polling — Firestore melakukan push update ke client.

JavaScript — Real-Time Listener
import { collection, doc, onSnapshot, query, where, orderBy, limit } from "firebase/firestore";
import { db } from "./firebase-config.js";

// === Listener untuk satu dokumen (real-time) ===
function watchDevice(deviceId) {
  const deviceRef = doc(db, "devices", deviceId);

  const unsubscribe = onSnapshot(deviceRef, (docSnap) => {
    if (docSnap.exists()) {
      const data = docSnap.data();
      console.log("Status device berubah:", data.status);

      // Update UI secara real-time
      document.getElementById("deviceName").textContent = data.name;
      document.getElementById("deviceStatus").textContent = data.status;
      document.getElementById("deviceStatus").className =
        data.status === "online" ? "badge-success" : "badge-danger";
    }
  }, (error) => {
    console.error("Error listening device:", error);
  });

  // Kembalikan fungsi unsubscribe untuk berhenti mendengarkan
  return unsubscribe;
}

// === Listener untuk data sensor terbaru ===
function watchLatestReadings(deviceId) {
  const q = query(
    collection(db, "devices", deviceId, "readings"),
    orderBy("timestamp", "desc"),
    limit(10)
  );

  const unsubscribe = onSnapshot(q, (snapshot) => {
    const readings = [];
    snapshot.forEach((doc) => {
      readings.push({ id: doc.id, ...doc.data() });
    });

    console.log(`Data sensor terbaru (${readings.length} records):`, readings);

    // Update grafik di dashboard
    updateChart(readings);

    // Update gauge suhu
    if (readings.length > 0) {
      const latestSuhu = readings[0].suhu;
      document.getElementById("gaugeSuhu").textContent = latestSuhu + "°C";

      // Alert jika suhu kritis
      if (latestSuhu > 35) {
        showAlert("Suhu kritis! " + latestSuhu + "°C");
      }
    }
  });

  return unsubscribe;
}

// === Menggunakan listener ===
const unsubDevice = watchDevice("device-001");
const unsubReadings = watchLatestReadings("device-001");

// Berhenti mendengarkan saat tidak diperlukan (hemat kuota)
// unsubDevice();
// unsubReadings();
💡 Hemat Kuota Firestore

Firestore menghitung setiap dokumen yang dibaca sebagai 1 read operation (termasuk dari listener). Jika listener mendengarkan 100 dokumen dan masing-masing berubah 1x, itu = 200 read operations. Gunakan limit() dan where() untuk membatasi data yang didengarkan. Unsubscribe listener saat halaman tidak aktif.



9. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Firebase Auth dan Firestore:

Pertanyaan 1: Mengapa Firebase API key TAK PERLU disembunyikan di source code?

a) Karena API key sudah dienkripsi oleh Firebase
b) Karena keamanan Firebase bergantung pada Security Rules, bukan API key
c) Karena Firebase memblokir akses dari IP yang tidak dikenal
d) Karena API key otomatis berubah setiap hari

Pertanyaan 2: Apa perbedaan antara addDoc() dan setDoc() di Firestore?

a) addDoc() untuk update, setDoc() untuk create
b) addDoc() membuat ID otomatis, setDoc() menggunakan ID manual
c) addDoc() untuk collection, setDoc() untuk field
d) Tidak ada perbedaan, keduanya sama

Pertanyaan 3: Fungsi apa yang digunakan untuk memantau perubahan data secara real-time di Firestore?

a) getDoc()
b) watchDoc()
c) onSnapshot()
d) subscribe()

Pertanyaan 4: Dalam Security Rules, request.auth.uid merujuk ke apa?

a) UID dari Firebase project
b) UID dari user yang sedang melakukan request (sudah login)
c) UID dari device IoT yang sedang mengirim data
d) UID dari dokumen Firestore

Pertanyaan 5: Mengapa onSnapshot() perlu di-unsubscribe saat halaman tidak aktif?

a) Untuk menghemat kuota baca Firestore
b) Untuk menghindari error di browser
c) Untuk menghapus data dari cache
d) Tidak perlu di-unsubscribe, Firebase menanganinya otomatis

← Sebelumnya Nginx Reverse Proxy Selanjutnya → Deploy ke VPS
🔍 Zoom
100%
🎨 Tema