Merge release/1.0 (f5afb42, SAFETY-123) into UX-54

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
This commit is contained in:
glenn schrooyen
2026-10-27 15:30:52 +01:00
co-authored by Claude
3 changed files with 564 additions and 4 deletions
@@ -0,0 +1,35 @@
# SAFETY-123 - the day plan's hour loop steps in UTC
**Status: for review.** Tests: `test_safety123.py`. No option, no text change.
`dayplan._hour_slices()` stepped to the next local hour by adding an hour to
the local wall clock and converting back. Where the zone has no tzdata
(`tariff._EUTimezone`: the CI image, a dev host, an image that loses tzdata)
the missing 02:00 of the spring change reads as summer time, which is
00:00 UTC again. At 28 March 2027 00:00 UTC `t` did not move and the list
grew until the process died. Control and the web page share one event loop,
so the whole add-on froze. `dayplan.plan()` calls it on every plan, before it
looks at a battery's mode, so a site with all batteries on Solar first reaches
it as well, if the prices give a plan.
The shipped image has tzdata (`amd64-base:3.20`), where this zone gives the
right answer, so a running add-on is not known to be hit. The fix is for any
host without it. (AUDIT-01 F4, card SAFETY-120, is the same defect.)
**Decision.** Each step adds the time left in the local hour to the UTC
instant. It is at least a microsecond, so `t` always advances and the loop
ends, in any zone, with or without tzdata. A day of 23 hours gives 23 slices
and a day of 25 hours gives 25, each at most an hour, none across a local
hour. On ordinary days the slices are the old ones.
**One change on the autumn day.** The old function (with tzdata) made one
two-hour slice for the doubled hour 02:00-03:00; it now makes two of an hour,
both labelled 2. `plan()` sums per slice, so only a forecast with sun in that
hour could tell the difference. There is none.
**Other loops.** The other code that walks local hours or days steps in UTC
or on the calendar date (`static_tariff`, `price_forecast`, `price_history`,
`price`, `maintenance`, `homeview.local_day`, `solarfc._bounds`), or has a
fixed bound. None can stall. One known inexactness stays, outside this fix:
`solarfc` spreads a state-only forecast over hours since local midnight, so on
the two change days its sun curve is an hour off the clock.