Panduan lengkap protokol MQTT untuk IoT โ broker, Quality of Service, topic hierarchy, retain message, last will and testament, serta keamanan MQTT dengan contoh kode praktis
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
Diagram: Model Publish/Subscribe MQTT
Model Publish/Subscribe MQTT
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).
Diagram: MQTT Packet Structure
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.
flowchart TD
subgraph qos0["QoS 0: At Most Once"]
A0["Publisher"] -->|"Fire & Forget"| B0["Broker"]
B0 -->|"No Ack"| C0["Subscriber"]
end
subgraph qos1["QoS 1: At Least Once"]
A1["Publisher"] -->|"Publish"| B1["Broker"]
B1 -->|"Deliver"| C1["Subscriber"]
C1 -->|"PUBACK โ "| B1
end
subgraph qos2["QoS 2: Exactly Once"]
A2["Publisher"] -->|"PUBREL"| B2["Broker"]
B2 -->|"PUBREC"| C2["Subscriber"]
C2 -->|"PUBCOMP โ "| B2
end
style qos0 fill:#0f2a1f,stroke:#3ecf8e
style qos1 fill:#0f1d3a,stroke:#60a5fa
style qos2 fill:#2a1f0a,stroke:#f59e0b
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
Contoh โ QoS Usage
# 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
Python โ QoS Example
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.
Bash โ Retain Message
# 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
Diagram: RETAIN MESSAGE FLOW
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.
Python โ Last Will and Testament
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
Python โ Connection 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
Diagram: Session Behavior
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
# /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
โ ๏ธ Checklist Keamanan MQTT
Selalu gunakan TLS/SSL untuk koneksi di jaringan publik
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
Arduino โ ESP32 MQTT Client
#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
}
}
}
}
๐ก Tips
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
JSON โ Payload Standar
// โ 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