document.addEventListener('DOMContentLoaded', () => { const openBtn = document.getElementById('led-tool-btn'); const modal = document.getElementById('led-tool-modal'); const closeBtn = document.getElementById('led-tool-close-btn'); const refreshPortsBtn = document.getElementById('led-tool-refresh-ports-btn'); const form = document.getElementById('led-tool-form'); const readBtn = document.getElementById('led-tool-read-btn'); const resetBtn = document.getElementById('led-tool-reset-btn'); const portSelect = document.getElementById('led-tool-port'); const outputEl = document.getElementById('led-tool-output'); const messageEl = document.getElementById('led-tool-message'); if (!openBtn || !modal || !form || !portSelect || !outputEl || !messageEl) { return; } const showMessage = (text, type = 'success') => { messageEl.textContent = text; messageEl.className = `message ${type} show`; }; const setOutput = (text) => { outputEl.value = text || ''; }; const parseApiResponse = async (response) => { const bodyText = await response.text(); let data = null; try { data = bodyText ? JSON.parse(bodyText) : {}; } catch (error) { data = { error: bodyText || `HTTP ${response.status}` }; } return data; }; const setFieldValue = (id, value) => { const el = document.getElementById(id); if (!el) return; if (value === undefined || value === null) return; el.value = String(value); }; const populateFormFromSettings = (settings) => { if (!settings || typeof settings !== 'object') return false; setFieldValue('led-tool-name', settings.name); setFieldValue('led-tool-num-leds', settings.num_leds); setFieldValue('led-tool-led-pin', settings.led_pin); setFieldValue('led-tool-brightness', settings.brightness); setFieldValue('led-tool-transport', settings.transport_type); setFieldValue('led-tool-ssid', settings.ssid); setFieldValue('led-tool-password', settings.password); setFieldValue('led-tool-wifi-channel', settings.wifi_channel); setFieldValue('led-tool-default', settings.default); return true; }; const loadPorts = async () => { const defaultPort = '/dev/ttyACM0'; try { const response = await fetch('/led-tool/ports'); const data = await response.json(); const previous = portSelect.value; portSelect.innerHTML = ''; for (const port of data.ports || []) { const option = document.createElement('option'); option.value = port.device; option.textContent = `${port.device} - ${port.description || 'Unknown'}`; portSelect.appendChild(option); } if (previous) { portSelect.value = previous; } else if ((data.ports || []).some((p) => p.device === defaultPort)) { portSelect.value = defaultPort; } else { const fallback = document.createElement('option'); fallback.value = defaultPort; fallback.textContent = `${defaultPort} - default`; portSelect.appendChild(fallback); portSelect.value = defaultPort; } if (!data.led_cli_exists) { showMessage('led-tool/cli.py was not found on the host.', 'error'); } else if ((data.ports || []).length === 0) { showMessage('No serial ports found.', 'error'); } else { showMessage(`Found ${(data.ports || []).length} serial port(s).`, 'success'); } } catch (error) { showMessage(`Failed to read serial ports: ${error.message}`, 'error'); } }; openBtn.addEventListener('click', () => { modal.classList.add('active'); loadPorts(); }); if (closeBtn) { closeBtn.addEventListener('click', () => { modal.classList.remove('active'); }); } if (refreshPortsBtn) { refreshPortsBtn.addEventListener('click', () => { loadPorts(); }); } if (readBtn) { readBtn.addEventListener('click', async () => { const port = portSelect.value.trim(); if (!port) { showMessage('Select a serial port first.', 'error'); return; } setOutput('Reading settings from device...'); showMessage('Reading settings over USB...', 'success'); try { const response = await fetch(`/led-tool/settings?port=${encodeURIComponent(port)}`); const data = await parseApiResponse(response); if (!response.ok) { showMessage(data.error || 'Read failed.', 'error'); setOutput(data.error || 'Request failed.'); return; } const output = [ `exit code: ${data.returncode}`, '', 'stdout:', data.stdout || '(none)', '', 'stderr:', data.stderr || '(none)', ].join('\n'); setOutput(output); if (data.ok) { const populated = populateFormFromSettings(data.settings); if (populated) { showMessage('Settings read and fields populated.', 'success'); } else { showMessage('Settings read successfully.', 'success'); } } else { showMessage('Read completed with errors. Check output.', 'error'); } } catch (error) { showMessage(`Request failed: ${error.message}`, 'error'); setOutput(error.message); } }); } if (resetBtn) { resetBtn.addEventListener('click', async () => { const port = portSelect.value.trim(); if (!port) { showMessage('Select a serial port first.', 'error'); return; } setOutput('Resetting device and following output...'); showMessage('Resetting device over USB...', 'success'); try { const response = await fetch('/led-tool/reset', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ port }), }); const data = await parseApiResponse(response); if (!response.ok) { showMessage(data.error || 'Reset failed.', 'error'); setOutput(data.error || 'Request failed.'); return; } const output = [ `exit code: ${data.returncode}`, '', 'stdout:', data.stdout || '(none)', '', 'stderr:', data.stderr || '(none)', ].join('\n'); setOutput(output); if (data.ok) { showMessage('Device reset complete.', 'success'); } else { showMessage('Reset completed with errors. Check output.', 'error'); } } catch (error) { showMessage(`Request failed: ${error.message}`, 'error'); setOutput(error.message); } }); } form.addEventListener('submit', async (event) => { event.preventDefault(); const port = portSelect.value.trim(); if (!port) { showMessage('Select a serial port first.', 'error'); return; } const payload = { port, name: document.getElementById('led-tool-name')?.value?.trim() || '', num_leds: document.getElementById('led-tool-num-leds')?.value?.trim() || '', led_pin: document.getElementById('led-tool-led-pin')?.value?.trim() || '', brightness: document.getElementById('led-tool-brightness')?.value?.trim() || '', transport: document.getElementById('led-tool-transport')?.value?.trim() || '', ssid: document.getElementById('led-tool-ssid')?.value?.trim() || '', password: document.getElementById('led-tool-password')?.value?.trim() || '', wifi_channel: document.getElementById('led-tool-wifi-channel')?.value?.trim() || '', default: document.getElementById('led-tool-default')?.value?.trim() || '', }; setOutput('Running led-tool command...'); showMessage('Running command over USB...', 'success'); try { const response = await fetch('/led-tool/settings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await parseApiResponse(response); if (!response.ok) { showMessage(data.error || 'Command failed.', 'error'); setOutput(data.error || 'Request failed.'); return; } const output = [ `exit code: ${data.returncode}`, '', 'stdout:', data.stdout || '(none)', '', 'stderr:', data.stderr || '(none)', ].join('\n'); setOutput(output); if (data.ok) { showMessage('Settings applied via USB.', 'success'); } else { showMessage('Command completed with errors. Check output.', 'error'); } } catch (error) { showMessage(`Request failed: ${error.message}`, 'error'); setOutput(error.message); } }); });