SMA-2: each inverter is reached through a driver; GoodWe behaviour unchanged
checks / unit (pull_request) Successful in 23m14s
infra-pin / fresh (pull_request) Successful in 2s

app/drivers.py holds one Driver per roster entry (configured, actuator_id,
limits, read, write, release, probe, link_stale_s, batt_bound, settle_s, brand,
words). GoodWeEsphomeDriver makes the calls the code it replaced made, in the
same order. Inverter gets driver; has_writer, is_live and link_note read it. The
SoC/power read, the write, the device range (run_control, amain, the settings
panel), rule 2 per unit and the SAFETY-28 census go through it.

setpoint_entity is optional per entry beside driver, host, port, unit_id and
maintenance; only goodwe_esphome is selectable, the rest are checked and unused.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
glenn schrooyen
2026-11-07 11:28:47 +01:00
co-authored by Claude
parent 23ff9d0920
commit e56eeef8f0
18 changed files with 1238 additions and 65 deletions
+9 -7
View File
@@ -1536,8 +1536,9 @@ _decl9 = dict(ln.strip().lstrip("- ").split(": ", 1)
for ln in _entry9.splitlines()[1:] if ": " in ln)
print(f" the shipped per-entry schema: {_decl9}")
check("...and the schema half declares it as a LIST OF OBJECTS whose `name`, "
"`setpoint_entity`, `max_w` and `bms_soc_floor` are REQUIRED - no "
"trailing `?` - so the Supervisor refuses a half-written entry before the "
"`max_w` and `bms_soc_floor` are REQUIRED - no "
"trailing `?` (SMA-2: `setpoint_entity` is the GoodWe driver's own key "
"and optional here; rule 9(d) requires it per driver) - so the Supervisor refuses a half-written entry before the "
"add-on sees it, and an entry can never fall back on a sibling's rating "
"or on a sibling's BMS cut-out because there is no entry without one. "
"⚠️ SAFETY-32 ADDED THE FOURTH ONE AS REQUIRED RATHER THAN AS "
@@ -1553,13 +1554,14 @@ check("...and the schema half declares it as a LIST OF OBJECTS whose `name`, "
"refuses every options blob written before it existed",
set(_decl9) == {"name", "setpoint_entity", "max_w", "bms_soc_floor",
"soc_entity", "batt_entity", "batt_invert",
"capacity_kwh"}
"capacity_kwh", "driver", "host", "port", "unit_id",
"maintenance"}
and not any(_decl9[k].endswith("?")
for k in ("name", "setpoint_entity", "max_w",
"bms_soc_floor"))
for k in ("name", "max_w", "bms_soc_floor"))
and all(_decl9[k].endswith("?")
for k in ("soc_entity", "batt_entity", "batt_invert",
"capacity_kwh")))
for k in ("setpoint_entity", "soc_entity", "batt_entity",
"batt_invert", "capacity_kwh", "driver", "host",
"port", "unit_id", "maintenance")))
# ⚠️ NOTHING IS INHERITED, AND THIS IS DEV-02 RESTATED AS A CONFIG RULE.
# ⚠️ THE FLAT KEYS ARE SET TO REAL ENTITIES HERE, AND THAT IS THE WHOLE CHECK.