From c70eeb691650c7e7cffbc7eb8087ec193f64bb37 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Sat, 7 Nov 2026 00:12:33 +0100 Subject: [PATCH] SAFETY-129 round 3: the real reason for the 16 s limit, a slow-start check, the row's tail Co-Authored-By: Claude --- .../DECISIONS/SAFETY-128-late-readings.md | 11 +++++++---- goodwe_controller/app/lateness.py | 6 ++++-- goodwe_controller/test_safety129.py | 13 +++++++++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/goodwe_controller/DECISIONS/SAFETY-128-late-readings.md b/goodwe_controller/DECISIONS/SAFETY-128-late-readings.md index 4d9a8f3..6b9e644 100644 --- a/goodwe_controller/DECISIONS/SAFETY-128-late-readings.md +++ b/goodwe_controller/DECISIONS/SAFETY-128-late-readings.md @@ -33,9 +33,10 @@ inverter limit in its last seconds (OPT-34 rig F-2). 16 new values in 60 s, so only a meter of about 3.5 s or faster: at 5 s it gave false delays. Late over 8 s. At a slower meter (a 5 s P1) the same fit runs over 120 s and calls only a delay over 16 s late, on 2 fits - in a row, and never ends a verdict (SAFETY-129): a 10-12 s slow battery - reads up to 15 s there, so 10 s late is not told from it, and it does not - swing at 5 s. + in a row, and never ends a verdict (SAFETY-129). Alone it reads 35-90 s on healthy + runs, a few times in a row; only the slow-start and battery-fit check + below keeps those from a verdict. 10 s late is not found: it cannot be + told from a 10 s slow battery, and it does not swing at 5 s. - A meter fit says late only with evidence from the batteries' side too: a request more than 100 W from the battery reading took 3 s or more to move a reading towards it (`SLOW_START_S`; on time they start within @@ -71,7 +72,9 @@ The fits run all the time; the pull request has the counts. - Found 36-68 s after a lag starts at 1-2 s meters; at a 5 s meter 30 s late is found within 100 s after it starts (88 s measured) (the loop first moves 100 W after 60 s, SAFETY-129) with the export above -200 W, and 10 s late is not found. Until - then control is as before. + then control is as before. In a quiet house the "readings late" row stays + about 2 minutes longer after the lag ends (126 s against 32 s on base); no + harm measured, and it clears as early as on base when the load changes. - A battery that answers slowly is read as late readings and held: a dead time of 10 s or more (8 s reads 7-8; 10 s reads 10 at 1-2 s meters, 9 at 5 s), or a 15-20 s lag (review round 2). The GoodWe measured settles in 6 s diff --git a/goodwe_controller/app/lateness.py b/goodwe_controller/app/lateness.py index 423342b..84480ef 100644 --- a/goodwe_controller/app/lateness.py +++ b/goodwe_controller/app/lateness.py @@ -174,8 +174,10 @@ M_SHARE, M_BETTER = 0.4, 0.7 # SAFETY-129: a meter slower than that (a 5 s P1) has fewer than M_ROWS values # in M_FIT_S, so it is fitted over M_SLOW_FIT_S instead, from the same M_ROWS # values. It calls a delay late only over M_SLOW_LATE_S and on ON_FITS fits in -# a row: the slow-battery runs (10-12 s dead time, R2-1) read up to 15 s at a -# 5 s meter, and a 10 s lag cannot be told from them, nor does it swing. +# a row. Alone it reads 35-90 s on healthy runs, a few times in a row; what +# keeps those from a verdict is the slow-start and battery-fit check in +# watch(), not the limit. A 10 s lag is not found: it cannot be told from a +# slow battery (R2-1), nor does it swing at 5 s. M_SLOW_FIT_S = 120.0 M_SLOW_LATE_S = 16.0 # A meter fit counts only after an ask that took this long to start moving a diff --git a/goodwe_controller/test_safety129.py b/goodwe_controller/test_safety129.py index 11c1c45..08c96df 100644 --- a/goodwe_controller/test_safety129.py +++ b/goodwe_controller/test_safety129.py @@ -121,6 +121,15 @@ for dead in (8.0, 10.0): check(f"{dead:.0f} s dead time at a 5 s meter is not read as late " f"(R2-1 does not get worse)", secs == 0) +# At a 6 s meter an 8 s dead time reads late on the slow fit alone; only the +# slow-start and battery-fit check keeps it from a verdict (122 s late +# without the check, from 1 084 s). +r, secs, first = run_late(house=owner, noise=80.0, units=AB, p1_s=6.0, + dead_s=8.0, dur=1500.0) +print(f" 8 s dead time, 6 s meter: late {secs} s") +check("an 8 s dead time at a 6 s meter is never late (the slow fit needs an " + "ask slow to start and no battery fit on time)", secs == 0) + # A 12 s dead time is already read as late (R2-1, SAFETY-128); the slow-meter # fit must not make that longer. The same run with the slow fit off is the # tree before this card. @@ -219,8 +228,8 @@ check("one late slow-meter fit is no fit; two in a row are one, and " check("the slow fit asks for a longer window and a later delay than the " "fast one", lateness.M_SLOW_FIT_S > lateness.M_FIT_S and lateness.M_SLOW_LATE_S > lateness.M_LATE_S) -check("the slow fit's delay is above what a 10-12 s slow battery reads " - "(R2-1: up to 15 s at a 5 s meter)", lateness.M_SLOW_LATE_S >= 16.0) +check("the slow fit's late limit is above the fast one's and above a " + "10 s lag", lateness.M_SLOW_LATE_S >= 16.0) print() if fails: