OPT-34 review: test that a battery leaving the plan leaves the latch
test_opt34.py part 4 drives Controller._latch_charge() directly: a battery that leaves the plan is dropped at once, does not rejoin while nothing charges, an empty latch is cleared from the store, and the screen says the charge goes on only while the latched battery is below its level. Catches two reviewer mutants that survived the round-2 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,8 @@ DECISIONS note and the dev report.
|
||||
and before a charge has started, up and down;
|
||||
e. the last hour, after the kept figure has ended at 06:00: the charge under
|
||||
way goes on to its level, also over a restart; the screens say so.
|
||||
3. The text, EN and NL.
|
||||
4. `_latch_charge()` alone: a battery that leaves the plan leaves the latch.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@@ -566,6 +568,63 @@ check("'kept for tonight' is unchanged (EN and NL)",
|
||||
and nl["home_words"]["solar"]["kept"]
|
||||
== "Zonneprognose van {at}, bewaard voor vannacht.")
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
print("\n4. The latch alone: a battery that leaves the plan leaves the latch")
|
||||
from types import SimpleNamespace # noqa: E402
|
||||
from app import modetrade, priceruns # noqa: E402
|
||||
|
||||
_tmp = tempfile.mkdtemp(prefix="o34-")
|
||||
lc = Controller(dict(opts()), rp.Hass(("a", "b"), lambda t: 300.0,
|
||||
{"a": 40.0, "b": 40.0}),
|
||||
rp._Store(), rp._Pub(), stop=asyncio.Event(),
|
||||
peak_db_path=os.path.join(_tmp, "tariff.db"),
|
||||
price_history_path=os.path.join(_tmp, "ph.json"))
|
||||
n0 = at(4, 1, 0)
|
||||
lruns = SimpleNamespace(cheap=priceruns.Run(at(3, 22, 0), at(4, 7, 0), 0.26))
|
||||
charging = SimpleNamespace(action=modetrade.CHARGE,
|
||||
roles={A: modetrade.CHARGE, B: modetrade.CHARGE})
|
||||
resting = SimpleNamespace(action=None, roles={A: modetrade.HOLD,
|
||||
B: modetrade.HOLD})
|
||||
|
||||
|
||||
def latch_step(fc, tick, targets, now=n0):
|
||||
lc.solar_fc, lc.mode_tick = fc, tick
|
||||
lc._latch_charge(now, lruns, targets)
|
||||
return lc._charge_latch, lc.store.data.get(m.CHARGE_LATCH_KEY)
|
||||
|
||||
|
||||
FC = object() # a forecast is read (fresh or kept)
|
||||
lt, saved = latch_step(FC, charging, {A: 80.0, B: 70.0})
|
||||
check("both batteries charge with a forecast: both are latched at their "
|
||||
"levels, to the run's end + one slot, and saved",
|
||||
lt is not None and lt[1] == {A: 80.0, B: 70.0}
|
||||
and lt[0] == at(4, 7, 15) and saved is not None
|
||||
and saved["levels"] == {A: 80.0, B: 70.0})
|
||||
lt, saved = latch_step(FC, charging, {B: 70.0})
|
||||
check("A leaves the plan (its mode or use changed): A is dropped from the "
|
||||
"latch at once, B stays", lt is not None and lt[1] == {B: 70.0}
|
||||
and saved["levels"] == {B: 70.0})
|
||||
lc.solar_fc = None
|
||||
check("... and with the forecast then gone, A has no latched level (it is "
|
||||
"not charged back to 80 %)", lc.plan_targets() == {B: 70.0})
|
||||
lt, saved = latch_step(FC, resting, {A: 80.0, B: 70.0})
|
||||
check("A back in the plan while nothing charges: it does not rejoin",
|
||||
lt is not None and lt[1] == {B: 70.0})
|
||||
lt, saved = latch_step(FC, resting, {A: 80.0})
|
||||
check("B leaves the plan too: the latch is empty, so it is gone and "
|
||||
"cleared from the store", lt is None and saved is None
|
||||
and lc.plan_targets() is None)
|
||||
latch_step(FC, charging, {A: 80.0})
|
||||
lc.solar_fc = None
|
||||
ia = next(i for i in lc.inverters if i.name == A)
|
||||
ia.soc = 50.0
|
||||
st_below = homeview.plan_state(lc)
|
||||
ia.soc = 80.0
|
||||
st_at = homeview.plan_state(lc)
|
||||
check("the screen says the charge goes on only while the latched battery is "
|
||||
f"below its level ({st_below!r} at 50 %, {st_at!r} at 80 %)",
|
||||
st_below == "latched" and st_at == "no_forecast")
|
||||
|
||||
print()
|
||||
if fails:
|
||||
print(f"{len(fails)} FAILED:")
|
||||
|
||||
Reference in New Issue
Block a user