Skip to content

Eye-zone model with reflected-glare constraints - #3

Merged
vfilby merged 1 commit into
mainfrom
worktree-reflected-glare
Aug 17, 2026
Merged

Eye-zone model with reflected-glare constraints#3
vfilby merged 1 commit into
mainfrom
worktree-reflected-glare

Conversation

@vfilby

@vfilby vfilby commented Aug 17, 2026

Copy link
Copy Markdown
Owner

What

Replaces the floor-strip protect_depth model with an optional eye zone — a height range × depth range to keep sun out of — plus reflectors (floor, countertops) that catch sun bouncing up into it. protect_depth is unchanged and remains the default; nothing changes for existing configs until a zone opts in.

How it works

All geometry stays in the profile-angle plane, so each reflector is just {height, from, to} — no 3D. Reflections are handled by unfolding the mirror: a bounce off a plane at height r into the eye zone is a straight ray into the zone's mirror image below that plane, so every reflector is one more linear constraint in the same min(). Constraints are clipped to the strip of surface that can actually bounce into the zone and to the patch the sun actually lights, which yields the escape case (bounce lands beyond the hazard, rises past the eyes) for free.

The result is deliberately non-monotonic over a day — glare when high (floor bounce), open mid-descent, closing again as the sun reaches eye level — matching the observed kitchen behavior.

Changes

  • calculator.py: EyeZone, Reflector, sill_height; glare() takes the min over direct + per-reflector constraints and reports which one bound via a new constraint field
  • __init__.py: YAML schema (eye_zone, reflectors, sill_height), cross-field validation, protect_depth now optional-but-one-required
  • sensor.py: constraint attribute on the glare sensor (direct/reflected/none) for shadow-mode tuning
  • README section, manifest → 0.3.0
  • 8 new calculator tests (28 total pass): protect_depth equivalence, mirror-formula exactness, counter extent clipping, sill escape branch, non-monotonic daily pattern, above-zone reflector ignored

Verification

  • pytest tests/ -q → 28 passed
  • YAML schema smoke-tested end-to-end with HA stubbed (valid configs map to geometry; 5 invalid shapes rejected)

Suggested rollout: add an eye_zone + floor/counter reflectors to the kitchen zone only, shadow the constraint attribute for a few sunny days, and narrow reflector spans if reflected binds at glare-free hours.

🤖 Generated with Claude Code

protect_depth protects a strip of floor; the real target is eyes. New
optional window config models them directly:

- eye_zone: a height range and depth range to keep sun out of, replacing
  protect_depth (which remains as the degenerate floor-level case and is
  unchanged for existing configs).
- reflectors: horizontal reflective surfaces (floor, counters) as
  height + distance span. Each adds one linear constraint by unfolding
  the mirror: a bounce into the eye zone is a straight ray into the
  zone's reflection below the surface. Constraints are clipped to the
  strip that can actually bounce into the zone and the patch the sun
  actually lights, so the escape case (bounces landing beyond the
  hazard) falls out for free.
- sill_height: absolute heights now matter, so the bottom of the glass
  is a real input (default 0 keeps old behavior).

The published position is the highest satisfying every constraint —
non-monotonic over a day by design: high sun can close (floor bounce
climbs into eyes), mid-descent opens, low sun closes again. The glare
sensor gains a 'constraint' attribute (direct/reflected/none) for
shadow-mode tuning.

Worst-case assumptions (specular bounce, full window width) over-shade
rather than under-shade; narrow a reflector's span if it binds at hours
nobody experiences glare.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vfilby
vfilby marked this pull request as ready for review August 17, 2026 16:52
@vfilby
vfilby merged commit b05c252 into main Aug 17, 2026
3 checks passed
@vfilby
vfilby deleted the worktree-reflected-glare branch August 17, 2026 16:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant