SAFETY-73: a battery that refuses, per inverter, with two or more
SAFETY-52's hold applied per unit at N>1 (owner, 2026-09-27, option R). A unit that gives < 100 W for 12 cycles in one direction while asked > 200 W, or trips its stale-reading gate on a ~0 W reading, gets a P_SAFETY `refused` unit limit closing that direction, so the allocator hands its share to the others within their own limits. Probe: a +-200 W pin every 15 min, one unit at a time, only while the site asks 200 W that way. All units refusing: the site law holds 0 W. Exits reseed the site target from the wire. INFO plus one WARNING (REFUSES_ABOVE_CUT_OUT) above the configured cut-out; SAFETY-42/43 no longer report a refusing unit. N=1 unchanged. test_refusal_units.py: cases a/b/c on flat and jitter registers against the old behaviour, probes, recovery, exits; mutations U1-U13 all red. TEST-19 no-fault campaign: 0 engagements in 5280 runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
652097abde
commit
016ed5a5a3
@@ -786,6 +786,14 @@ def row_battery_stuck(unit) -> str:
|
||||
f"for now")
|
||||
|
||||
|
||||
def row_battery_refuses(unit, sign, probing) -> str:
|
||||
"""SAFETY-73. One inverter's battery refuses, the others take its share."""
|
||||
way = "give" if sign > 0 else "take"
|
||||
if probing:
|
||||
return f"{unit}: testing if the battery will {way} power again"
|
||||
return f"{unit}: the battery refuses to {way} power, the others take over"
|
||||
|
||||
|
||||
# The top of the page: why the battery does what it does (the "Why" line).
|
||||
WHY_WINNER = {
|
||||
"loop": "Keeping the grid near zero",
|
||||
@@ -805,6 +813,8 @@ WHY_WINNER = {
|
||||
# SAFETY-52: the loop's two words for a battery that gives nothing.
|
||||
"battery refuses": "The battery refuses to give power",
|
||||
"battery probe": "Testing if the battery gives power again",
|
||||
# SAFETY-73: a refusing inverter's own claim, closed or probing.
|
||||
"refused": "A battery refuses power, the others take over",
|
||||
}
|
||||
WHY_LIMIT = {
|
||||
"peak(quarter peak)": "the peak limit",
|
||||
@@ -815,6 +825,7 @@ WHY_LIMIT = {
|
||||
"pack": "the battery level",
|
||||
"reserve": "the battery reserve",
|
||||
"maintenance": "battery maintenance",
|
||||
"refused": "a battery that refuses power",
|
||||
}
|
||||
|
||||
|
||||
@@ -857,6 +868,8 @@ HINTS = {
|
||||
"battery_back": "{unit}: battery power reading is used again",
|
||||
"battery_refuses": "The battery refuses to give power, the add-on asks 0 W",
|
||||
"battery_gives": "The battery refusal ended, control asks for power again",
|
||||
"unit_refuses": "{unit}: the battery refuses power, the others take over",
|
||||
"unit_gives": "{unit}: the battery refusal ended, it is asked for power again",
|
||||
"bad_value": "The add-on made an invalid power value, inverters set to 0 W",
|
||||
"write_blocked": "{unit}: a power request was blocked, it is set to 0 W",
|
||||
"all_blocked": "A power request was blocked, inverters set to 0 W",
|
||||
@@ -1027,6 +1040,12 @@ def status_samples() -> list:
|
||||
("row_peak_guard_on", AMBER, row_peak_guard_on(1200, 2500,
|
||||
shadow=True)),
|
||||
("row_battery_stuck", AMBER, row_battery_stuck("inverter-b")),
|
||||
("row_battery_refuses", AMBER, row_battery_refuses("inverter-b", 1,
|
||||
False)),
|
||||
("row_battery_refuses", AMBER, row_battery_refuses("inverter-b", -1,
|
||||
False)),
|
||||
("row_battery_refuses", AMBER, row_battery_refuses("inverter-b", 1,
|
||||
True)),
|
||||
("row_circulating_check", GREEN, row_circulating_check(0, 0, 60)),
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user