diff --git a/HANDOVER.md b/HANDOVER.md new file mode 100644 index 0000000..89ed637 --- /dev/null +++ b/HANDOVER.md @@ -0,0 +1,139 @@ +# Handover — 2026-08-23 + +Start here. `README.md` is what the thing is; this is where it stands, what is +known to be broken, and what to do next. + +--- + +## 1. State of the world + +The add-on **is controlling a real battery right now** — the author's own house, +a GoodWe GW5000S-BP. + +| | | +|---|---| +| running | `local_goodwe_controller` **0.2.0**, `boot: auto`, holding grid at zero | +| installed as | a **Local** add-on: `/addons/goodwe_controller` on HA OS at 192.168.2.158 | +| repo | Gitea `admin/goodwe-addon` (ssh://git@192.168.2.147:2222) — **private** | +| tuning | gain 0.6, `max_w` 5000, slew 1000, deadband 15, step 10, saturation 500/3, heartbeat 10 s | +| maintenance | **disabled**, and with **no completion history** — first cycle is "due" the moment it is enabled | +| e-stop | fitted at this site, Pi tap armed with `--panic` | + +The thing it replaced — a working Home Assistant YAML implementation — is parked +at `/config/packages_disabled_addon_migration/` on that machine. **Rollback** is: +stop the add-on, move those four files back into `/config/packages/`, reload +automations and helpers, switch `input_boolean.goodwe_auto` on. + +⚠️ **Never run both.** They write the same setpoint. Two controllers on one +actuator is the failure the whole design exists to prevent. + +The research record — protocol, register map, why every tuning value is what it +is, and a long "ruled out, do not re-investigate" list — lives in the *other* +repo, `Documents/goodwe`, in `NOTES.md`. Read it before changing a constant. + +--- + +## 2. Deploying a change + +```bash +# 1. edit under goodwe_controller/ +# 2. BUMP version: in goodwe_controller/config.yaml <-- not optional +scp -r goodwe_controller root@192.168.2.158:/addons/ +ssh root@192.168.2.158 "ha store reload && ha addons update local_goodwe_controller" +ssh root@192.168.2.158 "ha addons logs local_goodwe_controller | tail -20" +``` + +⚠️ **Supervisor keys the built image by `version:`.** Without a bump it silently +reuses the old image and your change appears not to work. This cost two rounds of +"the fix doesn't work" in one evening. It applies to client updates too — a +client only gets a change when the version increments. + +Run the checks before deploying. No framework needed: + +```bash +cd goodwe_controller +python3 test_control.py && python3 test_maintenance.py && python3 test_arbiter.py +``` + +--- + +## 3. Known broken / unfinished + +1. **MQTT status entities are not adopted by Home Assistant.** The add-on + publishes correct discovery and live state — verified on the broker itself + (`goodwe_ctl/setpoint => 940.0`). After the entities were deleted from the + registry during development, HA would not re-adopt them, even after clearing + the retained topics and reconnecting. Affects **observability only**; control + is untouched. Try again after an HA restart, which is the cheapest next test. +2. **The repository is private**, so it cannot be used as an add-on repository + URL — HA clones anonymously. Either make it public, or keep installing + locally as at this site. Decide before the first client. +3. **No real maintenance cycle has ever run.** The mechanism is proven + end-to-end in simulated time and partially on hardware, but a genuine + low→full→hold cycle takes hours and has not happened. Do not decommission a + client's vendor controller before one has. +4. **The HA-side offline alarm is unproven.** The Pi's 30 s panic write is the + real cover; treat the HA alert as "within a few minutes". +5. **Only platform 105 is supported** — see §5. + +--- + +## 4. What to do next, in order + +1. **Peak shaving as a real strategy.** This is why the arbiter exists, and it is + now purely additive: a claim producer emitting `Claim.set("peak", P_PEAK, …)` + from the quarter-hour forecast, plus a priority. Nothing existing needs to + change — the maintenance charge-only limit already cannot bind it. Highest + value per unit of work in a capacity-tariff market. +2. **Run a full maintenance cycle** at the reference site and record what it + actually costs in energy and time. +3. **Fleet health before more features.** This system's signature failure is + *silent*: an entity-id prefix killed two safety alarms for a day, a shebang + made every call 401 while looking healthy. One site with the author watching + found those. Twenty sites will not. +4. **Decide the repository question** (§3.2). + +--- + +## 5. The commercial question nobody has answered + +**A GoodWe "-20" / G2 inverter cannot be driven by this.** + +Platform comes from characters 6–8 of the serial number. Only +`ESU EMU ESA BPS BPU EMJ IJL` — platform 105, the AA55-era meter bus — are +supported. SBP G2 (`SPB`/`SPN`) and ES G2 (`ESN`/`ESC`) are platform 745, a +different protocol. The reference unit is `BPS`. + +That matters more than it first sounds: **the SBP G2 is the model GoodWe +currently sells to replace a GW5000S-BP.** So today's product serves the +installed base, not the base being installed. Everything above the firmware — +control law, arbiter, maintenance, add-on, field guide — is protocol-agnostic +and would carry over; only the register map is platform-specific. + +Answering it is an afternoon: put the Pi tap passively on a G2 unit's meter bus +with its vendor controller running, and capture. That either hands over the new +register map or proves the approach does not transfer. **Do this before building +more features on top of a shrinking base.** + +--- + +## 6. Things that will bite you + +Each of these was found the expensive way. They are in the code comments too. + +- **`run.sh` must start `#!/usr/bin/with-contenv sh`.** s6-overlay sanitises the + environment, so a plain shebang means no `SUPERVISOR_TOKEN` and every HA call + returns 401 — while `homeassistant_api: true` makes permissions look granted. +- **A wrong entity id is not an error anywhere in HA.** It just never produces a + value, and the automation's own state still reads `on`. +- **HA composes entity ids from the device area and device name.** The same + firmware yields `sensor.goodwe_master_…` at one site and + `sensor.cellar_goodwe_master_…` at another. +- **`input_datetime` states parse timezone-naive**; subtracting `now()` raises + and kills the whole automation before it records itself as triggered. Use the + `timestamp` attribute. +- **Alpine ships paho-mqtt 1.x**, which has no `CallbackAPIVersion`, and musl has + no aiohttp wheel — install from apk, not pip. +- **The inverter holds its last command forever.** It has no meter-timeout. Every + failsafe here exists because of that one fact, and anything in doubt commands + **0 W** rather than holding. diff --git a/README.md b/README.md index 7d8a120..7a00479 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,9 @@ docs/build_guide.py its single source - rebuilds the HTML and PDF FIELD-GUIDE.md how to edit and rebuild the guide ``` +**Picking this up after a break? Read `HANDOVER.md` first** — current state, +what is known broken, and what to do next. + ## Install Settings → Add-ons → Add-on store → ⋮ → **Repositories** → add