OPT-34: the night charge keeps its level when the kept forecast ends
With the forecast sensors silent from 17:05 the kept evening figure ended at midnight + 3 h, in the middle of the night grid charge, and Leftover solar's planned level went with it (rig: A 49.8 % against 79.9 %). - A night grid charge that has started keeps its planned level when the forecast goes (Controller._latch_charge, store key night_charge_latch), and the narrow price gap with it (weather_held). A fresh figure still moves the level. - The evening's tomorrow figure is today's until the bell starts (06:00 local), up to 15 h old but only if it was usable at midnight (solarfc.Hold.stand_in). - Screen: "No solar forecast now. The charge under way goes on to its planned level." (EN/NL) while a latched battery is below its level. - test_opt34.py (whole nights through the real control cycle, mutants), test_opt27 and test_modes_p4 adjusted to the new window and the kept level. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
This commit is contained in:
co-authored by
Claude
parent
deee98d352
commit
412e47f111
@@ -7,9 +7,10 @@ Forecast.Solar site was "no forecast": a price mode's night cheap run needed
|
||||
fresh reading of each sensor, for the day it is FOR:
|
||||
|
||||
* up to `FRESH_S` when the sensor is missing or unavailable (a short outage);
|
||||
* from the end of the bell (20:00) until local midnight + 3 h, if the reading
|
||||
is at most `KEPT_MAX_AGE_S` (12 h) old when used (the night plan); never
|
||||
beyond, never for another day.
|
||||
* from the end of the bell (20:00) until local midnight, if the reading is at
|
||||
most `KEPT_MAX_AGE_S` (12 h) old when used (the night plan); after midnight
|
||||
the evening's tomorrow figure is today's until the bell starts (06:00, OPT-34,
|
||||
test_opt34.py); never beyond, never for another day.
|
||||
|
||||
DECISIONS/OPT-27-last-fresh-forecast-for-the-night.md.
|
||||
|
||||
@@ -21,7 +22,7 @@ DECISIONS/OPT-27-last-fresh-forecast-for-the-night.md.
|
||||
b. no forecast all day: the night run still needs 1.5x and does not charge;
|
||||
c. an evening restart keeps it (a new Controller on the saved store);
|
||||
d. a one-hour outage at 18:47 does not drop it;
|
||||
e. past midnight + 3 h the figure is not used, before it it is.
|
||||
e. from 06:00 (the bell) the figure is not used, before it it is (OPT-34).
|
||||
3. The screens: the forecast line says when it was read and that it is kept
|
||||
for tonight (EN and NL), and Home agrees with control.
|
||||
|
||||
@@ -153,7 +154,7 @@ for label, tm in (("stale", st(12.0, at(4, 9, 5))), ("unavailable", GONE)):
|
||||
check(f"11:00, tomorrow {label} for under 3 h: still covered, not kept",
|
||||
fs is not None and fs.tomorrow is not None and not fs.kept)
|
||||
|
||||
# The bound: midnight + 3 h, and the day a figure is for.
|
||||
# The bound: the bell start (06:00), and the day a figure is for.
|
||||
fm = rs(st(0.0, at(3, 23, 0)), st(0.0, at(3, 23, 0)), at(4, 1, 0), h2)[0]
|
||||
check("00:30 is covered by the 18:05 tomorrow figure, as TODAY's",
|
||||
rs(GONE, GONE, at(4, 0, 30), h2)[0] is not None)
|
||||
@@ -165,9 +166,12 @@ check("02:59: tomorrow's 12.0 kWh is now today's, there is no tomorrow",
|
||||
check("... its sun is counted on the day it is for (06:00-20:00 on the 4th)",
|
||||
fmid is not None and fmid.between(at(4, 3, 0), at(4, 7, 0)) is not None
|
||||
and fmid.between(at(4, 3, 0), at(4, 7, 0)) > 0.0)
|
||||
check("03:01 (midnight + 3 h): not used any more",
|
||||
rs(GONE, GONE, at(4, 3, 1), h2)[0] is None)
|
||||
check("... and not the next evening either (past midnight + 3 h)",
|
||||
check("03:01: still used (OPT-34: until the bell starts at 06:00)",
|
||||
rs(GONE, GONE, at(4, 3, 1), h2)[0] is not None
|
||||
and rs(GONE, GONE, at(4, 5, 59), h2)[0] is not None)
|
||||
check("06:00 (the bell starts): not used any more",
|
||||
rs(GONE, GONE, at(4, 6, 0), h2)[0] is None)
|
||||
check("... and not the next evening either (past 06:00)",
|
||||
rs(GONE, GONE, at(4, 22, 0), h2)[0] is None)
|
||||
fe = rs(st(0.1, at(4, 21, 50)), GONE, at(4, 22, 0), h2)[0]
|
||||
check("... the next evening, with today fresh and tomorrow's sensor down, "
|
||||
@@ -268,11 +272,16 @@ hy = solarfc.Hold()
|
||||
rs(st(0.4, at(3, 17, 5)), st(12.0, at(3, 17, 5)), at(3, 17, 10), hy)
|
||||
check("F1: a 17:05 reading is kept at 22:00 (5 h) ...",
|
||||
(lambda f: f is not None and f.kept)(rs(GONE, GONE, at(3, 22, 0), hy)[0]))
|
||||
check("... and at 02:59 next day (9 h 54 min), the midnight + 3 h bound ...",
|
||||
check("... and at 02:59 next day (9 h 54 min) ...",
|
||||
(lambda f: f is not None and f.kept)(rs(GONE, GONE, at(4, 2, 59),
|
||||
hy)[0]))
|
||||
check("... and at 03:00 next day it is not (midnight + 3 h; 9 h 55 min old)",
|
||||
rs(GONE, GONE, at(4, 3, 0), hy)[0] is None)
|
||||
check("... and at 03:00 and 05:59 next day (OPT-34: the bell starts at 06:00)",
|
||||
(lambda f: f is not None and f.kept)(rs(GONE, GONE, at(4, 3, 0),
|
||||
hy)[0])
|
||||
and (lambda f: f is not None and f.kept)(rs(GONE, GONE, at(4, 5, 59),
|
||||
hy)[0]))
|
||||
check("... and at 06:00 it is not (12 h 55 min old, the bell has started)",
|
||||
rs(GONE, GONE, at(4, 6, 0), hy)[0] is None)
|
||||
hm = solarfc.Hold()
|
||||
rs(st(0.9, at(3, 9, 5)), st(12.0, at(3, 9, 5)), at(3, 9, 10), hm)
|
||||
check("F1: a 09:05 reading is kept at 20:00 (10 h 55 min) but not at 22:00",
|
||||
@@ -564,18 +573,18 @@ check("... and the 22:00 night run is planned and charges",
|
||||
present(ld) and ld["runs_on"] is True
|
||||
and sum(r["charging"] for r in rd) > len(rd) // 2)
|
||||
|
||||
# e. the bound: midnight + 3 h
|
||||
# e. the bound: until the bell starts (06:00, OPT-34; it was midnight + 3 h)
|
||||
mid = [at(DAY3, 16, 0) + timedelta(minutes=30 * i) for i in range(12)]
|
||||
ce, re_, pe = drive27(opts(), stops_at(LAST), pre=mid + [at(4, 2, 30)],
|
||||
start=at(4, 2, 30))
|
||||
ce, re_, pe = drive27(opts(), stops_at(LAST), pre=mid + [at(4, 5, 30)],
|
||||
start=at(4, 5, 30))
|
||||
le = nth(re_, -1, "last cycle")
|
||||
check("02:30 (before midnight + 3 h): the figure from 17:05 is still used, "
|
||||
check("05:30 (before the bell starts): the figure from 17:05 is still used, "
|
||||
"as today's; the night run is planned",
|
||||
present(le) and le["kept"] and le["runs_on"] is True)
|
||||
cf, rf, pf = drive27(opts(), stops_at(LAST), pre=mid + [at(4, 3, 30)],
|
||||
start=at(4, 3, 30))
|
||||
cf, rf, pf = drive27(opts(), stops_at(LAST), pre=mid + [at(4, 6, 30)],
|
||||
start=at(4, 6, 30))
|
||||
lf = nth(rf, -1, "last cycle")
|
||||
check("03:30 (after midnight + 3 h): a figure from before the night is not "
|
||||
check("06:30 (the bell has started): a figure from before the night is not "
|
||||
"used: no forecast, 1.5x, not worth, no charge",
|
||||
present(lf) and lf["fc_none"] and lf["runs_on"] is False
|
||||
and lf["reason"] == "not_worth" and not any(r["charging"] for r in rf))
|
||||
|
||||
Reference in New Issue
Block a user