MAINT-10: maintenance start hour in local time, default 19:00

The start hour was compared with the UTC hour, so the shipped 10 started at
12:00 in a Belgian summer. It is now read in Home Assistant's time zone
(fallback: the container's TZ, then UTC, one log line says which), and the
default moves to 19. DST: a missing hour starts at the first hour after the
jump; a repeated hour starts only in its first pass. Stored options are not
rewritten: a saved 10 now means 10:00 local (DOCS, CHANGELOG).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
goodwe-agent
2026-09-29 22:52:05 +02:00
parent 35cdffe766
commit 02c0a3dd7b
13 changed files with 678 additions and 27 deletions
+6 -7
View File
@@ -20,7 +20,7 @@ from datetime import datetime, timedelta, timezone
from . import arbitrage, messages, peakguard, uitext
from .maintenance import CHARGE as M_CHARGE, DRAIN as M_DRAIN, HOLD as M_HOLD
from .maintenance import IDLE as M_IDLE
from .maintenance import IDLE as M_IDLE, next_slot_start
from .packmode import CHEAP_HOURS, GRID_CHARGE_MODES, LEFTOVER_SOLAR, SOLAR_FIRST
from .price import Absence, Uncertainty, brussels
from .static_tariff import static_plan
@@ -384,8 +384,8 @@ def mode_runs(c, day0, day1, now, shadow):
def maintenance_runs(c, day0, day1, now, shadow):
"""The monthly battery cycle: under way now, or starting later today.
The cycle starts in the hour `maintenance_start_hour` names, read as the
control cycle reads it (UTC hour of `now`), shown in local time."""
The cycle starts in the hour `maintenance_start_hour` names, read in the
site's zone exactly as the control cycle reads it (MAINT-10)."""
runs, lines = [], []
waiting = []
for i, (inv, m) in enumerate(zip(c.inverters, c.maints)):
@@ -404,10 +404,9 @@ def maintenance_runs(c, day0, day1, now, shadow):
if not m.due(now) and (m.next_due(now) is None
or m.next_due(now) >= day1):
continue
start = now.replace(hour=cfg.start_hour, minute=0, second=0,
microsecond=0)
if start + timedelta(hours=1) <= now:
start += timedelta(days=1)
start = next_slot_start(now, cfg.start_hour, m.tz)
if start is None:
continue
due_at = m.next_due(now)
if due_at is not None and due_at > start:
continue