Add Art-Net / sACN (E1.31) DMX device support
Full-stack implementation of DMX output for stage lighting and LED controllers: - DMXClient with Art-Net and sACN packet builders, multi-universe splitting - DMXDeviceProvider with manual_led_count capability and URL parsing - Device store, API schemas, routes wired with dmx_protocol/start_universe/start_channel - Frontend: add/settings modals with DMX fields, IconSelect protocol picker - Fix add device modal dirty check on type change (re-snapshot after switch) - i18n keys for DMX in en/ru/zh locales Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,9 +5,9 @@
|
||||
import {
|
||||
_deviceBrightnessCache, updateDeviceBrightness,
|
||||
} from '../core/state.js';
|
||||
import { API_BASE, getHeaders, fetchWithAuth, escapeHtml, isSerialDevice, isMockDevice, isMqttDevice, isWsDevice, isOpenrgbDevice } from '../core/api.js';
|
||||
import { API_BASE, getHeaders, fetchWithAuth, escapeHtml, isSerialDevice, isMockDevice, isMqttDevice, isWsDevice, isOpenrgbDevice, isDmxDevice } from '../core/api.js';
|
||||
import { devicesCache } from '../core/state.js';
|
||||
import { _fetchOpenrgbZones, _getCheckedZones, _splitOpenrgbZone, _getZoneMode } from './device-discovery.js';
|
||||
import { _fetchOpenrgbZones, _getCheckedZones, _splitOpenrgbZone, _getZoneMode, ensureDmxProtocolIconSelect, destroyDmxProtocolIconSelect } from './device-discovery.js';
|
||||
import { t } from '../core/i18n.js';
|
||||
import { showToast, showConfirm, desktopFocus } from '../core/ui.js';
|
||||
import { Modal } from '../core/modal.js';
|
||||
@@ -35,6 +35,9 @@ class DeviceSettingsModal extends Modal {
|
||||
zones: JSON.stringify(_getCheckedZones('settings-zone-list')),
|
||||
zoneMode: _getZoneMode('settings-zone-mode'),
|
||||
tags: JSON.stringify(_deviceTagsInput ? _deviceTagsInput.getValue() : []),
|
||||
dmxProtocol: document.getElementById('settings-dmx-protocol')?.value || 'artnet',
|
||||
dmxStartUniverse: document.getElementById('settings-dmx-start-universe')?.value || '0',
|
||||
dmxStartChannel: document.getElementById('settings-dmx-start-channel')?.value || '1',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -359,6 +362,31 @@ export async function showSettings(deviceId) {
|
||||
}
|
||||
}
|
||||
|
||||
// DMX-specific fields
|
||||
const dmxProtocolGroup = document.getElementById('settings-dmx-protocol-group');
|
||||
const dmxStartUniverseGroup = document.getElementById('settings-dmx-start-universe-group');
|
||||
const dmxStartChannelGroup = document.getElementById('settings-dmx-start-channel-group');
|
||||
if (isDmxDevice(device.device_type)) {
|
||||
if (dmxProtocolGroup) dmxProtocolGroup.style.display = '';
|
||||
if (dmxStartUniverseGroup) dmxStartUniverseGroup.style.display = '';
|
||||
if (dmxStartChannelGroup) dmxStartChannelGroup.style.display = '';
|
||||
document.getElementById('settings-dmx-protocol').value = device.dmx_protocol || 'artnet';
|
||||
ensureDmxProtocolIconSelect('settings-dmx-protocol');
|
||||
document.getElementById('settings-dmx-start-universe').value = device.dmx_start_universe ?? 0;
|
||||
document.getElementById('settings-dmx-start-channel').value = device.dmx_start_channel ?? 1;
|
||||
// Relabel URL field as IP Address
|
||||
const urlLabel2 = urlGroup.querySelector('label[for="settings-device-url"]');
|
||||
const urlHint2 = urlGroup.querySelector('.input-hint');
|
||||
if (urlLabel2) urlLabel2.textContent = t('device.dmx.url');
|
||||
if (urlHint2) urlHint2.textContent = t('device.dmx.url.hint');
|
||||
urlInput.placeholder = t('device.dmx.url.placeholder') || '192.168.1.50';
|
||||
} else {
|
||||
destroyDmxProtocolIconSelect('settings-dmx-protocol');
|
||||
if (dmxProtocolGroup) dmxProtocolGroup.style.display = 'none';
|
||||
if (dmxStartUniverseGroup) dmxStartUniverseGroup.style.display = 'none';
|
||||
if (dmxStartChannelGroup) dmxStartChannelGroup.style.display = 'none';
|
||||
}
|
||||
|
||||
// Tags
|
||||
if (_deviceTagsInput) _deviceTagsInput.destroy();
|
||||
_deviceTagsInput = new TagInput(document.getElementById('device-tags-container'), {
|
||||
@@ -416,6 +444,11 @@ export async function saveDeviceSettings() {
|
||||
if (isOpenrgbDevice(settingsModal.deviceType)) {
|
||||
body.zone_mode = _getZoneMode('settings-zone-mode');
|
||||
}
|
||||
if (isDmxDevice(settingsModal.deviceType)) {
|
||||
body.dmx_protocol = document.getElementById('settings-dmx-protocol')?.value || 'artnet';
|
||||
body.dmx_start_universe = parseInt(document.getElementById('settings-dmx-start-universe')?.value || '0', 10);
|
||||
body.dmx_start_channel = parseInt(document.getElementById('settings-dmx-start-channel')?.value || '1', 10);
|
||||
}
|
||||
const deviceResponse = await fetchWithAuth(`/devices/${deviceId}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(body)
|
||||
|
||||
Reference in New Issue
Block a user