MAINT-13 round 2: gate open when nothing holds the charge back; safety93 scenario restored
- gate_open is true with no price gate set up, in a cheap window, or while the pack is taking charge; the stall rule and timeout now work on a no-tariff site. - reset the save timer on a phase change; exact 5 min gap-cap test. - test_safety93: original timeout scenario kept (B finished) plus a case where a due B takes the slot after A's failure. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
28eff568b5
commit
6f05b2e4be
@@ -37,7 +37,7 @@ import safety79_identity as s79 # noqa: E402
|
||||
import safety84_identity as s84 # noqa: E402
|
||||
from app import packmode # noqa: E402
|
||||
from app.main import Controller # noqa: E402
|
||||
from app.maintenance import (CHARGE_TIMEOUT_MIN, HOLD, IDLE, # noqa: E402
|
||||
from app.maintenance import (CHARGE_TIMEOUT_MIN, DRAIN, HOLD, IDLE, # noqa: E402
|
||||
MaintResult)
|
||||
from app.store import unit_key # noqa: E402
|
||||
from named_absence import first, present # noqa: E402
|
||||
@@ -203,10 +203,6 @@ def timed_out(end):
|
||||
s.data[unit_key(A, "phase_started")] = (
|
||||
rig.BASE + timedelta(seconds=end - CHARGE_TIMEOUT_MIN * 60 - 1)
|
||||
).isoformat()
|
||||
# MAINT-13: a timed-out charge now backs off 7 days instead of restarting
|
||||
# at once, so a due B would start its own drain here. B has finished its
|
||||
# cycle, as in b_done(), so only the charge end is graded.
|
||||
s.data[unit_key("inverter-b", "last_completed")] = rig.BASE.isoformat()
|
||||
return s
|
||||
|
||||
|
||||
@@ -225,9 +221,16 @@ def switch_off(at):
|
||||
return before
|
||||
|
||||
|
||||
def timed_out_b_done(end):
|
||||
"""timed_out(), with B's monthly cycle finished so it starts none."""
|
||||
s = timed_out(end)
|
||||
s.data[unit_key("inverter-b", "last_completed")] = rig.BASE.isoformat()
|
||||
return s
|
||||
|
||||
|
||||
ENDS = {
|
||||
"timeout": lambda: run(2, 6000.0, 9999.0, step=1760.0, dur=2080.0,
|
||||
store=timed_out(1780.0)),
|
||||
store=timed_out_b_done(1780.0)),
|
||||
"Off": lambda: run(2, 6000.0, 9999.0, step=1760.0, dur=2080.0,
|
||||
store=b_done(), before=switch_off(1780.0),
|
||||
extra={"battery_modes_enabled": True}),
|
||||
@@ -250,6 +253,27 @@ for k, fn in ENDS.items():
|
||||
f"the grid", at(old, 1780.0, "b") == -1600.0
|
||||
and charging_hi(old, 1780, 1798, hi1) >= 1)
|
||||
|
||||
# MAINT-13: A's timed-out charge is a failed cycle and backs off, so A no longer
|
||||
# restarts at once; a due B takes the slot instead and starts ITS drain. That is
|
||||
# a drain start (a step to the drain rate by design), not a charge end.
|
||||
rows, c = run(2, 6000.0, 9999.0, step=1760.0, dur=2080.0,
|
||||
store=timed_out(1780.0))
|
||||
print(f" timeout, B due: A {[cmd(r)['a'] for r in rows if 1776 <= r[0] <= 1790]}"
|
||||
f" B {[cmd(r)['b'] for r in rows if 1776 <= r[0] <= 1790]}")
|
||||
check("timeout with B due: the charge ends at 1780 s and A is not restarted",
|
||||
phase_at(rows, 1778.0) == "charge" and phase_at(rows, 1780.0) == IDLE
|
||||
and c.maints[0].phase == IDLE
|
||||
and c.maints[0].backoff_until(rig.BASE + timedelta(seconds=1800))
|
||||
is not None)
|
||||
check("⭐ timeout with B due: no battery charges from the grid after it",
|
||||
charging_hi(rows, 1780, 1798, hi1) == 0
|
||||
and min(cmd(r)["b"] for r in rows if r[0] >= 1780) >= 0.0)
|
||||
check("...B takes the slot and begins its own drain, which is the only large "
|
||||
"step, to the drain rate and no higher",
|
||||
c.maints[1].phase == DRAIN
|
||||
and max(cmd(r)["b"] for r in rows if r[0] >= 1780) <= 2000.0
|
||||
and moves(rows, "a", 1780, 1798) <= SLEW)
|
||||
|
||||
# ============================================================================ #
|
||||
print("\n4. the charge ends while the guard has suspended it")
|
||||
# House 6000 W from 1500 s: the guard suspends the shaping, the loop has both
|
||||
|
||||
Reference in New Issue
Block a user