Files
deploy_home/ansible/roles/podman/files/hass/scripts.yaml
T
Bastian de BylandClaude Opus 5.5 fd985e014c
CI Images / Plan (pull_request) Failing after 2s
CI Images / Build ${{ matrix.key }} (pull_request) Skipped
fix(hass): driveway lights ignore TV mode, ramped evening dimming, bump to 2026.9.3
The sunset automation required TV mode off, so an afternoon of TV skipped
the driveway string lights entirely (Sep 22 and 23) - not an outage. The
driveway now has its own sunset -1h automation, with catch-up on restart
or switch reconnect before 23:00.

Evening brightness lives in one script (evening_lights_apply) that blends
between the old step levels; a 5-minute ramp from 20:30 eases lights that
are on and leaves alone any a person has changed by hand. The Dining Hall
no longer bumps to 50% at 21:30.

TV off after 23:30 now only turns off the living room glow instead of
bringing the whole house back to full brightness, and TV on/off leave the
lights alone in daylight. Lights-out moves to 23:30, and a 01:00 sweep
catches anything switched back on at the wall.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 12:42:33 -04:00

77 lines
3.3 KiB
YAML

evening_lights_apply:
alias: Evening Lights - Apply Schedule
description: >-
Sets each evening light to its scheduled brightness for the current time,
blending linearly between the points in `schedule`. apply=force turns the
lights on (sunset, TV off); apply=ramp only eases lights that are already
on, and leaves alone any light someone has changed by hand. While TV mode
is on the living room and the lights that glare on the TV are left alone.
mode: queued
fields:
apply:
description: "force: turn lights on at the target. ramp: only adjust lights that are already on."
example: ramp
selector:
select:
options:
- force
- ramp
variables:
# [minute of day, brightness %] - 1230 = 20:30, 1260 = 21:00,
# 1290 = 21:30, 1350 = 22:30. Before the first point a light sits at the
# first value; after the last it holds the last value until lights-out.
schedule:
light.kitchen_lights: [[1230, 100], [1260, 50], [1290, 25], [1350, 1]]
light.kitchen_wall_light: [[1230, 100], [1260, 50], [1290, 25], [1350, 1]]
light.bathroom_hallway: [[1230, 75], [1260, 50], [1290, 25], [1350, 10]]
light.living_room: [[1230, 100], [1260, 50], [1290, 25], [1350, 10]]
light.dining_hall: [[1290, 25], [1350, 15]]
tv_mode_lights:
- light.living_room
- light.kitchen_wall_light
- light.dining_hall
- light.bathroom_hallway
apply_mode: "{{ apply | default('ramp') }}"
sequence:
- repeat:
for_each: "{{ schedule.keys() | list }}"
sequence:
- variables:
light: "{{ repeat.item }}"
# [target now, target 5 minutes ago - what the last ramp tick set]
levels: >-
{%- macro at(pts, t) -%}
{%- if t <= pts[0][0] -%}{{ pts[0][1] }}
{%- elif t >= pts[-1][0] -%}{{ pts[-1][1] }}
{%- else -%}
{%- for i in range(pts | length - 1) if pts[i][0] <= t < pts[i + 1][0] -%}
{{ (pts[i][1] + (pts[i + 1][1] - pts[i][1]) * (t - pts[i][0]) / (pts[i + 1][0] - pts[i][0])) | round(0) | int }}
{%- endfor -%}
{%- endif -%}
{%- endmacro -%}
{%- set t = now().hour * 60 + now().minute -%}
{{ [at(schedule[repeat.item], t) | int, at(schedule[repeat.item], t - 5) | int] }}
current: "{{ ((state_attr(repeat.item, 'brightness') or 0) / 2.55) | round(0) | int }}"
skip: "{{ is_state('input_boolean.tv_mode', 'on') and repeat.item in tv_mode_lights }}"
- choose:
- conditions: "{{ not skip and apply_mode == 'force' }}"
sequence:
- action: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness_pct: "{{ levels[0] }}"
transition: 2
# A light more than 10 points off the last tick was set by hand; the
# biggest scheduled change in 5 minutes is ~8
- conditions: >-
{{ not skip and apply_mode == 'ramp' and is_state(light, 'on')
and (current - levels[1]) | abs <= 10 and current != levels[0] }}
sequence:
- action: light.turn_on
target:
entity_id: "{{ light }}"
data:
brightness_pct: "{{ levels[0] }}"
transition: 60