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
@@ -19,7 +19,8 @@ empty chart. DECISIONS/UX-54-forecast-tab.md has the record.
|
||||
import dataclasses
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from . import arbitrage, dayplan, homeview as hv, modetrade, priceruns
|
||||
from . import arbitrage, cheaproll, dayplan, homeview as hv, modetrade
|
||||
from . import priceruns
|
||||
from . import solarfc
|
||||
from .daycurve import Batt, curve
|
||||
from .packmode import SOLAR_FIRST
|
||||
@@ -210,25 +211,18 @@ def _levels(c, est, fc, trust, now, end, runs, floor, ceil, notes_b, shadow,
|
||||
arbitrage.threshold_eur_kwh(c.o),
|
||||
uncertainty_of(plan.read.product)
|
||||
| arbitrage.weather_uncertainty(True, c.solar_fc))
|
||||
end_t = cheap.end
|
||||
for _ in range(24):
|
||||
ext = dataclasses.replace(rp, cheap=priceruns.Run(
|
||||
|
||||
def packs_at(end_t):
|
||||
"""The packs at the curve's level when a run ends at `end_t`."""
|
||||
at = dataclasses.replace(rp, cheap=priceruns.Run(
|
||||
cheap.start, end_t, cheap.mean_eur_kwh))
|
||||
rt, lv = settle(ext, lv0)
|
||||
at_end = [dataclasses.replace(packs[n], soc=v)
|
||||
for n, v in ((n, _level_at(lv.get(n, ()), end_t))
|
||||
for n in lv) if v is not None]
|
||||
e = modetrade.energy(at_end, floor, ceil, targets=targets)
|
||||
if e[0] <= 1e-6:
|
||||
break
|
||||
new = priceruns.plan(
|
||||
plan.read.points, end_t, required_eur_kwh=required,
|
||||
charge_kwh=e[0], charge_kw=e[1], sell_kwh=0.0, sell_kw=0.0)
|
||||
nxt = new.cheap
|
||||
if nxt is None or not new.charge_useful() or nxt.start > end_t \
|
||||
or nxt.end <= end_t:
|
||||
break
|
||||
end_t = nxt.end
|
||||
_rt, lv = settle(at, lv0)
|
||||
return [dataclasses.replace(packs[n], soc=v)
|
||||
for n, v in ((n, _level_at(lv.get(n, ()), end_t))
|
||||
for n in lv) if v is not None]
|
||||
end_t = cheaproll.roll_end(
|
||||
cheap, plan.read.points, packs_at, required=required,
|
||||
floor_pct=floor, ceiling_pct=ceil, targets=targets)
|
||||
ext = dataclasses.replace(rp, cheap=priceruns.Run(
|
||||
cheap.start, end_t, cheap.mean_eur_kwh))
|
||||
rt, lv = settle(ext, lv0)
|
||||
|
||||
Reference in New Issue
Block a user