import 'dart:io'; import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_server_client.dart'; import 'package:flutter/foundation.dart'; class MqttService extends ChangeNotifier { MqttServerClient? client; String _temp = "25"; String _humidity = "55"; String _light = "125"; bool _isIntakeOn = false; bool _isExhaustOn = false; String _currentMode = "MANUAL"; double _maxTemp = 48.0; double _maxHum = 75.0; String get temp => _temp; String get humidity => _humidity; String get light => _light; bool get isIntakeOn => _isIntakeOn; bool get isExhaustOn => _isExhaustOn; String get currentMode => _currentMode; double get maxTemp => _maxTemp; double get maxHum => _maxHum; void setLimits(double t, double h) { _maxTemp = t; _maxHum = h; notifyListeners(); } // Callback for UI notifications Function(String, bool)? onConnectionResult; Future connect() async { final String clientId = 'cli_kopi_${DateTime.now().millisecondsSinceEpoch % 10000}'; client = MqttServerClient.withPort( '1f7929299fd649388da5f2e234152531.s1.eu.hivemq.cloud', clientId, 8883 ); client!.secure = true; client!.setProtocolV311(); client!.onBadCertificate = (dynamic cert) => true; client!.keepAlivePeriod = 20; client!.connectTimeoutPeriod = 10000; client!.onDisconnected = onDisconnected; client!.onConnected = onConnected; client!.logging(on: true); final connMess = MqttConnectMessage() .withClientIdentifier(clientId) .authenticateAs('kopi_user', 'Kopikopi1') .startClean(); client!.connectionMessage = connMess; try { debugPrint('MQTT: Connecting to HiveMQ...'); await client!.connect(); } catch (e) { debugPrint('MQTT Exception: $e'); onConnectionResult?.call('Koneksi Gagal: $e', false); client!.disconnect(); } if (client?.connectionStatus?.state == MqttConnectionState.connected) { debugPrint('MQTT: SUCCESS!'); onConnectionResult?.call('✅ Terhubung ke Server Kopi', true); _subscribeToTopics(); notifyListeners(); return true; } else { onConnectionResult?.call('❌ Koneksi Terputus', false); notifyListeners(); return false; } } void _subscribeToTopics() { client!.subscribe("coffee/temp", MqttQos.atMostOnce); client!.subscribe("coffee/humidity", MqttQos.atMostOnce); client!.subscribe("coffee/light", MqttQos.atMostOnce); client!.subscribe("coffee/intake", MqttQos.atMostOnce); client!.subscribe("coffee/exhaust", MqttQos.atMostOnce); client!.subscribe("coffee/config/mode", MqttQos.atMostOnce); client!.updates!.listen((List>? c) { final recMess = c![0].payload as MqttPublishMessage; final pt = MqttPublishPayload.bytesToStringAsString(recMess.payload.message); final topic = c[0].topic; if (topic == "coffee/temp") _temp = pt; if (topic == "coffee/humidity") _humidity = pt; if (topic == "coffee/light") _light = pt; if (topic == "coffee/intake") _isIntakeOn = (pt == "ON"); if (topic == "coffee/exhaust") _isExhaustOn = (pt == "ON"); if (topic == "coffee/config/mode") _currentMode = pt; notifyListeners(); }); } void publish(String topic, String message) { if (topic == "coffee/intake") _isIntakeOn = (message == "ON"); if (topic == "coffee/exhaust") _isExhaustOn = (message == "ON"); notifyListeners(); if (client?.connectionStatus?.state == MqttConnectionState.connected) { final builder = MqttClientPayloadBuilder(); builder.addString(message); client!.publishMessage(topic, MqttQos.exactlyOnce, builder.payload!); } } void onConnected() { notifyListeners(); } void onDisconnected() { notifyListeners(); } void updateFromLastLog(String t, String h, String l, bool i, bool e) { _temp = t; _humidity = h; _light = l; _isIntakeOn = i; _isExhaustOn = e; notifyListeners(); } }