feat: scene/multi-zone world — per-zone lights, zone services, hypercolor 0.2.0 - #1
Merged
Conversation
Mention the companion Lovelace card in the overview section so new users discover it immediately. Add a lead-in to the dashboard recipe that links hyper-light-card before the stock entities example, and update the related-projects bullet to describe it as a companion to this integration rather than a generic catalog card.
The client realigned with the daemon's scene/multi-zone API: device
payloads carry origin/presentation/connection, control definitions are
name/control_type/default_value, and control values arrive externally
tagged ({"float": 12.0}). Pin hypercolor>=0.2.0,<0.3.0; the local dev
source stays at ../hypercolor/python, the client's home inside the
main repo.
The live-control numbers were reading bare scalars out of
control_values, which a real daemon never sends — they showed unknown
against live hardware. A control_scalar helper unwraps tagged values
(and tolerates the bare form older payloads used), and the control
matcher also accepts the new name field. The e2e fake daemon now
serves the real control wire shape so this can't drift silently again.
Co-Authored-By: Nova (Claude Fable 5) <noreply@anthropic.com>
The state coordinator now carries the active scene's render groups: zones, groups_revision, and active_scene_name flow from GET /scenes/active into coordinator data, and the WebSocket refresh triggers cover the zone-world events (render_group_changed, active_scene_changed, layer_*, brightness_changed) that previously slipped through the prefix filter. Each non-display zone becomes a light entity: brightness maps the zone's 0..1 multiplier, effects apply with render_group targeting so one zone changes without touching its siblings, and turn_off disables the zone. Zones are scene-scoped, so entities appear dynamically as scenes introduce new zone ids and go unavailable when the active scene no longer carries theirs. Display-face zones are excluded — they drive LCDs, not LEDs, and have their own service surface. The e2e fake daemon grew a full active-scene fixture with a primary zone and a zone PATCH route; the test drives brightness, zone-targeted effect apply, and disable round-trips through a real config entry. Co-Authored-By: Nova (Claude Fable 5) <noreply@anthropic.com>
apply_effect (and its preset routing) accepts zone_id for render-group targeting. New services: set_zone patches zone name/brightness/enabled/ make_primary (brightness as 0-100 percent, scaled to the daemon's 0..1 multiplier), list_zones returns the zone set with its groups_revision for automations, deactivate_scene returns to the synthesized default, and set_unassigned_behavior sets the off/hold/fallback policy for unclaimed device outputs. Zone services default to the active scene when no scene_id is given. Co-Authored-By: Nova (Claude Fable 5) <noreply@anthropic.com>
Matches the manifest version and the hypercolor 0.2.0 client adoption that brought the scene/multi-zone surface. Co-Authored-By: Nova (Claude Fable 5) <noreply@anthropic.com>
Zone ids are per-scene UUIDs, so zone churn (deleting zones, cycling through scenes) would grow the entity registry without bound — every vanished zone left a permanently-unavailable light behind. Setup now removes registry entries under the instance's zone namespace whose zone no longer exists in the active scene. Pruning is deliberately setup-only: mid-session scene switches leave entities unavailable instead of yanking them out from under dashboards and automations; the registry gets reconciled on the next reload. Found by adversarial review of the zone adaptation. Co-Authored-By: Nova (Claude Fable 5) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
Adapts the integration to Hypercolor's scene/multi-zone system (spec 64) on top of the hypercolor 0.2.0 client that landed in hyperb1iss/hypercolor#103.
Per-zone light entities
The state coordinator now carries the active scene's render groups — zones,
groups_revision, and the scene name flow fromGET /scenes/activeinto coordinator data. Every non-display zone of the active scene becomes its own light entity: brightness maps the zone's 0..1 multiplier (lossless round-trip across the full 0-255 range), effects apply withrender_grouptargeting so one zone changes without touching its siblings, and turn-off disables the zone. Zones are scene-scoped, so entities appear dynamically as scenes introduce new zone ids and go unavailable when the active scene no longer carries theirs; stale registry entries are pruned at setup so UUID zone churn can't grow the registry without bound. Display-face zones are excluded — they drive LCDs and have their own service surface.The WebSocket refresh triggers also widen to the zone-world events (
render_group_changed,active_scene_changed,layer_*,brightness_changed) that previously slipped through the prefix filter.Zone-aware services
apply_effect(and its preset routing) acceptszone_id. New services:set_zonepatches zone name/brightness/enabled/make_primary,list_zonesreturns the zone set with itsgroups_revisionfor automations,deactivate_scenereturns to the synthesized default, andset_unassigned_behaviorsets the off/hold/fallback policy for unclaimed device outputs. Zone services default to the active scene when noscene_idis given.Fixes that came out of live testing
The live-control number entities were reading bare scalars out of
control_values, but a real daemon sends externally tagged values ({"float": 12.0}) — they showed unknown against actual hardware. Acontrol_scalarhelper unwraps tagged values while tolerating the bare legacy form, and the e2e fake daemon now serves the real control wire shape so this can't drift silently again.Verification
HYPERCOLOR_HASS_REAL_E2E=1) passed against a live daemon with 21 devices and a 5-zone active scene.Requires hypercolor>=0.2.0 (in the main repo as of #103; needs a PyPI release before HACS installs resolve).
🤖 Generated with Claude Code