Files
ledgrab/TODO.md
T
alexei.dolgolyov 384362ccf1
Lint & Test / test (push) Successful in 1m27s
feat: new value source types (HA entity, gradient map, strip extract) + UI fixes
New value source types:
- ha_entity: reads numeric values from HA entity state/attribute, normalizes
  via min/max range, applies EMA smoothing. EntitySelect for HA connection
  and entity selection with live entity list fetching.
- gradient_map: maps a float value source (0-1) through a gradient entity.
  EntitySelect for both input source and gradient with inline previews.
- css_extract: extracts single color by averaging LED range from a color
  strip source. EntitySelect for source selection.

Value source type picker:
- Filter tabs (All / Numeric / Color) above the icon grid
- showTypePicker extended with filterTabs + onFilterChange support

Palette selectors converted to EntitySelect:
- Effect palette, gradient preset, and audio palette selectors now use
  command-palette style EntitySelect with gradient strip previews

Tab indicator fixes:
- Icon now updates on tab switch (was passing no args to updateTabIndicator)
- Visible with any background effect active, not just Noise Field
- Noise Field is the default background effect for new users

Dashboard section collapse fix:
- Split header into clickable toggle (chevron+label) and non-clickable
  actions area — buttons no longer trigger collapse/expand

Discriminated union fix (422 errors):
- source_type/target_type now always included in update payloads for:
  CSS editor, LED target, HA light target, simple calibration,
  advanced calibration
2026-03-29 20:38:22 +03:00

11 KiB

New Value Source Types + Filter Support

Feature 1: HA Value Source (ha_entity)

A value source that reads numeric values from a Home Assistant entity's state or attribute. Allows binding any scalar property in the system to a live HA sensor/entity value.

Configuration

  • ha_source_id: str — HA connection entity (EntitySelect picker)
  • entity_id: str — HA entity (EntitySelect picker, populated from /api/v1/home-assistant/sources/{id}/entities)
  • attribute: str — optional attribute name (text input or dropdown populated from entity attributes)
  • min_ha_value: float — raw HA value corresponding to output 0.0
  • max_ha_value: float — raw HA value corresponding to output 1.0
  • smoothing: float — EMA smoothing factor (0..1)
  • return_type: "float" — always float

Backend

  • Storage modelHAEntityValueSource subclass in storage/value_source.py

    • Fields: ha_source_id, entity_id, attribute, min_ha_value, max_ha_value, smoothing
    • Register in _VALUE_SOURCE_MAP as "ha_entity"
    • to_dict() / from_dict() / _parse_common_fields()
  • Store — add "ha_entity" case in ValueSourceStore.create_source() and update_source()

    • Validate: ha_source_id must be non-empty, entity_id must be non-empty
  • API schemasHAEntityValueSourceCreate, HAEntityValueSourceResponse in api/schemas/value_sources.py

    • Add to ValueSourceCreate / ValueSourceResponse discriminated unions
    • Fields: ha_source_id, entity_id, attribute (optional), min_ha_value, max_ha_value, smoothing
  • API routes — add HAEntityValueSource → response builder in _RESPONSE_MAP

  • StreamHAEntityValueStream in core/processing/value_stream.py

    • start(): acquire HA runtime via ha_manager.acquire(ha_source_id)
    • get_value(): read ha_manager.get_state(ha_source_id, entity_id) → extract state or attribute → clamp/normalize to [0,1] via min/max range → apply EMA smoothing
    • stop(): release HA runtime
    • update_source(): hot-update parameters
    • Add to ValueStreamManager._create_stream()

Frontend

  • TypeScript typeHAEntityValueSource interface in types.ts

    • source_type: 'ha_entity', return_type: 'float'
    • Fields: ha_source_id, entity_id, attribute, min_ha_value, max_ha_value, smoothing
    • Add to ValueSourceType union and ValueSource union
  • Icon — add ha_entity: _svg(P.home) to _valueSourceTypeIcons in icons.ts

  • i18n — add keys in en.json:

    • value_source.type.ha_entity: "Home Assistant Entity"
    • value_source.type.ha_entity.desc: "Reads value from a Home Assistant sensor or entity attribute"
    • value_source.ha_source: "HA Connection:"
    • value_source.entity_id: "Entity:"
    • value_source.attribute: "Attribute (optional):"
    • value_source.min_ha_value: "Min HA Value:"
    • value_source.max_ha_value: "Max HA Value:"
  • Editor modal — add ha_entity section to value-source-editor.html

    • HA connection selector (EntitySelect from HA sources cache)
    • Entity selector (EntitySelect populated from HA entities endpoint)
    • Attribute text input (optional)
    • Min/Max HA value range inputs
    • Smoothing slider
  • Editor logic — add ha_entity handler in value-sources.ts

    • onValueSourceTypeChange(): show/hide ha_entity section
    • _typeHandlers['ha_entity']: load/reset/getPayload
    • EntitySelect for HA source + EntitySelect for entity (refreshes when HA source changes)
    • Auto-name: "{entity_friendly_name}" or "{entity_id}"
  • Card renderer — show HA source link + entity ID + attribute (if set) + range

  • VS_TYPE_KEYS — add 'ha_entity' to the array


Feature 2: Lerp Color Value Source (gradient_map)

A color value source that maps a numeric value source's output through a color gradient. Given a float value source (0..1), interpolates the color at that position in a user-defined gradient.

Configuration

  • value_source_id: str — reference to a float-returning value source (EntitySelect)
  • stops: List[ColorStop] — gradient color stops [{position: float, color: [R,G,B]}] (reuse existing ColorStop model from color strip sources)
  • easing: str — interpolation mode: "linear", "step" (reuse existing easing modes)
  • return_type: "color" — always color

Backend

  • Storage modelGradientMapValueSource subclass in storage/value_source.py

    • Fields: value_source_id, stops (list of dicts with position + color), easing
    • Register in _VALUE_SOURCE_MAP as "gradient_map"
  • Store — add "gradient_map" case in create_source() / update_source()

    • Validate: at least 2 stops, value_source_id non-empty
  • API schemasGradientMapValueSourceCreate, GradientMapValueSourceResponse

    • Reuse ColorStop schema from color_strip_sources schemas (or define minimal version)
    • Add to discriminated unions
  • API routes — add to _RESPONSE_MAP

  • StreamGradientMapValueStream in value_stream.py

    • start(): acquire the referenced value stream via ValueStreamManager.acquire(value_source_id)
    • get_value(): return BT.601 luminance of current color
    • get_color(): call inner_stream.get_value() → interpolate through gradient stops → return RGB tuple
    • Reuse _compute_gradient_colors() logic from color_strip_stream.py (or a shared helper for single-point interpolation)
    • stop(): release inner value stream
    • update_source(): hot-update stops/easing, re-acquire if value_source_id changed

Frontend

  • TypeScript typeGradientMapValueSource interface

    • source_type: 'gradient_map', return_type: 'color'
    • Fields: value_source_id, stops: ColorStop[], easing
  • Icon — add gradient_map: _svg(P.rainbow) to _valueSourceTypeIcons

  • i18n — add keys:

    • value_source.type.gradient_map: "Gradient Map"
    • value_source.type.gradient_map.desc: "Maps a numeric value through a color gradient"
    • value_source.input_source: "Input Value Source:"
    • value_source.gradient_stops: "Gradient:"
    • value_source.easing: "Interpolation:"
  • Editor modal — add gradient_map section

    • Value source selector (EntitySelect from float value sources)
    • Gradient stop editor (reuse gradient stop UI from CSS editor if possible, or build minimal version: list of position + color picker rows)
    • Easing selector (IconSelect: linear, step)
    • Live gradient preview bar (CSS linear-gradient from stops)
  • Editor logic_typeHandlers['gradient_map']: load/reset/getPayload

  • Card renderer — CSS gradient preview bar + input source link + stop count

  • VS_TYPE_KEYS — add 'gradient_map'


Feature 3: CSS Extraction Color Value Source (css_extract)

A color value source that extracts a single color from a color strip source by averaging a range of LEDs. Useful for deriving a single color signal from an existing color strip.

Configuration

  • color_strip_source_id: str — reference to a color strip source (EntitySelect)
  • led_start: int — start of LED range (0-based, optional, default 0)
  • led_end: int — end of LED range (exclusive, optional, default -1 = whole strip)
  • return_type: "color" — always color

Backend

  • Storage modelCSSExtractValueSource subclass in storage/value_source.py

    • Fields: color_strip_source_id, led_start, led_end
    • Register as "css_extract"
  • Store — add "css_extract" case in create_source() / update_source()

    • Validate: color_strip_source_id non-empty
  • API schemasCSSExtractValueSourceCreate, CSSExtractValueSourceResponse

    • Add to discriminated unions
  • API routes — add to _RESPONSE_MAP

  • StreamCSSExtractValueStream in value_stream.py

    • start(): acquire color strip stream via ColorStripStreamManager.acquire(color_strip_source_id, led_count=needed)
    • get_color(): read strip colors → average the specified LED range → return single RGB tuple
    • get_value(): BT.601 luminance of extracted color
    • stop(): release color strip stream
    • update_source(): hot-update range, re-acquire if source changed
    • Note: Needs access to ColorStripStreamManager — may need to inject it into ValueStreamManager or pass via constructor

Frontend

  • TypeScript typeCSSExtractValueSource interface

    • source_type: 'css_extract', return_type: 'color'
    • Fields: color_strip_source_id, led_start, led_end
  • Icon — add css_extract: _svg(P.eyedropper) (or P.pipette if available, else P.palette)

  • i18n — add keys:

    • value_source.type.css_extract: "Strip Color Extract"
    • value_source.type.css_extract.desc: "Extracts a single color from a color strip source"
    • value_source.color_strip_source: "Color Strip Source:"
    • value_source.led_start: "LED Start:"
    • value_source.led_end: "LED End (-1 = all):"
  • Editor modal — add css_extract section

    • Color strip source selector (EntitySelect from color strip sources cache)
    • LED start/end numeric inputs
    • Optional: live color preview swatch
  • Editor logic_typeHandlers['css_extract']: load/reset/getPayload

  • Card renderer — color strip source link + LED range badge

  • VS_TYPE_KEYS — add 'css_extract'


Feature 4: Value Source Type Filter in Icon Grid

Add a filter/category system to the value source type IconSelect so users can filter by return type or category.

Implementation

  • Add filter tabs above the value source type icon grid in the editor modal

    • "All" (default) — show all types
    • "Float" — show float-returning types: static, animated, audio, adaptive_time, adaptive_scene, daylight, ha_entity
    • "Color" — show color-returning types: static_color, animated_color, adaptive_time_color, gradient_map, css_extract
  • IconSelect enhancement — either:

    • Option A: Add groups support to IconSelect (items grouped by category with filter tabs)
    • Option B: Filter VS_TYPE_KEYS before building items, with toggle buttons above the grid
    • Decision: Option B is simpler and follows existing patterns — add filter buttons that rebuild the icon grid
  • i18n — add keys:

    • value_source.filter.all: "All"
    • value_source.filter.float: "Float"
    • value_source.filter.color: "Color"

Implementation Order

  1. Feature 4 (filter) — smallest, unblocks better UX for the growing type list
  2. Feature 1 (ha_entity) — standalone float type, no cross-dependencies
  3. Feature 3 (css_extract) — needs ColorStripStreamManager injection
  4. Feature 2 (gradient_map) — needs float VS reference + gradient UI

Cross-Cutting Concerns

  • All new types need entries in _VALUE_SOURCE_MAP (backend) and VS_TYPE_KEYS (frontend)
  • All new types need _RESPONSE_MAP entries in routes
  • All new types need ValueStreamManager._create_stream() factory case
  • All new types need icon in _valueSourceTypeIcons
  • All new types need i18n keys in en.json (and ru.json, zh.json — can defer translations)
  • ValueSourceStore referential integrity check on delete should verify new references (ha_entity → ha_source, gradient_map → value_source, css_extract → color_strip_source)
  • Graph editor: new edge types for ha_entity → HA source node, gradient_map → value source node, css_extract → color strip node