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:
@@ -85,6 +85,7 @@
|
||||
<button class="tab-btn" data-tab="profiles" onclick="switchTab('profiles')" role="tab" aria-selected="false" aria-controls="tab-profiles" id="tab-btn-profiles" title="Ctrl+2"><svg class="icon" viewBox="0 0 24 24"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M12 11h4"/><path d="M12 16h4"/><path d="M8 11h.01"/><path d="M8 16h.01"/></svg> <span data-i18n="profiles.title">Profiles</span><span class="tab-badge" id="tab-badge-profiles" style="display:none"></span></button>
|
||||
<button class="tab-btn" data-tab="targets" onclick="switchTab('targets')" role="tab" aria-selected="false" aria-controls="tab-targets" id="tab-btn-targets" title="Ctrl+3"><svg class="icon" viewBox="0 0 24 24"><path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/></svg> <span data-i18n="targets.title">Targets</span><span class="tab-badge" id="tab-badge-targets" style="display:none"></span></button>
|
||||
<button class="tab-btn" data-tab="streams" onclick="switchTab('streams')" role="tab" aria-selected="false" aria-controls="tab-streams" id="tab-btn-streams" title="Ctrl+4"><svg class="icon" viewBox="0 0 24 24"><path d="m17 2-5 5-5-5"/><rect width="20" height="15" x="2" y="7" rx="2"/></svg> <span data-i18n="streams.title">Sources</span></button>
|
||||
<button class="tab-btn" data-tab="scenes" onclick="switchTab('scenes')" role="tab" aria-selected="false" aria-controls="tab-scenes" id="tab-btn-scenes" title="Ctrl+5"><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.title">Scenes</span><span class="tab-badge" id="tab-badge-scenes" style="display:none"></span></button>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" id="tab-dashboard" role="tabpanel" aria-labelledby="tab-btn-dashboard">
|
||||
@@ -111,6 +112,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" id="tab-scenes" role="tabpanel" aria-labelledby="tab-btn-scenes">
|
||||
<div id="scenes-content">
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Apply saved tab immediately during parse to prevent visible jump
|
||||
(function() {
|
||||
@@ -153,6 +160,7 @@
|
||||
{% include 'modals/stream.html' %}
|
||||
{% include 'modals/pp-template.html' %}
|
||||
{% include 'modals/profile-editor.html' %}
|
||||
{% include 'modals/scene-preset-editor.html' %}
|
||||
{% include 'modals/audio-source-editor.html' %}
|
||||
{% include 'modals/test-audio-source.html' %}
|
||||
{% include 'modals/audio-template.html' %}
|
||||
|
||||
Reference in New Issue
Block a user