Files
goodwe-addon/goodwe_controller/DOCS.md
T
adminandClaude Opus 5 0a1e61dbc9 Packaged as a Home Assistant add-on, with a field guide
Turns the reference RS485 controller into something a technician can install
at a client site: a typed config form instead of YAML, an ingress UI that
names misconfiguration in words, and persistent state that cannot be broken by
a timezone.

Why an add-on rather than YAML packages or blueprints:

- Blueprints cannot create helpers, and the maintenance cycle is a state
  machine whose phase and completion date must survive restarts.
- YAML packages need filesystem access, a configuration.yaml edit and a
  restart - none of which belong in a client install.
- Add-ons authenticate with SUPERVISOR_TOKEN, so there is no long-lived token
  to generate, store or leak on someone else's machine.
- Requires HA OS/Supervised. Container and Core installs cannot run add-ons at
  all, which is a market decision, not an oversight.

The control law and the maintenance machine are pure functions with no Home
Assistant imports, and both ship with runnable checks (22 and 22 assertions).
Every assertion corresponds to a rule whose absence caused an observed failure
on hardware - the saturation duration term, the clamp-before-slew ordering, the
deadband, the sign convention.

One behaviour deliberately differs from the implementation it replaces: when
its inputs go missing this commands 0 W rather than replaying the last
setpoint. The reference version kept replaying, which the hardware watchdog
cannot catch - from the ESP32's side, Home Assistant is still talking to it.

Includes the ESPHome firmware (now parameterised: node name, inverter rating,
watchdog timeout) and the optional RS485 e-stop. FIELD-GUIDE.md carries the
commissioning gates, all judged on the wire rather than on how Home Assistant
looks, plus the written statement a site without an e-stop needs signed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NckgXecasQb2eSsPYNSW6
2026-08-23 01:15:25 +02:00

4.6 KiB
Raw Blame History

GoodWe RS485 Controller

Drives a GoodWe ES/BP battery inverter over its RS485 meter bus: holds net grid exchange at zero, and runs a monthly battery maintenance cycle so the BMS can balance cells and recalibrate its coulomb counter.

Installers: read FIELD-GUIDE.md in the repository. It is not optional reading — it contains the commissioning gates and the failure modes.

Before you start

You need:

  • A GoodWe ES / BP family inverter (AA55 / RS485 meter-bus generation)
  • The vendor's meter-emulating controller disconnected from the bus
  • A T-CAN485 (ESP32) flashed with firmware/goodwe-master.yaml
  • A grid-power sensor already working in Home Assistant, updating every ~510 s

The safety model, in short

The inverter holds its last command forever — it has no meter-timeout. So:

  • The ESP32 commands 0 W if this add-on stops refreshing for ~30 s, and keeps commanding it.
  • This add-on commands 0 W when its inputs go missing, when you stop control, and when it shuts down.
  • The optional RS485 e-stop is the only thing that covers this machine dying. Without it, a failed host leaves the battery latched at its last command until someone intervenes.

If anything looks wrong: stop the add-on. That commands 0 W and the hardware holds it there.

Configuration

Sources

option required meaning
meter_entity yes Net grid power. Positive must mean importing
meter_invert Flip the sign if the meter reports the other way
soc_entity yes Battery state of charge — use the ESP32's own read
batt_entity yes Battery power — again the ESP32's read, + = discharging
batt_invert Flip if needed
setpoint_entity yes The ESPHome number.*_goodwe_setpoint_w

Use the ESP32's readings rather than the inverter's cloud or dongle sensors: those serve cached values, and a stale reading here ends the maintenance charge phase having charged nothing.

Control

option default meaning
max_w 2000 Hard limit on what may be commanded. Start low, raise after commissioning
gain 0.6 Correction per cycle. At the limit — do not raise
slew_w 1000 Maximum change per cycle
deadband_w 15 Ignore errors smaller than this
step_w 10 Quantisation
saturation_w 500 Divergence that counts as "the inverter is at a limit"
saturation_cycles 3 How many consecutive cycles before freezing. Do not set to 1
heartbeat_s 10 Refresh interval; must stay well under the firmware watchdog
stale_input_s 15 How long inputs may be missing before commanding 0 W
auto_start false Start controlling on boot (only after commissioning)

Maintenance

option default meaning
maintenance_enabled false Enable the monthly cycle
maintenance_interval_days 28 Minimum gap between cycles
maintenance_start_hour 10 Hour of day a due cycle begins
maintenance_discharge_w 2500 Drain rate (exports the surplus)
maintenance_charge_w 2500 Charge ceiling, capped again by peak headroom
maintenance_soc_floor 11 Drain target — stay just above the inverter's own floor
maintenance_soc_target 99 Charge target
maintenance_hold_min 120 Hold at full so the BMS can balance

Tariff (all optional)

option meaning
peak_forecast_entity Quarter-hour demand forecast, for capacity-tariff markets. Empty = no cap
peak_cap_w The site's capacity-tariff target
price_now_entity, price_avg_entity Dynamic tariff. Empty = never force a paid grid top-up

On a capacity-tariff site the maintenance charge is capped by the headroom left under peak_cap_w, and if the forecast goes over the cap the charge-only clamp is dropped so the battery can shave the peak instead. Money outranks the maintenance schedule.

Site

option meaning
estop_fitted Whether the RS485 e-stop is installed. Drives the warning banner
log_level trace/debug/info/warning/error

The Web UI

The ingress panel shows live values, why the controller is commanding what it is, and a Commissioning checklist that names any problem in words. It also carries the three buttons: start/stop control, force a maintenance cycle, and abort one.

Status entities

If an MQTT broker is available the add-on publishes setpoint, grid power, battery power, state of charge, maintenance phase and controller status by MQTT discovery. This is observability only — the controller works fine without a broker, and MQTT problems can never affect control.