/** * Device discovery — add device modal, network/serial scanning, device type switching. */ import { _discoveryScanRunning, set_discoveryScanRunning, _discoveryCache, set_discoveryCache, csptCache, } from '../core/state.js'; import { API_BASE, fetchWithAuth, isSerialDevice, isMockDevice, isMqttDevice, isWsDevice, isOpenrgbDevice, isDmxDevice, isEspnowDevice, isHueDevice, isUsbhidDevice, isSpiDevice, isChromaDevice, isGameSenseDevice, escapeHtml } from '../core/api.js'; import { devicesCache } from '../core/state.js'; import { t } from '../core/i18n.js'; import { showToast, desktopFocus } from '../core/ui.js'; import { Modal } from '../core/modal.js'; import { _computeMaxFps, _renderFpsHint } from './devices.js'; import { getDeviceTypeIcon, ICON_RADIO, ICON_GLOBE, ICON_CPU, ICON_KEYBOARD, ICON_MOUSE, ICON_HEADPHONES, ICON_PLUG, ICON_TARGET_ICON, ICON_ACTIVITY, ICON_TEMPLATE } from '../core/icons.js'; import { EntitySelect } from '../core/entity-palette.js'; import { IconSelect, showTypePicker } from '../core/icon-select.js'; class AddDeviceModal extends Modal { constructor() { super('add-device-modal'); } snapshotValues() { return { name: document.getElementById('device-name').value, type: document.getElementById('device-type').value, url: document.getElementById('device-url').value, serialPort: document.getElementById('device-serial-port').value, ledCount: document.getElementById('device-led-count').value, baudRate: document.getElementById('device-baud-rate').value, ledType: document.getElementById('device-led-type')?.value || 'rgb', sendLatency: document.getElementById('device-send-latency')?.value || '0', zones: JSON.stringify(_getCheckedZones('device-zone-list')), zoneMode: _getZoneMode(), csptId: document.getElementById('device-css-processing-template')?.value || '', dmxProtocol: document.getElementById('device-dmx-protocol')?.value || 'artnet', dmxStartUniverse: document.getElementById('device-dmx-start-universe')?.value || '0', dmxStartChannel: document.getElementById('device-dmx-start-channel')?.value || '1', }; } } const addDeviceModal = new AddDeviceModal(); /* ── Icon-grid type selector ──────────────────────────────────── */ const DEVICE_TYPE_KEYS = ['wled', 'adalight', 'ambiled', 'mqtt', 'ws', 'openrgb', 'dmx', 'espnow', 'hue', 'usbhid', 'spi', 'chroma', 'gamesense', 'mock']; function _buildDeviceTypeItems() { return DEVICE_TYPE_KEYS.map(key => ({ value: key, icon: getDeviceTypeIcon(key), label: t(`device.type.${key}`), desc: t(`device.type.${key}.desc`), })); } let _deviceTypeIconSelect = null; let _csptEntitySelect = null; function _ensureDeviceTypeIconSelect() { const sel = document.getElementById('device-type'); if (!sel) return; if (_deviceTypeIconSelect) { _deviceTypeIconSelect.updateItems(_buildDeviceTypeItems()); return; } _deviceTypeIconSelect = new IconSelect({ target: sel, items: _buildDeviceTypeItems(), columns: 3 }); } function _ensureCsptEntitySelect() { const sel = document.getElementById('device-css-processing-template'); if (!sel) return; const templates = csptCache.data || []; // Populate native