OPT-23, OPT-28: the day plan counts the sun right, and the night charge covers the expensive-hour shortfall
OPT-23: a state-only forecast is read from now for every span (Forecast.between since=), so the plan's per-hour sun adds up to the day's figure, today and tomorrow. Hourly splits are unchanged. The Forecast tab reads spans the same way. OPT-28: a Leftover solar battery buys, from the floor, the sum over the expensive hours of max(0, house - trust x sun), / EFF. Several Leftover solar batteries hold it together by capacity, the ceiling passes the rest on, and what none can hold is said (Plan.uncovered_kwh). Home's grid block, the Batteries line and the mode help (EN + NL) say the level, what it covers, and that Leftover solar buys only what the sun will not give. 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
4a1f6cc2d9
commit
995028bc5d
@@ -76,12 +76,20 @@ class Forecast:
|
||||
tomorrow: Day | None
|
||||
at: datetime # when the sensor last reported
|
||||
|
||||
def between(self, t0: datetime, t1: datetime) -> float | None:
|
||||
def between(self, t0: datetime, t1: datetime,
|
||||
since: datetime | None = None) -> float | None:
|
||||
"""kWh the sun should give between `t0` (now or later) and `t1`.
|
||||
None when the span reaches the sunny hours of a day with no
|
||||
forecast (tomorrow, when its sensor is not set)."""
|
||||
forecast (tomorrow, when its sensor is not set).
|
||||
|
||||
`since` is the moment a state-only "left today" figure counts from
|
||||
(OPT-23): `t0` itself when not given, so a span that starts later
|
||||
than now would be spread over what is left of the bell from its own
|
||||
start. Pass now for every span of a plan, and the spans add up to
|
||||
the figure. An hourly split ignores it."""
|
||||
if t1 <= t0:
|
||||
return 0.0
|
||||
since = t0 if since is None else since
|
||||
last = self.tomorrow or self.today
|
||||
if t1 > last.day0 + timedelta(days=1, hours=BELL_FROM_H):
|
||||
return None
|
||||
@@ -92,7 +100,7 @@ class Forecast:
|
||||
a = max(t0, day.day0)
|
||||
b = min(t1, day.day0 + timedelta(days=1))
|
||||
if b > a:
|
||||
total += _day_between(day, a, b, t0)
|
||||
total += _day_between(day, a, b, since)
|
||||
return total
|
||||
|
||||
|
||||
@@ -124,8 +132,12 @@ def _day_between(day: Day, a: datetime, b: datetime, now: datetime) -> float:
|
||||
out += kwh * (hi - lo).total_seconds() / (e - s).total_seconds()
|
||||
return out
|
||||
# State only: `kwh` is what is left from `max(now, day0)` to the day's
|
||||
# end, spread over the bell.
|
||||
h_from = _hours_since(day.day0, max(now, day.day0))
|
||||
# end, spread over the bell. Nothing of it is before that moment.
|
||||
start = max(now, day.day0)
|
||||
a = max(a, start)
|
||||
if b <= a:
|
||||
return 0.0
|
||||
h_from = _hours_since(day.day0, start)
|
||||
left = 1.0 - _bell(h_from)
|
||||
if left <= 1e-9:
|
||||
return 0.0
|
||||
|
||||
Reference in New Issue
Block a user