feat: BindableFloat — universal value source binding for all scalar properties
Lint & Test / test (push) Successful in 1m20s

Introduce BindableFloat abstraction that allows any numeric property to be
either a static value or dynamically driven by a ValueSource. Backward-compatible
serialization: plain float when unbound, {value, source_id} dict when bound.

Backend:
- storage/bindable.py — BindableFloat dataclass + bfloat() helper
- 25+ scalar properties converted across all entity types
- Runtime VS acquisition in ColorStripStreamManager for CSS bindings
- All stream hot loops use self.resolve() for live values
- KeyColorsColorStripStream now inherits ColorStripStream

Frontend:
- BindableScalarWidget (slider + VS picker toggle) for all editors
- TypeScript BindableFloat type + helpers
- Graph editor edges for all bindable properties
- Audio source channel IconSelect grid

Fixes: daylight longitude, candlelight wind_strength/candle_type from_dict
This commit is contained in:
2026-03-29 00:33:24 +03:00
parent 5f70302263
commit 8a17bb5caa
48 changed files with 2512 additions and 887 deletions
@@ -39,29 +39,25 @@
<!-- Update Rate -->
<div class="form-group">
<div class="label-row">
<label for="ha-light-editor-update-rate">
<label>
<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 id="ha-light-editor-update-rate-container"></div>
</div>
<!-- Transition -->
<div class="form-group">
<div class="label-row">
<label for="ha-light-editor-transition">
<label>
<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 id="ha-light-editor-transition-container"></div>
</div>
<!-- Brightness Value Source -->
@@ -74,6 +70,30 @@
</select>
</div>
<!-- Color Tolerance -->
<div class="form-group">
<div class="label-row">
<label>
<span data-i18n="ha_light.color_tolerance">Color Tolerance:</span>
</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.color_tolerance.hint">Skip sending color updates when the RGB delta is below this threshold. Reduces HA traffic for near-static scenes.</small>
<div id="ha-light-editor-color-tolerance-container"></div>
</div>
<!-- Min Brightness Threshold -->
<div class="form-group">
<div class="label-row">
<label>
<span data-i18n="ha_light.min_brightness_threshold">Min Brightness Threshold:</span>
</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.min_brightness_threshold.hint">Effective output brightness below this value turns lights off completely (0 = disabled)</small>
<div id="ha-light-editor-min-brightness-threshold-container"></div>
</div>
<!-- Light Mappings -->
<div class="form-group">
<div class="label-row">