import { createSignal, createEffect, For, Show, onCleanup } from 'solid-js'; import { invoke } from '@tauri-apps/api/core'; import { listen } from '@tauri-apps/api/event'; import { useLanguage } from '../../i18n/index'; interface BoardInfo { fullname: string; host: string; address: string; port: number; connect_status: 'Connected' | 'Disconnected' | { Connecting: number }; } interface TestPattern { name: string; description: string; effect_type: string; } interface TestEffectConfig { effect_type: string; led_count: number; led_type: string; speed: number; } export const LedStripTest = () => { const { t } = useLanguage(); const [boards, setBoards] = createSignal([]); const [selectedBoard, setSelectedBoard] = createSignal(null); const [ledCount, setLedCount] = createSignal(60); const [ledType, setLedType] = createSignal<'WS2812B' | 'SK6812'>('WS2812B'); const [isRunning, setIsRunning] = createSignal(false); const [currentPattern, setCurrentPattern] = createSignal(null); const [animationSpeed, setAnimationSpeed] = createSignal(33); // ~30fps // Load available boards and listen for changes createEffect(() => { // Initial load invoke('get_boards').then((boardList) => { setBoards(boardList); if (boardList.length > 0 && !selectedBoard()) { setSelectedBoard(boardList[0]); } }).catch((error) => { console.error('Failed to load boards:', error); }); // Listen for board changes const unlisten = listen('boards_changed', (event) => { const boardList = event.payload; setBoards(boardList); // If currently selected board is no longer available, select the first available one const currentBoard = selectedBoard(); if (currentBoard) { const stillExists = boardList.find(board => board.host === currentBoard.host && board.address === currentBoard.address && board.port === currentBoard.port ); if (stillExists) { // Update to the new board object to reflect any status changes setSelectedBoard(stillExists); } else { // Current board is no longer available, select first available or null setSelectedBoard(boardList.length > 0 ? boardList[0] : null); } } else if (boardList.length > 0) { // No board was selected, select the first one setSelectedBoard(boardList[0]); } }); // Cleanup listener when effect is disposed onCleanup(() => { unlisten.then((unlistenFn) => unlistenFn()); }); }); // Cleanup when component is unmounted onCleanup(() => { if (isRunning() && selectedBoard()) { // Stop the test effect in backend invoke('stop_led_test_effect', { boardAddress: `${selectedBoard()!.address}:${selectedBoard()!.port}`, ledCount: ledCount(), ledType: ledType() }).catch((error) => { console.error('Failed to stop test during cleanup:', error); }); // Update local state immediately setIsRunning(false); setCurrentPattern(null); } }); // Test patterns const testPatterns: TestPattern[] = [ { name: t('ledTest.flowingRainbow'), description: t('ledTest.flowingRainbowDesc'), effect_type: 'FlowingRainbow' }, { name: t('ledTest.groupCounting'), description: t('ledTest.groupCountingDesc'), effect_type: 'GroupCounting' }, { name: t('ledTest.singleScan'), description: t('ledTest.singleScanDesc'), effect_type: 'SingleScan' }, { name: t('ledTest.breathing'), description: t('ledTest.breathingDesc'), effect_type: 'Breathing' } ]; // Test effect management - now handled by Rust backend const startTest = async (pattern: TestPattern) => { if (isRunning()) { await stopTest(); } if (!selectedBoard()) { console.error('No board selected'); return; } try { const effectConfig: TestEffectConfig = { effect_type: pattern.effect_type, led_count: ledCount(), led_type: ledType(), speed: 1.0 / (animationSpeed() / 50) // Convert animation speed to effect speed }; // Start the test effect in Rust backend await invoke('start_led_test_effect', { boardAddress: `${selectedBoard()!.address}:${selectedBoard()!.port}`, effectConfig: effectConfig, updateIntervalMs: animationSpeed() }); setCurrentPattern(pattern); setIsRunning(true); } catch (error) { console.error('Failed to start test effect:', error); } }; const stopTest = async () => { if (!selectedBoard()) { setIsRunning(false); setCurrentPattern(null); return; } try { // Stop the test effect in Rust backend await invoke('stop_led_test_effect', { boardAddress: `${selectedBoard()!.address}:${selectedBoard()!.port}`, ledCount: ledCount(), ledType: ledType() }); // Only update UI state after successful backend call setIsRunning(false); setCurrentPattern(null); } catch (error) { console.error('Failed to stop test effect:', error); // Still update UI state even if backend call fails setIsRunning(false); setCurrentPattern(null); } }; return (

{t('ledTest.title')}

{/* Hardware Selection */}
{/* LED Configuration */}
setLedCount(parseInt(e.target.value) || 60)} />
setAnimationSpeed(parseInt(e.target.value) || 33)} />
{/* Test Patterns */}

Test Patterns

{(pattern) => (

{pattern.name}

{pattern.description}

startTest(pattern)} disabled={!selectedBoard()} > {t('ledTest.startTestButton')} } >
)}
Test pattern "{currentPattern()?.name}" is running on {selectedBoard()?.host}
Please select a hardware board to start testing
); };