Files
goodwe-addon/goodwe_controller/DECISIONS/SMA-2-driver-seam.md
T

3.0 KiB

SMA-2 - each inverter is reached through a driver

Status: for review. Tests: test_sma2_driver.py. Source: SMA-9 report section 1.1. A pure refactor: no behaviour change for GoodWe, no change to a command, a log line or a sentence the add-on shows.

Every place that read or steered an inverter used the GoodWe ESPHome entities directly, so a second make meant touching all of them. app/drivers.py now holds one Driver per roster entry (Inverter.driver): configured(), actuator_id(), limits(), read(), write(), release(), probe(), and link_stale_s, batt_bound, settle_s, brand, words. GoodWeEsphomeDriver makes the same calls in the same order as the code it replaced; its release() is write(0).

Moved to the driver: the SoC and power read (_read_unit), the write (_write_unit, still under the SAFETY-28 gate, the clamp, shadow mode and the write budget), the device range (run_control, amain, the settings panel), liveness and its window (has_writer, is_live, link_note), the freshness bound, the status rows' "is a source set" test, rule 2's per-unit range check and SAFETY-28's census. Not moved: the clamp, the gate, the heartbeat and command_site_zero(); stop is still 0 W for every unit, and nothing calls release() yet (SMA-10). settle_s and the control constants are not read from the driver yet either: with only GoodWe they would change nothing.

The seam is not TCP-shaped. The census asks each entry's driver for its actuator id: the setpoint entity for GoodWe, host:port:unit_id for a driver reached over a socket, so two units behind one gateway are two actuators and one unit named twice is the SAFETY-28 refusal. The census still counts every setpoint_entity key as before and adds the driver's own actuator to it (parity with 23ff9d0 on 349 option shapes is a test). The driver binds its Home Assistant on first use by the Controller, so a unit added later is wired too.

Schema. The brief says "setpoint_entity becomes optional" (SMA-2, "Schema per inverter entry"; SMA-9 section 1.1): it is the GoodWe driver's own key, so a driver reached by host and port has none. setpoint_entity is optional per entry in config.yaml; rule 9(d) still refuses a GoodWe entry without it, with the same sentence (test_sma2_driver.py part 6), beside driver (only goodwe_esphome), host, port, unit_id, maintenance. The last four are checked for shape and not read. The Supervisor shape probe was re-run (section K).

Checked against 23ff9d0: replay digests and a log of every Home Assistant call are byte-identical at N=1 and N=2; the TEL-07 announce diff is 0/0/0; a fake driver beside a GoodWe unit allocates, grades, drops and publishes per unit; a call site that goes round the seam is caught.

Per-entry keys the page does not draw are listed in uilayout.ROSTER_HIDDEN; test_uilayout and test_sma2_driver fail for a key that is neither a card field nor hidden, and a save through the page keeps them (a test).