SMA-10 round 3: Start clears a failed hand-back streak; the hook is tested
When control takes the unit again, release_fails, release_retry_at and release_zero_sent are reset, so the next Stop is a new streak with its own one 0 W, error line and event. Tests: a streak that Start interrupts without a recovery; a driver that overrides release_fallback(). _BACK_NL "de eigen sturing" (round 2) is kept. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
d26cc573fe
commit
313503724d
@@ -4162,9 +4162,15 @@ class Controller:
|
||||
if self.stopping or self.shadow or not self.auto:
|
||||
await self._hand_back(inv)
|
||||
return
|
||||
if inv.released:
|
||||
if inv.released or inv.release_fails or inv.release_zero_sent:
|
||||
# Control has the unit again: forget the hand-back, and any
|
||||
# failed streak with it, so the next Stop starts clean (its own
|
||||
# one 0 W, its own error line and event).
|
||||
inv.released = False
|
||||
inv.last_write = None
|
||||
inv.release_fails = 0
|
||||
inv.release_retry_at = 0.0
|
||||
inv.release_zero_sent = False
|
||||
entity = inv.driver.actuator_id() # for the log line below
|
||||
|
||||
# --- SAFETY-03: THE CLAMP, AND IT IS ON THE ONLY PATH TO THE WIRE -----
|
||||
|
||||
@@ -1004,6 +1004,58 @@ check("SHUTDOWN with a failed release: the one 0 W is sent, inside the bound",
|
||||
check("a driver's own fallback replaces the 0 W (the hook), not the add-on",
|
||||
"release_fallback" in dir(HB) and HB.release_fallback is
|
||||
drivers.Driver.release_fallback)
|
||||
|
||||
# a failed streak that Start interrupts WITHOUT a recovery: the next Stop is a
|
||||
# new streak with its own one 0 W, its own error line and its own event
|
||||
c, h, f = failing_site("false")
|
||||
_cap.clear()
|
||||
run(c.handle_action("auto_toggle")) # Stop, release fails
|
||||
w1 = writes_of(f).count(0.0)
|
||||
run(c.handle_action("auto_toggle")) # Start, no recovery
|
||||
iv = c.inverters[1]
|
||||
run(cycles(c, 5))
|
||||
nz = [w for w in writes_of(f) if w]
|
||||
check("START after a failed release: control writes non-zero again and the "
|
||||
"failed-streak state is cleared",
|
||||
nz and writes_of(f)[-1] != 0.0 and iv.release_fails == 0
|
||||
and not iv.release_zero_sent and iv.release_retry_at == 0.0)
|
||||
n_before = len(writes_of(f))
|
||||
run(c.handle_action("auto_toggle")) # Stop, release fails again
|
||||
after = writes_of(f)[n_before:]
|
||||
errs = [m for lv, m in _cap if lv >= logging.ERROR and "inverter-b" in m]
|
||||
evs = [e for e in c.events if "hand-back failed" in str(e)]
|
||||
check("SECOND STREAK (Start came between, no recovery): the unit gets its own "
|
||||
"one 0 W write",
|
||||
after == [0.0] and w1 == 1)
|
||||
check("SECOND STREAK: a second error line and a second action-log event",
|
||||
len(errs) == 2 and len(evs) == 2)
|
||||
run(c.send_heartbeats(70_000.0, 10.0))
|
||||
check("...and still only the one 0 W in that streak",
|
||||
writes_of(f)[n_before:] == [0.0])
|
||||
|
||||
# the hook: a driver's own fallback replaces the 0 W, and _hand_back does not
|
||||
# call write(0) itself
|
||||
class HookHB(HB):
|
||||
name = "hookhb"
|
||||
|
||||
async def release_fallback(self):
|
||||
self.calls.append(("fallback", None))
|
||||
return await self.write(5.0) # a non-zero safe value
|
||||
|
||||
|
||||
REGISTRY["hookhb"] = HookHB
|
||||
c, h, p = site([gw("inverter-a", "a"), fk("inverter-b", "hookhb")])
|
||||
f = fakes(c)[0]
|
||||
run(cycles(c, 4))
|
||||
f.mode = "false"
|
||||
n0 = len(f.calls)
|
||||
run(c.handle_action("auto_toggle"))
|
||||
tail = [x for x in f.calls[n0:] if x[0] in ("release", "fallback", "write")]
|
||||
print(f" a driver with its own fallback: {tail}")
|
||||
check("HOOK: after a failed release the driver's release_fallback() is called "
|
||||
"once, its own value (5 W) is the only write, and the add-on does not "
|
||||
"write 0 W itself",
|
||||
tail == [("release", None), ("fallback", None), ("write", 5.0)])
|
||||
logging.getLogger("goodwe").removeHandler(_h2)
|
||||
|
||||
# --- 3i. per-unit state and the other counts ---------------------------------
|
||||
@@ -1149,3 +1201,5 @@ print("all passed")
|
||||
# o. (round 2) a failed release is retried on every idle write.
|
||||
# p. (round 2) every failed try is logged.
|
||||
# q. (round 2) no fallback 0 W after a failed release.
|
||||
# r. (round 3) Start does not clear a failed streak.
|
||||
# s. (round 3) _hand_back writes 0 W itself instead of calling the hook.
|
||||
|
||||
Reference in New Issue
Block a user