Dashboard & Visualisasi

Dashboard Monitoring Real-time: Node-RED + Grafana + MQTT

TOKEN

Bangun sistem monitoring IoT real-time dari nol β€” dari MQTT broker hingga dashboard Grafana yang interaktif, lengkap dengan alerting otomatis

1. Mengapa Dashboard Monitoring?

Di era IoT, ribuan data dihasilkan setiap detik dari sensor suhu, kelembaban, tekanan, arus listrik, dan banyak lagi. Tanpa visualisasi yang tepat, data mentah ini hanyalah angka-angka yang sulit dipahami. Dashboard monitoring real-time mengubah data mentah menjadi informasi visual yang bisa langsung ditindaklanjuti.

Bayangkan sebuah gudang penyimpanan farmasi yang membutuhkan pemantauan suhu 24/7. Jika suhu melewati batas aman, obat-obatan bisa rusak dan menimbulkan kerugian ratusan juta rupiah. Dengan dashboard monitoring real-time, petugas bisa langsung melihat perubahan suhu dari layar mana pun dan menerima notifikasi otomatis saat terjadi anomali.

Diagram: Alur Data Monitoring IoT
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Sensor   │───▢│  Gateway  │───▢│  Server   │───▢│   Dashboard   β”‚
β”‚  (Edge)   β”‚    β”‚  (MQTT)   β”‚    β”‚  (InfluxDBβ”‚    β”‚   (Grafana)   β”‚
β”‚           β”‚    β”‚           β”‚    β”‚   +NR)    β”‚    β”‚               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                          β”‚
                                          β–Ό
                                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                   β”‚   Alert      β”‚
                                   β”‚ (Telegram /  β”‚
                                   β”‚  Email)      β”‚
                                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  1. Sensor mengumpulkan data (suhu, kelembaban, dll.)
  2. Gateway mengirim data via MQTT
  3. Server menyimpan & memproses data
  4. Dashboard menampilkan visualisasi real-time

Manfaat Utama Dashboard Monitoring

Manfaat Penjelasan
Visibilitas Real-timeLihat kondisi sistem kapan saja dari browser mana pun tanpa akses fisik ke perangkat
Detect Anomali DiniPola grafik membantu mengidentifikasi masalah sebelum menjadi kritis
Historical AnalysisAnalisis tren data historis untuk pengambilan keputusan jangka panjang
Alerting OtomatisSistem notifikasi otomatis via Telegram, Email, atau Webhook saat threshold terlewati
SkalabilitasMenambah sensor baru tanpa mengubah arsitektur dashboard
Remote AccessPantau dari mana saja selama ada koneksi internet
πŸ’‘ Mengapa Bukan Spreadsheet?

Google Sheets atau Excel memang bisa menyimpan data, tetapi tidak dirancang untuk pemantauan real-time. Spreadsheet tidak memiliki fitur alerting otomatis, refresh data otomatis, atau kemampuan menampilkan ratusan panel grafik secara bersamaan. Tool dedicated seperti Grafana dirancang khusus untuk use case ini.

2. Arsitektur Sistem

Sistem dashboard monitoring yang kita bangun terdiri dari empat komponen utama yang saling terhubung: MQTT Broker sebagai pusat komunikasi, Node-RED sebagai middleware pemrosesan data, InfluxDB sebagai database time-series, dan Grafana sebagai platform visualisasi.

Diagram: Arsitektur Lengkap Dashboard Monitoring
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       SERVER / RASPBERRY PI                         β”‚
β”‚                                                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                    Mosquitto MQTT Broker                     β”‚   β”‚
β”‚  β”‚                    (Port: 1883 / 8883 TLS)                   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚         β”‚ Subscribe              β”‚ Subscribe                        β”‚
β”‚         β–Ό                       β–Ό                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                           β”‚
β”‚  β”‚  Node-RED    β”‚       β”‚  Grafana     β”‚                           β”‚
β”‚  β”‚  (Port 1880) β”‚       β”‚  (Port 3000) β”‚                           β”‚
β”‚  β”‚              β”‚       β”‚              β”‚                           β”‚
β”‚  β”‚  Flow:       β”‚       β”‚  Datasources:β”‚                           β”‚
β”‚  β”‚  - Parse JSONβ”‚       β”‚  - InfluxDB  β”‚                           β”‚
β”‚  β”‚  - Validasi  β”‚       β”‚  - MQTT      β”‚                           β”‚
β”‚  β”‚  - Simpan DB β”‚       β”‚              β”‚                           β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜                           β”‚
β”‚         β”‚ Write                β”‚ Read                              β”‚
β”‚         β–Ό                      β–Ό                                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                      β”‚
β”‚  β”‚            InfluxDB 2.x                  β”‚                      β”‚
β”‚  β”‚        (Port: 8086)                      β”‚                      β”‚
β”‚  β”‚  Database: iot_sensors                   β”‚                      β”‚
β”‚  β”‚  Retention: 30 hari                      β”‚                      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                      β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β–²                        β–²
         β”‚ MQTT                   β”‚ MQTT
         β”‚ (WiFi)                 β”‚ (WiFi/LAN)
  β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
  β”‚  ESP32 #1   β”‚          β”‚  ESP32 #2   β”‚
  β”‚  Suhu+RH    β”‚          β”‚  Suhu+RH    β”‚
  β”‚  Ruang Serverβ”‚         β”‚  Gudang     β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Peran Setiap Komponen

Komponen Peran Port Default Bahasa
MosquittoMQTT Broker β€” menerima & meneruskan pesan antara publisher dan subscriber1883 (TCP), 8883 (TLS)C
Node-REDMiddleware visual β€” menerima data MQTT, memproses, dan menyimpan ke database1880JavaScript (Node.js)
InfluxDBDatabase time-series β€” menyimpan data sensor dengan timestamp presisi tinggi8086Go
GrafanaPlatform visualisasi β€” menampilkan grafik, gauge, table, dan alert3000Go + JavaScript
ℹ️ Mengapa InfluxDB, bukan MySQL/PostgreSQL?

InfluxDB adalah database yang dioptimalkan untuk data time-series β€” data yang memiliki timestamp. Query seperti "ambil rata-rata suhu selama 1 jam terakhir" jauh lebih cepat di InfluxDB dibanding relational database. Selain itu, fitur retention policy memudahkan otomatisasi penghapusan data lama.

3. Setup MQTT Broker (Mosquitto)

Eclipse Mosquitto adalah broker MQTT open-source yang ringan dan populer. Mosquitto mendukung MQTT 3.1.1 dan 5.0, menjadikannya pilihan standar untuk proyek-proyek IoT. Kita akan menginstalnya di Raspberry Pi atau server Linux.

Instalasi Mosquitto di Ubuntu/Debian

Bash β€” Instalasi
# Update repository
sudo apt update

# Instal Mosquitto broker dan client
sudo apt install -y mosquitto mosquitto-cliences

# Verifikasi versi
mosquitto -v

Konfigurasi Mosquitto

Edit file konfigurasi /etc/mosquitto/mosquitto.conf:

Bash β€” mosquitto.conf
# Konfigurasi Mosquitto Broker
# /etc/mosquitto/mosquitto.conf

# Listener MQTT (tanpa TLS)
listener 1883

# Listener MQTTS (dengan TLS)
listener 8883
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
cafile /etc/mosquitto/certs/ca.crt

# Otentikasi (WAJIB untuk produksi)
allow_anonymous false
password_file /etc/mosquitto/passwd

# Persistence untuk message retain
persistence true
persistence_location /var/lib/mosquitto/

# Interval autosave (detik)
autosave_interval 300

# Logging
log_dest syslog
log_type error
log_type warning
log_type notice
log_type information
connection_messages true
log_timestamp true

Membuat User & Password

Bash β€” Autentikasi
# Buat file password (jika belum ada)
sudo mosquitto_passwd -c /etc/mosquitto/passwd iotuser

# Tambah user tambahan
sudo mosquitto_passwd -b /etc/mosquitto/passwd iotadmin admin123

# Restart Mosquitto
sudo systemctl restart mosquitto

# Cek status
sudo systemctl status mosquitto

Menguji Broker MQTT

Buka dua terminal untuk menguji komunikasi publish/subscribe:

Bash β€” Terminal 1 (Subscriber)
# Subscribe ke topik sensor
mosquitto_sub -h localhost -t "iot/sensor/+" -u iotuser -P iotpass

# Subscribe dengan verbose output
mosquitto_sub -h localhost -t "iot/#" -v -u iotuser -P iotpass
Bash β€” Terminal 2 (Publisher)
# Publish data suhu
mosquitto_pub -h localhost -t "iot/sensor/suhu_ruang1" \
  -m '{"suhu":28.5,"kelembaban":72.0,"ts":1718800000}' \
  -u iotuser -P iotpass
Output Terminal 1 (Subscriber): iot/sensor/suhu_ruang1 {"suhu":28.5,"kelembaban":72.0,"ts":1718800000}
⚠️ Keamanan MQTT

Jangan pernah menjalankan Mosquitto dengan allow_anonymous true di jaringan publik. Selalu gunakan autentikasi password dan pertimbangkan TLS/SSL (port 8883) untuk enkripsi data dalam transit. Untuk produksi, gunakan sertifikat dari CA yang dipercaya.

4. Konfigurasi Node-RED

Node-RED adalah tool pemrograman visual berbasis browser yang dibangun di atas Node.js. Node-RED memungkinkan kita menghubungkan hardware device, API, dan layanan online dengan mudah menggunakan antarmuka drag-and-drop. Dalam arsitektur monitoring, Node-RED berfungsi sebagai middleware yang menerima data MQTT, memprosesnya, dan menyimpannya ke InfluxDB.

Instalasi Node-RED

Bash β€” Instalasi via npm
# Instalasi Node-RED (global)
sudo npm install -g --unsafe-perm node-red

# Install flow untuk InfluxDB
cd ~/.node-red
npm install node-red-contrib-influxdb

# Jalankan Node-RED
node-red

Buka browser dan akses http://<IP_SERVER>:1880. Anda akan melihat antarmuka visual editor Node-RED.

Instalasi Package yang Dibutuhkan

Package Fungsi Install Command
node-red-contrib-influxdbKoneksi ke InfluxDB dari Node-REDnpm i node-red-contrib-influxdb
node-red-dashboardDashboard UI bawaan Node-RED (opsional)npm i node-red-dashboard
node-red-node-emailKirim email notifikasinpm i node-red-node-email

Flow Node-RED: MQTT ke InfluxDB

Berikut adalah flow dasar untuk menerima data dari MQTT dan menyimpannya ke InfluxDB:

Flow: MQTT β†’ Parse β†’ InfluxDB
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  MQTT    │───▢│  JSON    │───▢│  Range   │───▢│  InfluxDBβ”‚
β”‚  In     β”‚    β”‚  Parse   β”‚    β”‚  Check   β”‚    β”‚  Out     β”‚
β”‚          β”‚    β”‚          β”‚    β”‚          β”‚    β”‚          β”‚
β”‚ Topic:   β”‚    β”‚ msg.     β”‚    β”‚ Validate β”‚    β”‚ Bucket:  β”‚
β”‚ iot/sensorβ”‚   β”‚ payload  β”‚    β”‚ data     β”‚    β”‚ iot_data β”‚
β”‚ /+       β”‚    β”‚ β†’ object β”‚    β”‚          β”‚    β”‚          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Konfigurasi Node-RED Flow (JSON)

Copy kode JSON berikut dan import ke Node-RED via menu Import β†’ Clipboard:

JSON β€” Node-RED Flow
[
    {
        "id": "mqtt_in_suhu",
        "type": "mqtt in",
        "name": "MQTT: Sensor Suhu",
        "topic": "iot/sensor/+",
        "qos": "1",
        "datatype": "json",
        "broker": "mqtt_broker_01",
        "wires": [["parse_json"]]
    },
    {
        "id": "parse_json",
        "type": "function",
        "name": "Parse & Validasi Data",
        "func": "var data = msg.payload;\n\n// Validasi field wajib\nif (!data.suhu || !data.kelembaban) {\n    node.warn('Data tidak lengkap: ' + JSON.stringify(data));\n    return null;\n}\n\n// Parse topik untuk device_id\nvar parts = msg.topic.split('/');\nvar deviceId = parts[parts.length - 1];\n\n// Buat payload untuk InfluxDB\nmsg.payload = [\n    {\n        measurement: 'sensor_reading',\n        tags: {\n            device_id: deviceId,\n            location: 'ruang_server'\n        },\n        fields: {\n            suhu: parseFloat(data.suhu),\n            kelembaban: parseFloat(data.kelembaban),\n            wifi_rssi: parseInt(data.wifi_rssi) || 0\n        }\n    }\n];\n\nmsg.topic = '';\nreturn msg;",
        "wires": [["influx_out"]]
    },
    {
        "id": "influx_out",
        "type": "influxdb out",
        "name": "Tulis ke InfluxDB",
        "influxdb": "influxdb_config",
        "precision": "",
        "retentionPolicy": "",
        "database": "",
        "precision": "ms",
        "retentionPolicy": "",
        "wires": []
    },
    {
        "id": "influxdb_config",
        "type": "influxdb",
        "hostname": "127.0.0.1",
        "port": "8086",
        "protocol": "http",
        "dbname": "",
        "name": "InfluxDB Local",
        "usetls": false,
        "tls": "",
        "influxdbVersion": "2.0",
        "url": "http://127.0.0.1:8086",
        "rejectUnauthorized": true
    },
    {
        "id": "mqtt_broker_01",
        "type": "mqtt-broker",
        "name": "Mosquitto Local",
        "broker": "127.0.0.1",
        "port": "1883",
        "clientid": "nodered_client",
        "autoConnect": true,
        "usetls": false,
        "keepalive": "60",
        "cleansession": true,
        "autoUnsubscribe": true,
        "birthTopic": "nodered/status",
        "birthQos": "0",
        "birthPayload": "online",
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "willTopic": "nodered/status",
        "willQos": "0",
        "willPayload": "offline",
        "sessionExpiry": ""
    }
]
πŸ’‘ Testing Node-RED

Untuk menguji flow, kirim data via terminal: mosquitto_pub -h localhost -t "iot/sensor/esp32_01" -m '{"suhu":29.3,"kelembaban":68.5}'. Lihat log Node-RED di debug panel (sisi kanan editor) untuk memverifikasi data sampai dan tersimpan ke InfluxDB.

5. Database InfluxDB (Time-Series Storage)

InfluxDB 2.x adalah database open-source yang dirancang khusus untuk menyimpan data time-series. Setiap data point tersimpan bersama timestamp nanosecond, menjadikannya ideal untuk monitoring IoT yang membutuhkan presisi waktu tinggi.

Instalasi InfluxDB 2.x

Bash β€” Instalasi InfluxDB
# Import GPG key
curl https://repos.influxdata.com/influxdata-archive_compat.key | \
  gpg --dearmor | \
  sudo tee /etc/apt/trusted.gpg.d/influxdata-archive_compat.gpg > /dev/null

# Tambah repository
echo "deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive_compat.gpg] \
  https://repos.influxdata.com/debian stable main" | \
  sudo tee /etc/apt/sources.list.d/influxdata.list

sudo apt update
sudo apt install -y influxdb2

# Jalankan InfluxDB
sudo systemctl enable influxdb
sudo systemctl start influxdb

Setup Awal InfluxDB via CLI

Bash β€” Konfigurasi Awal
# Setup awal InfluxDB
influx setup \
  --username admin \
  --password MySecurePass123! \
  --org iotlab \
  --bucket iot_sensors \
  --retention 720h \
  --force

# Simpan token (ganti dengan token dari setup)
influx auth create \
  --org iotlab \
  --description "Node-RED write access" \
  --write-bucket iot_sensors

Retention Policies

Retention policy menentukan berapa lama data disimpan sebelum otomatis dihapus. Ini penting untuk mengelola ruang disk dan menjaga performa query tetap optimal.

Retention Policy Durasi Use Case
realtime24 jamData untuk dashboard real-time, resolution tinggi
short_term7 hariData harian, analisis mingguan
long_term30 hariData bulanan, laporan periodik
archive365 hariData tahunan, compliance, audit trail
Flux β€” Query InfluxDB
// Query rata-rata suhu 1 jam terakhir
from(bucket: "iot_sensors")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "sensor_reading")
  |> filter(fn: (r) => r._field == "suhu")
  |> aggregateWindow(every: 5m, fn: mean)
  |> yield(name: "avg_suhu")

// Query suhu maksimum hari ini
from(bucket: "iot_sensors")
  |> range(start: -24h)
  |> filter(fn: (r) => r._measurement == "sensor_reading")
  |> filter(fn: (r) => r._field == "suhu")
  |> max()

// Query jumlah data per device
from(bucket: "iot_sensors")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "sensor_reading")
  |> group(columns: ["device_id"])
  |> count()
ℹ️ InfluxDB Cloud vs Self-Hosted

InfluxDB tersedia dalam versi cloud (gratis hingga 300MB/month) dan self-hosted (gratis, unlimited). Untuk proyek belajar, versi self-hosted sangat direkomendasikan karena Anda memiliki kontrol penuh atas data. Untuk produksi skala besar, pertimbangkan InfluxDB Cloud yang dikelola sepenuhnya.

6. Grafana Dashboard

Grafana adalah platform visualisasi data open-source yang mendukung berbagai data source termasuk InfluxDB, PostgreSQL, Prometheus, dan banyak lagi. Grafana memungkinkan Anda membuat dashboard interaktif dengan berbagai jenis panel: grafik garis, gauge, stat, heatmap, dan alert rules.

Instalasi Grafana

Bash β€” Instalasi Grafana OSS
# Tambah repository Grafana
sudo apt-get install -y apt-transport-https software-properties-common
wget -q -O - https://apt.grafana.com/gpg.key | sudo apt-key add -
echo "deb [signed-by=/usr/share/keyrings/grafana.gpg] \
  https://apt.grafana.com stable main" | \
  sudo tee /etc/apt/sources.list.d/grafana.list

sudo apt update
sudo apt install -y grafana

# Jalankan Grafana
sudo systemctl enable grafana-server
sudo systemctl start grafana-server

Akses Grafana di http://<IP_SERVER>:3000. Login default: admin / admin.

Setup Data Source InfluxDB

  1. Buka Grafana β†’ Configuration (βš™οΈ) β†’ Data Sources
  2. Klik "Add data source"
  3. Pilih InfluxDB
  4. Isi konfigurasi berikut:
Field Nilai
Query LanguageFlux
URLhttp://127.0.0.1:8086
Organizationiotlab
Token[token dari InfluxDB setup]
Default Bucketiot_sensors
πŸ’‘ Tips Data Source

Klik tombol "Save & Test" setelah mengisi konfigurasi. Jika muncul hijau "Data source is working", artinya koneksi ke InfluxDB berhasil. Jika merah, periksa token, URL, dan nama bucket.

Jenis Panel Grafana

Panel Type Fungsi Cocok Untuk
Time SeriesGrafik garis dengan sumbu X waktuTren suhu, kelembaban dari waktu ke waktu
GaugeIndikator analog/digitalSuhu saat ini, persentase baterai
StatAngka besar dengan warna dinamisSuhu terkini, jumlah device online
Bar ChartGrafik batangPerbandingan antar device/ruangan
TableTabel dataDaftar semua sensor dan status terkini
HeatmapPeta panasDistribusi suhu di area luas

Query Flux untuk Panel Suhu

Flux β€” Panel Grafana
// Panel: Grafik Suhu Real-time (6 jam terakhir)
from(bucket: "iot_sensors")
  |> range(start: -6h)
  |> filter(fn: (r) => r._measurement == "sensor_reading")
  |> filter(fn: (r) => r._field == "suhu")
  |> aggregateWindow(every: 5m, fn: mean, createEmpty: false)
  |> yield(name: "suhu_trend")

// Panel: Gauge Suhu Terkini
from(bucket: "iot_sensors")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "sensor_reading")
  |> filter(fn: (r) => r._field == "suhu")
  |> last()
  |> yield(name: "suhu_current")

// Panel: Tabel Status Semua Device
from(bucket: "iot_sensors")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "sensor_reading")
  |> last()
  |> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value")
  |> keep(columns: ["device_id", "suhu", "kelembaban", "_time"])

Membuat Alert di Grafana

  1. Buka panel Grafana β†’ Alert tab
  2. Klik "Create alert rule"
  3. Atur kondisi: suhu > 35 selama 5 menit
  4. Atur notification channel: Email atau Telegram
  5. Simpan dan aktifkan alert
Diagram: Alur Alert Grafana
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  InfluxDB  │────▢│  Grafana   │────▢│  Alert     β”‚
  β”‚  Query     β”‚     β”‚  Rule Eval β”‚     β”‚  Notif.    β”‚
  β”‚            β”‚     β”‚            β”‚     β”‚            β”‚
  β”‚ suhu > 35? β”‚     β”‚ Every 1m   β”‚     β”‚ - Email    β”‚
  β”‚            β”‚     β”‚            β”‚     β”‚ - Telegram β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚ - Webhook  β”‚
                                        β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
                                               β”‚
                                               β–Ό
                                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                        β”‚  Telegram  β”‚
                                        β”‚  Bot Msg   β”‚
                                        β”‚ "⚠️ Suhu   β”‚
                                        β”‚  37.2Β°C!"  β”‚
                                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

7. Proyek: Dashboard Suhu & Kelembaban Real-time

Sekarang kita akan menggabungkan seluruh komponen ke dalam satu proyek utuh. Pastikan Mosquitto, Node-RED, InfluxDB, dan Grafana sudah terinstal dan berjalan di server yang sama (atau Raspberry Pi).

Step 1: Kode ESP32 untuk Proyek

ESP32 akan membaca sensor DHT22 dan mengirim data ke MQTT broker setiap 10 detik:

C++ β€” esp32_monitoring.ino
#include "WiFi.h"
#include "PubSubClient.h"
#include "DHT.h"

#define DHT_PIN 4
#define DHT_TYPE DHT22

const char* WIFI_SSID = "NamaWiFi";
const char* WIFI_PASS = "PasswordWiFi";
const char* MQTT_SERVER = "192.168.1.100";
const int   MQTT_PORT = 1883;
const char* MQTT_TOPIC = "iot/sensor/esp32_01";

DHT dht(DHT_PIN, DHT_TYPE);
WiFiClient espClient;
PubSubClient mqtt(espClient);

void setup() {
  Serial.begin(115200);
  dht.begin();
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  mqtt.setServer(MQTT_SERVER, MQTT_PORT);
}

void loop() {
  if (!mqtt.connected()) {
    mqtt.connect("esp32_01", "iotuser", "iotpass");
  }
  mqtt.loop();

  float suhu = dht.readTemperature();
  float rh = dht.readHumidity();
  if (!isnan(suhu) && !isnan(rh)) {
    char payload[128];
    snprintf(payload, sizeof(payload),
      "{\"suhu\":%.1f,\"kelembaban\":%.1f,\"rssi\":%d}",
      suhu, rh, WiFi.RSSI());
    mqtt.publish(MQTT_TOPIC, payload);
    Serial.println(payload);
  }
  delay(10000);
}

Step 2: Import Flow Node-RED

Buka Node-RED di http://<IP>:1880, lalu import flow lengkap berikut:

JSON β€” Node-RED Full Flow
[
    {
        "id": "dashboard_flow",
        "type": "tab",
        "label": "IoT Dashboard Flow",
        "disabled": false,
        "info": "Flow lengkap untuk dashboard monitoring IoT"
    },
    {
        "id": "mqtt_in_all",
        "type": "mqtt in",
        "z": "dashboard_flow",
        "name": "All Sensor Data",
        "topic": "iot/sensor/+",
        "qos": "1",
        "datatype": "auto",
        "broker": "mosquitto_local",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "wires": [["func_validate", "debug_raw"]]
    },
    {
        "id": "func_validate",
        "type": "function",
        "z": "dashboard_flow",
        "name": "Validate & Transform",
        "func": "// Extract device ID dari topik\nvar deviceId = msg.topic.split('/').pop();\nvar data = msg.payload;\n\n// Validasi data\nif (!data.suhu || !data.kelembaban) {\n    node.warn('Invalid data dari ' + deviceId);\n    return null;\n}\n\n// Siapkan untuk InfluxDB\nmsg.payload = [{\n    measurement: 'sensor_reading',\n    tags: { device_id: deviceId },\n    fields: {\n        suhu: parseFloat(data.suhu),\n        kelembaban: parseFloat(data.kelembaban)\n    }\n}];\nmsg.topic = '';\n\n// Duplikat untuk threshold check\nvar msg2 = {\n    payload: data,\n    device_id: deviceId\n};\n\nreturn [msg, msg2];",
        "outputs": 2,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "wires": [["influx_write", "func_threshold"]]
    },
    {
        "id": "influx_write",
        "type": "influxdb out",
        "z": "dashboard_flow",
        "influxdb": "influxdb_01",
        "name": "Write InfluxDB",
        "precision": "ms",
        "retentionPolicy": "",
        "database": "",
        "precision": "ms",
        "retentionPolicy": "",
        "wires": []
    },
    {
        "id": "func_threshold",
        "type": "function",
        "z": "dashboard_flow",
        "name": "Threshold Check",
        "func": "var data = msg.payload;\nif (data.suhu > 35) {\n    node.warn('ALERT: Suhu ' + data.suhu + 'Β°C dari ' + msg.device_id);\n    msg.payload = {\n        alert: 'HIGH_TEMPERATURE',\n        suhu: data.suhu,\n        device: msg.device_id,\n        timestamp: new Date().toISOString()\n    };\n    return msg;\n}\nreturn null;",
        "outputs": 1,
        "wires": [["mqtt_alert_out"]]
    },
    {
        "id": "mqtt_alert_out",
        "type": "mqtt out",
        "z": "dashboard_flow",
        "name": "Publish Alert",
        "topic": "iot/alert",
        "qos": "0",
        "retain": "false",
        "broker": "mosquitto_local",
        "wires": []
    },
    {
        "id": "mosquitto_local",
        "type": "mqtt-broker",
        "name": "Mosquitto",
        "broker": "127.0.0.1",
        "port": "1883",
        "clientid": "nodered",
        "autoConnect": true,
        "usetls": false,
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "nodered/status",
        "birthQos": "0",
        "birthPayload": "online",
        "willTopic": "nodered/status",
        "willQos": "0",
        "willPayload": "offline"
    },
    {
        "id": "influxdb_01",
        "type": "influxdb",
        "hostname": "127.0.0.1",
        "port": "8086",
        "protocol": "http",
        "dbname": "",
        "name": "InfluxDB IoT",
        "influxdbVersion": "2.0",
        "url": "http://127.0.0.1:8086",
        "rejectUnauthorized": true
    }
]

Step 3: Import Dashboard Grafana

Buka Grafana β†’ βž• β†’ Import Dashboard β†’ paste JSON berikut:

JSON β€” Grafana Dashboard
{
  "title": "IoT Monitoring Dashboard",
  "tags": ["iot", "sensor", "suhu"],
  "timezone": "Asia/Jakarta",
  "panels": [
    {
      "title": "Suhu Saat Ini",
      "type": "gauge",
      "fieldConfig": {
        "defaults": {
          "thresholds": {
            "steps": [
              {"color": "green", "value": null},
              {"color": "yellow", "value": 30},
              {"color": "red", "value": 35}
            ]
          },
          "unit": "celsius",
          "min": 15,
          "max": 50
        }
      },
      "targets": [{
        "query": "from(bucket:\"iot_sensors\") |> range(start:-1h) |> filter(fn:(r) => r._measurement==\"sensor_reading\") |> filter(fn:(r) => r._field==\"suhu\") |> last()"
      }]
    },
    {
      "title": "Grafik Suhu 24 Jam",
      "type": "timeseries",
      "fieldConfig": {
        "defaults": {
          "unit": "celsius",
          "custom": {"drawStyle": "line", "fillOpacity": 10}
        }
      },
      "targets": [{
        "query": "from(bucket:\"iot_sensors\") |> range(start:-24h) |> filter(fn:(r) => r._measurement==\"sensor_reading\") |> filter(fn:(r) => r._field==\"suhu\") |> aggregateWindow(every:5m, fn:mean)"
      }]
    },
    {
      "title": "Kelembaban Saat Ini",
      "type": "stat",
      "fieldConfig": {
        "defaults": {
          "unit": "percent",
          "thresholds": {
            "steps": [
              {"color": "yellow", "value": null},
              {"color": "green", "value": 40},
              {"color": "red", "value": 80}
            ]
          }
        }
      },
      "targets": [{
        "query": "from(bucket:\"iot_sensors\") |> range(start:-1h) |> filter(fn:(r) => r._measurement==\"sensor_reading\") |> filter(fn:(r) => r._field==\"kelembaban\") |> last()"
      }]
    },
    {
      "title": "Status Device",
      "type": "table",
      "targets": [{
        "query": "from(bucket:\"iot_sensors\") |> range(start:-1h) |> filter(fn:(r) => r._measurement==\"sensor_reading\") |> last() |> pivot(rowKey:[\"_time\"], columnKey:[\"_field\"], valueColumn:\"_value\")"
      }]
    }
  ],
  "time": {"from": "now-24h", "to": "now"},
  "refresh": "30s"
}

Step 4: Verifikasi Seluruh Sistem

ℹ️ Checklist Verifikasi
  1. βœ… Mosquitto berjalan: sudo systemctl status mosquitto
  2. βœ… InfluxDB berjalan: curl http://localhost:8086/health
  3. βœ… Node-RED berjalan: akses http://<IP>:1880
  4. βœ… Grafana berjalan: akses http://<IP>:3000
  5. βœ… Data MQTT mengalir: cek debug panel Node-RED
  6. βœ… Data terimpan di InfluxDB: cek via InfluxDB UI atau CLI
  7. βœ… Dashboard Grafana menampilkan data real-time
  8. βœ… Alert berfungsi: simulasikan suhu tinggi

8. Optimasi & Maintenance

Sistem monitoring yang berjalan 24/7 membutuhkan perhatian khusus dari sisi performa dan maintenance. Berikut adalah tips optimasi untuk menjaga sistem tetap stabil dan efisien.

Optimasi Performa

Area Optimasi Dampak
InfluxDBGunakan retention policy < 30 hari untuk data high-frequencyHemat disk 70-80%
InfluxDBAktifkan compression (TSM engine default)Ukuran data turun 5-10x
GrafanaGunakan aggregateWindow() untuk range > 1 jamQuery 10x lebih cepat
Node-REDGunakan batch write ke InfluxDB alih-alih per-pesanMengurangi I/O 50%
MQTTAtur QoS = 0 untuk data non-kritisMengurangi overhead jaringan
ServerPisahkan InfluxDB ke volume SSD terpisahWrite latency turun 3x

Cron Job Maintenance

Bash β€” Maintenance Scripts
# Backup InfluxDB (via cron daily)
influx backup /backups/influxdb_$(date +%Y%m%d) --org iotlab

# Cleanup backup lama (hapus backup > 7 hari)
find /backups -name "influxdb_*" -mtime +7 -exec rm -rf {} \;

# Monitor disk usage
df -h /var/lib/influxdb

# Cek log errors
sudo journalctl -u mosquitto --since "1 hour ago" --priority=3
sudo journalctl -u influxdb --since "1 hour ago" --priority=3
sudo journalctl -u grafana-server --since "1 hour ago" --priority=3

Monitoring Layanan (Systemd)

Gunakan systemd untuk memastikan semua service otomatis restart jika crash:

Bash β€” Service Status & Auto-restart
# Cek status semua service
echo "=== Mosquitto ===" && sudo systemctl is-active mosquitto
echo "=== InfluxDB ===" && sudo systemctl is-active influxdb
echo "=== Grafana  ===" && sudo systemctl is-active grafana-server
echo "=== Node-RED ===" && systemctl --user is-active nodered

# Restart semua service
sudo systemctl restart mosquitto influxdb grafana-server
systemctl --user restart nodered

# Auto-restart (sudah default di systemd, tapi pastikan):
# Edit /lib/systemd/system/mosquitto.service
# Tambahkan: Restart=always, RestartSec=10
⚠️ Tips Penting

Selalu backup InfluxDB secara rutin. Database time-series bisa tumbuh sangat cepat jika volume data tinggi. Pastikan disk space minimal 20% kosong. Gunakan logrotate untuk rotasi log file Mosquitto dan Grafana agar tidak memenuhi disk.

9. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang dashboard monitoring IoT:

Pertanyaan 1: Komponen apa yang berfungsi sebagai middleware visual untuk menghubungkan MQTT ke InfluxDB dalam arsitektur dashboard monitoring?

a) Grafana
b) Node-RED
c) Mosquitto
d) Prometheus

Pertanyaan 2: Port default apa yang digunakan oleh Mosquitto MQTT Broker untuk koneksi TCP tanpa TLS?

a) 1883
b) 8883
c) 3000
d) 1880

Pertanyaan 3: InfluxDB adalah database yang dioptimalkan khusus untuk tipe data apa?

a) Document store (JSON)
b) Key-value pairs
c) Relational (SQL)
d) Time-series

Pertanyaan 4: Untuk mengimpor flow dari JSON ke Node-RED, menu apa yang harus digunakan?

a) Deploy β†’ Import
b) Edit β†’ Paste
c) Import β†’ Clipboard
d) File β†’ Import

Pertanyaan 5: Apa fungsi retention policy di InfluxDB?

a) Menentukan jumlah maksimum kolom per tabel
b) Menentukan berapa lama data disimpan sebelum otomatis dihapus
c) Mengatur kecepatan write data ke disk
d) Membatasi jumlah query per jam
← Sebelumnya Otomasi IoT dengan Python: MQTT, GPIO & Scheduling Selanjutnya β†’ Panduan Lengkap ESP32: Dari Setup Hingga Proyek IoT Pertama