From 0ba3a200fe62a32f39e0a7743afa9d038b1ccb4f Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Sun, 30 Aug 2026 02:49:55 +0200 Subject: [PATCH] SAFETY-18: verify on the real rig, and record what it showed AC3 says "verified on the rig". The previous commit drove hwsim in-process because `riglock status` reported UNKNOWN - which is the tool declining to observe, not an observation. riglock shells out to the local docker CLI; on a Windows host without DOCKER_HOST that resolves to a Docker Desktop npipe which is not running, and the result is indistinguishable from a genuinely absent rig. The rig was up the whole time. With DOCKER_HOST=ssh://homelab@192.168.2.147 it reads FREE. Re-run under sim/riglock.py against the real goodwe-sim compose project, with the shipped modules staged into goodwe-sim-plant so they poll that container's own hwsim while plantsim drives it. Both phases passed, lock released cleanly. The rig produced a result the in-process stub could not, and it strengthens the design rather than merely confirming it: in the NEGATIVE twin - +8000 W of house load, healthy meter, correctly railed command - `active_power_w` did not move at all, sitting at exactly 10130.0 W for 26 consecutive polls. The only thing keeping `unchanged_s` at 0.0 s was the kWh registers advancing. So the register terms in measurement_fingerprint() are not belt-and-braces for this detector, they ARE the negative case: fingerprinted on the power figure alone it would have raised a false alarm on a healthy meter under a real load, which is precisely how a safety guard gets switched off. Recorded in freeze.py so nobody simplifies the fingerprint without meeting that run first. No behaviour change - documentation and the harness note only. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015VXjA3LWccN1rJsk3okyPC --- goodwe_controller/app/freeze.py | 14 ++++++++++++++ goodwe_controller/test_freeze.py | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/goodwe_controller/app/freeze.py b/goodwe_controller/app/freeze.py index b4096cc..1a11544 100644 --- a/goodwe_controller/app/freeze.py +++ b/goodwe_controller/app/freeze.py @@ -71,6 +71,20 @@ meter, and a kilowatt advances a 1 Wh register every 3.6 s. The two terms fail for independent reasons. That is the whole design. +⚠️ AND THE SECOND HALF OF THAT WAS MEASURED ON THE RIG, WITH A RESULT WORTH +READING CAREFULLY. Driving the real transport against the rig's own hwsim under ++8000 W of house load - a genuinely railed command, meter perfectly healthy - the +POWER FIGURE DID NOT MOVE AT ALL: `active_power_w` sat at exactly 10130.0 W for +26 consecutive polls. What kept `unchanged_s` pinned at 0.0 s was the kWh +registers advancing, and nothing else. + +So the register terms in `measurement_fingerprint()` are not belt-and-braces +here, they are the entire negative case. A freeze detector fingerprinted on the +power figure alone would have raised a false alarm on that rig run - a healthy +meter, a real load, a correctly railed command - which is the exact failure mode +that gets a safety guard switched off. Anyone tempted to simplify the fingerprint +should read that run first. + ------------------------------------------------------------------------------ WHERE `hold_s` COMES FROM diff --git a/goodwe_controller/test_freeze.py b/goodwe_controller/test_freeze.py index 492f818..09f0f81 100644 --- a/goodwe_controller/test_freeze.py +++ b/goodwe_controller/test_freeze.py @@ -28,6 +28,29 @@ is replayed rather than lived. same railed command against a meter that is still MOVING, at the same 10 s threshold. If that one alarms, the detector is a `unchanged_s` threshold with extra steps and the whole reason for the conjunction is gone. + +------------------------------------------------------------------------------ +THE RIG RUN THIS STANDS IN FOR + +Part 3 is the portable version of a run done on the real rig - the `goodwe-sim` +compose project on 192.168.2.147, under `sim/riglock.py`, with the driver staged +into `goodwe-sim-plant` so it polls that container's own hwsim while plantsim +drives it. Both phases passed there. To repeat it: + + DOCKER_HOST=ssh://homelab@192.168.2.147 python sim/riglock.py status + +⚠️ WITHOUT `DOCKER_HOST` SET, ON A WINDOWS HOST, `riglock status` REPORTS +`rig: UNKNOWN` - it shells out to the local `docker` CLI, which resolves to a +Docker Desktop npipe that is not running. That is INDISTINGUISHABLE from a +genuinely absent rig, and it is not one: the rig lives on the homelab box and was +up the whole time. `UNKNOWN` is the tool declining to observe, not an +observation. Do not read it as "no rig" (this cost this ticket a wrong caveat). + +The rig run also produced a result part 3's stub cannot: under +8000 W of house +load the meter's POWER FIGURE never moved - 10130.0 W for 26 consecutive polls - +and only the kWh registers kept `unchanged_s` at zero. See the note in +freeze.py; it is why the fingerprint's register terms are the negative case +rather than a nicety. """ import asyncio