import React, { useState, useEffect } from 'react'; import { serialService } from './services/serialService'; import { JBDProtocol, CMD_BASIC_INFO, CMD_CELL_INFO, CMD_HW_VERSION } from './services/jbdProtocol'; import { BMSBasicInfo, BMSCellInfo, ConnectionState } from './types'; import Dashboard from './components/Dashboard'; import Settings from './components/Settings'; import Terminal from './components/Terminal'; import { LayoutDashboard, Settings as SettingsIcon, Usb, AlertCircle, RefreshCw, PanelRightClose, PanelRightOpen } from 'lucide-react'; const App: React.FC = () => { const [connectionState, setConnectionState] = useState(ConnectionState.DISCONNECTED); const [basicInfo, setBasicInfo] = useState(null); const [cellInfo, setCellInfo] = useState(null); const [hwVersion, setHwVersion] = useState(null); const [activeTab, setActiveTab] = useState<'dashboard' | 'settings'>('dashboard'); const [errorMsg, setErrorMsg] = useState(null); const [isTerminalOpen, setIsTerminalOpen] = useState(false); useEffect(() => { let isMounted = true; let timeoutId: number; const runPoll = async () => { // ONLY POLL IF ON DASHBOARD AND CONNECTED if (connectionState !== ConnectionState.CONNECTED || activeTab !== 'dashboard') return; try { // 1. Get Basic Info const basicData = await serialService.sendCommand(CMD_BASIC_INFO); const parsedBasic = JBDProtocol.parseBasicInfo(basicData); if (isMounted) setBasicInfo(parsedBasic); // Delay 500ms await new Promise(r => setTimeout(r, 500)); if (!isMounted) return; // 2. Get Cell Info const cellData = await serialService.sendCommand(CMD_CELL_INFO); const parsedCells = JBDProtocol.parseCellInfo(cellData); if (isMounted) setCellInfo(parsedCells); // Delay 500ms await new Promise(r => setTimeout(r, 500)); if (!isMounted) return; // 3. Get Hardware Version (CMD 0x05) const hwData = await serialService.sendCommand(CMD_HW_VERSION); // CMD 0x05 usually returns raw ASCII string in payload const versionStr = new TextDecoder().decode(hwData); if (isMounted) setHwVersion(versionStr); if (isMounted) setErrorMsg(null); } catch (e: any) { console.error("Polling error:", e); // Log to terminal for debugging serialService.log('error', `Poll Fail: ${e.message}`); setIsTerminalOpen(true); } finally { // Schedule next poll cycle in 500ms if (isMounted && connectionState === ConnectionState.CONNECTED && activeTab === 'dashboard') { timeoutId = window.setTimeout(runPoll, 500); } } }; if (connectionState === ConnectionState.CONNECTED && activeTab === 'dashboard') { runPoll(); } return () => { isMounted = false; window.clearTimeout(timeoutId); }; }, [connectionState, activeTab]); const handleConnect = async () => { try { setConnectionState(ConnectionState.CONNECTING); await serialService.connect(); setConnectionState(ConnectionState.CONNECTED); setErrorMsg(null); } catch (e: any) { console.error(e); setConnectionState(ConnectionState.ERROR); setErrorMsg(e.message || "시리얼 포트 연결 실패"); setIsTerminalOpen(true); } }; const handleDisconnect = async () => { try { await serialService.disconnect(); setConnectionState(ConnectionState.DISCONNECTED); setBasicInfo(null); setCellInfo(null); setHwVersion(null); } catch (e) { console.error(e); } }; const toggleMosfet = async (type: 'charge' | 'discharge', currentState: boolean) => { if (!basicInfo) return; try { const newCharge = type === 'charge' ? !currentState : basicInfo.mosfetStatus.charge; const newDischarge = type === 'discharge' ? !currentState : basicInfo.mosfetStatus.discharge; await serialService.toggleMosfet(newCharge, newDischarge); } catch (e: any) { alert("MOSFET 제어 실패: " + e.message); } }; const renderContent = () => { switch (activeTab) { case 'dashboard': return ; case 'settings': return ; default: return null; } }; return (
{/* Sidebar / Topbar */}
J
JBD Tool
{/* AdSense Area - Expanded */}
{/* Main Content Area */}
{/* Header */}

{activeTab === 'dashboard' ? 'Overview' : 'Configuration'}

{connectionState === ConnectionState.CONNECTED ? ( ) : ( )}
{/* Content Body with Right Sidebar */}
{/* Main View */}
{errorMsg && (
{errorMsg}
)} {renderContent()} {/* Empty State Overlay */} {connectionState !== ConnectionState.CONNECTED && (

장치가 연결되지 않았습니다

JBD BMS를 UART-to-USB 어댑터로 연결하여 실시간 상태를 확인하고 설정을 변경하세요.

)}
{/* Right Terminal Panel */}
); }; export default App;