UX-77: Home draws today's grid charge for the hours control will really charge
The cheap run is sized at the full rating, so under the peak limit a battery is still short when it ends, and control plans the next run then. Home drew only the run under way. `cheaproll` rolls the run on the way control does (`modetrade.energy()` + `priceruns.plan()` at each run end, lifted from `dayview._levels()`), reading the levels at the charge power the peak limit leaves (peak aim less the house, else the rating). `homeview.mode_runs()` and `price_windows()` use it for today: the grid block, the Today line and the chart's cheap bars run to where control stops, each battery's block to its own stop. Display only: no control change. test_ux54: today's grid block of the night-before scenario now follows the roll. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
af2d0d2f61
commit
45535e19d7
@@ -39,7 +39,8 @@ sys.path.insert(0, os.path.join(HERE, "tools"))
|
||||
logging.disable(logging.WARNING)
|
||||
|
||||
import ux54_scenarios as S # noqa: E402
|
||||
from app import arbitrage, dayplan, dayview, homeview, modetrade # noqa: E402
|
||||
from app import arbitrage, cheaproll, dayplan, dayview, homeview # noqa: E402
|
||||
from app import modetrade # noqa: E402
|
||||
from app import packmode, packshare, peakguard, solarfc, uitext # noqa: E402
|
||||
from app.main import pack_energy_of # noqa: E402
|
||||
from app.price import Uncertainty # noqa: E402
|
||||
@@ -232,11 +233,19 @@ END_S = S.brussels(END).strftime("%H:%M")
|
||||
check(f"the cheap run is 01:00 to {END_S} (02:30 for this house)",
|
||||
c_n.mode_runs.cheap.start == at(1, 0, 0) and END == at(2, 30, 0))
|
||||
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",
|
||||
all([r["kind"] for r in b["blocks"]] == ["grid", "give"] for b in nb)
|
||||
and all(b["blocks"][0]["from"] == "01:00"
|
||||
and b["blocks"][0]["to"] == END_S for b in nb))
|
||||
# UX-77: today's block runs to where control stops charging: the 1.5 h run is
|
||||
# sized at the full rating, the peak limit leaves 3.1 kW, so control plans the
|
||||
# next run when it ends (`cheaproll`), and each battery's block ends at its stop.
|
||||
RL = cheaproll.for_today(c_n, c_n.mode_runs, at(0, 18))
|
||||
ENDS = [S.brussels(RL.end_for(inv.name, END)).strftime("%H:%M")
|
||||
for inv in c_n.inverters]
|
||||
check("in the night before the cheap run both charge from the grid from "
|
||||
f"01:00 to where control stops ({ENDS}, the run rolls on after "
|
||||
f"{END_S}), then give at 17:00",
|
||||
RL is not None and RL.end > END and ENDS[0] < ENDS[1]
|
||||
and all([r["kind"] for r in b["blocks"]] == ["grid", "give"] for b in nb)
|
||||
and all(b["blocks"][0]["from"] == "01:00" for b in nb)
|
||||
and [b["blocks"][0]["to"] for b in nb] == ENDS)
|
||||
# UX-53: no grid block while the gate refuses.
|
||||
for why in ("peak", "not_worth"):
|
||||
c_n.mode_gate = why
|
||||
@@ -255,12 +264,16 @@ def at_h(b, h):
|
||||
|
||||
|
||||
LVL_A = c_n.plan_targets()[c_n.inverters[0].name]
|
||||
END_HS = [(S.brussels(RL.end_for(inv.name, END)).replace(tzinfo=None)
|
||||
- S.brussels(DAY0).replace(tzinfo=None)).total_seconds() / 3600.0
|
||||
for inv in c_n.inverters]
|
||||
check(f"the curve charges in a grid block: A (planned level {LVL_A:.0f} %) "
|
||||
"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 + 0.5) - at_h(b, END_H)) < 1e-6
|
||||
for b in nb) and nb[0]["levels"][0][1] == 30.0)
|
||||
"and B (Cheap hours, to the end of its block) are well above where "
|
||||
"they were at 01:00, and stay put after the block",
|
||||
all(at_h(b, eh) - at_h(b, 1.0) > 8.0
|
||||
and all(abs(v - at_h(b, eh)) < 1e-6 for x, v in b["levels"]
|
||||
if eh + 1e-6 < x < eh + 3.0)
|
||||
for b, eh in zip(nb, END_HS)) and nb[0]["levels"][0][1] == 30.0)
|
||||
# Modes off: the verdict's legs.
|
||||
c_f = S.make("off", at(10, 7))
|
||||
fb = tab(c_f, at(10, 7))
|
||||
|
||||
Reference in New Issue
Block a user