166 lines
5.7 KiB
Dart
166 lines
5.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:firebase_database/firebase_database.dart';
|
|
import 'package:intl/intl.dart';
|
|
|
|
class RealtimeMonitoring extends StatefulWidget {
|
|
const RealtimeMonitoring({super.key});
|
|
|
|
@override
|
|
State<RealtimeMonitoring> createState() => _RealtimeMonitoringState();
|
|
}
|
|
|
|
class _RealtimeMonitoringState extends State<RealtimeMonitoring> {
|
|
final DatabaseReference _ref = FirebaseDatabase.instance.ref('monitoring');
|
|
Map<dynamic, dynamic> _data = {};
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
// Mendengarkan perubahan data pada node 'monitoring' di Firebase
|
|
_ref.onValue.listen((event) {
|
|
final value = event.snapshot.value;
|
|
if (value != null && value is Map) {
|
|
setState(() {
|
|
_data = value;
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
// Mengambil data dari _data map, dengan nilai default jika null
|
|
final suhu = _data['suhu_udara']?.toStringAsFixed(1) ?? '-';
|
|
final ph = _data['ph']?.toStringAsFixed(2) ?? '-';
|
|
final tds = _data['tds']?.toString() ?? '-';
|
|
final timestamp = _data['timestamp'];
|
|
|
|
String timeString = '-';
|
|
if (timestamp != null && timestamp is int) {
|
|
// Mengonversi Unix timestamp ke format tanggal dan waktu yang mudah dibaca
|
|
final time = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
|
|
timeString = DateFormat('dd MMM yyyy HH:mm:ss').format(time);
|
|
}
|
|
|
|
// Status perangkat
|
|
final fanStatus = (_data['fan'] ?? false) ? 'ON' : 'OFF';
|
|
final pompaUtamaStatus = (_data['pompa'] ?? false) ? 'ON' : 'OFF';
|
|
final pompaAbMixStatus = (_data['pompa_abmix'] ?? false) ? 'ON' : 'OFF';
|
|
final abmixHabisStatus = (_data['abmix_habis'] ?? false) ? 'YA' : 'TIDAK';
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(title: const Text('Realtime Data'), centerTitle: true),
|
|
body: SingleChildScrollView(
|
|
// <--- PERBAIKAN: Tambahkan SingleChildScrollView di sini
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Card(
|
|
elevation: 6,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(20.0),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment:
|
|
CrossAxisAlignment.stretch, // Agar tabel mengisi lebar
|
|
children: [
|
|
const Text(
|
|
"📊 Data Realtime Monitoring",
|
|
style: TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.green,
|
|
),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
const SizedBox(height: 20),
|
|
// Tabel untuk menampilkan data
|
|
Table(
|
|
columnWidths: const {
|
|
0: FlexColumnWidth(1.5), // Label
|
|
1: FlexColumnWidth(2.5), // Value
|
|
},
|
|
border: TableBorder.all(
|
|
color: Colors.grey.shade300,
|
|
borderRadius: BorderRadius.circular(10),
|
|
width: 1.0,
|
|
),
|
|
children: [
|
|
_buildTableRow('Waktu Update', timeString),
|
|
_buildTableRow('Suhu Udara', '$suhu °C'),
|
|
_buildTableRow('TDS', '$tds ppm'),
|
|
_buildTableRow('pH', ph),
|
|
_buildTableRow(
|
|
'Kipas',
|
|
fanStatus,
|
|
statusColor: fanStatus == 'ON'
|
|
? Colors.green
|
|
: Colors.red,
|
|
),
|
|
_buildTableRow(
|
|
'Pompa Utama',
|
|
pompaUtamaStatus,
|
|
statusColor: pompaUtamaStatus == 'ON'
|
|
? Colors.green
|
|
: Colors.red,
|
|
),
|
|
_buildTableRow(
|
|
'Pompa AB Mix',
|
|
pompaAbMixStatus,
|
|
statusColor: pompaAbMixStatus == 'ON'
|
|
? Colors.green
|
|
: Colors.red,
|
|
),
|
|
_buildTableRow(
|
|
'AB Mix Habis',
|
|
abmixHabisStatus,
|
|
statusColor: abmixHabisStatus == 'YA'
|
|
? Colors.red
|
|
: Colors.green,
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 20),
|
|
Text(
|
|
"Data diperbarui secara otomatis dari ESP32.",
|
|
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// Fungsi pembantu untuk membuat baris tabel
|
|
TableRow _buildTableRow(String label, String value, {Color? statusColor}) {
|
|
return TableRow(
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(10.0),
|
|
child: Text(
|
|
label,
|
|
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 16),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(10.0),
|
|
child: Text(
|
|
value,
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 16,
|
|
color:
|
|
statusColor ?? Colors.black, // Gunakan warna status jika ada
|
|
),
|
|
textAlign: TextAlign.right, // Rata kanan untuk nilai
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|