GoodWe RS485 Controller

Field installation & commissioning guide — v0.1.0
Installer copy

Read this before touching anything

The inverter holds its last command forever. It has no meter-timeout. If the controller stops talking, the battery keeps charging or discharging at whatever it was last told — indefinitely.

Measured: a controller went silent mid-command and the inverter held 5 kW of discharge for 113 seconds until a person intervened.

If anything looks wrong at any point: STOP THE ADD-ON. That commands 0 W and the hardware watchdog holds it there. Nothing is at risk while you think.

Order of operations

Do not reorder. Each step assumes the previous one passed.

StepActionGate to pass
0Pre-visit checks (client, warranty, HA type)All boxes ticked
1Survey & photograph existing wiringPhotos taken
2Bring system to 0 W, disconnect vendor controllerBattery idle
3Wire and power the T-CAN485Board online
4Flash the ESP32 firmwareEntities appear in HA
5Install & configure the add-onAll checks green
6Commissioning gates 1–6Every gate passes
7E-stop: fit & test, or get signatureTested or signed
8Prove a maintenance cyclePhases observed
9Handover & sign-offSheet complete

The safety model

LayerCoversWhere it lives
1 WatchdogController alive but silent → 0 W, and keeps writing itESP32 firmware
2 Wind-downPlanned firmware update → 0 W before it startsESP32 firmware
3 E-stopThe HA machine itself dying → 0 W after 30 s of bus silenceOptional Pi + RS485
Only layer 3 covers the host dying. Nothing running on the HA machine can cover its own death. On a site without the e-stop, a failed host leaves the battery latched until someone intervenes manually. See Step 7.

Step 0 — Before you travel

Confirm with the client

  • Inverter is GoodWe ES / BP family
  • Vendor controller may be disconnected
  • Warranty / installer agreement acknowledged in writing
  • Grid rules checked (BE: Synergrid C10/11)
  • Vendor subscription — cancel only after sign-off

Confirm on their system

  • HA is OS or Supervised (Settings → System → Repairs → ⋮ → System information)
  • Grid power sensor exists, updates ≤ 10 s
  • Note its entity id and update rate
  • E-stop in the van, or signature form printed

Stop conditions

If HA is Container or Core, add-ons cannot be installed and this product cannot go in. If the grid sensor updates slower than ~10 s, the default tuning is wrong for the site — do not proceed without adjusting gain.

Never do these

NeverBecause
Flash third-party firmware on the inverter's WiFi dongleCommon image targets different hardware — bricks it
Long-press (3–5 s) the inverter's WiFi Reset buttonFactory-resets the dongle, loses network access. Short press (~1 s) is safe
Connect our controller while the vendor box is still attachedTwo masters on one bus — contradictory commands
"Compensate" for an inverted meter sign in the tuningFix meter_invert or the wiring. A wrong sign drives the grid away from zero at full gain
Raise the e-stop's 30 s threshold to stop it firing during updatesFiring during an update is correct behaviour

Steps 1–3 — Hardware

Qualified persons only. Mains AC and battery DC are present. The meter bus is low-voltage but sits inside an energised installation.

1 Survey and record

  1. Photograph the meter-port wiring before touching it.
  2. Identify the RS485 pair (A/B) running to the vendor controller.
  3. Record inverter model + serial, battery capacity (Ah) and nominal voltage.
VERIFY — photos on file; A/B pair positively identified.

2 Disconnect the vendor controller

  1. Bring the system to 0 W — battery neither charging nor discharging (check the inverter display).
  2. Disconnect the vendor controller from the meter port.
  3. Leave it physically mounted but unplugged — that keeps the install reversible and gives you a rollback story.
VERIFY — battery at 0 W, vendor box disconnected.
IF NOT — do not continue while the vendor box can still write to the bus.

3 Fit and power the T-CAN485

  1. Wire A→A, B→B to the meter port, plus its own supply.
  2. If fitting the e-stop, connect its USB-RS485 adapter to the same pair, in parallel.
  3. Power the T-CAN485 last.
VERIFY — board joins WiFi and appears in ESPHome.
IF NOT — swapped A/B gives a completely silent bus, not an error. Swap and retry before suspecting anything else.
It transmits within seconds of boot. Never power it up while the vendor controller is connected.

Step 4 — Flash the firmware

4 ESPHome

  1. Open the ESPHome Device Builder add-on on the client's HA.
  2. Create a device from firmware/goodwe-master.yaml.
  3. Set the three substitutions at the top — and nothing else.
  4. Add the client's WiFi to ESPHome's secrets.yaml.
  5. Install: first flash by USB, everything after that over the air.
VERIFY — device shows Online, and number.<node>_goodwe_setpoint_w exists in HA.
SubstitutionSet toWhy it matters
nameNode name, e.g. goodwe-master Write it on the sheet. Changing it later renames every entity in HA and silently breaks the add-on
max_wInverter continuous rating, e.g. 5000 Hard firmware limit, independent of HA. Last line of defence against a controller bug
wd_ms30000 Watchdog timeout. Must stay well above the add-on heartbeat (10 s)
ESPHome Device Builder
ESPHome Device Builder — the node must read Online before you continue. (Reference bench shown.)
Testing firmware changes: an update that lands new shutdown-path code still runs the old code on the way out. If you change wind-down or watchdog behaviour, upload twice before believing a test result.

Step 5 — Install and configure the add-on

5 Add-on

  1. Settings → Add-ons → Add-on store → ⋮ → Repositories → add the repository URL.
  2. Install GoodWe RS485 Controller. Do not start it yet.
  3. Open Configuration and fill in the table below.
  4. Start the add-on, open its Web UI.
  5. Work down the Commissioning list until every line is green.
VERIFY — banner is green or amber, no red lines.
IF NOT — the banner names the failing item. Copy entity ids from Developer Tools → States. Do not type them from memory.
OptionSet to
meter_entityClient's grid power sensor. Positive must mean importing — else set meter_invert
soc_entitysensor.<node>_goodwe_battery_socthe ESP32's own read, never the cloud/dongle sensor
batt_entitysensor.<node>_goodwe_inverter_ac_power
setpoint_entitynumber.<node>_goodwe_setpoint_w
max_w1000 for commissioning. Raise at the end of Step 6
estop_fittedtrue only if you actually fitted one
peak_forecast_entityCapacity-tariff sites only, else leave empty
price_now_entity / price_avg_entityDynamic-tariff sites only, else leave empty

Entity ids are the #1 install error

HA prefixes entity ids with the device's area at creation time, so the same firmware yields sensor.goodwe_master_… on one site and sensor.cellar_goodwe_master_… on another. A wrong entity id is not an error anywhere in HA — it simply never produces a value. On the reference system two safety alarms pointed at non-existent entities and were dead for a day while reading “on”.

Reading the Web UI

Two states you must tell apart at a glance. The banner is the summary; the Commissioning list is the detail.

Web UI running normally
HEALTHY. Green banner. All checks ✓. Why reads tracking. Grid near zero and the commanded figure resting between updates — a command that moves every single cycle means the deadband is too small for this meter.
Web UI showing NOT READY
NOT READY. Red = must fix before going further; the banner names the first failing item. Amber = permitted, but the client must have signed for it — here, no e-stop fitted. Note Why reads inputs-missing and Commanded has gone to 0 W: with a source missing, the controller zeroes the inverter rather than guessing.

Step 6 — Commissioning gates

Judge every gate on the wire or the meter — never on how Home Assistant looks.

#DoPassIf it fails
1Add-on running, control stopped Steady 0 W written, inverter idle, no errorsCheck wiring and Step 5
2By hand (Developer Tools → number.set_value): +300 W, then −300 W Battery discharges ~300 W, then charges ~300 W, within ~10 s Sign inverted → fix batt_invert/wiring, not the tuning
3Compare ESP32 readings to inverter display SoC identical; power within ~5 %Wrong entity, or dongle sensor used by mistake
4Set +300 W, then STOP the add-on Inverter reaches 0 W within ~30 s and stays STOP THE INSTALL. Nothing here is safe without this
5max_w=1000, start control Grid settles within tens of watts of zero and rests Hunting → raise deadband_w; slow meter → lower gain
6Switch on a kettle/oven (~2 kW) Grid back near zero within ~20 s; command stops rising once the battery catches up Command keeps climbing = runaway. Stop the add-on immediately
THEN — raise max_w to the value the site is sold with and repeat gate 6 once.

Step 7 — The e-stop

7a If fitted

  1. Connect the Pi to the same RS485 pair; power it.
  2. Run: python3 rs485_log.py --out /home/pi/bus.log --panic
  3. Confirm it prints PANIC ARMED.
  4. Test it: with the battery at +300 W, cut power to the T-CAN485.
VERIFY — within ~35 s the log shows a TX line and the inverter goes to 0 W.
IF NOT — check the adapter is on the correct pair and that the tap was started with --panic.
Arm the panic write only while our controller owns the bus. Pointed at a bus somebody else drives, it is unrequested interference.
It will fire during every firmware update — the upload silence exceeds 30 s. That is correct. Do not raise the threshold.

7b — If not fitted: client acknowledgement

Read this to the client and have them sign. Note it on the sign-off sheet.

Without the RS485 e-stop: if the Home Assistant machine fails, loses power, or its storage fails, the battery inverter will continue charging or discharging at whatever level it was last commanded, indefinitely, until someone intervenes manually. The inverter has no automatic fallback of its own. The e-stop is the only component that prevents this.

Client name
Signature
Date

Step 8 — Prove a maintenance cycle

8 Do not wait a month to find out it never fires

  1. Web UI → Force maintenance cycle.
  2. Watch the phase go drain → charge → hold → idle.
  3. Confirm the inverter exports during drain, charges during charge, sits at 0 W during hold.
  4. Set maintenance_enabled: true.
SHORT VERSION (~10 min) if the client cannot spare hours: set maintenance_soc_floor just below current SoC, maintenance_soc_target just below that, maintenance_hold_min: 5. Restore real values afterwards and record it as a partial test.

Why it matters: the full charge is when the BMS balances cells; the deep discharge recalibrates the coulomb counter. Skipping it breaks nothing visibly — it degrades the pack over months, and the first symptom is a state-of-charge reading nobody can trust.

Step 9 — Handover & sign-off

Tell the client, in these words

Commissioning record

Site / client
Inverter model / serial
ESPHome node name
Add-on version / max_w
Meter entity + update rate
Technician
Signature
Date

Troubleshooting

SymptomLikely causeDo this
Web UI says NOT READYWrong entity id, or sensor unavailableBanner names it. Copy the id from Developer Tools → States
Configured, but nothing movesControl is stoppedPress start; banner turns green
Inverter does nothing, no errorsA/B swapped, or vendor box still connectedSwapped RS485 gives a silent bus, not an error
HA shows one setpoint, inverter does anotherFirmware max_w below add-on max_wFirmware wins by design. Align them
Log shows writes rejected (HTTP 400)Value outside the number entity's rangeLower max_w; check the firmware substitution
Command keeps climbing while the battery is pinnedRunaway — sign inverted or saturation defeatedStop the add-on now. Verify meter_invert with a known load
Grid hunts, never restsDeadband too small, or meter too slowRaise deadband_w; if meter > 10 s, lower gain
Battery flat overnight and stays flatMaintenance drain never exitedCheck the SoC entity is the ESP32's, not a cached cloud value
Maintenance never runsDisabled, or not yet dueCheck maintenance_enabled and the “Maintenance due” row
E-stop fires on every updateExpected — upload silence > 30 sNothing to fix. Do not raise the threshold
Add-on will not installHA is Container/CoreNot supportable — see Step 0

Why the tuning is what it is

Every value came from hardware. Do not change them without measuring.

SettingValueReason
gain0.6Inverter needs 3–6 s to settle (1.4 s dead time, 94 % by 3.3 s) against a ~5 s cycle. At the limit — do not raise
slew_w1000Most of a correction in the first cycle without running far ahead of the hardware
deadband_w15Measured residual: mean 15.4 W, max 27 W. At 10 W the command never rests
saturation_w / cycles500 / 3Divergence = inverter at a limit → magnitude may fall, never rise. The 3-cycle term is essential: tested instantly it fires on every large correction
step_w10Register is 1 W but response lands on a ~17.6 W ladder. Finer is meaningless
heartbeat_s10Three chances to be heard before the 30 s watchdog acts
The failure this guards against is real: the vendor controller commanded −14 547 W against an inverter reporting −5250 W, and kept climbing for six minutes, because its integrator never stopped.