OPT-36: Leftover solar counts Cheap hours and Solar first batteries before buying #229
@@ -268,6 +268,7 @@ PROFILE_LATE = ('{"periods": ['
|
||||
CHOICE = {"a": (True, "leftover_solar", False),
|
||||
"b": (True, "cheap_hours", False)}
|
||||
LAST = at(3, 17, 5)
|
||||
MIDNIGHT = at(4, 0, 0)
|
||||
EVENING = [at(3, 16, 0) + timedelta(minutes=30 * i) for i in range(12)] \
|
||||
+ [at(3, 21, 55)]
|
||||
|
||||
@@ -290,7 +291,12 @@ def sensors(*, silent=True, fresh_from=None, fresh=(1.0, 5.0),
|
||||
when = now if fresh_until is None else min(now, fresh_until)
|
||||
return st(fresh[0] if ent == T_ENT else fresh[1], when)
|
||||
when = min(now, LAST) if silent else now
|
||||
return st(0.4 if ent == T_ENT else 6.0, when)
|
||||
# OPT-36: a fresh sensor reads the day it is on. After midnight "today"
|
||||
# is the 4th (6.0 kWh, the figure the 17:05 reading called tomorrow's),
|
||||
# not the evening's 0.4 kWh left of the 3rd; with that, fresh and
|
||||
# kept are the same figure all night (before, the plans only agreed
|
||||
# because A was capped at the ceiling in both).
|
||||
return st(0.4 if ent == T_ENT and now < MIDNIGHT else 6.0, when)
|
||||
return f
|
||||
|
||||
|
||||
@@ -509,12 +515,14 @@ for k in R:
|
||||
fa, si, rr = R["fresh"], R["silent"], R["restart"]
|
||||
|
||||
# a. silent from 17:05
|
||||
check("a fresh figure all night: A ends high (OPT-36: the ceiling, 87 % "
|
||||
"before B was counted), B full", fa["soc"][0] > 80.0 and fa["soc"][1] > 94.5)
|
||||
# OPT-36: A's level is 95 % to ~05:00, then 78.4 % when B's cheap run is longer
|
||||
# (B's give 5.9 -> 7.1 kWh); A, already at 81.5 %, stops there.
|
||||
check("a fresh figure all night: A ends at 81.5 % (the plan's 78.4 % came "
|
||||
"after it had passed), B full",
|
||||
abs(fa["soc"][0] - 81.5) < 0.5 and fa["soc"][1] > 94.5)
|
||||
check("sensors silent from 17:05: A ends where the fresh run ends it "
|
||||
f"({si['soc'][0]:.1f} against {fa['soc'][0]:.1f} %; OPT-36: the "
|
||||
"plans are equal at 04:30 below, the path to them is not)",
|
||||
abs(si["soc"][0] - fa["soc"][0]) < 15.0 and si["soc"][0] > 75.0)
|
||||
f"({si['soc'][0]:.1f} against {fa['soc'][0]:.1f} %)",
|
||||
abs(si["soc"][0] - fa["soc"][0]) < 0.3)
|
||||
check("... and so does B (Cheap hours; the wide no-forecast gap does not "
|
||||
f"stop its slices): {si['soc'][1]:.1f} against {fa['soc'][1]:.1f} %",
|
||||
abs(si["soc"][1] - fa["soc"][1]) < 0.3)
|
||||
@@ -530,7 +538,7 @@ check("01:00 and 04:30: the kept figure is in use, with a day plan, and the "
|
||||
and m4["target_a"] is not None
|
||||
and near(m4["target_a"], fa["marks"]["04:30"]["target_a"], 1e-9))
|
||||
check("... and the level is the fresh run's (the kept figure counts as a "
|
||||
"fresh one)", m4["target_a"] > 50.0)
|
||||
"fresh one)", near(m4["target_a"], 95.0, 0.2))
|
||||
m6 = si["marks"]["06:30"]
|
||||
check("06:30: the kept figure has ended (the bell started) and the screen "
|
||||
"does not say 'kept' (the charge was done by then in this shape)",
|
||||
@@ -653,15 +661,19 @@ md = fd["marks"]
|
||||
print(f" f1_dark: A level 01:55 {md['01:55']['target_a']} -> 02:15 "
|
||||
f"{md['02:15']['target_a']}; A {fd['soc_at']['06:55'][0]:.1f} % "
|
||||
"at 06:55")
|
||||
# OPT-36: the level (82.3 % at 02:15) falls to 64.2 % by 04:00 as B's cheap run
|
||||
# is made longer (B's expected give grows); A stops at its SoC of that moment
|
||||
# (72.8 %) and the latch holds 64.2 % after the figure ends.
|
||||
check("F-1 darker fresh figure at 02:00: the level rises, is held after "
|
||||
"05:00 with no forecast (never 'read 17:05'), and A charges to it",
|
||||
"05:00 with no forecast (never 'read 17:05'), and A charges while it is "
|
||||
"above its level",
|
||||
md["02:15"]["target_a"] is not None
|
||||
and md["01:55"]["target_a"] is not None
|
||||
and md["02:15"]["target_a"] > md["01:55"]["target_a"] + 3.0
|
||||
and all("17:05" not in md[h]["line"] for h in md if h >= "02:15")
|
||||
and all(md[h]["fc_none"] for h in md if "05:15" <= h < "07:00")
|
||||
and fd["soc_at"]["06:55"][0] > fd["soc_at"]["02:15"][0] + 8.0
|
||||
and fd["soc_at"]["06:55"][0] < md["02:15"]["target_a"] + 1.5)
|
||||
and near(md["05:15"]["target_a"], 64.24, 0.2)
|
||||
and near(fd["soc_at"]["06:55"][0], 72.8, 0.5))
|
||||
|
||||
tb = R["tail_bfull"]
|
||||
check("B full: the run ends at 06:33 before A is at its level, so the next "
|
||||
|
||||
@@ -225,9 +225,7 @@ check("Leftover solar and Cheap hours: a give block exactly on the give run "
|
||||
# OPT-36: a larger evening (4.8 kW) so that B (Cheap hours) does not cover the
|
||||
# dear hours alone and A still buys from the grid; A starts at 30 %.
|
||||
c_n = S.make("dynamic", at(0, 18), soc=(30.0, 40.0), evening=4800.0)
|
||||
RUN_END = c_n.mode_runs.cheap.end
|
||||
END_S = RUN_END.astimezone(S.brussels(RUN_END).tzinfo).strftime("%H:%M")
|
||||
END_H = S.brussels(RUN_END).hour + S.brussels(RUN_END).minute / 60.0
|
||||
END_S, END_H = "03:00", 3.0 # the run's end, recomputed for this house
|
||||
nb = tab(c_n, at(0, 18))["days"][0]["batteries"]
|
||||
check("in the night before the cheap run both charge from the grid in it "
|
||||
f"(01:00 to {END_S}), then give at 17:00",
|
||||
@@ -251,11 +249,11 @@ def at_h(b, h):
|
||||
return dict((round(x, 3), v) for x, v in b["levels"]).get(h, float("nan"))
|
||||
|
||||
|
||||
check("the curve charges in a grid block: A (planned level 64 %) and B "
|
||||
check("the curve charges in a grid block: A (planned level 73 %) and B "
|
||||
"(Cheap hours, to the end of its run) are well above where they "
|
||||
"were at 01:00, and stay put after the run",
|
||||
all(at_h(b, END_H) - at_h(b, 1.0) > 8.0
|
||||
and abs(at_h(b, END_H + 1.0) - at_h(b, END_H)) < 1e-6
|
||||
and abs(at_h(b, 4.0) - at_h(b, END_H)) < 1e-6
|
||||
for b in nb) and nb[0]["levels"][0][1] == 30.0)
|
||||
# Modes off: the verdict's legs.
|
||||
c_f = S.make("off", at(10, 7))
|
||||
|
||||
Reference in New Issue
Block a user