TKK_E32230814/DUAL_MODE_IMPLEMENTATION.md

12 KiB
Raw Blame History

🎉 Implementasi Dual Mode System & Bug Fixes

Tanggal: 26 Januari 2026
Status: COMPLETED


🚀 Fitur Baru: Dual Mode System

Mode 1: Smart Mode (Adaptif) 🧠

Konsep:

  • Pompa ON: ketika soil < Batas Minimal
  • Pompa OFF: ketika soil >= Batas Maksimal ATAU timeout (durasi habis)
  • Prioritas: Mencapai target > durasi

Cara Kerja:

Trigger: soil_1 = 25% < 30% (batas minimal)
├─ Pompa Air ON
├─ Valve POT 1 ON
├─ Loop setiap 5 detik:
│  ├─ Check soil_1 value
│  ├─ Jika soil_1 >= 80% → STOP (target tercapai) ✅
│  └─ Jika waktu >= durasi (misal 60s) → STOP (timeout) ⏱️
└─ Pompa & Valve OFF

Log Example:

🧠 Smart Mode: Target soil_1 >= 80 (currently: 25), max 60s
💧 POT 1 watering: 5s, soil_1: 35
💧 POT 1 watering: 10s, soil_1: 55
💧 POT 1 watering: 15s, soil_1: 82
✅ POT 1 reached target: 82 >= 80 (Smart Mode)
✅ Sensor Mode: Watering completed for POT 1 (15s, mode: smart)

Use Case:

  • Tanaman sensitif terhadap over-watering
  • Ingin efisiensi air maksimal
  • Sensor soil moisture berfungsi baik

Mode 2: Fixed Duration (Durasi Tetap) ⏱️

Konsep:

  • Pompa ON: ketika soil < Batas Minimal
  • Pompa OFF: setelah tepat durasi yang ditentukan
  • Prioritas: Durasi tetap (tidak peduli sensor)

Cara Kerja:

Trigger: soil_1 = 25% < 30% (batas minimal)
├─ Pompa Air ON
├─ Valve POT 1 ON
├─ Loop setiap 5 detik (monitoring only):
│  ├─ Log soil_1 value (tidak break)
│  └─ Continue sampai durasi habis
└─ Setelah durasi (misal 30s) → Pompa & Valve OFF

Log Example:

⏱️ Fixed Duration Mode: Watering for exactly 30s
💧 POT 1 watering: 5s/30s, soil_1: 40
💧 POT 1 watering: 10s/30s, soil_1: 60
💧 POT 1 watering: 15s/30s, soil_1: 78
💧 POT 1 watering: 20s/30s, soil_1: 88
💧 POT 1 watering: 25s/30s, soil_1: 92
💧 POT 1 watering: 30s/30s, soil_1: 95
✅ POT 1 fixed duration completed: 30s
✅ Sensor Mode: Watering completed for POT 1 (30s, mode: fixed)

Use Case:

  • Sensor tidak akurat atau rusak
  • Ingin penyiraman konsisten setiap kali
  • Sudah tahu berapa lama perlu menyiram

🎨 UI Changes

Sensor Config Page

Tambahan Baru:

┌─────────────────────────────────────────────┐
│ Mode Penyiraman                             │
├─────────────────────────────────────────────┤
│ ● Smart Mode (Adaptif)                      │
│   Siram hingga batas atas tercapai atau     │
│   timeout                                   │
├─────────────────────────────────────────────┤
│ ○ Fixed Duration (Durasi Tetap)            │
│   Siram selama durasi yang ditentukan      │
└─────────────────────────────────────────────┘

Batas Minimal (%): 30
Batas Maksimal (%): 80
Durasi Penyiraman: 10 detik

 Smart Mode: Pompa akan mati otomatis saat 
   mencapai batas atas atau durasi habis 
   sebagai safety timeout

   Fixed Duration: Pompa akan menyiram selama 
   durasi yang ditentukan, tidak peduli nilai 
   sensor

Interaksi:

  • Radio buttons untuk pilih mode
  • Info text berubah dinamis sesuai mode
  • Durasi memiliki fungsi berbeda per mode:
    • Smart: Max timeout (safety)
    • Fixed: Durasi aktual penyiraman

🔧 Technical Implementation

1. Data Model Changes

Local Storage (sensor_config):

{
  'batasMinimal': '30',
  'batasMaksimal': '80',
  'durasi': '10',
  'durasiUnit': 'detik',
  'mode': 'smart',  // ← NEW: 'smart' or 'fixed'
}

Firebase (kontrol):

{
  "batas_atas": 80,
  "batas_bawah": 30,
  "durasi_sensor": 10,      // ← NEW: dalam detik
  "mode_sensor": "smart",   // ← NEW: 'smart' or 'fixed'
  "otomatis": true
}

2. Code Changes

File Modified:

  1. lib/screens/sensor_config_page.dart

    • Tambah radio buttons untuk mode selection
    • Update _sensorConfig dengan field mode
    • Convert durasi ke seconds sebelum save ke Firebase
    • Dynamic info text berdasarkan mode
  2. lib/services/kontrol_automation_service.dart

    • Update _checkSensorThreshold() untuk ambil mode_sensor dan durasi_sensor
    • Update _waterPotBySensor() dengan parameter mode dan durasiSeconds
    • Implementasi dual logic dengan if-else:
      • Smart mode: break jika soil >= batasAtas
      • Fixed mode: continue sampai durasi habis
  3. lib/services/firebase_database_service.dart

    • Tidak perlu perubahan, sudah support updateKontrolConfig()

3. Logic Flow

Smart Mode:

if (mode == 'smart') {
  while (elapsedSeconds < durasiSeconds && _isSensorModeActive) {
    await Future.delayed(Duration(seconds: 5));
    elapsedSeconds += 5;
    
    currentSoil = await getSensorData();
    
    if (currentSoil >= batasAtas) {
      break; // ✅ Target tercapai
    }
  }
  
  if (elapsedSeconds >= durasiSeconds) {
    // ⏰ Timeout (safety)
  }
}

Fixed Mode:

if (mode == 'fixed') {
  while (elapsedSeconds < durasiSeconds && _isSensorModeActive) {
    await Future.delayed(Duration(seconds: 5));
    elapsedSeconds += 5;
    
    currentSoil = await getSensorData(); // Log only, tidak break
  }
  
  // ✅ Durasi selesai
}

🐛 Bug Fixes

Bug #1: Logout Tiba-tiba ke Login Page FIXED

Root Cause:

  • Auth state listener trigger saat first load
  • Listener tidak memeriksa apakah user sudah login sebelumnya
  • Bisa menyebabkan loop redirect

Solution:

class _DashboardPageState extends State<DashboardPage> {
  bool _isInitialized = false;
  
  @override
  void initState() {
    super.initState();
    
    // Verify user on init
    if (_authService.currentUser == null) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (mounted) {
          Navigator.of(context).pushNamedAndRemoveUntil(
            '/login', 
            (route) => false,
          );
        }
      });
      return;
    }
    
    _isInitialized = true;
    
    // Listener hanya trigger jika sudah initialized
    _authService.authStateChanges.listen((user) {
      if (_isInitialized && user == null && mounted) {
        Navigator.of(context).pushNamedAndRemoveUntil(
          '/login', 
          (route) => false,
        );
      }
    });
  }
}

Key Changes:

  1. Tambah flag _isInitialized
  2. Check currentUser di initState()
  3. Listener hanya trigger setelah initialized
  4. Always check mounted sebelum navigate

Bug #2: Crash yang Menyebabkan Logout

Root Cause:

  • Unhandled exceptions di Firebase calls
  • setState() dipanggil setelah widget disposed
  • StreamBuilder error tidak di-handle

Solution:

// Always wrap await dengan try-catch
try {
  final data = await _dbService.getSensorData();
  if (mounted) {  // ← Check mounted
    setState(() {
      // Update state
    });
  }
} catch (e) {
  debugPrint('Error: $e');
  if (mounted) {
    // Show error tapi tidak crash
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Error: $e')),
    );
  }
}

Files Enhanced with Error Handling:

  1. dashboard_page.dart - StreamBuilder error state
  2. kontrol_page.dart - Load Firebase state
  3. sensor_config_page.dart - Load config
  4. waktu_config_page.dart - Load config
  5. pot_selection_page.dart - Load mode status

📊 Comparison Table

Feature Smart Mode 🧠 Fixed Duration ⏱️
Stop Condition Target OR timeout Durasi habis
Sensor Dependency High Low
Water Efficiency Optimal ⚠️ Depends
Predictability ⚠️ Variable Consistent
If Sensor Fails ⚠️ Use timeout Still works
Over-watering Risk Low ⚠️ Possible
Best For Smart irrigation Manual control

🧪 Testing Checklist

Dual Mode Testing

Smart Mode:

  • Trigger penyiraman (soil < 30%)
  • Pompa mati saat mencapai target (soil >= 80%)
  • Pompa mati saat timeout (durasi habis)
  • Log menunjukkan "Smart Mode" dengan target
  • Cooldown 2 menit bekerja

Fixed Duration:

  • Trigger penyiraman (soil < 30%)
  • Pompa menyiram selama durasi penuh
  • Pompa TIDAK mati meskipun target tercapai
  • Log menunjukkan "Fixed Duration Mode"
  • Progress counter: 5s/30s, 10s/30s, dst

Edge Cases:

  • Switch mode saat automation aktif
  • Durasi 0 atau negatif (validation)
  • Multiple pot trigger bersamaan
  • Sensor return invalid value (null, "", 0)
  • Firebase disconnected saat watering

Bug Fixes Testing

Auth & Navigation:

  • Login → Dashboard (tidak logout)
  • Dashboard → Kontrol → tidak logout
  • Dashboard → Histori → tidak logout
  • Drawer navigation → tidak logout
  • Back button → tidak logout
  • Network ON/OFF → tidak logout
  • Multiple tab/window → tidak logout

Error Handling:

  • Firebase call error → show snackbar, tidak crash
  • setState after dispose → tidak crash
  • StreamBuilder error → tampil error state
  • Invalid sensor data → handle gracefully

📝 Migration Guide

Existing Users

Jika sudah ada konfigurasi lama:

  1. App akan auto-migrate ke format baru
  2. Default mode: smart
  3. Default durasi unit: detik
  4. Konfigurasi lama tetap tersimpan

Jika belum ada konfigurasi:

  1. Default values:
    • Batas Minimal: 30%
    • Batas Maksimal: 80%
    • Durasi: 10 detik
    • Mode: Smart

Firebase Update

Manual Steps (Optional):

// Di Firebase Console, tambahkan fields baru:
{
  "kontrol": {
    "durasi_sensor": 30,     // Default 30 detik
    "mode_sensor": "smart"   // Default smart mode
  }
}

Auto Update:

  • Fields akan otomatis ter-create saat user save config pertama kali

🔮 Future Enhancements

  1. Hybrid Mode: Kombinasi smart + fixed (min & max duration)
  2. Per-Pot Mode: Setiap pot bisa punya mode berbeda
  3. Schedule Mode: Smart mode di pagi, fixed mode di sore
  4. Learning Mode: AI adjust durasi berdasarkan history
  5. Notification: Push notif saat watering complete
  6. History Graph: Chart durasi vs hasil kelembaban

📞 Support

Jika ada masalah:

  1. Check Console Log:

    🧠 Smart Mode: Target ... 
    ⏱️ Fixed Duration Mode: ...
    ✅ Watering completed ...
    ❌ Error: ...
    
  2. Verify Firebase:

    • kontrol/mode_sensor exist?
    • kontrol/durasi_sensor valid number?
    • kontrol/otomatis = true?
  3. Reset Config:

    • Delete local storage
    • Delete Firebase /kontrol node
    • Restart app
    • Setup ulang

🎯 Summary

Completed

  1. Dual Mode System

    • Smart Mode (adaptif dengan sensor)
    • Fixed Duration (durasi tetap)
    • UI untuk selection
    • Backend logic implementation
  2. Bug Fixes

    • Fix logout tiba-tiba
    • Enhanced error handling
    • Prevent crashes
    • Safe navigation
  3. Code Quality

    • Better logging
    • Comprehensive error handling
    • Clean separation of modes
    • Well documented

📈 Improvements

Performance:

  • Check interval: 10s → 5s (lebih responsif)
  • Cooldown: 5 min → 2 min (lebih cepat)

Reliability:

  • Auth state management fixed
  • Error boundaries added
  • Graceful degradation

User Experience:

  • Clear mode selection
  • Dynamic info text
  • Better feedback
  • Predictable behavior

Happy Gardening! 🌱