import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'mqtt_manager.dart'; class ModeKontrolPage extends StatefulWidget { final String title; const ModeKontrolPage({Key? key, required this.title}) : super(key: key); @override _ModeKontrolPageState createState() => _ModeKontrolPageState(); } class _ModeKontrolPageState extends State { bool relaySwitch = false; bool autoSwitch = false; int parameterMinimal = 0; int parameterMaximal = 0; String _soil = '0'; // Nilai default untuk menghindari format exception late MQTTManager _mqttManager; @override void initState() { super.initState(); final clientId = 'flutter_client_${DateTime.now().millisecondsSinceEpoch}'; _mqttManager = MQTTManager( serverUri: '192.168.43.27', // URI server clientId: clientId, // ID Client unik onDataReceived: _onDataReceived, ); _mqttManager.connect(); } void _onDataReceived(String soil, String humidity, String temperature, String intensity, String batLevel) { double adcValue = double.tryParse(soil) ?? 0; double adcMin = 570; double adcMax = 650; // Hitung persentase kelembapan menggunakan rumus kalibrasi double soilPercentage = ((adcMax - adcValue) / (adcMax - adcMin)) * 100; // Pastikan nilai persentase dalam rentang 0-100% if (soilPercentage < 0) soilPercentage = 0; if (soilPercentage > 100) soilPercentage = 100; setState(() { _soil = soilPercentage.toStringAsFixed(2); }); if (autoSwitch) { if (soilPercentage < parameterMinimal) { _publishSwitchStatus(true); // Nyalakan pompa } else if (soilPercentage > parameterMaximal) { _publishSwitchStatus(false); // Matikan pompa } } } void _publishSwitchStatus(bool status) { String switchStatus = status ? 'On' : 'Off'; _mqttManager.publishMessage('home/switch/status', switchStatus); setState(() { relaySwitch = status; }); } @override Widget build(BuildContext context) { double soilValue = double.tryParse(_soil) ?? 0; return Scaffold( appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () { Navigator.pushReplacementNamed(context, '/home'); }, ), backgroundColor: Colors.brown, title: Text( widget.title, style: TextStyle( fontFamily: 'Quicksand', fontWeight: FontWeight.bold, ), ), ), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Column( children: [ const Text( 'Kelembaban Tanah', style: TextStyle( fontSize: 18, ), ), const SizedBox(height: 10), AnimatedSwitcher( duration: Duration(milliseconds: 500), child: SfRadialGauge( key: ValueKey(soilValue), axes: [ RadialAxis( minimum: 0, maximum: 100, ranges: [ GaugeRange( startValue: 0, endValue: 30, color: Colors.red), GaugeRange( startValue: 30, endValue: 70, color: Colors.orange), GaugeRange( startValue: 70, endValue: 100, color: Colors.green), ], pointers: [ NeedlePointer(value: soilValue), ], annotations: [ GaugeAnnotation( widget: Container( child: Text( '$_soil %', style: TextStyle( fontSize: 25, fontWeight: FontWeight.bold), ), ), angle: 90, positionFactor: 0.5, ), ], ), ], ), ), const SizedBox(height: 20), ], ), ), const Divider(), const SizedBox(height: 20), Card( elevation: 5, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const Text( 'Kontrol Manual', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('Kontrol Pompa:'), Switch( value: relaySwitch, onChanged: !autoSwitch // Nonaktifkan kontrol manual saat kontrol otomatis aktif ? (bool value) { setState(() { relaySwitch = value; }); _publishSwitchStatus(value); } : null, ), ], ), ], ), ), ), const SizedBox(height: 20), Card( elevation: 5, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const Text( 'Kontrol Otomatis', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('Kontrol Otomatis:'), Switch( value: autoSwitch, onChanged: (bool value) { setState(() { autoSwitch = value; if (autoSwitch) { relaySwitch = false; // Matikan kontrol manual saat kontrol otomatis aktif _publishSwitchStatus( false); // Pastikan pompa mati saat kontrol otomatis aktif } }); }, ), ], ), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('Parameter Minimum:'), Container( width: 100, child: TextFormField( initialValue: parameterMinimal.toString(), keyboardType: TextInputType.number, decoration: InputDecoration( border: OutlineInputBorder(), ), onChanged: (value) { setState(() { parameterMinimal = int.tryParse(value) ?? parameterMinimal; }); }, ), ), ], ), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('Parameter Maksimum:'), Container( width: 100, child: TextFormField( initialValue: parameterMaximal.toString(), keyboardType: TextInputType.number, decoration: InputDecoration( border: OutlineInputBorder(), ), onChanged: (value) { setState(() { parameterMaximal = int.tryParse(value) ?? parameterMaximal; }); }, ), ), ], ), ], ), ), ), ], ), ), ), ); } }