Add profile conditions, scene presets, MQTT integration, and Scenes tab

Feature 1 — Profile Conditions: time-of-day, system idle (Win32
GetLastInputInfo), and display state (GUID_CONSOLE_DISPLAY_STATE)
condition types for automatic profile activation.

Feature 2 — Scene Presets: snapshot/restore system that captures target
running states, device brightness, and profile enables. Server-side
capture with 5-step activation order. Dedicated Scenes tab with
CardSection-based card grid, command palette integration, and dashboard
quick-activate section.

Feature 3 — MQTT Integration: MQTTService singleton with aiomqtt,
MQTTLEDClient device provider for pixel output, MQTT profile condition
type with topic/payload matching, and frontend support for MQTT device
type and condition editor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 16:57:42 +03:00
parent bd8d7a019f
commit 2e747b5ece
38 changed files with 2269 additions and 32 deletions

View File

@@ -30,6 +30,7 @@
<option value="wled">WLED</option>
<option value="adalight">Adalight</option>
<option value="ambiled">AmbiLED</option>
<option value="mqtt">MQTT</option>
<option value="mock">Mock</option>
</select>
</div>

View File

@@ -0,0 +1,47 @@
<!-- Scene Preset Editor Modal -->
<div id="scene-preset-editor-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="scene-preset-editor-title">
<div class="modal-content">
<div class="modal-header">
<h2 id="scene-preset-editor-title"><svg class="icon" viewBox="0 0 24 24"><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"/><path d="M20 3v4"/><path d="M22 5h-4"/><path d="M4 17v2"/><path d="M5 18H3"/></svg> <span data-i18n="scenes.add">Capture Scene</span></h2>
<button class="modal-close-btn" onclick="closeScenePresetEditor()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
<div class="modal-body">
<form id="scene-preset-editor-form">
<input type="hidden" id="scene-preset-editor-id">
<div class="form-group">
<div class="label-row">
<label for="scene-preset-editor-name" data-i18n="scenes.name">Name:</label>
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
</div>
<small class="input-hint" style="display:none" data-i18n="scenes.name.hint">A descriptive name for this scene preset</small>
<input type="text" id="scene-preset-editor-name" required>
</div>
<div class="form-group">
<div class="label-row">
<label for="scene-preset-editor-description" data-i18n="scenes.description">Description:</label>
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
</div>
<small class="input-hint" style="display:none" data-i18n="scenes.description.hint">Optional description of what this scene does</small>
<input type="text" id="scene-preset-editor-description">
</div>
<div class="form-group">
<div class="label-row">
<label for="scene-preset-editor-color" data-i18n="scenes.color">Card Color:</label>
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
</div>
<small class="input-hint" style="display:none" data-i18n="scenes.color.hint">Accent color for the scene card on the dashboard</small>
<input type="color" id="scene-preset-editor-color" value="#4fc3f7">
</div>
<div id="scene-preset-editor-error" class="error-message" style="display: none;"></div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-icon btn-secondary" onclick="closeScenePresetEditor()" title="Cancel" data-i18n-aria-label="aria.cancel">&#x2715;</button>
<button class="btn btn-icon btn-primary" onclick="saveScenePreset()" title="Save" data-i18n-aria-label="aria.save">&#x2713;</button>
</div>
</div>
</div>