# MQTT Quick Reference - Client Migration ## 🚨 Kritische Änderungen ### Port-Änderung (WICHTIG!) ``` Alt: mqtt-2.assecutor.de:1883 Neu: mqtt-2.assecutor.de:42099 ``` ### Authentifizierung (NEU!) ``` Username: app Password: apppwd ``` ### Timeout-Erhöhung ``` Connection Timeout: 60 Sekunden (vorher 30s) Keep-Alive: 60 Sekunden (vorher 30s) ``` ## 📋 Flutter/Dart Code-Snippets ### 1. Verbindung herstellen ```dart import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_server_client.dart'; Future connectToMqtt(String clientId) async { final client = MqttServerClient.withPort( 'mqtt-2.assecutor.de', clientId, 42099, // NEUER PORT! ); client.keepAlivePeriod = 60; client.connectTimeoutPeriod = 60000; client.autoReconnect = true; client.setProtocolV311(); final connMessage = MqttConnectMessage() .withClientIdentifier(clientId) .authenticateAs('app', 'apppwd') // NEU: Authentifizierung .withWillQos(MqttQos.atLeastOnce) .startClean() .keepAliveFor(60); client.connectionMessage = connMessage; await client.connect(); return client; } ``` ### 2. Message Envelope (NEU!) ```dart class MessageEnvelope { final String messageId; final DateTime timestamp; final String topic; final Map payload; final bool requiresAck; final int retryCount; final DateTime? expiresAt; MessageEnvelope({ required this.messageId, required this.timestamp, required this.topic, required this.payload, this.requiresAck = true, this.retryCount = 0, this.expiresAt, }); factory MessageEnvelope.fromJson(Map json) { return MessageEnvelope( messageId: json['messageId'], timestamp: DateTime.parse(json['timestamp']), topic: json['topic'], payload: json['payload'], requiresAck: json['requiresAck'] ?? true, retryCount: json['retryCount'] ?? 0, expiresAt: json['expiresAt'] != null ? DateTime.parse(json['expiresAt']) : null, ); } Map toJson() => { 'messageId': messageId, 'timestamp': timestamp.toIso8601String(), 'topic': topic, 'payload': payload, 'requiresAck': requiresAck, 'retryCount': retryCount, if (expiresAt != null) 'expiresAt': expiresAt!.toIso8601String(), }; } ``` ### 3. Nachricht senden ```dart import 'package:uuid/uuid.dart'; import 'dart:convert'; Future sendMessage( MqttServerClient client, String clientId, String messageType, Map payload, ) async { final envelope = MessageEnvelope( messageId: Uuid().v4(), timestamp: DateTime.now(), topic: '/server/$clientId/$messageType', payload: payload, requiresAck: true, ); final builder = MqttClientPayloadBuilder(); builder.addString(jsonEncode(envelope.toJson())); client.publishMessage( envelope.topic, MqttQos.exactlyOnce, builder.payload!, ); } // Beispiel-Verwendung: await sendMessage( client, 'app-user-123', 'task_completed', { 'taskId': '456', 'status': 'completed', 'completedAt': DateTime.now().toIso8601String(), }, ); ``` ### 4. Nachricht empfangen ```dart void setupMessageListener(MqttServerClient client, String clientId) { // Subscribe zu allen relevanten Topics client.subscribe('/client/$clientId/#', MqttQos.exactlyOnce); client.subscribe('/ack/client/$clientId/#', MqttQos.exactlyOnce); client.updates!.listen((List> messages) { for (var message in messages) { final topic = message.topic; final payloadString = MqttPublishPayload.bytesToStringAsString( (message.payload as MqttPublishMessage).payload.message, ); try { final json = jsonDecode(payloadString); // Prüfen ob Envelope-Format if (json.containsKey('messageId') && json.containsKey('payload')) { final envelope = MessageEnvelope.fromJson(json); // Nachricht verarbeiten handleEnvelopeMessage(envelope); // ACK senden wenn erforderlich if (envelope.requiresAck) { sendAck(client, envelope.messageId, true); } } else { // Legacy-Format handleLegacyMessage(topic, json); } } catch (e) { print('Error processing message: $e'); } } }); } ``` ### 5. Acknowledgment senden (NEU!) ```dart class AcknowledgmentMessage { final String messageId; final DateTime timestamp; final String status; final String? errorMessage; AcknowledgmentMessage({ required this.messageId, required this.timestamp, required this.status, this.errorMessage, }); Map toJson() => { 'messageId': messageId, 'timestamp': timestamp.toIso8601String(), 'status': status, if (errorMessage != null) 'errorMessage': errorMessage, }; } void sendAck( MqttServerClient client, String messageId, bool success, [String? errorMessage] ) { final ack = AcknowledgmentMessage( messageId: messageId, timestamp: DateTime.now(), status: success ? 'SUCCESS' : 'FAILED', errorMessage: errorMessage, ); final topic = '/ack/server/$messageId'; final builder = MqttClientPayloadBuilder(); builder.addString(jsonEncode(ack.toJson())); client.publishMessage( topic, MqttQos.exactlyOnce, builder.payload!, ); } ``` ## 📊 Topic-Struktur (unverändert) ### Client → Server ``` /server/{clientId}/task_completed /server/{clientId}/login /server/{clientId}/message /server/{clientId}/jobs/assigned ``` ### Server → Client ``` /client/{clientId}/jobs/assigned /client/{clientId}/message /client/{clientId}/task_update ``` ### Acknowledgments ``` Client → Server: /ack/server/{messageId} Server → Client: /ack/client/{clientId}/{messageId} ``` ## 🔍 Debugging ### Verbindung testen ```dart Future testConnection() async { try { final client = await connectToMqtt('test-${Uuid().v4()}'); if (client.connectionStatus!.state == MqttConnectionState.connected) { print('✅ Connection successful!'); // Test-Nachricht senden await sendMessage( client, 'test-client', 'test', {'message': 'Hello from client'}, ); print('✅ Test message sent!'); } else { print('❌ Connection failed: ${client.connectionStatus}'); } } catch (e) { print('❌ Error: $e'); } } ``` ### Häufige Fehler #### 1. Connection Timeout ``` Fehler: TimeoutException after 60 seconds Lösung: - Prüfen Sie, ob Port 42099 erreichbar ist - Firewall-Einstellungen überprüfen - Netzwerkverbindung testen ``` #### 2. Authentication Failed ``` Fehler: Connection refused Lösung: - Username: 'app' - Password: 'apppwd' - Stellen Sie sicher, dass authenticateAs() aufgerufen wird ``` #### 3. Message not received ``` Fehler: Keine Nachrichten empfangen Lösung: - Subscription überprüfen: client.subscribe('/client/$clientId/#', ...) - Listener registriert: client.updates!.listen(...) - Topic-Format korrekt: /client/{clientId}/{messageType} ``` ## 📦 Dependencies ### pubspec.yaml ```yaml dependencies: mqtt_client: ^10.2.0 uuid: ^4.0.0 ``` ## ✅ Migration Checklist - [ ] Port auf 42099 geändert - [ ] Authentifizierung hinzugefügt (app/apppwd) - [ ] Connection-Timeout auf 60s erhöht - [ ] Keep-Alive auf 60s gesetzt - [ ] MessageEnvelope-Klasse implementiert - [ ] AcknowledgmentMessage-Klasse implementiert - [ ] Envelope-basiertes Senden implementiert - [ ] Envelope-basiertes Empfangen implementiert - [ ] ACK-Handling implementiert - [ ] Fehlerbehandlung für ACKs implementiert - [ ] Verbindung getestet - [ ] Nachrichtenversand getestet - [ ] Nachrichtenempfang getestet ## 🔗 Weitere Dokumentation - **Detaillierte Migration**: `MQTT_MIGRATION_GUIDE.md` - **Changelog**: `CHANGELOG_MQTT.md` - **Architektur**: `MESSAGING_LAYER.md` - **API-Referenz**: `MQTT_README.md` ## 💡 Best Practices 1. **Eindeutige Client-IDs**: Verwenden Sie stabile, geräte-spezifische IDs 2. **Fehlerbehandlung**: Implementieren Sie Retry-Logik für fehlgeschlagene Verbindungen 3. **ACK-Timeout**: Warten Sie maximal 30 Sekunden auf ACKs 4. **Message-Expiry**: Prüfen Sie `expiresAt` vor der Verarbeitung 5. **Logging**: Loggen Sie alle Verbindungsereignisse für Debugging ## 🆘 Support Bei Problemen: 1. Logs auf Client- und Server-Seite prüfen 2. Netzwerk-Konnektivität testen (Port 42099) 3. MQTT-Client-Tool verwenden (z.B. MQTT Explorer) 4. Dokumentation konsultieren