IoT

πŸ“¨ MQTT Protocol: Panduan Lengkap

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

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
RinganHeader hanya 2 byte, cocok untuk perangkat dengan resource terbatas
Low BandwidthSangat efisien di jaringan dengan bandwidth rendah seperti LoRa, NB-IoT
Bi-directionalMendukung komunikasi dua arah antara device dan server
ScalableBisa menangani jutaan koneksi perangkat secara simultan
ReliableMemiliki 3 level QoS untuk menjamin pengiriman pesan
DecoupledPublisher dan subscriber tidak perlu online bersamaan
Standar TerbukaDiatur oleh OASIS dan didukung luas di industri IoT

MQTT vs Protokol Lain

Aspek MQTT HTTP WebSocket CoAP
ModelPub/SubRequest/ResponseFull DuplexRequest/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 untukIoT, MessagingWeb APIReal-time WebConstrained Devices
Diagram: Model Publish/Subscribe MQTT
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              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
PublisherMengirim pesan ke broker pada topik tertentuESP32, sensor, Raspberry Pi
BrokerMenerima pesan dan mendistribusikannya ke subscriberMosquitto, HiveMQ, EMQX
SubscriberMenerima pesan dari broker berdasarkan topik yang di-subscribeMobile 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 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
CONNECTClient β†’ BrokerPermintaan koneksi baru
CONNACKBroker β†’ ClientKonfirmasi koneksi
PUBLISHDua arahMengirim pesan
PUBACKDua arahKonfirmasi QoS 1
PUBREC/PUBREL/PUBCOMPDua arahHandshake QoS 2
SUBSCRIBEClient β†’ BrokerLangganan topik
SUBACKBroker β†’ ClientKonfirmasi subscribe
UNSUBSCRIBEClient β†’ BrokerBerhenti langganan
PINGREQ/PINGRESPDua arahHeartbeat / keep-alive
DISCONNECTClient β†’ BrokerPutus 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
MosquittoOpen Sourceβœ…Ringan, mudah setup, populerPrototyping, home IoT
EMQXOpen Source + Cloudβœ… (Community)Skalabilitas tinggi, clusteringEnterprise, industri
HiveMQCommercialβœ… (CE)Enterprise grade, MQTT 5.0Enterprise
VerneMQOpen Sourceβœ…Distributed, Erlang-basedHigh availability
AWS IoT CoreCloud ManagedπŸ’³ Pay-as-you-goFully managed, integrasi AWSCloud-native IoT
HiveMQ CloudCloud Managedβœ… (Free tier)Serverless, MQTT 5.0Quick start

Instalasi Mosquitto Broker

Mosquitto adalah broker MQTT open source yang paling populer dan cocok untuk memulai belajar.

Bash β€” Instalasi Mosquitto
# 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

Config β€” /etc/mosquitto/mosquitto.conf
# /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

Bash β€” Autentikasi Mosquitto
# 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
πŸ’‘ Tips

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.

Diagram: Hierarki Topic MQTT
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              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 LevelMenangkap satu level sajagedung1/+/ruang1/suhu cocok dengan semua lantai di gedung1
#Multi LevelMenangkap semua level di bawahnyagedung1/# cocok dengan semua topic di gedung1
Contoh β€” Wildcard Topics
# 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:

Contoh β€” $SYS Topics
# 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
⚠️ Peringatan

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

Diagram: Perbandingan QoS 0, 1, 2
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    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
DeliveryAt most onceAt least onceExactly once
Pesan Hilang?⚠️ Mungkin❌ Tidak❌ Tidak
Pesan Duplikat?❌ Tidak⚠️ Mungkin❌ Tidak
Round Trip124
Bandwidth🟒 Paling hemat🟑 SedangπŸ”΄ Paling boros
Latency🟒 Terendah🟑 SedangπŸ”΄ Tertinggi
Cocok untukSensor periodikNotifikasi, alarmTransaksi 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
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              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.

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 connectPublish manual"online" dengan retain
Device heartbeatPublish 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
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              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
TransportTLS/SSLEnkripsi data dalam transit, mencegah eavesdropping
AuthenticationUsername/Password, Client CertificateVerifikasi identitas client
AuthorizationACL (Access Control List)Kontrol siapa bisa publish/subscribe ke topik mana
ApplicationPayload EncryptionEnkripsi data di level aplikasi (end-to-end)

TLS/SSL Configuration

Config β€” TLS Mosquitto
# 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)

Config β€” ACL Mosquitto
# /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
  1. Selalu gunakan TLS/SSL untuk koneksi di jaringan publik
  2. Jangan gunakan default credentials β€” ganti password default broker
  3. Gunakan Client ID yang unik untuk setiap perangkat
  4. Implementasi ACL untuk membatasi akses per topik
  5. Rotasi password/certificate secara berkala
  6. Monitor log broker untuk aktivitas mencurigakan
  7. Rate limiting untuk mencegah DDoS melalui broker
  8. 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 logisgedung/lantai/ruang/sensorsensor_data_room1_temp
Hindari leading slashdevice/sensor01/device/sensor01
Gunakan lowercasesensor/suhuSensor/Suhu
Tidak ada spasidata/suhudata / suhu
KonsistenSemua sensor sama formatFormat 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

Error Handling dan Reconnection

Python β€” Robust MQTT Client
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 refusedBroker offline / port salahCek broker: telnet broker 1883
Auth failedUsername/password salahCek credential, cek ACL
Client ID conflictDua device pakai ID samaGunakan ID unik per device
Pesan tidak diterimaTopic salah / tidak subscribeCek exact match topic (case-sensitive)
Retain tidak bekerjaTidak pakai flag retainPastikan publish dengan retain=True
Koneksi putus-putusKeepalive terlalu pendekTambah keepalive, cek jaringan
QoS downgradeBroker tidak support QoSCek broker capability, gunakan QoS lebih rendah
Bash β€” Debugging MQTT
# 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:

Pertanyaan 1: Berapa ukuran minimal header MQTT packet?

a) 1 byte
b) 2 byte
c) 4 byte
d) 8 byte

Pertanyaan 2: QoS level berapa yang menjamin pesan diterima tepat sekali (exactly once)?

a) QoS 0
b) QoS 1
c) QoS 2
d) Semua QoS menjamin exactly once

Pertanyaan 3: Apa fungsi dari Last Will and Testament (LWT) di MQTT?

a) Mengirim data sensor secara periodik
b) Mengenkripsi pesan MQTT
c) Mengirim pesan otomatis saat client terputus tak terduga
d) Menyimpan semua pesan yang pernah dikirim

Pertanyaan 4: Apa wildcard yang digunakan untuk menangkap semua level topik di bawahnya?

a) *
b) +
c) #
d) ?

Pertanyaan 5: Apa yang terjadi jika subscriber baru subscribe ke topik yang punya retained message?

a) Tidak menerima apa-apa
b) Menerima retained message langsung dari broker
c) Menerima semua pesan yang pernah dikirim ke topik tersebut
d) Error karena topik sudah digunakan
πŸ” Zoom
100%
🎨 Tema