# GoodWe RS485 Controller — Home Assistant add-on repository Replaces a GoodWe battery inverter's vendor controller with a local one: holds net grid exchange at zero by emulating the inverter's smart meter over RS485, and runs the monthly battery maintenance cycle the vendor box was doing. ``` repository.yaml add-on repository metadata goodwe_controller/ the add-on config.yaml manifest + options schema (the per-site config form) app/ the controller control.py the control law — pure functions, no I/O maintenance.py the monthly cycle state machine hass.py Supervisor/Core API access store.py persistent state in /data mqtt.py optional status entities web.py ingress UI main.py orchestration, heartbeat, failsafe behaviour test_control.py runnable checks — no framework needed test_maintenance.py runnable checks — walks a full cycle in fake time DOCS.md the add-on's documentation tab firmware/goodwe-master.yaml ESPHome config for the T-CAN485 estop/rs485_log.py optional RS485 e-stop / bus witness docs/GoodWe-RS485-Field-Guide.pdf the guide techs carry (10pp, A4) 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 ``` https://gittea.kammenstraatha.duckdns.org/admin/goodwe-addon ``` then install **GoodWe RS485 Controller**. ⚠️ **The repository must be PUBLIC for this to work.** Home Assistant clones it anonymously; against a private repo the store shows nothing and gives no useful error. If it must stay private, install locally instead: copy `goodwe_controller/` into the machine's `/addons/` folder, then `ha store reload` — it appears as a Local add-on. ⚠️ **Bump `version:` in `goodwe_controller/config.yaml` for every change.** Supervisor keys the built image by that version, so without a bump it silently reuses the old image and your fix appears not to work — on your bench and on every client's machine. Requires **Home Assistant OS or Supervised**. Add-ons cannot be installed on HA Container or Core. ## Read this first **The inverter holds its last command forever.** It has no meter-timeout of its own — a controller that dies mid-command leaves the battery running until a human intervenes. Measured on real hardware: 5 kW of discharge held for 113 seconds after a controller went silent. Three layers exist because of that, and only the third covers the Home Assistant machine itself dying: 1. **ESP32 watchdog** — no fresh setpoint for ~30 s → command 0 W, and keep commanding it. 2. **Wind-down before firmware updates** — 0 W written before the update starts. 3. **RS485 e-stop (optional)** — writes 0 W after 30 s of total bus silence. Sites sold without the e-stop must have the acknowledgement in `FIELD-GUIDE.md` §10 signed. ## Development The control law and the maintenance machine are pure Python with no Home Assistant imports, so they run anywhere: ```bash cd goodwe_controller python3 test_control.py python3 test_maintenance.py ``` Both must pass before shipping any change. They are not unit-test theatre — each assertion corresponds to a rule whose absence produced an observed failure on real hardware, and the comments in `control.py` say which. ## Compatibility **Check the serial number, not the model name.** Characters 6-8 of the serial are the platform tag: | tag | platform | verdict | |---|---|---| | `ESU EMU ESA BPS BPU EMJ IJL` | 105 — ES/EM/BP, AA55-era meter bus | **supported** | | `SPB SPN` | 745 — SBP **G2** (`GW…-SBP-20`) | no | | `ESN ESC` | 745 — ES **G2** (`GW…-ES-20`) | no | | `ETU EHU BTU …` | 205/745/753 — ET/EH/BT hybrids | no | | `SDT DST MSU NSU …` | PV-only inverters — no battery to control | no | A "-20" or "G2" suffix means a different platform with a different meter protocol. The tags come from the `goodwe` library's `PLATFORM_105_MODELS`, which is also what Home Assistant's own integration uses to pick a protocol. - GoodWe **ES / BP family** inverters (AA55 / RS485 meter-bus generation) - The protocol is **reverse-engineered**. There is no vendor contract, and a firmware change on GoodWe's side could break every installation at once. Say so when you sell it.