Skip to content

Proposal: visual brightness curve editor (Lovelace card) #149

@florianhorner

Description

@florianhorner

Visual brightness curve editor (Lovelace card)

Refs #147, #117.

Problem

The text-based 60:100 config works, but it doesn't scale. You can't see the curve shape until you save and test, you can't compare lights side by side, and the auto-interpolation is completely invisible to the user. Anyone with more than a handful of bulbs (see @fcassata's 16-bulb setup in #117) is flying blind.

Proposal

A custom Lovelace card — not a panel — that renders interactive brightness curves per Lightener device.

Card over panel because:

  • No sidebar clutter, no panel registration overhead
  • User decides where it lives (config tab, room view, wherever)
  • Matches how other config-oriented cards ship (scheduler-card, mini-graph-card)
  • Simpler HACS distribution

What this looks like

┌─────────────────────────────────────┐
│  Living Room                    ⚙️  │
│                                     │
│  100% ┤                      ●──────│  ← Ceiling LEDs
│       │                 ╱           │
│       │            ╱                │
│   50% ┤       ╱                     │
│       │  ╱   ● ─ ─ ─ ─ ─ ─ ●──────│  ← Sofa lamp
│       │╱                            │
│    0% ┤●                            │
│       └──┬────┬────┬────┬────┬──────│
│         0%  20%  40%  60%  80% 100% │
│              Group brightness →      │
│                                     │
│  ● Ceiling LEDs  ● Sofa lamp        │
│  ● Main ceiling                     │
└─────────────────────────────────────┘
  • Draggable control points per curve (tap + drag)
  • All lights overlaid on one graph — the whole point is visual comparison
  • Interpolation line redraws in real-time as you drag
  • Touch-friendly (tablet dashboards)
  • Curve hide/show toggles per light (legend click) to keep dense overlays readable

Curve model and edit rules

Matching Lightener's existing behavior:

  • Interpolation: Piecewise-linear between defined points (same as today's auto-interpolation)
  • Bounds: X-axis 1–100 (group %), Y-axis 0–100 (light %)
  • Implicit endpoint: 100:100 is always present (Lightener adds this automatically); users can override it but not remove it
  • Monotonic X required: No two points can share the same X value
  • Add points: Tap/click on the curve line to insert a new control point
  • Remove points: Double-tap or long-press a point to delete it (implicit endpoints can't be deleted)
  • Snapping: Points snap to integer percentages (matching the X:Y format's integer constraint)
  • Drag constraints: Points can't be dragged past their neighbors on the X-axis

Data flow and permissions

The card does not write to config entries directly. Instead:

  • Reads: Can use HA's existing config_entries/get WS command to retrieve current curve data — no custom handler needed for reads
  • Writes: Dedicated lightener/save_curves WS command registered with @websocket_api.require_admin. The backend validates the curve (bounds, monotonic X, integer values), calls async_update_entry(), and triggers a config reload. Returns success or a structured error
  • Non-admin users see the card as read-only — curves render but control points aren't draggable and Save is hidden
  • Unsaved changes: Visual indicator (dot on Save button or similar) when the in-memory curve diverges from persisted config. Explicit Save/Cancel — no auto-persist on drag

Implementation

Layer Stack Scope
Frontend Lit web component, SVG graph, vanilla pointer events ~400 LOC TS
Data config_entries/get for reads; custom lightener/save_curves for validated writes
Backend WS handler in __init__.py with @require_admin, validation, async_update_entry() ~50 LOC Python
Build Rollup or rspack + TypeScript → single JS file HACS-ready

No breaking changes. Text-based config flow stays untouched — the card is purely additive.

Prior art

Extensibility

Worth noting: @joshmwilliams' color calibration fork uses the same X:Y pattern for CCT/RGB mapping. The graph component would be directly reusable there — different axis labels, same interaction model.

Before I start prototyping

  1. Card vs. panel — any objections to the card approach?
  2. Separate repo (lightener-card) or bundled into main integration?
  3. Any concerns about the WS command / admin-gating approach for writes?
  4. Anything else you'd want in v1 scope?

Happy to build this. Just want alignment before writing code.

cc @Salamandar @joshmwilliams

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions