# Catatan Seekor: MQTT

MQTT (Message Queuing Telemetry Transport) adalah lightweight messaging protocol yang dirancang untuk IoT dan machine-to-machine communication.

## Fundamental

### MQTT Concepts

* **Client**: Device atau aplikasi yang menggunakan MQTT
* **Broker**: Server yang menerima dan mendistribusikan pesan
* **Topic**: Hierarchical naming structure untuk pesan
* **Message**: Data yang dikirim antara client dan broker
* **QoS**: Quality of Service level untuk delivery guarantee

### MQTT Architecture

```
┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   Client    │◄───│   Broker    │◄───│   Client    │
│             │───▶│             │───▶│             │
└─────────────┘    └─────────────┘    └─────────────┘
     │                    │                    │
     ▼                    ▼                    ▼
┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   Client    │    │   Client    │    │   Client    │
└─────────────┘    └─────────────┘    └─────────────┘
```

## Topic Structure

### Topic Naming

```bash
# Basic topics
home/livingroom/temperature
home/kitchen/humidity
office/floor1/lighting

# Wildcard topics
home/+/temperature    # + matches one level
home/#                # # matches multiple levels
sensor/+/+/reading    # Multiple single-level wildcards
```

### Topic Examples

```bash
# Home automation
home/floor1/room1/temperature
home/floor1/room1/humidity
home/floor1/room1/light/status
home/floor1/room1/light/control

# Industrial monitoring
factory/building1/machine1/temperature
factory/building1/machine1/pressure
factory/building1/machine1/status

# Weather stations
weather/station1/temperature
weather/station1/humidity
weather/station1/pressure
weather/station1/wind_speed
```

## QoS Levels

### QoS 0 - At Most Once

```python
import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, rc):
    print(f"Connected with result code {rc}")
    # Subscribe to topic with QoS 0
    client.subscribe("home/temperature", qos=0)

def on_message(client, userdata, msg):
    print(f"Received message: {msg.topic} {str(msg.payload.decode())}")

# Create client
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

# Connect to broker
client.connect("localhost", 1883, 60)

# Publish with QoS 0
client.publish("home/temperature", "25.5", qos=0)

# Start loop
client.loop_forever()
```

### QoS 1 - At Least Once

```python
def on_publish(client, userdata, mid):
    print(f"Message {mid} published successfully")

def on_subscribe(client, userdata, mid, granted_qos):
    print(f"Subscribed with QoS: {granted_qos}")

client.on_publish = on_publish
client.on_subscribe = on_subscribe

# Subscribe with QoS 1
client.subscribe("home/temperature", qos=1)

# Publish with QoS 1
client.publish("home/temperature", "25.5", qos=1)
```

### QoS 2 - Exactly Once

```python
# Subscribe with QoS 2
client.subscribe("home/temperature", qos=2)

# Publish with QoS 2
client.publish("home/temperature", "25.5", qos=2)
```

## Client Implementation

### Python Client

```python
import paho.mqtt.client as mqtt
import json
import time

class MQTTClient:
    def __init__(self, broker="localhost", port=1883):
        self.client = mqtt.Client()
        self.broker = broker
        self.port = port
        
        # Set callbacks
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        self.client.on_publish = self.on_publish
        self.client.on_subscribe = self.on_subscribe
        
    def on_connect(self, client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT broker")
            # Subscribe to topics
            client.subscribe("home/+/temperature", qos=1)
            client.subscribe("home/+/humidity", qos=1)
        else:
            print(f"Connection failed with code {rc}")
    
    def on_message(self, client, userdata, msg):
        try:
            payload = json.loads(msg.payload.decode())
            print(f"Received: {msg.topic} = {payload}")
        except json.JSONDecodeError:
            print(f"Received: {msg.topic} = {msg.payload.decode()}")
    
    def on_publish(self, client, userdata, mid):
        print(f"Message {mid} published")
    
    def on_subscribe(self, client, userdata, mid, granted_qos):
        print(f"Subscribed with QoS: {granted_qos}")
    
    def connect(self):
        try:
            self.client.connect(self.broker, self.port, 60)
            self.client.loop_start()
        except Exception as e:
            print(f"Connection error: {e}")
    
    def publish(self, topic, payload, qos=1):
        if isinstance(payload, dict):
            payload = json.dumps(payload)
        result = self.client.publish(topic, payload, qos=qos)
        return result
    
    def disconnect(self):
        self.client.loop_stop()
        self.client.disconnect()

# Usage
mqtt_client = MQTTClient()
mqtt_client.connect()

# Publish sensor data
sensor_data = {
    "temperature": 25.5,
    "humidity": 60.2,
    "timestamp": time.time()
}
mqtt_client.publish("home/livingroom/sensor", sensor_data)

time.sleep(5)
mqtt_client.disconnect()
```

### JavaScript Client

```javascript
const mqtt = require('mqtt');

class MQTTClient {
    constructor(broker = 'mqtt://localhost:1883') {
        this.broker = broker;
        this.client = null;
    }
    
    connect() {
        this.client = mqtt.connect(this.broker, {
            clientId: `mqtt_client_${Math.random().toString(16).slice(3)}`,
            clean: true,
            connectTimeout: 4000,
            reconnectPeriod: 1000,
        });
        
        this.client.on('connect', () => {
            console.log('Connected to MQTT broker');
            this.subscribe('home/+/temperature');
        });
        
        this.client.on('message', (topic, message) => {
            try {
                const payload = JSON.parse(message.toString());
                console.log(`Received: ${topic} = ${JSON.stringify(payload)}`);
            } catch (e) {
                console.log(`Received: ${topic} = ${message.toString()}`);
            }
        });
        
        this.client.on('error', (err) => {
            console.error('MQTT error:', err);
        });
    }
    
    subscribe(topic, qos = 1) {
        this.client.subscribe(topic, { qos }, (err) => {
            if (err) {
                console.error('Subscribe error:', err);
            } else {
                console.log(`Subscribed to ${topic}`);
            }
        });
    }
    
    publish(topic, payload, qos = 1) {
        const message = typeof payload === 'object' ? JSON.stringify(payload) : payload;
        this.client.publish(topic, message, { qos }, (err) => {
            if (err) {
                console.error('Publish error:', err);
            } else {
                console.log(`Published to ${topic}`);
            }
        });
    }
    
    disconnect() {
        if (this.client) {
            this.client.end();
        }
    }
}

// Usage
const mqttClient = new MQTTClient();
mqttClient.connect();

// Publish sensor data
setInterval(() => {
    const sensorData = {
        temperature: 20 + Math.random() * 10,
        humidity: 50 + Math.random() * 20,
        timestamp: Date.now()
    };
    mqttClient.publish('home/livingroom/sensor', sensorData);
}, 5000);

setTimeout(() => {
    mqttClient.disconnect();
}, 30000);
```

## Mosquitto Broker

### Installation and Configuration

```bash
# Install Mosquitto
sudo apt-get install mosquitto mosquitto-clients

# Start Mosquitto service
sudo systemctl start mosquitto
sudo systemctl enable mosquitto

# Check status
sudo systemctl status mosquitto
```

### Configuration File

```bash
# /etc/mosquitto/mosquitto.conf

# Network settings
listener 1883
protocol mqtt

# Security settings
allow_anonymous false
password_file /etc/mosquitto/passwd

# Logging
log_type all
log_dest file /var/log/mosquitto/mosquitto.log
log_dest stdout

# Persistence
persistence true
persistence_location /var/lib/mosquitto/

# Maximum connections
max_connections 1000

# Keep alive
keepalive_interval 60
```

### User Management

```bash
# Create password file
sudo mosquitto_passwd -c /etc/mosquitto/passwd username1
sudo mosquitto_passwd /etc/mosquitto/passwd username2

# Set permissions
sudo chown mosquitto:mosquitto /etc/mosquitto/passwd
sudo chmod 600 /etc/mosquitto/passwd

# Restart service
sudo systemctl restart mosquitto
```

## Advanced Features

### Retained Messages

```python
# Publish retained message
client.publish("home/status", "online", qos=1, retain=True)

# Subscribe to get retained message
client.subscribe("home/status", qos=1)
```

### Last Will and Testament

```python
# Set last will and testament
client.will_set("home/status", "offline", qos=1, retain=True)

# Connect to broker
client.connect("localhost", 1883, 60)
```

### Message Filtering

```python
# Subscribe with multiple topics
client.subscribe([
    ("home/+/temperature", 1),
    ("home/+/humidity", 1),
    ("home/+/light/status", 1)
])

# Subscribe with wildcards
client.subscribe("sensor/+/+/reading", qos=1)
```

## Security

### TLS/SSL Configuration

```python
import ssl

# Configure TLS
client.tls_set(ca_certs="ca.crt",
               certfile="client.crt",
               keyfile="client.key",
               cert_reqs=ssl.CERT_REQUIRED,
               tls_version=ssl.PROTOCOL_TLSv1_2)

# Connect with TLS
client.connect("localhost", 8883, 60)
```

### Authentication

```python
# Username/password authentication
client.username_pw_set("username", "password")

# Connect to broker
client.connect("localhost", 1883, 60)
```

## Monitoring and Management

### Broker Statistics

```bash
# Get broker statistics
mosquitto_sub -h localhost -t '$SYS/#' -v

# Monitor connections
mosquitto_sub -h localhost -t '$SYS/broker/clients/connected' -v

# Monitor message rates
mosquitto_sub -h localhost -t '$SYS/broker/messages/sent' -v
mosquitto_sub -h localhost -t '$SYS/broker/messages/received' -v
```

### Client Monitoring

```python
def on_log(client, userdata, level, buf):
    print(f"Log: {buf}")

# Enable logging
client.enable_logger()
client.on_log = on_log
```

## Best Practices

### Topic Design

* **Hierarchical Structure**: Use forward slashes for topic hierarchy
* **Descriptive Names**: Use clear, descriptive topic names
* **Consistent Format**: Maintain consistent naming conventions
* **Wildcard Usage**: Use wildcards carefully for subscriptions

### Message Design

* **JSON Format**: Use JSON for structured data
* **Small Payloads**: Keep messages small and focused
* **Metadata**: Include timestamps and source information
* **Error Handling**: Implement proper error handling

### Performance

* **Connection Reuse**: Reuse connections when possible
* **QoS Selection**: Choose appropriate QoS levels
* **Batch Processing**: Process messages in batches
* **Monitoring**: Monitor message rates and latency

### Security

* **Authentication**: Use username/password or certificates
* **Encryption**: Enable TLS/SSL for sensitive data
* **Access Control**: Implement topic-based access control
* **Network Security**: Restrict network access to broker

## References

### MQTT Resources

* [Mosquitto: Getting started](https://www.stackhero.io/en/services/Mosquitto/documentations/Getting-started)

### Additional Resources

* MQTT Specification: <http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html>
* Mosquitto Documentation: <https://mosquitto.org/documentation/>
* Paho MQTT Client: <https://www.eclipse.org/paho/>
* MQTT.js: <https://github.com/mqttjs/MQTT.js>
