OPT-38 round 2: a kept tomorrow reading is flagged kept only from 20:00
Before the bell ends it replaced today's Home line and the event log with the kept-for-tonight wording. stand_in() docstring covers the tomorrow case. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
c43873b142
commit
0bacafadf0
@@ -332,8 +332,9 @@ class Hold:
|
|||||||
|
|
||||||
The kept reading must be for `day0`, and either (a) at most `FRESH_S`
|
The kept reading must be for `day0`, and either (a) at most `FRESH_S`
|
||||||
old, or (b) used at night: from the end of the bell to local midnight,
|
old, or (b) used at night: from the end of the bell to local midnight,
|
||||||
at most `KEPT_MAX_AGE_S` old. `kept` is true when (b) was needed,
|
at most `KEPT_MAX_AGE_S` old; a "tomorrow" reading at any hour
|
||||||
or `as_today` (OPT-34: a tomorrow figure standing in for today, after
|
(OPT-38; `read_sum()` flags it kept only from the end of the bell).
|
||||||
|
`kept` is true when (b) was needed, or `as_today` (OPT-34: a tomorrow figure standing in for today, after
|
||||||
midnight and until the bell starts, `KEPT_MORNING_MAX_AGE_S`)."""
|
midnight and until the bell starts, `KEPT_MORNING_MAX_AGE_S`)."""
|
||||||
rec = self._r.get((kind, entity, day0))
|
rec = self._r.get((kind, entity, day0))
|
||||||
if rec is None:
|
if rec is None:
|
||||||
@@ -558,6 +559,9 @@ def read_sum(today, tomorrow, now: datetime, hold: Hold | None = None):
|
|||||||
if why0 is not None:
|
if why0 is not None:
|
||||||
return None, why0, gaps
|
return None, why0, gaps
|
||||||
tday = _sum(tdays) if tomorrow and len(tdays) == len(tomorrow) else None
|
tday = _sum(tdays) if tomorrow and len(tdays) == len(tomorrow) else None
|
||||||
kept = kept or (tday is not None and tkept)
|
# OPT-38: before the bell ends a kept tomorrow reading is no "kept for
|
||||||
|
# tonight": it must not replace today's line or the log.
|
||||||
|
kept = kept or (tday is not None and tkept
|
||||||
|
and _local_hour(now) >= BELL_TO_H)
|
||||||
# The oldest member's report is when the sum was last fully known.
|
# The oldest member's report is when the sum was last fully known.
|
||||||
return Forecast(_sum(days), tday, min(ats), kept), None, gaps
|
return Forecast(_sum(days), tday, min(ats), kept), None, gaps
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ for label, tm in (("stale", st(12.0, at(4, 9, 5))), ("unavailable", GONE)):
|
|||||||
check(f"14:00, today fresh, tomorrow {label} since 09:05 (over 3 h): "
|
check(f"14:00, today fresh, tomorrow {label} since 09:05 (over 3 h): "
|
||||||
"the 09:05 figure covers it, kept (OPT-38: at any hour)",
|
"the 09:05 figure covers it, kept (OPT-38: at any hour)",
|
||||||
fd is not None and fd.tomorrow is not None
|
fd is not None and fd.tomorrow is not None
|
||||||
and fd.tomorrow.kwh == 12.0 and fd.kept)
|
and fd.tomorrow.kwh == 12.0 and not fd.kept)
|
||||||
fn = rs(st(0.1, at(4, 20, 55)), tm, at(4, 21, 0), h9)[0]
|
fn = rs(st(0.1, at(4, 20, 55)), tm, at(4, 21, 0), h9)[0]
|
||||||
check(f"21:00, tomorrow {label}: the 09:05 figure covers it, kept",
|
check(f"21:00, tomorrow {label}: the 09:05 figure covers it, kept",
|
||||||
fn is not None and fn.tomorrow is not None
|
fn is not None and fn.tomorrow is not None
|
||||||
|
|||||||
@@ -186,9 +186,9 @@ check("a fresh figure replaces the kept one at once (04:00: 5.0 today, "
|
|||||||
and fy.today.kwh == 5.0 and fy.tomorrow.kwh == 9.0)
|
and fy.today.kwh == 5.0 and fy.tomorrow.kwh == 9.0)
|
||||||
fy2 = rs(st(5.0, at(4, 7, 55)), GONE, at(4, 8, 0), hd)[0]
|
fy2 = rs(st(5.0, at(4, 7, 55)), GONE, at(4, 8, 0), hd)[0]
|
||||||
check("... and at 08:00, today fresh and tomorrow's sensor down for over 3 h: "
|
check("... and at 08:00, today fresh and tomorrow's sensor down for over 3 h: "
|
||||||
"tomorrow is the 03:50 figure for the 5th (9.0, kept: OPT-38), never "
|
"tomorrow is the 03:50 figure for the 5th (9.0, not flagged kept before 20:00: OPT-38), never "
|
||||||
"the 3rd's 12.0", fy2 is not None and fy2.today.kwh == 5.0
|
"the 3rd's 12.0", fy2 is not None and fy2.today.kwh == 5.0
|
||||||
and fy2.tomorrow is not None and fy2.tomorrow.kwh == 9.0 and fy2.kept)
|
and fy2.tomorrow is not None and fy2.tomorrow.kwh == 9.0 and not fy2.kept)
|
||||||
|
|
||||||
# Restart: the saved hold keeps the figure.
|
# Restart: the saved hold keeps the figure.
|
||||||
for label, now in (("01:00", at(4, 1, 0)), ("04:00", at(4, 4, 0))):
|
for label, now in (("01:00", at(4, 1, 0)), ("04:00", at(4, 4, 0))):
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from datetime import datetime, timedelta, timezone
|
|||||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
|
|
||||||
from app import solarfc # noqa: E402
|
from app import homeview, solarfc # noqa: E402
|
||||||
|
|
||||||
fails = []
|
fails = []
|
||||||
|
|
||||||
@@ -55,15 +55,16 @@ run(h, [(4.0, at(6, 14, 0)), (5.0, at(6, 14, 54)), (6.0, at(6, 14, 0))],
|
|||||||
at(6, 14, 55))
|
at(6, 14, 55))
|
||||||
fresh = lambda w: [(4.0, w), (5.0, at(6, 14, 54)), (6.0, w)] # noqa: E731
|
fresh = lambda w: [(4.0, w), (5.0, at(6, 14, 54)), (6.0, w)] # noqa: E731
|
||||||
f, why, gaps = run(h, fresh(at(6, 18, 20)), at(6, 18, 30))
|
f, why, gaps = run(h, fresh(at(6, 18, 20)), at(6, 18, 30))
|
||||||
check("18:30, one member last reported 14:54: tomorrow sum is there, kept",
|
check("18:30, one member last reported 14:54: tomorrow sum is there (not "
|
||||||
|
"flagged kept before 20:00)",
|
||||||
f is not None and f.tomorrow is not None and f.tomorrow.kwh == 15.0
|
f is not None and f.tomorrow is not None and f.tomorrow.kwh == 15.0
|
||||||
and f.kept and gaps == ())
|
and not f.kept and gaps == ())
|
||||||
f, _w, _g = run(h, fresh(at(6, 17, 40)), at(6, 17, 50))
|
f, _w, _g = run(h, fresh(at(6, 17, 40)), at(6, 17, 50))
|
||||||
check("17:50 (just under 3 h): fresh, not kept",
|
check("17:50 (just under 3 h): fresh, not kept",
|
||||||
f is not None and f.tomorrow.kwh == 15.0 and not f.kept)
|
f is not None and f.tomorrow.kwh == 15.0 and not f.kept)
|
||||||
f, _w, _g = run(h, fresh(at(6, 17, 55)), at(6, 18, 0))
|
f, _w, _g = run(h, fresh(at(6, 17, 55)), at(6, 18, 0))
|
||||||
check("18:00 (stale since 17:54): kept, tomorrow there",
|
check("18:00 (stale since 17:54): tomorrow there",
|
||||||
f is not None and f.tomorrow is not None and f.kept)
|
f is not None and f.tomorrow is not None and not f.kept)
|
||||||
f, _w, _g = run(h, fresh(at(6, 19, 50)), at(6, 19, 55))
|
f, _w, _g = run(h, fresh(at(6, 19, 50)), at(6, 19, 55))
|
||||||
check("19:55 (before the bell ends): tomorrow there", f.tomorrow is not None)
|
check("19:55 (before the bell ends): tomorrow there", f.tomorrow is not None)
|
||||||
|
|
||||||
@@ -80,7 +81,7 @@ check("member 12 h 10 min old: no tomorrow sum (OPT-17 rule), today stays",
|
|||||||
f, _w, _g = run(h2, [(4.0, w), (5.0, at(6, 5, 0)), (6.0, w)],
|
f, _w, _g = run(h2, [(4.0, w), (5.0, at(6, 5, 0)), (6.0, w)],
|
||||||
at(6, 16, 50))
|
at(6, 16, 50))
|
||||||
check("... and 11 h 50 min old is still kept",
|
check("... and 11 h 50 min old is still kept",
|
||||||
f is not None and f.tomorrow is not None and f.kept)
|
f is not None and f.tomorrow is not None and not f.kept)
|
||||||
|
|
||||||
# Not a partial sum: a member never read has nothing to stand in.
|
# Not a partial sum: a member never read has nothing to stand in.
|
||||||
f, _w, gaps = run(solarfc.Hold(), [(4.0, at(6, 18, 0)),
|
f, _w, gaps = run(solarfc.Hold(), [(4.0, at(6, 18, 0)),
|
||||||
@@ -117,6 +118,38 @@ for label, now in (("00:30", at(7, 0, 30)), ("10:00", at(7, 10, 0)),
|
|||||||
check(f"{label} on the 7th: the 6th's tomorrow figure is not the "
|
check(f"{label} on the 7th: the 6th's tomorrow figure is not the "
|
||||||
"7th's tomorrow", f is not None and f.tomorrow is None)
|
"7th's tomorrow", f is not None and f.tomorrow is None)
|
||||||
|
|
||||||
|
# Before 20:00 a kept tomorrow reading is not "kept for tonight": today's
|
||||||
|
# line stays the normal one (EN and NL) and the event log (main.py, from
|
||||||
|
# `fc.kept`) has no "kept".
|
||||||
|
h5 = solarfc.Hold()
|
||||||
|
solarfc.read_sum([("t", st(3.0, at(6, 9, 0)))], [("m", st(12.0, at(6, 9, 5)))],
|
||||||
|
at(6, 9, 6), h5)
|
||||||
|
for hh in (14, 18, 19):
|
||||||
|
f, _w, _g = solarfc.read_sum([("t", st(2.5, at(6, hh - 1, 55)))],
|
||||||
|
[("m", st(12.0, at(6, 9, 5)))],
|
||||||
|
at(6, hh, 0), h5)
|
||||||
|
check(f"{hh}:00, today fresh, tomorrow kept from 09:05: tomorrow there, "
|
||||||
|
"not flagged kept", f is not None and f.tomorrow is not None
|
||||||
|
and f.tomorrow.kwh == 12.0 and f.kept is False)
|
||||||
|
f, _w, _g = solarfc.read_sum([("t", st(2.5, at(6, 13, 55)))],
|
||||||
|
[("m", st(12.0, at(6, 9, 5)))], at(6, 14, 0), h5)
|
||||||
|
for lang in ("en", "nl"):
|
||||||
|
with homeview.in_lang(lang):
|
||||||
|
line = homeview.line_solar(f.today.kwh, f.today.kwh * 0.7,
|
||||||
|
homeview.hhmm(f.at), kept=f.kept)
|
||||||
|
kept_line = homeview.line_solar(1, 1, homeview.hhmm(f.at), kept=True)
|
||||||
|
print(f" {lang}: {line!r}")
|
||||||
|
if lang == "en":
|
||||||
|
check("... EN says 'Solar still to come today'",
|
||||||
|
line.startswith("Solar still to come today"))
|
||||||
|
check(f"14:00 Home line ({lang}) is the normal line, not the kept one",
|
||||||
|
line != kept_line and "2,5" in line.replace(".", ",")
|
||||||
|
and "13:55" in line)
|
||||||
|
f, _w, _g = solarfc.read_sum([("t", st(0.2, at(6, 20, 55)))],
|
||||||
|
[("m", st(12.0, at(6, 9, 5)))], at(6, 21, 0), h5)
|
||||||
|
check("21:00 as before: tomorrow kept from 09:05 is flagged kept",
|
||||||
|
f is not None and f.kept and f.tomorrow.kwh == 12.0)
|
||||||
|
|
||||||
print()
|
print()
|
||||||
if fails:
|
if fails:
|
||||||
print(f"{len(fails)} FAILED:")
|
print(f"{len(fails)} FAILED:")
|
||||||
|
|||||||
Reference in New Issue
Block a user