import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_database/firebase_database.dart'; import '../models/sensor_data.dart'; class FirebaseService { final DatabaseReference _database = FirebaseDatabase.instance.ref(); final FirebaseFirestore _firestore = FirebaseFirestore.instance; // === PENGAMBILAN PATH RTDB === Stream getSensorData() { return _database.onValue.map((event) { final data = event.snapshot.value as Map; return SensorData( suhu: (data['suhu'] ?? 0.0).toDouble(), timer: data['timer'] ?? 0, manualMode: data['manualMode'] ?? false, manualButton: data['manualButton'] ?? false, elemen: data['elemen']?.toString() ?? 'off', suhuMaks: data['suhuMaks'] ?? 45, suhuMin: data['suhuMin'] ?? 40, kadarAir: (data['kadarAir'] ?? 0.0).toDouble(), ); }); } // === UPDATEDATA RTDB === Future updateManualMode(bool value) => _database.child('manualMode').set(value); Future updateManualButton(bool value) => _database.child('manualButton').set(value); Future updateElemen(String value) => _database.child('elemen').set(value); Future updateTimer(int value) => _database.child('timer').set(value); Future updateSuhuMaks(int value) => _database.child('suhuMaks').set(value); Future updateSuhuMin(int value) => _database.child('suhuMin').set(value); Future updateKadarAir(double value) => _database.child('kadarAir').set(value); Future updateKoneksiAndroid(bool value) => _database.child('koneksiandroid').set(value); // Fungsi untuk mereset timer ke 0 Future resetTimer() => _database.child('timer').set(0); // === SYNC DATA RTDB TO FIRESTORE === /// Sinkron seluruh data dari RTDB path ke koleksi Firestore Future syncPathToFirestore( String rtdbPath, String firestoreCollection) async { try { final snapshot = await _database.child(rtdbPath).get(); if (!snapshot.exists) return; final data = snapshot.value as Map; final batch = _firestore.batch(); data.forEach((key, value) { final docData = Map.from(value as Map) ..['timestamp'] = FieldValue.serverTimestamp(); final docRef = _firestore.collection(firestoreCollection).doc(key.toString()); batch.set(docRef, docData); }); await batch.commit(); print('Sync RTDB `$rtdbPath` → Firestore `$firestoreCollection` selesai'); } catch (e) { print('Error syncPathToFirestore: $e'); } } /// Mirror perubahan RTDB secara realtime ke Firestore void listenAndMirror(String rtdbPath, String firestoreCollection) { final ref = _database.child(rtdbPath); ref.onChildAdded.listen((event) { final key = event.snapshot.key!; final data = Map.from(event.snapshot.value as Map) ..['timestamp'] = FieldValue.serverTimestamp(); _firestore .collection(firestoreCollection) .doc(key) .set(data) .then((_) => verifyDocument(key)) .catchError((err) => print('onChildAdded error: $err')); }, onError: (err) => print('RTDB onChildAdded listener error: $err')); ref.onChildChanged.listen((event) { final key = event.snapshot.key!; final data = Map.from(event.snapshot.value as Map); _firestore .collection(firestoreCollection) .doc(key) .update(data) .catchError((err) => print('onChildChanged error: $err')); }, onError: (err) => print('RTDB onChildChanged listener error: $err')); ref.onChildRemoved.listen((event) { final key = event.snapshot.key!; _firestore .collection(firestoreCollection) .doc(key) .delete() .catchError((err) => print('onChildRemoved error: $err')); }, onError: (err) => print('RTDB onChildRemoved listener error: $err')); } /// Verifikasi bahwa dokumen tersimpan di Firestore Future verifyDocument(String docId) async { try { final doc = await _firestore.collection('sensorData_firestore').doc(docId).get(); if (doc.exists) { print('Verifikasi berhasil: ${doc.data()}'); } else { print('Dokumen $docId tidak ditemukan di Firestore'); } } catch (e) { print('Verifikasi error: $e'); } } }