E32221333_iot-penyiraman-ja.../lib/main.dart

443 lines
13 KiB
Dart

import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:async';
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: const FirebaseOptions(
databaseURL: 'https://rifky-ea47a-default-rtdb.firebaseio.com',
apiKey:
'AIzaSyCtV4taj9jDIY31GtedIWmS9z5zP8JPmmY', // You'll need to add your API key here
appId:
'1:381205401183:web:2d37bb3d8cb686227115ea', // You need to get this from Firebase Console
messagingSenderId:
'381205401183', // You'll need to add your Sender ID here
projectId: 'rifky-ea47a', // Your project ID
),
);
await initializeService();
runApp(const MyApp());
}
Future<void> initializeService() async {
final service = FlutterBackgroundService();
/// OPTIONAL, using custom notification channel id
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'my_foreground', // id
'MY FOREGROUND SERVICE', // title
description:
'This channel is used for important notifications.', // description
importance: Importance.low, // importance must be at low or higher level
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher'); // TANPA .png
const InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
);
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await service.configure(
androidConfiguration: AndroidConfiguration(
// this will be executed when app is in foreground or background in separated isolate
onStart: onStart,
// auto start service
autoStart: true,
isForegroundMode: true,
notificationChannelId: 'my_foreground',
initialNotificationTitle: 'Jamur',
initialNotificationContent: 'Jamur Sedang Berjalan',
foregroundServiceNotificationId: 888,
foregroundServiceTypes: [AndroidForegroundType.location],
),
iosConfiguration: IosConfiguration(
// auto start service
autoStart: true,
// this will be executed when app is in foreground in separated isolate
onForeground: onStart,
// you have to enable background fetch capability on xcode project
onBackground: onIosBackground,
),
);
}
// to ensure this is executed
// run app from xcode, then from xcode menu, select Simulate Background Fetch
@pragma('vm:entry-point')
Future<bool> onIosBackground(ServiceInstance service) async {
WidgetsFlutterBinding.ensureInitialized();
DartPluginRegistrant.ensureInitialized();
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.reload();
final log = preferences.getStringList('log') ?? <String>[];
log.add(DateTime.now().toIso8601String());
await preferences.setStringList('log', log);
return true;
}
@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
DartPluginRegistrant.ensureInitialized();
await Firebase.initializeApp();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final DatabaseReference _database = FirebaseDatabase.instance.ref();
double? lastTemp;
double? lastHumidity;
// Listener suhu
_database.child('Temperature').onValue.listen((event) async {
final data = event.snapshot.value;
if (data != null) {
final double temp = double.tryParse(data.toString()) ?? 0.0;
if (temp >= 30 && (lastTemp == null || lastTemp! < 30)) {
await showNotification(
'Suhu Tinggi!',
'Suhu sekarang $temp°C. Aktifkan kipas!',
);
}
lastTemp = temp;
}
});
// Listener kelembaban
_database.child('Humidity').onValue.listen((event) async {
final data = event.snapshot.value;
if (data != null) {
final double humidity = double.tryParse(data.toString()) ?? 0.0;
if (humidity <= 70 && (lastHumidity == null || lastHumidity! > 70)) {
await showNotification(
'Kelembaban Rendah!',
'Humidity sekarang $humidity%. Periksa kelembaban ruangan.',
);
}
lastHumidity = humidity;
}
});
// Background service commands
if (service is AndroidServiceInstance) {
service.on('setAsForeground').listen((event) {
service.setAsForegroundService();
});
service.on('setAsBackground').listen((event) {
service.setAsBackgroundService();
});
}
service.on('stopService').listen((event) {
service.stopSelf();
});
}
Future<void> showNotification(String title, String body) async {
const androidDetails = AndroidNotificationDetails(
'temp_channel_id',
'Temperature Alerts',
channelDescription: 'Notification for temperature threshold',
importance: Importance.max,
priority: Priority.high,
showWhen: false,
);
const platformDetails = NotificationDetails(android: androidDetails);
await flutterLocalNotificationsPlugin.show(
0,
title,
body,
platformDetails,
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Monitoring App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const MonitoringScreen(),
);
}
}
class MonitoringScreen extends StatefulWidget {
const MonitoringScreen({super.key});
@override
State<MonitoringScreen> createState() => _MonitoringScreenState();
}
class _MonitoringScreenState extends State<MonitoringScreen> {
final DatabaseReference _database = FirebaseDatabase.instance.ref();
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
Map<String, dynamic> _monitoringData = {
'Fan': 'OFF',
'Humidity': 0.0,
'Pump': 'OFF',
'Temperature': 0.0,
};
@override
void initState() {
super.initState();
//_initializeNotifications(); // Inisialisasi notifikasi
_setupRealtimeUpdates();
}
// void _initializeNotifications() {
// flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// const AndroidInitializationSettings initializationSettingsAndroid =
// AndroidInitializationSettings('@mipmap/ic_launcher');
// const InitializationSettings initializationSettings =
// InitializationSettings(android: initializationSettingsAndroid);
// flutterLocalNotificationsPlugin.initialize(initializationSettings);
// }
// Future<void> _showNotification(String title, String body) async {
// const AndroidNotificationDetails androidPlatformChannelSpecifics =
// AndroidNotificationDetails(
// 'temp_channel_id',
// 'Temperature Alerts',
// importance: Importance.max,
// priority: Priority.high,
// showWhen: false,
// );
// const NotificationDetails platformChannelSpecifics =
// NotificationDetails(android: androidPlatformChannelSpecifics);
// await flutterLocalNotificationsPlugin.show(
// 0, // Notification ID
// title,
// body,
// platformChannelSpecifics,
// );
// }
void _setupRealtimeUpdates() {
_database.onValue.listen((DatabaseEvent event) {
if (event.snapshot.value != null) {
setState(() {
_monitoringData =
Map<String, dynamic>.from(event.snapshot.value as Map);
});
}
});
}
void _toggleDevice(String device) {
final currentStatus = _monitoringData[device] as String;
final newStatus = currentStatus == 'ON' ? 'OFF' : 'ON';
_database.update({device: newStatus});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Monitoring & Control Dashboard'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Monitoring',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: _buildMonitoringCard(
'Temperature',
'${_monitoringData['Temperature']}°C',
Icons.thermostat,
Colors.red,
),
),
const SizedBox(width: 16),
Expanded(
child: _buildMonitoringCard(
'Humidity',
'${_monitoringData['Humidity']}%',
Icons.water_drop,
Colors.blue,
),
),
],
),
const SizedBox(height: 32),
const Text(
'Control',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: _buildControlCard(
'Fan',
_monitoringData['Fan'] ?? 'OFF',
Icons.air,
Colors.green,
() => _toggleDevice('Fan'),
),
),
const SizedBox(width: 16),
Expanded(
child: _buildControlCard(
'Pump',
_monitoringData['Pump'] ?? 'OFF',
Icons.water,
Colors.orange,
() => _toggleDevice('Pump'),
),
),
],
),
],
),
),
),
);
}
Widget _buildMonitoringCard(
String title, String value, IconData icon, Color color) {
return Card(
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Icon(icon, size: 40, color: color),
const SizedBox(height: 8),
Text(
title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
value,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: color,
),
),
],
),
),
);
}
Widget _buildControlCard(String title, String status, IconData icon,
Color color, VoidCallback onTap) {
return Card(
elevation: 4,
child: InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Icon(icon, size: 40, color: color),
const SizedBox(height: 8),
Text(
title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Container(
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: status == 'ON' ? Colors.green : Colors.red,
borderRadius: BorderRadius.circular(20),
),
child: Text(
status,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
const SizedBox(height: 8),
Text(
'Tap to toggle',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
],
),
),
),
);
}
}