"use client"; import { useState, useEffect } from "react"; import { Activity, Power, ZapOff, Zap, AlertTriangle, Lightbulb, Wind, Projector, Clock } from "lucide-react"; export default function PowerMonitoringPage() { // ========================================================================= // 1. DEKLARASI STATE // ========================================================================= const [rooms, setRooms] = useState([]); const [roomDeviceStatus, setRoomDeviceStatus] = useState<{ [roomId: string]: { [deviceName: string]: boolean } }>({}); // State khusus untuk menampung rincian 3 MCB di D101 const [powerDataD101, setPowerDataD101] = useState({ umum: 0, ac1: 0, ac2: 0 }); // 🌟 TAMBAHAN STATE UNTUK TIMER AUTO-CUTOFF const [timer, setTimer] = useState({ is_active: false, off_time: "22:00", on_time: "05:00" }); const [isSavingTimer, setIsSavingTimer] = useState(false); // ========================================================================= // 2. FUNGSI FETCH DATA DARI BACKEND // ========================================================================= // A. Tarik Data Daya (Power / Watt) const fetchPowerStatus = async () => { try { const response = await fetch("http://172.17.172.17:8080/api/hardware/power-status"); if (response.ok) { const data = await response.json(); const umum = parseFloat(data.umum) || 0; const ac1 = parseFloat(data.ac1) || 0; const ac2 = parseFloat(data.ac2) || 0; const totalD101 = umum + ac1 + ac2; setPowerDataD101({ umum, ac1, ac2 }); // Update nilai power D101 di dalam array rooms setRooms(prev => prev.map(room => room.name === "Kelas D101" ? { ...room, power: totalD101, lastUpdate: "Real-time" } : room )); } } catch (err) { console.error("Gagal mengambil data daya:", err); } }; // B. Tarik Data Status Perangkat (Sinkronisasi Real-time) const fetchDeviceStatus = async () => { try { const response = await fetch("http://172.17.172.17:8080/api/hardware/status"); const result = await response.json(); if (result.status === "success") { const backendData = result.data; setRoomDeviceStatus(prev => ({ ...prev, "room_1": { // room_1 diasumsikan sebagai D101 ...prev["room_1"], "Lampu 1": backendData.lampu1 === "on", "Lampu 2": backendData.lampu2 === "on", "AC": backendData.ac === "on", "Proyektor": backendData.projector === "on", } })); } } catch (err) { console.error("Gagal sinkronisasi status perangkat:", err); } }; // 🌟 C. Tarik Data Timer dari Golang const fetchTimer = async () => { try { const res = await fetch("http://172.17.172.17:8080/api/power/timer"); const data = await res.json(); setTimer(data); } catch (e) { console.error("Gagal mengambil data timer:", e); } }; // ========================================================================= // 3. INISIALISASI & POLLING (AUTO-REFRESH) // ========================================================================= useEffect(() => { // Simulasi Data Ruangan const dummyRooms = [ { id: 1, name: "Kelas D101", power: 0, isRelayOn: true, lastUpdate: "Menunggu..." }, { id: 2, name: "Kelas D102", power: 0, isRelayOn: false, lastUpdate: "2 mnt lalu" }, { id: 3, name: "Kelas D103", power: 45, isRelayOn: true, lastUpdate: "Baru saja" }, { id: 4, name: "Kelas D104", power: 0, isRelayOn: false, lastUpdate: "10 mnt lalu" }, ]; setRooms(dummyRooms); // Inisialisasi status default semua device OFF const initialStatus: { [roomId: string]: { [deviceName: string]: boolean } } = {}; dummyRooms.forEach(room => { initialStatus[`room_${room.id}`] = { "Lampu 1": false, "Lampu 2": false, "AC": false, "Proyektor": false, }; }); setRoomDeviceStatus(initialStatus); // Panggil fungsi awal fetchTimer(); fetchPowerStatus(); fetchDeviceStatus(); const interval = setInterval(() => { fetchPowerStatus(); fetchDeviceStatus(); }, 3000); // Polling 3 detik return () => clearInterval(interval); }, []); // ========================================================================= // 4. FUNGSI KONTROL DEVICE, GLOBAL POWER & SIMPAN TIMER // ========================================================================= // 🌟 D. Simpan Jadwal Timer ke Golang const saveTimer = async () => { setIsSavingTimer(true); try { const res = await fetch("http://172.17.172.17:8080/api/power/timer", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(timer) }); if (res.ok) alert("Jadwal Auto-Cutoff Berhasil Disimpan!"); } catch (e) { alert("Gagal menyimpan jadwal timer."); } finally { setIsSavingTimer(false); } }; const handleDeviceToggle = async (roomId: number, roomName: string, deviceName: string) => { const roomIdKey = `room_${roomId}`; const currentStatus = roomDeviceStatus[roomIdKey]?.[deviceName] || false; const actionType = currentStatus ? "off" : "on"; if (currentStatus) { const confirmMsg = `Apakah Anda yakin ingin mematikan ${deviceName} di ${roomName}?`; if (!window.confirm(confirmMsg)) return; } if (roomName !== "Kelas D101") { setRoomDeviceStatus(prev => ({ ...prev, [roomIdKey]: { ...prev[roomIdKey], [deviceName]: !currentStatus } })); return; } let backendDevice = ""; if (deviceName === 'AC') backendDevice = "ac"; else if (deviceName === 'Proyektor') backendDevice = "projector"; else if (deviceName === 'Lampu 1') backendDevice = "lampu1"; else if (deviceName === 'Lampu 2') backendDevice = "lampu2"; setRoomDeviceStatus(prev => ({ ...prev, [roomIdKey]: { ...prev[roomIdKey], [deviceName]: !currentStatus } })); try { const response = await fetch("http://172.17.172.17:8080/api/hardware/control", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ device: backendDevice, action: actionType }), }); if (!response.ok) { setRoomDeviceStatus(prev => ({ ...prev, [roomIdKey]: { ...prev[roomIdKey], [deviceName]: currentStatus } })); alert("Gagal mengontrol perangkat."); } } catch (error) { setRoomDeviceStatus(prev => ({ ...prev, [roomIdKey]: { ...prev[roomIdKey], [deviceName]: currentStatus } })); alert("GAGAL: Tidak dapat terhubung ke Server Golang."); } }; const handleGlobalPower = async (roomName: string, roomId: number, currentRelayStatus: boolean) => { if (roomName === "Kelas D101") { const actionType = currentRelayStatus ? "off" : "on"; const confirmMessage = currentRelayStatus ? `PERINGATAN FATAL: Anda yakin ingin MEMUTUS 3 MCB Daya di ${roomName}? (Proses berurutan ~3 detik)` : `RESTORE POWER: Anda yakin ingin MENYALAKAN KEMBALI 3 MCB Daya di ${roomName}? (Proses berurutan ~3 detik)`; if (!window.confirm(confirmMessage)) return; setRooms(prev => prev.map(r => r.name === roomName ? { ...r, isRelayOn: !currentRelayStatus } : r)); try { const response = await fetch("http://172.17.172.17:8080/api/power/global", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: actionType }), }); if (response.ok) { alert(`Daya di ${roomName} berhasil di-${actionType.toUpperCase()}!`); fetchPowerStatus(); fetchDeviceStatus(); } else { setRooms(prev => prev.map(r => r.name === roomName ? { ...r, isRelayOn: currentRelayStatus } : r)); alert("Gagal mengontrol MCB utama. Cek koneksi server."); } } catch (error) { setRooms(prev => prev.map(r => r.name === roomName ? { ...r, isRelayOn: currentRelayStatus } : r)); alert("Terjadi kesalahan jaringan saat menghubungi server."); } } else { const actionType = currentRelayStatus ? "Mematikan" : "Menyalakan"; if (window.confirm(`Simulasi ${actionType} daya di ${roomName}?`)) { setRooms(prev => prev.map(r => r.name === roomName ? { ...r, isRelayOn: !currentRelayStatus, power: 0 } : r)); } } }; // ========================================================================= // 5. TAMPILAN UI (RENDER) // ========================================================================= return (

Power Monitoring & Control

Pantau konsumsi daya kWh meter dan kendalikan relay sirkuit ruangan.

{/* 🌟 PANEL BARU: NIGHT MODE (AUTO-CUTOFF TIMER) */}

Global Night Mode Auto-Cutoff

Otomatis putus daya listrik (MCB) seluruh kelas pada jam malam.

{/* Input Jam */}
setTimer({...timer, off_time: e.target.value})} className="bg-slate-900 border border-slate-600 rounded px-2 py-1 text-sm outline-none focus:border-blue-500 transition-colors" disabled={timer.is_active} />
-
setTimer({...timer, on_time: e.target.value})} className="bg-slate-900 border border-slate-600 rounded px-2 py-1 text-sm outline-none focus:border-blue-500 transition-colors" disabled={timer.is_active} />
{/* Tombol Aksi */}
{/* 🌟 AKHIR PANEL NIGHT MODE */}
{[...rooms].sort((a, b) => a.name.localeCompare(b.name)).map((room) => { const roomIdKey = `room_${room.id}`; const currentRoomStatus = roomDeviceStatus[roomIdKey] || {}; return (
{room.isRelayOn ? 'Sirkuit Aktif' : 'Sirkuit Terputus'}

{room.name}

{room.name === "Kelas D101" &&

(Live Connected API)

} {room.name !== "Kelas D101" &&

(Simulasi / Offline)

}
3000 ? 'text-red-500' : room.power > 1000 ? 'text-orange-500' : 'text-gray-800'}`}> {typeof room.power === 'number' ? room.power.toFixed(1) : room.power} Watts
{/* RINCIAN KHUSUS D101 */} {room.name === "Kelas D101" && (
Umum: {powerDataD101.umum.toFixed(0)}W AC1: {powerDataD101.ac1.toFixed(0)}W AC2: {powerDataD101.ac2.toFixed(0)}W
)} {room.name !== "Kelas D101" &&
} {room.power > 3000 && (
Batas Daya Terlampaui!
)}

IoT Device Control

Update: {room.lastUpdate}
); })}
); }