1. Pengenalan MQTT
MQTT (Message Queuing Telemetry Transport) adalah protokol komunikasi ringan yang dirancang khusus untuk perangkat IoT dan jaringan dengan bandwidth terbatas. Protokol ini pertama kali dikembangkan oleh Andy Stanford-Clark (IBM) dan Arlen Nipper pada tahun 1999 untuk memantau jalur pipa minyak melalui jaringan satelit.
MQTT menggunakan model publish/subscribe (pub/sub) di mana pengirim pesan (publisher) dan penerima pesan (subscriber) tidak perlu saling mengenal secara langsung. Komunikasi dimediasi oleh sebuah broker yang bertugas meneruskan pesan dari publisher ke subscriber yang relevan.
Mengapa MQTT Penting untuk IoT?
| Keunggulan | Penjelasan |
|---|---|
| Ringan | Header hanya 2 byte, cocok untuk perangkat dengan resource terbatas |
| Low Bandwidth | Sangat efisien di jaringan dengan bandwidth rendah seperti LoRa, NB-IoT |
| Bi-directional | Mendukung komunikasi dua arah antara device dan server |
| Scalable | Bisa menangani jutaan koneksi perangkat secara simultan |
| Reliable | Memiliki 3 level QoS untuk menjamin pengiriman pesan |
| Decoupled | Publisher dan subscriber tidak perlu online bersamaan |
| Standar Terbuka | Diatur oleh OASIS dan didukung luas di industri IoT |
MQTT vs Protokol Lain
| Aspek | MQTT | HTTP | WebSocket | CoAP |
|---|---|---|---|---|
| Model | Pub/Sub | Request/Response | Full Duplex | Request/Response |
| Header Size | π’ 2 byte | π΄ Besar | π‘ Sedang | π’ 4 byte |
| Persistent Connection | β Ya | β Tidak | β Ya | β Opsional |
| QoS | β 3 Level | β Tidak ada | β Tidak ada | β Konfirmasi |
| Bidirectional | β Ya | β Satu arah | β Ya | β Satu arah |
| Cocok untuk | IoT, Messaging | Web API | Real-time Web | Constrained Devices |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β MODEL PUBLISH/SUBSCRIBE MQTT β β β β ββββββββββββ ββββββββββββββββ β β β Sensor β publish β β β β β Suhu β ββββββββββββββββΊ β β β β ββββββββββββ "ruang/suhu" β β β β β MQTT β β β ββββββββββββ β BROKER β β β β Sensor β publish β β β β β Kelembabanβ βββββββββββββββΊ β β β β ββββββββββββ "ruang/lembab" β β β β ββββββββ¬βββββββ β β subscribeβ β β ββββββββββββ ββββββββββββ β β β β Mobile βββββββββββ Dashboardββββββββββ β β β App β β Web β β β ββββββββββββ ββββββββββββ β β β β Publisher dan Subscriber TERPISAH oleh Broker β β Komunikasi ASYNCHRON β tidak perlu online bersamaan β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2. Arsitektur dan Komponen MQTT
Sistem MQTT terdiri dari tiga komponen utama yang saling berinteraksi. Memahami arsitektur ini sangat penting sebelum mulai mengimplementasikan MQTT di proyek IoT Anda.
Tiga Komponen Utama
| Komponen | Fungsi | Contoh |
|---|---|---|
| Publisher | Mengirim pesan ke broker pada topik tertentu | ESP32, sensor, Raspberry Pi |
| Broker | Menerima pesan dan mendistribusikannya ke subscriber | Mosquitto, HiveMQ, EMQX |
| Subscriber | Menerima pesan dari broker berdasarkan topik yang di-subscribe | Mobile app, dashboard, server |
Packet Structure MQTT
Setiap pesan MQTT terdiri dari fixed header (minimal 2 byte), variable header (tergantung tipe pesan), dan payload (data aktual).
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β MQTT PACKET STRUCTURE β β β β βββββββββββββββββββββββββββββββββββββββββββββββ β β β FIXED HEADER (2+ bytes) β β β β βββββββββββββββ¬βββββββββββββββββββββββ β β β β β Byte 1 β Byte 2-5 β β β β β β Packet Type β Remaining Length β β β β β β (4 bits) β (1-4 bytes) β β β β β β + Flags β Variable-length β β β β β βββββββββββββββ΄βββββββββββββββββββββββ β β β βββββββββββββββββββββββββββββββββββββββββββββββ β β β β βββββββββββββββββββββββββββββββββββββββββββββββ β β β VARIABLE HEADER (0+ bytes) β β β β Tergantung tipe packet: β β β β - CONNECT: Protocol name + level + flags β β β β - PUBLISH: Topic name + Packet ID β β β β - SUBSCRIBE: Packet ID β β β βββββββββββββββββββββββββββββββββββββββββββββββ β β β β βββββββββββββββββββββββββββββββββββββββββββββββ β β β PAYLOAD (0+ bytes) β β β β Data aktual: sensor reading, command, dll β β β β Maksimal 256 MB (praktis biasanya < 1 KB) β β β βββββββββββββββββββββββββββββββββββββββββββββββ β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
MQTT Packet Types
| Tipe | Direction | Fungsi |
|---|---|---|
| CONNECT | Client β Broker | Permintaan koneksi baru |
| CONNACK | Broker β Client | Konfirmasi koneksi |
| PUBLISH | Dua arah | Mengirim pesan |
| PUBACK | Dua arah | Konfirmasi QoS 1 |
| PUBREC/PUBREL/PUBCOMP | Dua arah | Handshake QoS 2 |
| SUBSCRIBE | Client β Broker | Langganan topik |
| SUBACK | Broker β Client | Konfirmasi subscribe |
| UNSUBSCRIBE | Client β Broker | Berhenti langganan |
| PINGREQ/PINGRESP | Dua arah | Heartbeat / keep-alive |
| DISCONNECT | Client β Broker | Putus koneksi secara graceful |
3. MQTT Broker
Broker adalah jantung dari sistem MQTT. Broker bertanggung jawab menerima semua pesan dari publisher, memfilter pesan berdasarkan topik, dan mendistribusikannya ke subscriber yang sesuai. Pemilihan broker yang tepat sangat mempengaruhi performa sistem IoT Anda.
Perbandingan MQTT Broker Populer
| Broker | Tipe | Gratis? | Fitur Utama | Cocok Untuk |
|---|---|---|---|---|
| Mosquitto | Open Source | β | Ringan, mudah setup, populer | Prototyping, home IoT |
| EMQX | Open Source + Cloud | β (Community) | Skalabilitas tinggi, clustering | Enterprise, industri |
| HiveMQ | Commercial | β (CE) | Enterprise grade, MQTT 5.0 | Enterprise |
| VerneMQ | Open Source | β | Distributed, Erlang-based | High availability |
| AWS IoT Core | Cloud Managed | π³ Pay-as-you-go | Fully managed, integrasi AWS | Cloud-native IoT |
| HiveMQ Cloud | Cloud Managed | β (Free tier) | Serverless, MQTT 5.0 | Quick start |
Instalasi Mosquitto Broker
Mosquitto adalah broker MQTT open source yang paling populer dan cocok untuk memulai belajar.
# Instalasi di Ubuntu/Debian sudo apt update sudo apt install mosquitto mosquitto-clients -y # Start dan enable service sudo systemctl start mosquitto sudo systemctl enable mosquitto # Cek status sudo systemctl status mosquitto # Output: Active: active (running) # Instalasi di Windows # Download dari https://mosquitto.org/download/ # Jalankan installer, ikuti wizard # Instalasi di macOS dengan Homebrew brew install mosquitto brew services start mosquitto # Verifikasi dengan test subscriber (terminal 1) mosquitto_sub -h localhost -t "test/hello" # Publish pesan (terminal 2) mosquitto_pub -h localhost -t "test/hello" -m "Hello MQTT!" # Terminal 1 akan menerima: Hello MQTT!
Konfigurasi Dasar Mosquitto
# /etc/mosquitto/mosquitto.conf # Listener port (default 1883) listener 1883 # Izinkan koneksi tanpa autentikasi (untuk testing saja!) allow_anonymous true # Untuk produksi, gunakan autentikasi: # allow_anonymous false # password_file /etc/mosquitto/passwd # Logging log_dest file /var/log/mosquitto/mosquitto.log log_type all # Persistence persistence true persistence_location /var/lib/mosquitto/ # Maximum connections max_connections -1 # unlimited # Message size limit message_size_limit 1048576 # 1 MB # TLS/SSL (produksi) # listener 8883 # certfile /etc/mosquitto/certs/server.crt # cafile /etc/mosquitto/certs/ca.crt # keyfile /etc/mosquitto/certs/server.key
Membuat Password File
# Buat password file baru sudo mosquitto_passwd -c /etc/mosquitto/passwd admin # Masukkan password saat diminta # Tambah user baru sudo mosquitto_passwd -b /etc/mosquitto/passwd sensor1 password123 # Update password user yang sudah ada sudo mosquitto_passwd -b /etc/mosquitto/passwd admin newpassword456 # Hapus user sudo mosquitto_passwd -D /etc/mosquitto/passwd sensor1 # Restart mosquitto setelah mengubah konfigurasi sudo systemctl restart mosquitto # Test dengan autentikasi mosquitto_sub -h localhost -t "sensor/suhu" -u admin -P newpassword456 mosquitto_pub -h localhost -t "sensor/suhu" -m "25.5" -u sensor1 -P password123
Untuk development, Anda bisa menggunakan broker publik gratis seperti broker.hivemq.com:1883 atau test.mosquitto.org:1883. Namun, jangan pernah menggunakannya untuk data produksi karena tidak ada privasi dan keamanan yang terjamin.
4. Topic dan Hierarki Topik
Topic adalah string UTF-8 yang digunakan broker untuk memfilter dan mendistribusikan pesan. Topic berfungsi sebagai "alamat" yang menentukan ke mana pesan harus dikirim. Desain topic yang baik sangat penting untuk skalabilitas sistem IoT.
Struktur Topic MQTT
Topic menggunakan forward slash (/) sebagai pembatas hierarki, mirip dengan path di file system.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β HIERARKI TOPIC MQTT β β β β root β β βββ gedung1/ β β β βββ lantai1/ β β β β βββ ruang1/suhu β 25.5Β°C β β β β βββ ruang1/lembab β 65% β β β β βββ ruang1/lampu β ON β β β β βββ ruang1/ac β 23Β°C β β β βββ lantai2/ β β β βββ ruang1/suhu β 24.8Β°C β β β βββ ruang1/lembab β 60% β β βββ gedung2/ β β βββ lantai1/ β β βββ ruang1/suhu β 26.1Β°C β β β β Topic: "gedung1/lantai1/ruang1/suhu" β β Level: 4 level hierarki β β β β β JANGAN gunakan: β β - Topic dimulai dengan "/" (empty root) β β - Spasi dalam topic β β - Karakter null (0x00) β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Wildcards (Wildcard Characters)
MQTT mendukung dua jenis wildcard untuk subscribe ke beberapa topik sekaligus:
| Wildcard | Nama | Fungsi | Contoh |
|---|---|---|---|
+ | Single Level | Menangkap satu level saja | gedung1/+/ruang1/suhu cocok dengan semua lantai di gedung1 |
# | Multi Level | Menangkap semua level di bawahnya | gedung1/# cocok dengan semua topic di gedung1 |
# Single Level Wildcard (+) # Subscribe ke suhu semua lantai gedung1, ruang1 mosquitto_sub -t "gedung1/+/ruang1/suhu" # Ini akan menerima pesan dari: # gedung1/lantai1/ruang1/suhu β # gedung1/lantai2/ruang1/suhu β # gedung1/lantai3/ruang1/suhu β # gedung2/lantai1/ruang1/suhu β (gedung berbeda) # Multi Level Wildcard (#) # Subscribe ke SEMUA topic di bawah gedung1 mosquitto_sub -t "gedung1/#" # Ini akan menerima: # gedung1/lantai1/ruang1/suhu β # gedung1/lantai1/ruang1/lampu β # gedung1/lantai2/ruang1/lembab β # Semua topic di bawah gedung1 β # Kombinasi wildcard mosquitto_sub -t "+/lantai1/#" # Cocok dengan: gedung1/lantai1/ruang1/suhu # Cocok dengan: gedung2/lantai1/any/topic/here # β οΈ HANYA bisa digunakan di SUBSCRIBE, tidak di PUBLISH! # mosquitto_pub -t "gedung1/#" -m "test" β ERROR!
$SYS Topics (System Topics)
Broker MQTT menyediakan topic khusus yang dimulai dengan $SYS/ untuk informasi internal broker:
# Monitor broker statistics mosquitto_sub -t '$SYS/#' -v # Output contoh: # $SYS/broker/version mosquitto version 2.0.18 # $SYS/broker/uptime 86400 seconds # $SYS/broker/clients/connected 42 # $SYS/broker/clients/total 150 # $SYS/broker/messages/sent 12345 # $SYS/broker/messages/received 9876 # $SYS/broker/load/messages/received/1min 15.23 # $SYS/broker/load/messages/sent/1min 22.45 # Topic $SYS tidak bisa di-publish secara manual # dan tidak termasuk dalam wildcard "#" biasa
Wildcard # di akhir topic bisa menyebabkan broker mengirim ribuan pesan sekaligus jika ada banyak data aktif. Gunakan wildcard dengan bijak dan hindari subscribe ke # tanpa filter yang spesifik pada sistem produksi.
5. Quality of Service (QoS)
Salah satu fitur terpenting MQTT adalah Quality of Service (QoS) yang menentukan tingkat jaminan pengiriman pesan. MQTT menyediakan 3 level QoS yang bisa disesuaikan dengan kebutuhan aplikasi Anda.
Tiga Level QoS
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β QoS LEVELS β β β β QoS 0: At most once (Fire and Forget) β β ββββββββββ ββββββββββ β β βPublisherβ βββββββββΊβ Broker β Pesan dikirim sekali β β ββββββββββ ββββββββββ tanpa konfirmasi β β β Mungkin hilang jika gagal β β β β QoS 1: At least once (Acknowledged) β β ββββββββββ ββββββββββ β β βPublisherβ βββββββββΊβ Broker β β β β β βββββββββ β β PUBACK β β ββββββββββ ββββββββββ Pasti sampai β β β οΈ Mungkin duplikat β β β β QoS 2: Exactly once (Assured) β β ββββββββββ ββββββββββ β β βPublisherβ βββββββββΊβ Broker β PUBLISH β β β β βββββββββ β β PUBREC β β β β βββββββββΊ β β PUBREL β β β β βββββββββ β β PUBCOMP β β ββββββββββ ββββββββββ Pasti tepat sekali β β β Tidak hilang, tidak duplikat β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Perbandingan Detail QoS
| Aspek | QoS 0 | QoS 1 | QoS 2 |
|---|---|---|---|
| Delivery | At most once | At least once | Exactly once |
| Pesan Hilang? | β οΈ Mungkin | β Tidak | β Tidak |
| Pesan Duplikat? | β Tidak | β οΈ Mungkin | β Tidak |
| Round Trip | 1 | 2 | 4 |
| Bandwidth | π’ Paling hemat | π‘ Sedang | π΄ Paling boros |
| Latency | π’ Terendah | π‘ Sedang | π΄ Tertinggi |
| Cocok untuk | Sensor periodik | Notifikasi, alarm | Transaksi keuangan |
Pemilihan QoS yang Tepat
# QoS 0 β Data sensor periodik (hilang sesekali tidak masalah)
# Contoh: pembacaan suhu setiap 5 detik
mosquitto_pub -t "sensor/suhu" -m "25.5" -q 0
# QoS 1 β Notifikasi alarm (harus sampai, duplikat tidak masalah)
# Contoh: notifikasi kebakaran
mosquitto_pub -t "alarm/kebakaran" -m "LANTAI3_API" -q 1
# QoS 2 β Data kritis (harus tepat sekali)
# Contoh: pembayaran atau perintah aktuator kritis
mosquitto_pub -t "cmd/pembayaran" -m '{"amount":100000}' -q 2
# Penting: QoS di sisi publisher dan subscriber BISA BERBEDA
# Broker mengirim dengan QoS MINIMUM dari keduanya
#
# Publisher QoS 2 + Subscriber QoS 1 β Broker mengirim QoS 1
# Publisher QoS 1 + Subscriber QoS 2 β Broker mengirim QoS 1
# Publisher QoS 1 + Subscriber QoS 1 β Broker mengirim QoS 1
QoS di Python dengan paho-mqtt
import paho.mqtt.client as mqtt
import json
import time
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Terhubung ke broker MQTT")
# Subscribe dengan QoS berbeda
client.subscribe("sensor/suhu", qos=0) # QoS 0
client.subscribe("alarm/#", qos=1) # QoS 1
client.subscribe("cmd/kritis", qos=2) # QoS 2
else:
print(f"Gagal koneksi, kode: {rc}")
def on_message(client, userdata, msg):
print(f"[QoS {msg.qos}] {msg.topic}: {msg.payload.decode()}")
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.hivemq.com", 1883, 60)
# Publish dengan QoS yang sesuai
client.publish("sensor/suhu", "25.5", qos=0) # Data sensor
client.publish("alarm/kebakaran", "API!", qos=1) # Alarm
client.publish("cmd/kritis", json.dumps({
"action": "emergency_stop",
"device": "conveyor_01"
}), qos=2) # Perintah kritis
client.loop_forever()
6. Retain Message dan Last Will
Dua fitur penting MQTT yang sering dilupakan pemula adalah Retain Message dan Last Will and Testament (LWT). Keduanya sangat berguna untuk membangun sistem IoT yang robust.
Retain Message
Retain message adalah pesan yang disimpan oleh broker dan dikirimkan ke subscriber baru yang pertama kali subscribe ke topik tersebut. Tanpa retain, subscriber baru harus menunggu publish berikutnya untuk mendapatkan data.
# Publish dengan retain flag (-r) mosquitto_pub -t "sensor/suhu" -m "25.5" -r mosquitto_pub -t "sensor/lembab" -m "65" -r mosquitto_pub -t "device/status" -m "online" -r # Subscriber yang baru bergabung langsung menerima data terakhir mosquitto_sub -t "sensor/#" -v # Output: # sensor/suhu 25.5 β diterima langsung (retain) # sensor/lembab 65 β diterima langsung (retain) # device/status online β diterima langsung (retain) # Hapus retained message dengan payload kosong mosquitto_pub -t "sensor/suhu" -m "" -r # Topik "sensor/suhu" sekarang tidak punya retained message # β οΈ Setiap topik hanya punya SATU retained message # Publish baru dengan retain akan MENGGANTIKAN retained sebelumnya
Cara Kerja Retain Message
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β RETAIN MESSAGE FLOW β β β β Step 1: Sensor publish dengan retain β β ββββββββββ ββββββββββ β β β Sensor β β(r)ββββΊβ Broker β Simpan retained msg β β ββββββββββ ββββββββββ β β β β Step 2: App subscribe (beberapa jam kemudian) β β ββββββββββ β β ββββββββββ β Broker β Kirim retained msg β β β App β βββββββ β β langsung ke subscriber β β ββββββββββ ββββββββββ baru β β β β Tanpa retain: App harus menunggu sensor publish lagi β β Dengan retain: App langsung punya data terakhir β β β β β οΈ Hanya SATU retained per topic β β β οΈ Payload kosong menghapus retained β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Last Will and Testament (LWT)
LWT adalah pesan "wasiat" yang dikirim broker secara otomatis ketika client terputus secara tidak terduga (abnormal disconnect). Ini sangat berguna untuk memantau status perangkat IoT.
import paho.mqtt.client as mqtt
client = mqtt.Client(client_id="sensor_gedung1_lantai1")
# Set Last Will sebelum connect
client.will_set(
topic="device/sensor_gedung1_lantai1/status",
payload="offline",
qos=1,
retain=True # Simpan sebagai retained message
)
def on_connect(client, userdata, flags, rc):
print("Terhubung!")
# Publish status online setelah connect
client.publish(
"device/sensor_gedung1_lantai1/status",
"online",
qos=1,
retain=True
)
def on_disconnect(client, userdata, rc):
if rc != 0:
print("Koneksi terputus secara tidak terduga!")
# Broker akan otomatis publish LWT "offline"
client.on_connect = on_connect
client.on_disconnect = on_disconnect
# Last Will + Retain = Sistem monitoring yang robust!
# Ketika device mati:
# 1. Broker mendeteksi koneksi terputus
# 2. Broker publish LWT "offline" ke topic status
# 3. Semua subscriber langsung tahu device offline
# 4. Subscriber baru yang subscribe juga langsung tahu
client.connect("broker.hivemq.com", 1883, keepalive=60)
client.loop_forever()
Skema LWT + Retain yang Ideal
| Kondisi | Aksi | Pesan |
|---|---|---|
| Device connect | Publish manual | "online" dengan retain |
| Device heartbeat | Publish periodik | "alive" setiap 30 detik |
| Device disconnect (graceful) | Publish manual | "offline" dengan retain |
| Device disconnect (crash) | LWT (otomatis) | "offline" dengan retain |
7. Koneksi dan Session
Memahami mekanisme koneksi dan session di MQTT penting untuk membangun sistem IoT yang reliable, terutama di lingkungan dengan koneksi jaringan yang tidak stabil.
CONNECT Packet Parameters
import paho.mqtt.client as mqtt
# Parameter koneksi MQTT
client = mqtt.Client(
client_id="sensor_001", # ID unik per device
clean_session=True, # True = session baru setiap connect
protocol=mqtt.MQTTv311 # Versi protokol
)
# Clean Session = True (default)
# - Broker tidak menyimpan subscription dan QoS messages
# - Cocok untuk device yang tidak peduli pesan yang terlewat
# - Lebih hemat resource broker
# Clean Session = False
# - Broker menyimpan subscription dan pending messages
# - Saat reconnect, device langsung menerima pesan yang terlewat
# - Cocok untuk device yang HARUS menerima semua pesan
# - Membutuhkan client_id yang sama
client = mqtt.Client(
client_id="sensor_001",
clean_session=False # Persistent session
)
# Keep Alive
# Interval (detik) di mana client mengirim PINGREQ ke broker
# Jika broker tidak menerima PINGREQ dalam 1.5x keepalive,
# broker menganggap client offline dan mengirim LWT
client.connect(
host="broker.example.com",
port=1883,
keepalive=60 # Ping setiap 60 detik
)
# Username & Password
client.username_pw_set("sensor_user", "secure_password123")
# Reconnect otomatis
client.reconnect_delay_set(
min_delay=1, # Delay minimum 1 detik
max_delay=120 # Delay maksimum 120 detik
)
# Connect dengan TLS/SSL
client.tls_set(
ca_certs="ca.crt",
certfile="client.crt",
keyfile="client.key"
)
client.connect("broker.example.com", 8883, 60) # Port 8883 = MQTTS
Clean Session vs Persistent Session
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β CLEAN vs PERSISTENT SESSION β β β β CLEAN SESSION (clean_session=True): β β β β Device ββconnectβββΊ Broker β β Device βββCONNACKββ Broker (session baru) β β Device ββsubscribeβΊ Broker β β Device ββdisconnectβΊ Broker (session dihapus) β β β β Device ββconnectβββΊ Broker β β Device βββCONNACKββ Broker (session baru lagi!) β β Device ββsubscribeβΊ Broker (harus subscribe ulang) β β β β PERSISTENT SESSION (clean_session=False): β β β β Device ββconnectβββΊ Broker β β Device βββCONNACKββ Broker (session baru) β β Device ββsubscribeβΊ Broker β β Device ββdisconnectβΊ Broker (session DISIMPAN!) β β β β Device ββconnectβββΊ Broker (client_id sama) β β Device βββCONNACKββ Broker (session lama dilanjut) β β Device βββpesanβββ Broker (pesan yang terlewat) β β (tidak perlu subscribe ulang) β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
8. Keamanan MQTT
Keamanan adalah aspek kritis dalam implementasi MQTT di lingkungan produksi. Tanpa keamanan yang tepat, data sensor dan perintah kontrol bisa disadap, dimanipulasi, atau diserang oleh pihak yang tidak berwenang.
Lapisan Keamanan MQTT
| Lapisan | Mekanisme | Fungsi |
|---|---|---|
| Transport | TLS/SSL | Enkripsi data dalam transit, mencegah eavesdropping |
| Authentication | Username/Password, Client Certificate | Verifikasi identitas client |
| Authorization | ACL (Access Control List) | Kontrol siapa bisa publish/subscribe ke topik mana |
| Application | Payload Encryption | Enkripsi data di level aplikasi (end-to-end) |
TLS/SSL Configuration
# Generate self-signed certificates (untuk testing)
# 1. Generate CA key dan certificate
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 365 -key ca.key -out ca.crt \
-subj "/CN=MQTT CA"
# 2. Generate server key dan CSR
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr \
-subj "/CN=mqtt.example.com"
# 3. Sign server certificate dengan CA
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out server.crt -days 365
# 4. Generate client key dan certificate
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr \
-subj "/CN=sensor_001"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out client.crt -days 365
# Mosquitto TLS config
# /etc/mosquitto/conf.d/tls.conf
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
require_certificate true
use_identity_as_username true
Access Control List (ACL)
# /etc/mosquitto/acl.conf # Admin bisa akses semua topic user admin topic readwrite # # Sensor hanya bisa publish ke topic sendiri user sensor_001 topic write device/sensor_001/# # Dashboard bisa subscribe ke semua data sensor user dashboard topic read device/+/data topic read device/+/status # Lampu controller bisa publish dan subscribe topic lampu user lampu_ctrl topic readwrite lampu/# # Anonymous access (disable untuk produksi) # topic read $SYS/#
Security Best Practices
- Selalu gunakan TLS/SSL untuk koneksi di jaringan publik
- Jangan gunakan default credentials β ganti password default broker
- Gunakan Client ID yang unik untuk setiap perangkat
- Implementasi ACL untuk membatasi akses per topik
- Rotasi password/certificate secara berkala
- Monitor log broker untuk aktivitas mencurigakan
- Rate limiting untuk mencegah DDoS melalui broker
- Hindari payload sensitif tanpa enkripsi tambahan
9. Contoh Praktik dengan ESP32
Mari kita implementasikan semua konsep MQTT yang sudah dipelajari dalam proyek nyata menggunakan ESP32. Kita akan membuat sistem monitoring suhu dan kelembaban dengan fitur retain, LWT, dan multiple QoS.
Sketch Arduino untuk ESP32
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
// WiFi credentials
const char* ssid = "WiFi-Rumah";
const char* password = "password123";
// MQTT Broker
const char* mqtt_server = "192.168.1.100";
const int mqtt_port = 1883;
const char* mqtt_user = "sensor_001";
const char* mqtt_pass = "secure_pass";
// Topics
const char* topic_suhu = "gedung1/lantai1/ruang1/suhu";
const char* topic_lembab = "gedung1/lantai1/ruang1/lembab";
const char* topic_status = "gedung1/lantai1/ruang1/status";
const char* topic_cmd_lampu = "gedung1/lantai1/ruang1/cmd/lampu";
const char* topic_cmd_ac = "gedung1/lantai1/ruang1/cmd/ac";
// DHT Sensor
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// LED dan Relay
#define LED_LAMPU 2
#define RELAY_AC 5
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastPublish = 0;
const long publishInterval = 5000; // Publish setiap 5 detik
void setup_wifi() {
delay(10);
Serial.println("Menghubungkan ke WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi terhubung!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
String message = "";
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.printf("Pesan diterima [%s]: %s\n", topic, message.c_str());
// Handle perintah lampu
if (String(topic) == topic_cmd_lampu) {
if (message == "ON") {
digitalWrite(LED_LAMPU, HIGH);
client.publish("gedung1/lantai1/ruang1/lampu/status",
"ON", true); // retain
Serial.println("Lampu: ON");
} else if (message == "OFF") {
digitalWrite(LED_LAMPU, LOW);
client.publish("gedung1/lantai1/ruang1/lampu/status",
"OFF", true); // retain
Serial.println("Lampu: OFF");
}
}
// Handle perintah AC
if (String(topic) == topic_cmd_ac) {
int targetTemp = message.toInt();
float currentTemp = dht.readTemperature();
if (!isnan(currentTemp)) {
if (currentTemp > targetTemp) {
digitalWrite(RELAY_AC, HIGH); // AC ON
client.publish("gedung1/lantai1/ruang1/ac/status",
"ON", true);
} else {
digitalWrite(RELAY_AC, LOW); // AC OFF
client.publish("gedung1/lantai1/ruang1/ac/status",
"OFF", true);
}
}
}
}
void reconnect() {
while (!client.connected()) {
Serial.print("Menghubungkan ke MQTT Broker...");
// Client ID unik + Last Will + Clean Session
if (client.connect(
"sensor_gedung1_lantai1_ruang1", // client_id
mqtt_user, // username
mqtt_pass, // password
topic_status, // will topic
1, // will QoS
true, // will retain
"offline" // will message
)) {
Serial.println(" TERHUBUNG!");
// Publish status online (retained)
client.publish(topic_status, "online", true);
// Subscribe ke perintah kontrol (QoS 1)
client.subscribe(topic_cmd_lampu, 1);
client.subscribe(topic_cmd_ac, 1);
Serial.println("Subscribe ke topik kontrol...");
} else {
Serial.printf(" GAGAL (rc=%d). Coba lagi 5 detik...\n",
client.state());
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(LED_LAMPU, OUTPUT);
pinMode(RELAY_AC, OUTPUT);
dht.begin();
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long now = millis();
if (now - lastPublish > publishInterval) {
lastPublish = now;
float suhu = dht.readTemperature();
float lembab = dht.readHumidity();
if (!isnan(suhu) && !isnan(lembab)) {
// Publish data sensor (QoS 0, retained)
char suhuStr[8], lembabStr[8];
dtostrf(suhu, 1, 2, suhuStr);
dtostrf(lembab, 1, 2, lembabStr);
client.publish(topic_suhu, suhuStr, true); // retained
client.publish(topic_lembab, lembabStr, true); // retained
Serial.printf("Published: Suhu=%sΒ°C, Lembab=%s%%\n",
suhuStr, lembabStr);
// Alert jika suhu tinggi (QoS 1)
if (suhu > 35.0) {
client.publish("alarm/suhu_tinggi",
"{\"device\":\"gedung1_lantai1_ruang1\","
"\"temp\":35.5,\"threshold\":35}",
1); // QoS 1
}
}
}
}
Gunakan library PubSubClient untuk Arduino/ESP32. Ukuran payload maksimal default adalah 256 byte. Jika membutuhkan payload lebih besar, gunakan client.setBufferSize(1024) sebelum connect().
10. Best Practices MQTT
Berikut adalah best practices yang harus diikuti saat mengimplementasikan MQTT di proyek IoT Anda untuk memastikan sistem yang reliable, aman, dan scalable.
Topic Design
| Praktik | Contoh Baik | Contoh Buruk |
|---|---|---|
| Hierarki logis | gedung/lantai/ruang/sensor | sensor_data_room1_temp |
| Hindari leading slash | device/sensor01 | /device/sensor01 |
| Gunakan lowercase | sensor/suhu | Sensor/Suhu |
| Tidak ada spasi | data/suhu | data / suhu |
| Konsisten | Semua sensor sama format | Format beda-beda |
Payload Design
// β
Payload yang BAIK β menggunakan JSON standar
{
"device_id": "sensor_001",
"timestamp": 1719484800,
"data": {
"temperature": 25.5,
"humidity": 65.2,
"pressure": 1013.25
},
"battery": 87,
"rssi": -45,
"version": "1.0"
}
// β Payload yang BURUK β tidak terstruktur
// "25.5,65.2,1013.25"
// "suhu=25.5 lembab=65.2"
// "sensor 1: temp 25.5 humidity 65"
// Pertimbangkan CBOR (binary) untuk device dengan
// resource sangat terbatas β lebih kecil dari JSON
// Standarisasi payload di seluruh sistem Anda!
// Buat schema dan dokumentasikan formatnya
Error Handling dan Reconnection
import paho.mqtt.client as mqtt
import json
import time
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("MQTT")
class RobustMQTTClient:
def __init__(self, broker, port, client_id):
self.client = mqtt.Client(client_id=client_id, clean_session=False)
self.broker = broker
self.port = port
self.connected = False
# Setup callbacks
self.client.on_connect = self._on_connect
self.client.on_disconnect = self._on_disconnect
self.client.on_message = self._on_message
# LWT
self.client.will_set(
f"device/{client_id}/status",
json.dumps({"status": "offline", "ts": int(time.time())}),
qos=1, retain=True
)
# Reconnect settings
self.client.reconnect_delay_set(min_delay=1, max_delay=60)
def _on_connect(self, client, userdata, flags, rc):
if rc == 0:
self.connected = True
logger.info("Terhubung ke broker MQTT")
# Publish online
self.client.publish(
f"device/{self.client._client_id.decode()}/status",
json.dumps({"status": "online", "ts": int(time.time())}),
qos=1, retain=True
)
else:
logger.error(f"Gagal koneksi: rc={rc}")
def _on_disconnect(self, client, userdata, rc):
self.connected = False
if rc != 0:
logger.warning(f"Terputus tak terduga (rc={rc}), reconnecting...")
def _on_message(self, client, userdata, msg):
try:
payload = json.loads(msg.payload.decode())
logger.info(f"[{msg.topic}] {payload}")
except json.JSONDecodeError:
logger.warning(f"Invalid JSON: {msg.payload}")
def connect(self):
self.client.connect(self.broker, self.port, keepalive=60)
self.client.loop_start()
def publish(self, topic, data, qos=0):
if self.connected:
payload = json.dumps(data)
result = self.client.publish(topic, payload, qos=qos)
return result.rc == mqtt.MQTT_ERR_SUCCESS
return False
# Penggunaan
client = RobustMQTTClient("broker.example.com", 1883, "sensor_001")
client.connect()
client.publish("sensor/suhu", {"value": 25.5, "unit": "celsius"}, qos=1)
11. Troubleshooting
Berikut masalah umum yang sering dihadapi saat bekerja dengan MQTT beserta solusinya.
Masalah Umum dan Solusi
| Masalah | Penyebab | Solusi |
|---|---|---|
| Connection refused | Broker offline / port salah | Cek broker: telnet broker 1883 |
| Auth failed | Username/password salah | Cek credential, cek ACL |
| Client ID conflict | Dua device pakai ID sama | Gunakan ID unik per device |
| Pesan tidak diterima | Topic salah / tidak subscribe | Cek exact match topic (case-sensitive) |
| Retain tidak bekerja | Tidak pakai flag retain | Pastikan publish dengan retain=True |
| Koneksi putus-putus | Keepalive terlalu pendek | Tambah keepalive, cek jaringan |
| QoS downgrade | Broker tidak support QoS | Cek broker capability, gunakan QoS lebih rendah |
# Test koneksi ke broker
telnet broker.example.com 1883
# Test dengan verbose output (-d = debug)
mosquitto_sub -h broker.example.com -t "test/#" -d -v
# Monitor semua pesan di broker (dengan auth)
mosquitto_sub -h localhost -t "#" -u admin -P password -v
# Test retain message
mosquitto_pub -t "test/retain" -m "hello" -r
mosquitto_sub -t "test/retain" # Langsung menerima "hello"
mosquitto_pub -t "test/retain" -m "" -r # Hapus retain
# Cek broker log
sudo tail -f /var/log/mosquitto/mosquitto.log
# Test TLS connection
mosquitto_sub -h broker.example.com -p 8883 \
--cafile ca.crt --cert client.crt --key client.key \
-t "test/#" -d
12. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang MQTT: