1. Apa Itu Firebase Realtime Database?
Firebase Realtime Database (RTDB) adalah cloud-hosted NoSQL database yang menyimpan data dalam format JSON dan menyinkronkan data secara real-time ke setiap client yang terhubung. Setiap kali data berubah, semua connected client akan menerima update secara otomatis — tanpa perlu polling atau WebSocket manual.
Untuk proyek IoT, Firebase RTDB sangat menarik karena kesederhanaannya. Kamu bisa dengan mudah mengirim data sensor dari ESP32 ke database, dan data tersebut langsung muncul di web dashboard dan mobile app secara real-time. Firebase juga menyediakan SDK untuk web, iOS, Android, dan bahkan Arduino/ESP32 melalui library pihak ketiga.
Firebase menyediakan Spark Plan (gratis) yang cukup untuk development dan proyek kecil: 1 GB storage, 10 GB/bulan bandwidth, 100 koneksi simultan. Untuk produksi, kamu perlu Blaze Plan (pay-as-you-go).
Firebase RTDB vs Firestore
| Aspek | Realtime Database | Cloud Firestore |
|---|---|---|
| Data Model | JSON tree besar | Collections & documents |
| Query | Sorting/filtering terbatas | Compound queries |
| Real-time | Ya (seluruh subtree) | Ya (per query) |
| Offline Support | Ya (Android/iOS) | Ya (Android/iOS/Web) |
| Scalability | Single database | Multi-region, auto-scaling |
| Pricing | Berbasis bandwidth | Berbasis operasi baca/tulis |
| Cocok untuk IoT | Ya (lebih sederhana) | Ya (lebih scalable) |
2. Setup Firebase Project
Langkah 1: Buat Firebase Project
- Buka Firebase Console
- Klik "Add project" → beri nama:
iot-monitoring - Nonaktifkan Google Analytics (opsional) → Create Project
- Setelah project dibuat, klik Build → Realtime Database
- Klik "Create Database" → pilih lokasi server terdekat
- Pilih "Start in test mode" (untuk development)
Langkah 2: Dapatkan Service Account Key
# Untuk ESP32/server-side:
# 1. Buka Project Settings → Service Accounts
# 2. Klik "Generate new private key"
# 3. Simpan file JSON dengan aman
# 4. Dari file JSON, ambil:
# - database_url: https://your-project.firebaseio.com
# - api_key: dari Project Settings → General → Web API Key
# Untuk ESP32, kamu perlu:
# - Firebase Host (database URL)
# - Firebase Auth Token (API key atau custom token)
Langkah 3: Install Library ESP32
# Arduino IDE: Install via Library Manager
# - Firebase ESP Client by mobizt
# - ArduinoJson by Benoit Blanchon
# PlatformIO: platformio.ini
[env:esp32]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
mobizt/Firebase ESP Client@^4.4.0
bblanchon/ArduinoJson@^7.0.0
3. Data Structure untuk IoT
Desain data structure yang baik sangat penting di Firebase RTDB karena tidak adanya schema. Flat structure lebih disukai daripada deeply nested data karena mempengaruhi performa query dan security rules.
Struktur Data yang Direkomendasikan
{
"devices": {
"sensor-01": {
"info": {
"name": "Sensor Suhu Ruang Server",
"location": "Building A, Floor 2",
"type": "DHT22",
"firmware": "2.1.0",
"last_seen": 1719600000
},
"telemetry": {
"1719600000": { "temp": 25.6, "humidity": 65 },
"1719600060": { "temp": 25.8, "humidity": 64 },
"1719600120": { "temp": 26.1, "humidity": 63 }
},
"latest": {
"temp": 26.1,
"humidity": 63,
"battery": 87,
"timestamp": 1719600120
},
"config": {
"report_interval": 60,
"temp_threshold": 40,
"alert_enabled": true
}
}
},
"alerts": {
"alert-001": {
"device": "sensor-01",
"type": "HIGH_TEMPERATURE",
"value": 41.2,
"threshold": 40,
"timestamp": 1719600120,
"status": "active"
}
},
"users": {
"user-uid-001": {
"name": "Admin",
"email": "admin@example.com",
"devices": {
"sensor-01": true
}
}
}
}
- Flat structure: Hindari nesting lebih dari 3 level
- Denormalize: Duplikasi data jika perlu untuk query yang lebih cepat
- Separate telemetry: Simpan time-series data terpisah dari metadata device
- Timestamp as key: Gunakan timestamp Unix sebagai key untuk ordering otomatis
- Limits: Node terbesar yang di-download sekaligus tidak boleh lebih dari 256MB
4. ESP32 + Firebase Integration
Koneksi ESP32 ke Firebase
// ESP32 + Firebase Realtime Database
#include <WiFi.h>
#include <Firebase_ESP_Client.h>
#include "addons/TokenHelper.h"
#include "addons/RTDBHelper.h"
#define WIFI_SSID "your-wifi"
#define WIFI_PASS "your-password"
#define API_KEY "your-firebase-api-key"
#define DATABASE_URL "https://your-project-default-rtdb.firebaseio.com"
#define USER_EMAIL "device@iot.com"
#define USER_PASS "device-password"
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;
void setup() {
Serial.begin(115200);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(500);
config.api_key = API_KEY;
config.database_url = DATABASE_URL;
auth.user.email = USER_EMAIL;
auth.user.password = USER_PASS;
Firebase.begin(&config, &auth);
Firebase.reconnectWiFi(true);
}
void sendTelemetry(float temp, float humidity) {
String path = "/devices/sensor-01/latest";
Firebase.RTDB.setFloat(&fbdo, path + "/temp", temp);
Firebase.RTDB.setFloat(&fbdo, path + "/humidity", humidity);
Firebase.RTDB.setInt(&fbdo, path + "/timestamp", (int)time(NULL));
Firebase.RTDB.setInt(&fbdo, path + "/battery", readBattery());
// Simpan ke history
String historyPath = "/devices/sensor-01/telemetry/" + String((int)time(NULL));
Firebase.RTDB.setFloat(&fbdo, historyPath + "/temp", temp);
Firebase.RTDB.setFloat(&fbdo, historyPath + "/humidity", humidity);
Serial.println("Data sent to Firebase!");
}
void readConfig() {
if (Firebase.RTDB.getInt(&fbdo, "/devices/sensor-01/config/report_interval")) {
int interval = fbdo.intData();
Serial.printf("Report interval: %d seconds\n", interval);
}
}
void loop() {
static unsigned long lastSend = 0;
if (millis() - lastSend > 60000) {
float temp = dht.readTemperature();
float hum = dht.readHumidity();
sendTelemetry(temp, hum);
readConfig();
lastSend = millis();
}
}
Streaming Data (Real-time Listener)
// Stream perubahan config dari Firebase ke ESP32
void streamCallback(FirebaseStream data) {
Serial.printf("Stream path: %s\n", data.streamPath().c_str());
Serial.printf("Data: %s\n", data.stringData().c_str());
if (data.streamPath() == "/config/report_interval") {
int newInterval = data.intData();
updateReportInterval(newInterval);
}
}
void streamTimeoutCallback(bool timeout) {
if (timeout) Serial.println("Stream timeout, reconnecting...");
}
void setup() {
// ... setelah Firebase.begin()
Firebase.RTDB.beginStream(&fbdo, "/devices/sensor-01/config");
Firebase.RTDB.setStreamCallback(&fbdo, streamCallback, streamTimeoutCallback);
}
void loop() {
// Stream berjalan di background
// Tidak perlu polling manual
}
5. Security Rules
Security rules sangat penting untuk melindungi data IoT kamu. Tanpa rules yang benar, siapa saja bisa membaca atau mengubah data device kamu.
Contoh Security Rules
{
"rules": {
"devices": {
"$device_id": {
// Device bisa tulis telemetry sendiri
"latest": {
".read": "auth != null",
".write": "auth != null && auth.uid == $device_id"
},
"telemetry": {
".read": "auth != null",
".write": "auth != null && auth.uid == $device_id",
// Validasi format data
"$timestamp": {
".validate": "newData.hasChildren(['temp', 'humidity'])",
"temp": {
".validate": "newData.isNumber() && newData.val() >= -40 && newData.val() <= 80"
},
"humidity": {
".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 100"
}
}
},
"config": {
".read": "auth != null",
".write": "root.child('users/' + auth.uid + '/devices/' + $device_id).exists()"
},
"info": {
".read": "auth != null",
".write": "false"
}
}
},
"alerts": {
".read": "auth != null",
".write": "false"
},
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid"
}
}
}
}
- Selalu autentikasi device menggunakan custom token atau email/password
- Validasi data type dan range di security rules
- Jangan pernah menggunakan
".read": trueatau".write": truedi produksi - Gunakan Firebase Admin SDK di server untuk operasi admin
- Test rules menggunakan Firebase Rules Playground
6. Offline Persistence & Sync
Firebase RTDB mendukung offline persistence di platform mobile (Android/iOS) dan web (dengan SDK web v9+). Ketika client kehilangan koneksi, data tetap tersimpan secara lokal dan disinkronkan otomatis saat koneksi pulih.
Web SDK: Enable Persistence
// Firebase Web SDK v9+
import { initializeApp } from "firebase/app";
import { getDatabase, ref, onValue, enableIndexedDbPersistence } from "firebase/database";
const app = initializeApp(firebaseConfig);
const db = getDatabase(app);
// Enable offline persistence
enableIndexedDbPersistence(db).catch((err) => {
if (err.code == 'failed-precondition') {
console.log('Multiple tabs open, persistence only works in one tab');
} else if (err.code == 'unimplemented') {
console.log('Browser does not support persistence');
}
});
// Listen to sensor data (works offline too)
const sensorRef = ref(db, 'devices/sensor-01/latest');
onValue(sensorRef, (snapshot) => {
const data = snapshot.val();
updateDashboard(data.temp, data.humidity);
// Data ini akan di-cache dan tersedia offline
});
Monitoring Connection Status
// Monitor koneksi Firebase
const connectedRef = ref(db, '.info/connected');
onValue(connectedRef, (snap) => {
if (snap.val() === true) {
console.log("Connected to Firebase");
document.getElementById('status').textContent = '🟢 Online';
} else {
console.log("Disconnected from Firebase");
document.getElementById('status').textContent = '🔴 Offline';
}
});
7. Cloud Functions untuk IoT Automation
Firebase Cloud Functions memungkinkan kamu menjalankan kode server-side secara otomatis saat data berubah di RTDB. Ini sangat berguna untuk IoT automation seperti alerting, data processing, dan integrasi dengan layanan lain.
Contoh Cloud Functions
// functions/index.js
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const nodemailer = require("nodemailer");
admin.initializeApp();
// Trigger: Kirim alert saat suhu melebihi threshold
exports.onTemperatureAlert = functions.database
.ref("/devices/{deviceId}/latest/temp")
.onWrite(async (change, context) => {
const newTemp = change.after.val();
const deviceId = context.params.deviceId;
const threshold = 40;
if (newTemp > threshold) {
// Simpan alert
const alertRef = admin.database().ref("/alerts").push();
await alertRef.set({
device: deviceId,
type: "HIGH_TEMPERATURE",
value: newTemp,
threshold: threshold,
timestamp: admin.database.ServerValue.TIMESTAMP,
status: "active"
});
// Kirim notifikasi (contoh: FCM)
const payload = {
notification: {
title: "⚠️ Suhu Tinggi!",
body: `Device ${deviceId}: ${newTemp}°C (threshold: ${threshold}°C)`
},
topic: "iot-alerts"
};
await admin.messaging().send(payload);
console.log(`Alert created for ${deviceId}: ${newTemp}°C`);
}
});
// Scheduled: Cleanup telemetry data lebih dari 30 hari
exports.cleanupTelemetry = functions.pubsub
.schedule("every 24 hours")
.onRun(async (context) => {
const db = admin.database();
const devices = await db.ref("/devices").once("value");
const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);
devices.forEach((device) => {
const deviceId = device.key();
const telemetry = device.child("telemetry");
telemetry.forEach((entry) => {
const timestamp = parseInt(entry.key) * 1000;
if (timestamp < thirtyDaysAgo) {
db.ref(`/devices/${deviceId}/telemetry/${entry.key}`).remove();
}
});
});
});
// HTTP: API endpoint untuk external integration
exports.getDeviceStatus = functions.https.onRequest(async (req, res) => {
const deviceId = req.query.device;
const snapshot = await admin.database()
.ref(`/devices/${deviceId}/latest`).once("value");
res.json(snapshot.val());
});
8. Web Dashboard dengan Firebase
Membuat web dashboard real-time dengan Firebase sangat mudah menggunakan Firebase Web SDK. Data sensor akan update otomatis tanpa perlu refresh halaman.
<!-- Web Dashboard sederhana -->
<div id="dashboard">
<div class="sensor-card">
<h3>🌡️ Temperature</h3>
<span id="temp-value">--</span>°C
</div>
<div class="sensor-card">
<h3>💧 Humidity</h3>
<span id="humidity-value">--</span>%
</div>
<div class="status-bar">
Status: <span id="connection-status">🔴</span>
Last update: <span id="last-update">--</span>
</div>
</div>
<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-app.js";
import { getDatabase, ref, onValue } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-database.js";
const app = initializeApp({ databaseURL: "https://your-project.firebaseio.com" });
const db = getDatabase(app);
// Real-time listener
onValue(ref(db, 'devices/sensor-01/latest'), (snapshot) => {
const data = snapshot.val();
document.getElementById('temp-value').textContent = data.temp.toFixed(1);
document.getElementById('humidity-value').textContent = data.humidity.toFixed(0);
document.getElementById('last-update').textContent = new Date(data.timestamp * 1000).toLocaleString();
});
// Connection status
onValue(ref(db, '.info/connected'), (snap) => {
document.getElementById('connection-status').textContent = snap.val() ? '🟢 Online' : '🔴 Offline';
});
</script>
9. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Firebase RTDB untuk IoT: