Vollständige Next.js 15 Portfolio-Website mit: - Blog-System mit 100+ Artikeln - Supabase-Integration - Responsive Design mit Tailwind CSS - TypeScript-Konfiguration - Testing-Setup mit Vitest und Playwright Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
816 lines
22 KiB
Markdown
816 lines
22 KiB
Markdown
# MQTT Protocol für IoT-Kommunikation
|
||
|
||
**Meta-Description:** MQTT Protokoll für IoT. Publish/Subscribe Pattern, QoS Levels, Broker Setup und Node.js Integration mit MQTT.js.
|
||
|
||
**Keywords:** MQTT, IoT, Publish Subscribe, MQTT.js, Mosquitto, Message Broker, QoS, Real-time
|
||
|
||
---
|
||
|
||
## Einführung
|
||
|
||
**MQTT** (Message Queuing Telemetry Transport) ist das Standard-Protokoll für IoT-Kommunikation. Leichtgewichtig, effizient und für instabile Netzwerke optimiert – perfekt für Sensor-Netzwerke und Smart Home Anwendungen.
|
||
|
||
---
|
||
|
||
## MQTT Architecture
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ MQTT ARCHITECTURE │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ Publishers Broker Subscribers │
|
||
│ ┌─────────┐ ┌──────────┐ ┌─────────┐ │
|
||
│ │ Sensor │────────→│ │────────→│Dashboard│ │
|
||
│ └─────────┘ │ │ └─────────┘ │
|
||
│ │ Mosquitto│ │
|
||
│ ┌─────────┐ │ / EMQX │ ┌─────────┐ │
|
||
│ │ Device │────────→│ │────────→│ Backend │ │
|
||
│ └─────────┘ │ │ └─────────┘ │
|
||
│ │ │ │
|
||
│ ┌─────────┐ │ │ ┌─────────┐ │
|
||
│ │ Gateway │←───────→│ │←───────→│ Mobile │ │
|
||
│ └─────────┘ └──────────┘ └─────────┘ │
|
||
│ │
|
||
│ Topic Structure: │
|
||
│ home/living-room/temperature → 21.5 │
|
||
│ home/living-room/humidity → 45 │
|
||
│ home/bedroom/light/state → on │
|
||
│ home/bedroom/light/brightness → 80 │
|
||
│ │
|
||
│ QoS Levels: │
|
||
│ 0: At most once (Fire & Forget) │
|
||
│ 1: At least once (Acknowledged) │
|
||
│ 2: Exactly once (Assured) │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## Mosquitto Broker Setup
|
||
|
||
```bash
|
||
# Docker Installation
|
||
docker run -d \
|
||
--name mosquitto \
|
||
-p 1883:1883 \
|
||
-p 9001:9001 \
|
||
-v $(pwd)/mosquitto/config:/mosquitto/config \
|
||
-v $(pwd)/mosquitto/data:/mosquitto/data \
|
||
-v $(pwd)/mosquitto/log:/mosquitto/log \
|
||
eclipse-mosquitto
|
||
|
||
# mosquitto/config/mosquitto.conf
|
||
listener 1883
|
||
listener 9001
|
||
protocol websockets
|
||
|
||
allow_anonymous false
|
||
password_file /mosquitto/config/password.txt
|
||
|
||
persistence true
|
||
persistence_location /mosquitto/data/
|
||
|
||
log_dest file /mosquitto/log/mosquitto.log
|
||
log_type all
|
||
|
||
# TLS Konfiguration
|
||
listener 8883
|
||
cafile /mosquitto/certs/ca.crt
|
||
certfile /mosquitto/certs/server.crt
|
||
keyfile /mosquitto/certs/server.key
|
||
require_certificate false
|
||
```
|
||
|
||
```yaml
|
||
# docker-compose.yml
|
||
version: '3.8'
|
||
services:
|
||
mosquitto:
|
||
image: eclipse-mosquitto:2
|
||
container_name: mosquitto
|
||
ports:
|
||
- "1883:1883" # MQTT
|
||
- "8883:8883" # MQTT/TLS
|
||
- "9001:9001" # WebSocket
|
||
volumes:
|
||
- ./mosquitto/config:/mosquitto/config
|
||
- ./mosquitto/data:/mosquitto/data
|
||
- ./mosquitto/log:/mosquitto/log
|
||
restart: unless-stopped
|
||
```
|
||
|
||
---
|
||
|
||
## MQTT.js Client
|
||
|
||
```typescript
|
||
// lib/mqtt-client.ts
|
||
import mqtt, { MqttClient, IClientOptions, QoS } from 'mqtt';
|
||
|
||
interface MQTTConfig {
|
||
brokerUrl: string;
|
||
options?: IClientOptions;
|
||
}
|
||
|
||
interface PublishOptions {
|
||
qos?: QoS;
|
||
retain?: boolean;
|
||
}
|
||
|
||
type MessageHandler = (topic: string, message: string, packet: any) => void;
|
||
|
||
class IoTMQTTClient {
|
||
private client: MqttClient | null = null;
|
||
private subscriptions: Map<string, Set<MessageHandler>> = new Map();
|
||
private connected = false;
|
||
private reconnectAttempts = 0;
|
||
private maxReconnectAttempts = 10;
|
||
|
||
constructor(private config: MQTTConfig) {}
|
||
|
||
async connect(): Promise<void> {
|
||
return new Promise((resolve, reject) => {
|
||
const options: IClientOptions = {
|
||
clientId: `mqtt_${Math.random().toString(16).slice(2, 10)}`,
|
||
clean: true,
|
||
connectTimeout: 30000,
|
||
reconnectPeriod: 5000,
|
||
keepalive: 60,
|
||
...this.config.options
|
||
};
|
||
|
||
this.client = mqtt.connect(this.config.brokerUrl, options);
|
||
|
||
this.client.on('connect', () => {
|
||
console.log('Connected to MQTT broker');
|
||
this.connected = true;
|
||
this.reconnectAttempts = 0;
|
||
|
||
// Re-subscribe nach Reconnect
|
||
this.resubscribe();
|
||
resolve();
|
||
});
|
||
|
||
this.client.on('message', (topic, payload, packet) => {
|
||
const message = payload.toString();
|
||
this.handleMessage(topic, message, packet);
|
||
});
|
||
|
||
this.client.on('error', (error) => {
|
||
console.error('MQTT Error:', error);
|
||
if (!this.connected) {
|
||
reject(error);
|
||
}
|
||
});
|
||
|
||
this.client.on('close', () => {
|
||
console.log('MQTT connection closed');
|
||
this.connected = false;
|
||
});
|
||
|
||
this.client.on('reconnect', () => {
|
||
this.reconnectAttempts++;
|
||
console.log(`Reconnecting... Attempt ${this.reconnectAttempts}`);
|
||
|
||
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
||
this.client?.end();
|
||
console.error('Max reconnection attempts reached');
|
||
}
|
||
});
|
||
|
||
this.client.on('offline', () => {
|
||
console.log('MQTT client offline');
|
||
});
|
||
});
|
||
}
|
||
|
||
private handleMessage(topic: string, message: string, packet: any) {
|
||
// Exakte Matches
|
||
const handlers = this.subscriptions.get(topic);
|
||
if (handlers) {
|
||
handlers.forEach(handler => handler(topic, message, packet));
|
||
}
|
||
|
||
// Wildcard Matches
|
||
for (const [pattern, patternHandlers] of this.subscriptions) {
|
||
if (this.matchTopic(pattern, topic)) {
|
||
patternHandlers.forEach(handler => handler(topic, message, packet));
|
||
}
|
||
}
|
||
}
|
||
|
||
private matchTopic(pattern: string, topic: string): boolean {
|
||
if (pattern === topic) return false; // Already handled above
|
||
|
||
const patternParts = pattern.split('/');
|
||
const topicParts = topic.split('/');
|
||
|
||
for (let i = 0; i < patternParts.length; i++) {
|
||
if (patternParts[i] === '#') {
|
||
return true; // Multi-level wildcard matches rest
|
||
}
|
||
if (patternParts[i] === '+') {
|
||
continue; // Single-level wildcard matches any single level
|
||
}
|
||
if (patternParts[i] !== topicParts[i]) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return patternParts.length === topicParts.length;
|
||
}
|
||
|
||
private resubscribe() {
|
||
for (const [topic] of this.subscriptions) {
|
||
this.client?.subscribe(topic, { qos: 1 });
|
||
}
|
||
}
|
||
|
||
// Publish
|
||
async publish(
|
||
topic: string,
|
||
message: string | object,
|
||
options: PublishOptions = {}
|
||
): Promise<void> {
|
||
return new Promise((resolve, reject) => {
|
||
if (!this.client || !this.connected) {
|
||
reject(new Error('Not connected to broker'));
|
||
return;
|
||
}
|
||
|
||
const payload = typeof message === 'object'
|
||
? JSON.stringify(message)
|
||
: message;
|
||
|
||
this.client.publish(
|
||
topic,
|
||
payload,
|
||
{
|
||
qos: options.qos || 1,
|
||
retain: options.retain || false
|
||
},
|
||
(error) => {
|
||
if (error) reject(error);
|
||
else resolve();
|
||
}
|
||
);
|
||
});
|
||
}
|
||
|
||
// Subscribe
|
||
subscribe(
|
||
topic: string,
|
||
handler: MessageHandler,
|
||
qos: QoS = 1
|
||
): () => void {
|
||
if (!this.subscriptions.has(topic)) {
|
||
this.subscriptions.set(topic, new Set());
|
||
this.client?.subscribe(topic, { qos });
|
||
}
|
||
|
||
this.subscriptions.get(topic)!.add(handler);
|
||
|
||
// Unsubscribe function
|
||
return () => {
|
||
const handlers = this.subscriptions.get(topic);
|
||
if (handlers) {
|
||
handlers.delete(handler);
|
||
if (handlers.size === 0) {
|
||
this.subscriptions.delete(topic);
|
||
this.client?.unsubscribe(topic);
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
// Disconnect
|
||
disconnect(): Promise<void> {
|
||
return new Promise((resolve) => {
|
||
this.client?.end(false, {}, () => {
|
||
this.connected = false;
|
||
resolve();
|
||
});
|
||
});
|
||
}
|
||
|
||
isConnected(): boolean {
|
||
return this.connected;
|
||
}
|
||
}
|
||
|
||
export { IoTMQTTClient };
|
||
```
|
||
|
||
---
|
||
|
||
## Sensor Data Publishing
|
||
|
||
```typescript
|
||
// devices/temperature-sensor.ts
|
||
import { IoTMQTTClient } from '../lib/mqtt-client';
|
||
|
||
interface SensorReading {
|
||
device_id: string;
|
||
timestamp: string;
|
||
temperature: number;
|
||
humidity: number;
|
||
battery: number;
|
||
}
|
||
|
||
class TemperatureSensor {
|
||
private client: IoTMQTTClient;
|
||
private deviceId: string;
|
||
private baseTopic: string;
|
||
private intervalId?: NodeJS.Timeout;
|
||
|
||
constructor(
|
||
brokerUrl: string,
|
||
deviceId: string,
|
||
options?: { username?: string; password?: string }
|
||
) {
|
||
this.deviceId = deviceId;
|
||
this.baseTopic = `sensors/${deviceId}`;
|
||
|
||
this.client = new IoTMQTTClient({
|
||
brokerUrl,
|
||
options: {
|
||
username: options?.username,
|
||
password: options?.password,
|
||
will: {
|
||
topic: `${this.baseTopic}/status`,
|
||
payload: Buffer.from('offline'),
|
||
qos: 1,
|
||
retain: true
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
async start(intervalMs: number = 60000): Promise<void> {
|
||
await this.client.connect();
|
||
|
||
// Online Status
|
||
await this.client.publish(
|
||
`${this.baseTopic}/status`,
|
||
'online',
|
||
{ retain: true }
|
||
);
|
||
|
||
// Device Info
|
||
await this.client.publish(
|
||
`${this.baseTopic}/info`,
|
||
{
|
||
device_id: this.deviceId,
|
||
type: 'temperature_humidity',
|
||
firmware: '1.0.0',
|
||
started_at: new Date().toISOString()
|
||
},
|
||
{ retain: true }
|
||
);
|
||
|
||
// Periodisch Daten senden
|
||
this.intervalId = setInterval(() => this.publishReading(), intervalMs);
|
||
|
||
// Initial Reading
|
||
await this.publishReading();
|
||
|
||
console.log(`Sensor ${this.deviceId} started`);
|
||
}
|
||
|
||
private async publishReading(): Promise<void> {
|
||
const reading: SensorReading = {
|
||
device_id: this.deviceId,
|
||
timestamp: new Date().toISOString(),
|
||
temperature: this.readTemperature(),
|
||
humidity: this.readHumidity(),
|
||
battery: this.readBattery()
|
||
};
|
||
|
||
// JSON Format
|
||
await this.client.publish(
|
||
`${this.baseTopic}/data`,
|
||
reading,
|
||
{ qos: 1 }
|
||
);
|
||
|
||
// Home Assistant Discovery Format
|
||
await this.client.publish(
|
||
`homeassistant/sensor/${this.deviceId}/temperature/state`,
|
||
reading.temperature.toString()
|
||
);
|
||
|
||
await this.client.publish(
|
||
`homeassistant/sensor/${this.deviceId}/humidity/state`,
|
||
reading.humidity.toString()
|
||
);
|
||
|
||
console.log(`Published: ${JSON.stringify(reading)}`);
|
||
}
|
||
|
||
// Simulierte Sensor-Werte (in Produktion: echte Hardware-Reads)
|
||
private readTemperature(): number {
|
||
return Math.round((20 + Math.random() * 5) * 10) / 10;
|
||
}
|
||
|
||
private readHumidity(): number {
|
||
return Math.round((40 + Math.random() * 20) * 10) / 10;
|
||
}
|
||
|
||
private readBattery(): number {
|
||
return Math.round((80 + Math.random() * 20) * 10) / 10;
|
||
}
|
||
|
||
async stop(): Promise<void> {
|
||
if (this.intervalId) {
|
||
clearInterval(this.intervalId);
|
||
}
|
||
|
||
await this.client.publish(
|
||
`${this.baseTopic}/status`,
|
||
'offline',
|
||
{ retain: true }
|
||
);
|
||
|
||
await this.client.disconnect();
|
||
console.log(`Sensor ${this.deviceId} stopped`);
|
||
}
|
||
}
|
||
|
||
// Verwendung
|
||
const sensor = new TemperatureSensor(
|
||
'mqtt://localhost:1883',
|
||
'living-room-01',
|
||
{
|
||
username: process.env.MQTT_USER,
|
||
password: process.env.MQTT_PASS
|
||
}
|
||
);
|
||
|
||
await sensor.start(30000); // Alle 30 Sekunden
|
||
|
||
// Graceful Shutdown
|
||
process.on('SIGTERM', async () => {
|
||
await sensor.stop();
|
||
process.exit(0);
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## Data Subscriber Service
|
||
|
||
```typescript
|
||
// services/mqtt-data-collector.ts
|
||
import { IoTMQTTClient } from '../lib/mqtt-client';
|
||
import { InfluxDBClient } from '../lib/influxdb';
|
||
|
||
interface SensorData {
|
||
device_id: string;
|
||
timestamp: string;
|
||
[key: string]: any;
|
||
}
|
||
|
||
class MQTTDataCollector {
|
||
private mqtt: IoTMQTTClient;
|
||
private influx: InfluxDBClient;
|
||
private subscriptions: Array<() => void> = [];
|
||
|
||
constructor(
|
||
mqttUrl: string,
|
||
influxConfig: { url: string; token: string; org: string; bucket: string }
|
||
) {
|
||
this.mqtt = new IoTMQTTClient({
|
||
brokerUrl: mqttUrl,
|
||
options: {
|
||
clientId: 'data-collector',
|
||
username: process.env.MQTT_USER,
|
||
password: process.env.MQTT_PASS
|
||
}
|
||
});
|
||
|
||
this.influx = new InfluxDBClient(influxConfig);
|
||
}
|
||
|
||
async start(): Promise<void> {
|
||
await this.mqtt.connect();
|
||
|
||
// Subscribe to all sensor data
|
||
const unsubSensors = this.mqtt.subscribe(
|
||
'sensors/+/data',
|
||
async (topic, message) => {
|
||
try {
|
||
const data = JSON.parse(message) as SensorData;
|
||
await this.processSensorData(topic, data);
|
||
} catch (error) {
|
||
console.error('Failed to process sensor data:', error);
|
||
}
|
||
}
|
||
);
|
||
this.subscriptions.push(unsubSensors);
|
||
|
||
// Subscribe to device status
|
||
const unsubStatus = this.mqtt.subscribe(
|
||
'sensors/+/status',
|
||
(topic, message) => {
|
||
const deviceId = topic.split('/')[1];
|
||
console.log(`Device ${deviceId} is ${message}`);
|
||
this.updateDeviceStatus(deviceId, message);
|
||
}
|
||
);
|
||
this.subscriptions.push(unsubStatus);
|
||
|
||
// Subscribe to commands
|
||
const unsubCommands = this.mqtt.subscribe(
|
||
'commands/#',
|
||
this.handleCommand.bind(this)
|
||
);
|
||
this.subscriptions.push(unsubCommands);
|
||
|
||
console.log('Data collector started');
|
||
}
|
||
|
||
private async processSensorData(topic: string, data: SensorData): Promise<void> {
|
||
const deviceId = topic.split('/')[1];
|
||
|
||
// In InfluxDB speichern
|
||
await this.influx.writePoint({
|
||
measurement: 'sensor_readings',
|
||
tags: {
|
||
device_id: deviceId,
|
||
location: this.getDeviceLocation(deviceId)
|
||
},
|
||
fields: {
|
||
temperature: data.temperature,
|
||
humidity: data.humidity,
|
||
battery: data.battery
|
||
},
|
||
timestamp: new Date(data.timestamp)
|
||
});
|
||
|
||
// Alerts prüfen
|
||
await this.checkAlerts(deviceId, data);
|
||
}
|
||
|
||
private async checkAlerts(deviceId: string, data: SensorData): Promise<void> {
|
||
// Temperatur-Alert
|
||
if (data.temperature > 30) {
|
||
await this.mqtt.publish('alerts/temperature/high', {
|
||
device_id: deviceId,
|
||
temperature: data.temperature,
|
||
timestamp: data.timestamp,
|
||
message: `High temperature alert: ${data.temperature}°C`
|
||
});
|
||
}
|
||
|
||
// Batterie-Alert
|
||
if (data.battery < 20) {
|
||
await this.mqtt.publish('alerts/battery/low', {
|
||
device_id: deviceId,
|
||
battery: data.battery,
|
||
timestamp: data.timestamp,
|
||
message: `Low battery alert: ${data.battery}%`
|
||
});
|
||
}
|
||
}
|
||
|
||
private handleCommand(topic: string, message: string): void {
|
||
const parts = topic.split('/');
|
||
const target = parts[1];
|
||
const action = parts[2];
|
||
|
||
console.log(`Command: ${action} for ${target}`);
|
||
|
||
// Command weiterleiten an Gerät
|
||
this.mqtt.publish(`devices/${target}/command`, {
|
||
action,
|
||
payload: JSON.parse(message),
|
||
timestamp: new Date().toISOString()
|
||
});
|
||
}
|
||
|
||
private getDeviceLocation(deviceId: string): string {
|
||
const locationMap: Record<string, string> = {
|
||
'living-room-01': 'living_room',
|
||
'bedroom-01': 'bedroom',
|
||
'kitchen-01': 'kitchen'
|
||
};
|
||
return locationMap[deviceId] || 'unknown';
|
||
}
|
||
|
||
private updateDeviceStatus(deviceId: string, status: string): void {
|
||
// Status in DB speichern
|
||
console.log(`Device ${deviceId} status: ${status}`);
|
||
}
|
||
|
||
async stop(): Promise<void> {
|
||
this.subscriptions.forEach(unsub => unsub());
|
||
await this.mqtt.disconnect();
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## WebSocket Bridge (Browser)
|
||
|
||
```typescript
|
||
// lib/mqtt-websocket.ts
|
||
import mqtt, { MqttClient } from 'mqtt';
|
||
|
||
class MQTTWebSocketClient {
|
||
private client: MqttClient | null = null;
|
||
|
||
async connect(wsUrl: string, options?: {
|
||
username?: string;
|
||
password?: string;
|
||
}): Promise<void> {
|
||
return new Promise((resolve, reject) => {
|
||
this.client = mqtt.connect(wsUrl, {
|
||
protocol: 'wss',
|
||
clientId: `web_${Math.random().toString(16).slice(2, 8)}`,
|
||
...options
|
||
});
|
||
|
||
this.client.on('connect', () => {
|
||
console.log('WebSocket MQTT connected');
|
||
resolve();
|
||
});
|
||
|
||
this.client.on('error', reject);
|
||
});
|
||
}
|
||
|
||
subscribe(topic: string, callback: (topic: string, message: string) => void): () => void {
|
||
this.client?.subscribe(topic);
|
||
|
||
const handler = (t: string, payload: Buffer) => {
|
||
if (this.topicMatches(topic, t)) {
|
||
callback(t, payload.toString());
|
||
}
|
||
};
|
||
|
||
this.client?.on('message', handler);
|
||
|
||
return () => {
|
||
this.client?.unsubscribe(topic);
|
||
this.client?.removeListener('message', handler);
|
||
};
|
||
}
|
||
|
||
publish(topic: string, message: any): void {
|
||
const payload = typeof message === 'object'
|
||
? JSON.stringify(message)
|
||
: String(message);
|
||
this.client?.publish(topic, payload);
|
||
}
|
||
|
||
private topicMatches(pattern: string, topic: string): boolean {
|
||
const patternParts = pattern.split('/');
|
||
const topicParts = topic.split('/');
|
||
|
||
for (let i = 0; i < patternParts.length; i++) {
|
||
if (patternParts[i] === '#') return true;
|
||
if (patternParts[i] === '+') continue;
|
||
if (patternParts[i] !== topicParts[i]) return false;
|
||
}
|
||
|
||
return patternParts.length === topicParts.length;
|
||
}
|
||
}
|
||
|
||
// React Hook
|
||
import { useState, useEffect, useCallback } from 'react';
|
||
|
||
export function useMQTT(wsUrl: string) {
|
||
const [client] = useState(() => new MQTTWebSocketClient());
|
||
const [connected, setConnected] = useState(false);
|
||
|
||
useEffect(() => {
|
||
client.connect(wsUrl).then(() => setConnected(true));
|
||
}, [wsUrl]);
|
||
|
||
const subscribe = useCallback((
|
||
topic: string,
|
||
callback: (topic: string, message: string) => void
|
||
) => {
|
||
return client.subscribe(topic, callback);
|
||
}, [client]);
|
||
|
||
const publish = useCallback((topic: string, message: any) => {
|
||
client.publish(topic, message);
|
||
}, [client]);
|
||
|
||
return { connected, subscribe, publish };
|
||
}
|
||
|
||
// Verwendung in React Component
|
||
function SensorDashboard() {
|
||
const { connected, subscribe } = useMQTT('wss://mqtt.example.com:9001');
|
||
const [temperature, setTemperature] = useState<number | null>(null);
|
||
|
||
useEffect(() => {
|
||
if (!connected) return;
|
||
|
||
const unsub = subscribe('sensors/+/data', (topic, message) => {
|
||
const data = JSON.parse(message);
|
||
setTemperature(data.temperature);
|
||
});
|
||
|
||
return unsub;
|
||
}, [connected, subscribe]);
|
||
|
||
return (
|
||
<div>
|
||
{connected ? (
|
||
<p>Temperature: {temperature ?? 'Loading...'}°C</p>
|
||
) : (
|
||
<p>Connecting...</p>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Secure MQTT with TLS
|
||
|
||
```typescript
|
||
// lib/secure-mqtt.ts
|
||
import mqtt from 'mqtt';
|
||
import fs from 'fs';
|
||
import path from 'path';
|
||
|
||
const secureClient = mqtt.connect('mqtts://mqtt.example.com:8883', {
|
||
clientId: `secure_${Date.now()}`,
|
||
username: process.env.MQTT_USER,
|
||
password: process.env.MQTT_PASS,
|
||
|
||
// TLS Optionen
|
||
ca: fs.readFileSync(path.join(__dirname, 'certs/ca.crt')),
|
||
cert: fs.readFileSync(path.join(__dirname, 'certs/client.crt')),
|
||
key: fs.readFileSync(path.join(__dirname, 'certs/client.key')),
|
||
|
||
// Bei selbstsignierten Zertifikaten
|
||
rejectUnauthorized: process.env.NODE_ENV === 'production',
|
||
|
||
// Protokoll-Version
|
||
protocolVersion: 5, // MQTT 5.0
|
||
|
||
// Clean Start (MQTT 5.0)
|
||
clean: true,
|
||
|
||
// Session Expiry (MQTT 5.0)
|
||
properties: {
|
||
sessionExpiryInterval: 3600
|
||
}
|
||
});
|
||
|
||
secureClient.on('connect', (connack) => {
|
||
console.log('Secure connection established');
|
||
console.log('Session present:', connack.sessionPresent);
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## QoS Level Comparison
|
||
|
||
| QoS | Name | Garantie | Use Case |
|
||
|-----|------|----------|----------|
|
||
| 0 | At most once | Keine | Telemetrie, unwichtige Daten |
|
||
| 1 | At least once | Zustellung garantiert | Sensor-Daten, Commands |
|
||
| 2 | Exactly once | Keine Duplikate | Zahlungen, kritische Daten |
|
||
|
||
---
|
||
|
||
## Fazit
|
||
|
||
MQTT für IoT bietet:
|
||
|
||
1. **Leichtgewichtig**: Minimaler Overhead
|
||
2. **Publish/Subscribe**: Entkoppelte Kommunikation
|
||
3. **QoS Levels**: Flexible Zustellgarantien
|
||
4. **Wildcards**: Flexible Topic-Struktur
|
||
|
||
Standard für IoT-Kommunikation.
|
||
|
||
---
|
||
|
||
## Bildprompts
|
||
|
||
1. "IoT devices connected through message broker, publish subscribe pattern"
|
||
2. "Sensor data flowing to central hub, MQTT network visualization"
|
||
3. "Quality of Service levels diagram, message delivery guarantee"
|
||
|
||
---
|
||
|
||
## Quellen
|
||
|
||
- [MQTT.js GitHub](https://github.com/mqttjs/MQTT.js/)
|
||
- [HiveMQ MQTT Guide](https://www.hivemq.com/blog/ultimate-guide-on-how-to-use-mqtt-with-node-js/)
|
||
- [EMQX MQTT Tutorial](https://www.emqx.com/en/blog/how-to-use-mqtt-in-nodejs)
|
||
- [Mosquitto Documentation](https://mosquitto.org/documentation/)
|