Skip to content

Add optional per-device follow-the-sun / schedule automation - #1

Merged
viggfred merged 2 commits into
mainfrom
feat/follow-the-sun
Jul 6, 2026
Merged

viggfred merged 2 commits into
mainfrom
feat/follow-the-sun

Conversation

@viggfred

@viggfred viggfred commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Each blind can now drive itself from the sun and the clock, with an emphasis on being battery-frugal: the decision is pure local math over the cached position, so evaluating costs no Bluetooth — only an actual move connects, which keeps automation compatible with the command-only power mode.

New packages:

  • pkg/solar: pure, dependency-free NOAA solar position (altitude/azimuth), profile angle, and sunrise/sunset/solar-noon with polar-day/night handling. Validated by oracle-free invariant tests (subsolar-point altitude, solstice declinations, equation-of-time extrema, azimuth quadrants, high latitudes).
  • pkg/blissha controller.go: a pure Decide() engine returning a target and reason via a fixed precedence ladder (override → presence-sim → after-dark privacy → mode → occupancy gate → battery guards), exhaustively table-tested.

Modes (per blind): sun_glare (proportional profile-angle cut-off that keeps direct sun off a protected zone, simple sensitivity knob or precise geometry), sun_shade (discrete + hysteresis), schedule (clock sleep/wake with a gradual host-driven wake ramp, decoupled from the sun with optional solar clamps for high latitudes), and thermal. Battery guards: deadband, quantize-to-step, min-move-interval and an hourly cap; a manual or RF-remote move pauses automation for override_timeout so it never fights the user.

Manager integration adds a sibling control channel and an independent eval timer in both run modes (including command-only, where it fires while disconnected and only a resulting move wakes the link), op-origin tagging for override, and at-rest external-move detection.

Signals (room/home occupancy, lux, outdoor temp) are supplied via a new embed API on Bridge (SetRoomOccupancy/SetHomeAway/SetLux/SetOutdoorTemp), routed O(1) via a byID map. The YAML layer gains a home location: block (explicit IANA timezone, with the tz database embedded via time/tzdata — no system-default fallback) and a per-blind automation: block. blissha -dry-run prints each blind's hourly decisions without touching Bluetooth or MQTT.

Viggo Fredriksen added 2 commits July 6, 2026 23:51
Each blind can now drive itself from the sun and the clock, with an emphasis on
being battery-frugal: the decision is pure local math over the cached position,
so evaluating costs no Bluetooth — only an actual move connects, which keeps
automation compatible with the command-only power mode.

New packages:
  - pkg/solar: pure, dependency-free NOAA solar position (altitude/azimuth),
    profile angle, and sunrise/sunset/solar-noon with polar-day/night handling.
    Validated by oracle-free invariant tests (subsolar-point altitude, solstice
    declinations, equation-of-time extrema, azimuth quadrants, high latitudes).
  - pkg/blissha controller.go: a pure Decide() engine returning a target and
    reason via a fixed precedence ladder (override → presence-sim → after-dark
    privacy → mode → occupancy gate → battery guards), exhaustively table-tested.

Modes (per blind): sun_glare (proportional profile-angle cut-off that keeps
direct sun off a protected zone, simple sensitivity knob or precise geometry),
sun_shade (discrete + hysteresis), schedule (clock sleep/wake with a gradual
host-driven wake ramp, decoupled from the sun with optional solar clamps for
high latitudes), and thermal. Battery guards: deadband, quantize-to-step,
min-move-interval and an hourly cap; a manual or RF-remote move pauses
automation for override_timeout so it never fights the user.

Manager integration adds a sibling control channel and an independent eval timer
in both run modes (including command-only, where it fires while disconnected and
only a resulting move wakes the link), op-origin tagging for override, and
at-rest external-move detection.

Signals (room/home occupancy, lux, outdoor temp) are supplied via a new embed
API on Bridge (SetRoomOccupancy/SetHomeAway/SetLux/SetOutdoorTemp), routed
O(1) via a byID map. The YAML layer gains a home location: block (explicit IANA
timezone, with the tz database embedded via time/tzdata — no system-default
fallback) and a per-blind automation: block. `blissha -dry-run` prints each
blind's hourly decisions without touching Bluetooth or MQTT.
An on-demand blind could get stuck "unavailable" in Home Assistant even though
commands were working. The bliss client reconnects on its own inside Send (it
retries a dropped write by tearing down and re-establishing the link), which the
manager never observes. ensureConnected only published "online" when it did the
Connect itself; when it later saw the link already up (restored by Send's
internal reconnect) it returned early, so an "offline" published by an earlier
failed connect was never corrected. With availability_mode "all", that left both
the cover and the battery sensor unavailable.

Fix: reconcile availability with the real connection state. ensureConnected now
publishes "online" whenever the link is up (not only when it connected), a
successful command publishes "online" immediately, and publishAvailability is
change-tracked so reconciling on every poll/track tick stays quiet (and is
mutex-guarded, since the bridge's shutdown path also publishes it).
@viggfred
viggfred force-pushed the feat/follow-the-sun branch from 5f12c5c to 119b3cd Compare July 6, 2026 21:57
@viggfred
viggfred merged commit 3077e70 into main Jul 6, 2026
2 checks passed
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