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:
2026-03-13 16:46:40 +03:00
parent 18c886cbc5
commit ff24ec95e6
18 changed files with 607 additions and 7 deletions

View File

@@ -33,6 +33,7 @@
<option value="mqtt">MQTT</option>
<option value="ws">WebSocket</option>
<option value="openrgb">OpenRGB</option>
<option value="dmx">DMX</option>
<option value="mock">Mock</option>
</select>
</div>
@@ -126,6 +127,33 @@
<small class="input-hint" style="display:none" data-i18n="device.send_latency.hint">Simulated network/serial delay per frame in milliseconds</small>
<input type="number" id="device-send-latency" min="0" max="5000" value="0">
</div>
<div class="form-group" id="device-dmx-protocol-group" style="display: none;">
<div class="label-row">
<label for="device-dmx-protocol" data-i18n="device.dmx_protocol">DMX Protocol:</label>
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
</div>
<small class="input-hint" style="display:none" data-i18n="device.dmx_protocol.hint">Art-Net uses UDP port 6454, sACN (E1.31) uses UDP port 5568</small>
<select id="device-dmx-protocol">
<option value="artnet">Art-Net</option>
<option value="sacn">sACN (E1.31)</option>
</select>
</div>
<div class="form-group" id="device-dmx-start-universe-group" style="display: none;">
<div class="label-row">
<label for="device-dmx-start-universe" data-i18n="device.dmx_start_universe">Start Universe:</label>
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
</div>
<small class="input-hint" style="display:none" data-i18n="device.dmx_start_universe.hint">First DMX universe (0-32767). Multiple universes are used automatically for >170 LEDs.</small>
<input type="number" id="device-dmx-start-universe" min="0" max="32767" value="0">
</div>
<div class="form-group" id="device-dmx-start-channel-group" style="display: none;">
<div class="label-row">
<label for="device-dmx-start-channel" data-i18n="device.dmx_start_channel">Start Channel:</label>
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
</div>
<small class="input-hint" style="display:none" data-i18n="device.dmx_start_channel.hint">First DMX channel within the universe (1-512)</small>
<input type="number" id="device-dmx-start-channel" min="1" max="512" value="1">
</div>
<div id="add-device-error" class="error-message" style="display: none;"></div>
</form>
</div>