feat: HA light output targets — cast LED colors to Home Assistant lights
Lint & Test / test (push) Has been cancelled
Lint & Test / test (push) Has been cancelled
New output target type `ha_light` that sends averaged LED colors to HA light entities via WebSocket service calls (light.turn_on/turn_off): Backend: - HARuntime.call_service(): fire-and-forget WS service calls - HALightOutputTarget: data model with light mappings, update rate, transition - HALightTargetProcessor: processing loop with delta detection, rate limiting - ProcessorManager.add_ha_light_target(): registration - API schemas/routes updated for ha_light target type Frontend: - HA Light Targets section in Targets tab tree nav - Modal editor: HA source picker, CSS source picker, light entity mappings - Target cards with start/stop/clone/edit actions - i18n keys for all new UI strings
This commit is contained in:
@@ -214,6 +214,7 @@
|
||||
{% include 'modals/sync-clock-editor.html' %}
|
||||
{% include 'modals/weather-source-editor.html' %}
|
||||
{% include 'modals/ha-source-editor.html' %}
|
||||
{% include 'modals/ha-light-editor.html' %}
|
||||
{% include 'modals/asset-upload.html' %}
|
||||
{% include 'modals/asset-editor.html' %}
|
||||
{% include 'modals/settings.html' %}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<!-- HA Light Target Editor Modal -->
|
||||
<div id="ha-light-editor-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="ha-light-editor-title">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 id="ha-light-editor-title" data-i18n="ha_light.add">Add HA Light Target</h2>
|
||||
<button class="modal-close-btn" onclick="closeHALightEditor()" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="ha-light-editor-form" onsubmit="return false;">
|
||||
<input type="hidden" id="ha-light-editor-id">
|
||||
|
||||
<div id="ha-light-editor-error" class="error-message" style="display: none;"></div>
|
||||
|
||||
<!-- Name -->
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="ha-light-editor-name" data-i18n="ha_light.name">Name:</label>
|
||||
</div>
|
||||
<input type="text" id="ha-light-editor-name" data-i18n-placeholder="ha_light.name.placeholder" placeholder="Living Room Lights" required>
|
||||
<div id="ha-light-tags-container"></div>
|
||||
</div>
|
||||
|
||||
<!-- HA Source -->
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="ha-light-editor-ha-source" data-i18n="ha_light.ha_source">HA Connection:</label>
|
||||
</div>
|
||||
<select id="ha-light-editor-ha-source"></select>
|
||||
</div>
|
||||
|
||||
<!-- CSS Source -->
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="ha-light-editor-css-source" data-i18n="ha_light.css_source">Color Strip Source:</label>
|
||||
</div>
|
||||
<select id="ha-light-editor-css-source"></select>
|
||||
</div>
|
||||
|
||||
<!-- Update Rate -->
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="ha-light-editor-update-rate">
|
||||
<span data-i18n="ha_light.update_rate">Update Rate:</span>
|
||||
<span id="ha-light-editor-update-rate-display">2.0</span> Hz
|
||||
</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="ha_light.update_rate.hint">How often to send color updates to HA lights (0.5-5.0 Hz). Lower values are safer for HA performance.</small>
|
||||
<input type="range" id="ha-light-editor-update-rate" min="0.5" max="5.0" step="0.5" value="2.0"
|
||||
oninput="document.getElementById('ha-light-editor-update-rate-display').textContent = parseFloat(this.value).toFixed(1)">
|
||||
</div>
|
||||
|
||||
<!-- Transition -->
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="ha-light-editor-transition">
|
||||
<span data-i18n="ha_light.transition">Transition:</span>
|
||||
<span id="ha-light-editor-transition-display">0.5</span>s
|
||||
</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="ha_light.transition.hint">Smooth fade duration between colors (HA transition parameter). Higher values give smoother but slower transitions.</small>
|
||||
<input type="range" id="ha-light-editor-transition" min="0" max="5.0" step="0.1" value="0.5"
|
||||
oninput="document.getElementById('ha-light-editor-transition-display').textContent = parseFloat(this.value).toFixed(1)">
|
||||
</div>
|
||||
|
||||
<!-- Light Mappings -->
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label data-i18n="ha_light.mappings">Light Mappings:</label>
|
||||
<button type="button" class="btn btn-sm btn-secondary" onclick="addHALightMapping()" data-i18n-title="ha_light.mappings.add">+</button>
|
||||
</div>
|
||||
<small class="input-hint" data-i18n="ha_light.mappings.hint">Map LED ranges to HA light entities. Each mapping averages the LED segment to a single color.</small>
|
||||
<div id="ha-light-mappings-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="ha-light-editor-description" data-i18n="ha_light.description">Description (optional):</label>
|
||||
</div>
|
||||
<input type="text" id="ha-light-editor-description" placeholder="">
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeHALightEditor()" title="Cancel" data-i18n-title="settings.button.cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveHALightEditor()" title="Save" data-i18n-title="settings.button.save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user