Initial public release
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
# Semantics
|
||||
|
||||
## Virtual Color Temperature Range
|
||||
|
||||
- A virtual light exposes the broadest native CT range available from its configured CT-capable emitters.
|
||||
- RGB emulation is not used to expand the published Home Assistant CT range.
|
||||
- Bogus deCONZ CT limits are ignored when config or calibration provides a better range.
|
||||
|
||||
## Brightness
|
||||
|
||||
- Home Assistant brightness `255` means the brightest achievable output at the requested color or color temperature.
|
||||
- Lower brightness values are derived after chroma selection. The solver first chooses the best reachable chroma set, then defines `255` from the brightest surviving combination at that chroma, and then scales down to the requested brightness.
|
||||
- Reverse mapping reports brightness relative to the brightest achievable output at the achieved reported color.
|
||||
|
||||
## Forward And Reverse Mapping
|
||||
|
||||
- The solver treats requested RGB or CT as exact whenever possible.
|
||||
- If the request is out of gamut, the solver keeps the combinations within a small chroma-error band of the best result and then continues the same elimination pipeline.
|
||||
- For CT requests, the primary white reference is not the ideal blackbody point. The solver uses the same reverse-CT model as readback and treats a requested CT as a constant-CT line in xy space.
|
||||
- CT-labeled emitters first maximize brightness along that constant-CT line. This defines the broad-spectrum white contribution and keeps forward/reverse CT mapping stable even when calibrated emitters do not lie on the blackbody locus.
|
||||
- RGB correction may be used at lower CT brightness if it can hit or approach the blackbody point while preserving most of the available CT-labeled contribution.
|
||||
- When exact blackbody correction is no longer feasible at the requested brightness, correction degrades by minimizing chroma error while staying on the requested constant-CT line instead of dropping correction abruptly.
|
||||
- At high brightness, CT-labeled output can remain approximate instead of sacrificing large amounts of white output for a small chroma correction.
|
||||
- `Settings.approximate_chroma_band` bounds how far a CT-line result may be from the blackbody target before it is rejected as too inaccurate.
|
||||
- RGB requests do not use this slack path. If any RGB-labeled emitter exists in the virtual light or group, RGB requests are solved using RGB-labeled emitters only. This prevents very bright white emitters from causing brightness cliffs as an RGB color sweep approaches the blackbody locus.
|
||||
- Home Assistant normally sees the achieved physical output, not a remembered request history.
|
||||
- Immediately after our own command, the accepted command state is treated as truth while deCONZ readback remains close enough to the command. This absorbs controller rounding, stale websocket events, and small drift without making HA sliders jump.
|
||||
- Physical controller commands use the solver's computed channel mix. They are not overwritten just to make a controller CT value equal the HA-requested CT.
|
||||
- Accepted CT command state preserves the requested CT chroma for reporting, but uses calibrated solver/channel output for brightness. This keeps HA -> physical -> HA stable even when the calibrated CCT emitters do not lie exactly on the blackbody locus.
|
||||
- Once readback no longer matches the accepted command within tolerance, accepted state is dropped and reverse mapping recomputes from calibrated physical channel output.
|
||||
- Repeated HA -> physical -> HA translation should converge to a stable reported state rather than drift.
|
||||
- When a physical controller changes externally, every exposed virtual light or group containing that controller should recompute from the shared controller state and publish an updated HA state.
|
||||
|
||||
## Groups
|
||||
|
||||
- Groups are exposed as Home Assistant lights, but at runtime they control member virtual lights instead of solving directly against physical controllers.
|
||||
- A group member may be constrained to a fixed RGB color or fixed color temperature. The restriction applies only through that group; direct control of the member light remains unchanged.
|
||||
- A constrained member is effectively a dimmable fixed-color contributor from the group point of view. The member's own solver still decides how to produce that fixed color physically.
|
||||
- Group capabilities are derived from effective member capabilities unless explicitly configured. A group whose members are all fixed-color or brightness-only contributors exposes `brightness`.
|
||||
- Group reverse mapping aggregates each member's accepted-or-physical output color, not the member's already-idealized HA-facing report color.
|
||||
- `relative_member` balancing sends the same relative brightness to every member, which is useful when a group represents physically separated areas that should brighten together.
|
||||
|
||||
## Mode Selection
|
||||
|
||||
- Native mode is not a separate solve path. Labels like `rgb` and `color_temp` are only prioritization hints after chroma and brightness feasibility are established.
|
||||
- Cross-family boosting is allowed when it increases reachable brightness while staying within the chosen chroma target or chroma fallback band.
|
||||
- On/off channels are last-resort brightness boosters and are minimized before final combination selection.
|
||||
- Reverse mapping chooses the dominant physical family for external states. Accepted command state reports the command's requested HA mode while it remains valid.
|
||||
- Ties fall back deterministically: `color_temp`, then `rgb`, then `brightness`, then `onoff`.
|
||||
|
||||
## Combination Elimination
|
||||
|
||||
- Only exclusivity groups create branches. Independent control paths may be active together.
|
||||
- If several combinations survive chroma and brightness filtering, the solver:
|
||||
1. minimizes on/off lumens
|
||||
2. maximizes same-label lumens
|
||||
3. prefers more output channels
|
||||
4. prefers higher total available lumens
|
||||
5. falls back to stable config order
|
||||
- After one combination is chosen, load balancing happens inside that combination rather than across several combinations.
|
||||
|
||||
## Remotes And Automations
|
||||
|
||||
- A physical remote is identified by its deCONZ sensor ID.
|
||||
- Automation rules do not bind directly to the physical sensor ID. They bind to an internal `remote_id`.
|
||||
- Replacing a remote should only require moving an existing `remote_id` to a different physical sensor ID.
|
||||
- Multiple physical remotes may share one `remote_id`, which makes them trigger the same automation rules.
|
||||
- Double-press state is tracked per physical sensor ID, not per `remote_id`, so two different remotes sharing one `remote_id` cannot accidentally combine into one double press.
|
||||
- `Settings.default_double_press_window` defines the global double-press window. A `RemoteSpec.double_press_window` override may replace it for one physical remote.
|
||||
- `RemoteSpec.model` documents the physical remote type. The current runtime does not branch on it yet.
|
||||
- For Philips Hue dimmer `RWL021`, deCONZ `buttonevent` values are interpreted as:
|
||||
- `1000`, `2000`, `3000`, `4000`: press for top/up/down/bottom
|
||||
- `1001`, `2001`, `3001`, `4001`: hold-active, exposed as `hold` or `double_hold`
|
||||
- `1002`, `2002`, `3002`, `4002`: short release, exposed as `single`
|
||||
- `1003`, `2003`, `3003`, `4003`: long release, exposed as `long` or `double_long`
|
||||
- A `single` action fires immediately on short release. If another short release for the same physical remote and button arrives inside the double-press window, an additional `double` action fires.
|
||||
- If a short release is followed by a second press inside the double-press window and that second press becomes a hold, hold events are exposed as `double_hold`; release is exposed as `double_long`.
|
||||
- Hold-count patterns are supported: `hold_x`, `double_hold_x`, `hold_x_y`, and `double_hold_x_y`. `x` must be positive. If `y < x`, the trigger starts at `x` and continues until release. If `y == x`, it fires only on the x'th hold event.
|
||||
- Automation target expressions support `+` and `-` over configured groups/lights. `All` and the empty string mean all individual virtual lights. Expressions are evaluated left-to-right.
|
||||
- Automation actions execute through the same virtual-light command path as Home Assistant commands.
|
||||
Reference in New Issue
Block a user