TKK_E32222428/lib/services/mqtt_service.dart

206 lines
5.7 KiB
Dart

import 'dart:convert';
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;
// Data sensor
String _suhu = "0";
String _kelembapan = "0";
String _intensitas = "0";
bool _isKipas1On = false;
bool _isKipas2On = false;
String _mode = "otomatis";
String _timestamp = "-";
// Batas sensor
double _maxSuhu = 45.0;
double _maxRh = 70.0;
// Getter sensor
String get suhu => _suhu;
String get kelembapan => _kelembapan;
String get intensitas => _intensitas;
bool get isKipas1On => _isKipas1On;
bool get isKipas2On => _isKipas2On;
String get mode => _mode;
String get timestamp => _timestamp;
// Getter batas
double _minSuhu = 0.0;
double _minRh = 0.0;
double get maxSuhu => _maxSuhu;
double get maxRh => _maxRh;
double get minSuhu => _minSuhu;
double get minRh => _minRh;
Function(String, bool)? onConnectionResult;
void setLimits(double suhuMax, double rhMax, double suhuMin, double rhMin) {
_maxSuhu = suhuMax;
_maxRh = rhMax;
_minSuhu = suhuMin;
_minRh = rhMin;
notifyListeners();
}
Future<bool> connect() async {
final String clientId =
'flutter_kopi_${DateTime.now().millisecondsSinceEpoch % 10000}';
client = MqttServerClient.withPort(
's1fd277a.ala.asia-southeast1.emqxsl.com', // EMQX host baru
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: kDebugMode);
final connMess = MqttConnectMessage()
.withClientIdentifier(clientId)
.authenticateAs('kopi_user', 'Kopikopi1')
.startClean();
client!.connectionMessage = connMess;
try {
await client!.connect();
} catch (e) {
debugPrint('MQTT Exception: $e');
onConnectionResult?.call('Koneksi Gagal: $e', false);
client!.disconnect();
return false;
}
if (client?.connectionStatus?.state == MqttConnectionState.connected) {
debugPrint('MQTT: Terhubung!');
onConnectionResult?.call(' Terhubung ke Server Kopi', true);
_subscribeToTopics();
notifyListeners();
return true;
} else {
onConnectionResult?.call(' Koneksi Gagal', false);
notifyListeners();
return false;
}
}
void _subscribeToTopics() {
client!.subscribe("kopi/sensor", MqttQos.atMostOnce);
client!.subscribe("kopi/relay/kipas1", MqttQos.atMostOnce);
client!.subscribe("kopi/relay/kipas2", MqttQos.atMostOnce);
client!.subscribe("kopi/relay/mode", MqttQos.atMostOnce);
client!.updates!.listen((List<MqttReceivedMessage<MqttMessage?>>? c) {
if (c == null || c.isEmpty) return;
final recMess = c[0].payload as MqttPublishMessage;
final pt = MqttPublishPayload.bytesToStringAsString(
recMess.payload.message);
final topic = c[0].topic;
if (topic == "kopi/sensor") {
try {
final data = jsonDecode(pt);
_suhu = data['suhu'].toString();
_kelembapan = data['kelembapan'].toString();
_intensitas = data['intensitas'].toString();
_isKipas1On = data['kipas1'] == 'ON';
_isKipas2On = data['kipas2'] == 'ON';
_mode = data['mode'] ?? 'otomatis';
_timestamp = data['timestamp'] ?? '-';
} catch (e) {
debugPrint('MQTT parse error: $e');
}
}
if (topic == "kopi/relay/kipas1") _isKipas1On = (pt == "ON");
if (topic == "kopi/relay/kipas2") _isKipas2On = (pt == "ON");
if (topic == "kopi/relay/mode") _mode = pt;
notifyListeners();
});
}
// Kirim perintah kipas manual
void perintahKipas(String nomorKipas, bool nyala) {
final payload = jsonEncode({
"kipas": nomorKipas,
"status": nyala ? "ON" : "OFF",
});
_publish("kopi/relay/manual", payload);
}
// Ganti mode otomatis/manual
void gantiMode(String mode) {
_publish("kopi/relay/mode", mode);
}
// Kirim interval foto dalam menit
// Kirim 0 untuk stop
void setIntervalFoto(int menit) {
if (menit == 0) {
_publish("kopi/setting/interval", "0");
} else {
_publish("kopi/setting/interval", menit.toString());
}
}
// Trigger foto manual
void triggerFoto() {
_publish("kopi/trigger/foto", "AMBIL");
}
// Kirim batas sensor ke ESP32 dan Node-RED
void setBatasSensor(
double suhuMin, double suhuMax, double rhMin, double rhMax) {
final payload = jsonEncode({
"suhu_min": suhuMin,
"suhu_max": suhuMax,
"rh_min": rhMin,
"rh_max": rhMax,
});
_publish("kopi/setting/batas", payload);
}
void _publish(String topic, String message) {
if (client?.connectionStatus?.state != MqttConnectionState.connected) {
debugPrint('MQTT: Tidak terhubung, tidak bisa publish');
return;
}
final builder = MqttClientPayloadBuilder();
builder.addString(message);
client!.publishMessage(topic, MqttQos.atMostOnce, builder.payload!);
debugPrint('MQTT publish → $topic : $message');
}
void onConnected() {
debugPrint('MQTT: onConnected');
notifyListeners();
}
void onDisconnected() {
debugPrint('MQTT: onDisconnected');
// 🔥 AUTO RECONNECT
Future.delayed(const Duration(seconds: 3), () {
debugPrint('MQTT: mencoba reconnect...');
connect();
});
notifyListeners();
}
void disconnect() {
client?.disconnect();
}
}