OPT-36: Leftover solar counts what Cheap hours and Solar first batteries will give before buying
checks / unit (pull_request) Failing after 59m31s
infra-pin / fresh (pull_request) Successful in 2s

Live 0.20.0: A (Leftover solar, 60 %) charged to 95 % while B (Cheap hours,
94 %) already covered the expensive hours. dayplan.plan() now takes off the
shortfall what Cheap hours batteries will hold when the hours start (the
ceiling or what their cheap run reaches under the peak aim) and what Solar
first batteries will still hold after the night's use. Home reads a give
block after the planned charge, plan_cover() is the plan's own figure, and
the Why line says other batteries cover.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
glenn schrooyen
2026-11-02 02:03:04 +01:00
co-authored by Claude
parent 01e88a24f2
commit 05746c0564
11 changed files with 867 additions and 23 deletions
@@ -7,5 +7,6 @@
- **Shortfall.** `sum_h max(0, house_h - trust x sun_h)` over every expensive hour, `/ EFF`, from the floor. It replaces the use over the run with no sun counted, which on a day and night tariff bought for the whole day (G1, `reports/UX-69-design-report.md`). The sun before the run is unchanged. A run with its dear hours after sunset gives the old number.
- **House use.** An hour with sun is read at no less than the night base, as the sun sum reads it (the profile is net of the sun). An hour without is read as measured. An hour with no forecast counts no sun.
- **Several batteries.** One total, shared by capacity with the ceiling passed on (`dayplan._spread()`). With the same floor and ceiling for all, they reach the ceiling together, so a shortfall that one battery cannot hold fills both to the same level, not one first. More than all hold: all go to the ceiling, `Plan.uncovered_kwh` is the rest, carried by another battery (Cheap hours, Solar first) or the grid, as the screen says.
- **Cheap hours** still fills up and is not counted in the share; **Solar first** still never charges from the grid. The mode help says so.
- **Not done:** the run length (OPT-25); netting what a Cheap hours or Solar first battery will hold against the shortfall.
- **Cheap hours** still fills up; **Solar first** still never charges from the grid. The mode help says so.
- **OPT-36 (0.20.1):** what Cheap hours batteries will give in the expensive hours is taken off the shortfall before Leftover solar shares it (`dayplan._cheap_give_kwh()`: its level when they start, the ceiling or what its cheap run reaches under the peak aim, minus the floor, x capacity x EFF). Owner, 2026-11-02: Solar first batteries count too (`_solar_first_give_kwh()`): their level now less the house's night use until the hours start, shared by the energy held, then the same sum; a battery the night drains to the floor counts 0. Live, 2026-11-02: A at 60 % went to 95 % while B at 94 % covered the hours. Test: `test_opt36.py`.
- **Not done:** the run length (OPT-25).