SMA-2 round 2: keep the driver keys out of the schema, translations and labels
Owner decision 2026-11-07: clients see nothing new until SMA-4. config.yaml, translations, labels and the page layout are back to 23ff9d0's. The validation of the keys stays for callers that skip the schema. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
0b20f53cf8
commit
c015230452
@@ -592,22 +592,29 @@ ent = sch[sch.index("\n inverters:"):]
|
||||
ent = ent[:ent.index("\n\n")]
|
||||
decl = dict(ln.strip().lstrip("- ").split(": ", 1)
|
||||
for ln in ent.splitlines()[1:] if ": " in ln)
|
||||
check("setpoint_entity is optional per entry, beside driver, host, port, "
|
||||
"unit_id and maintenance; name, max_w and bms_soc_floor stay required",
|
||||
decl["setpoint_entity"] == "str?" and decl["driver"] == "list(goodwe_esphome)?"
|
||||
and decl["host"] == "str?" and decl["port"] == "port?"
|
||||
and decl["unit_id"] == "int(0,247)?" and decl["maintenance"] == "bool?"
|
||||
and not any(decl[k].endswith("?") for k in ("name", "max_w",
|
||||
"bms_soc_floor")))
|
||||
check("config.yaml lists exactly the selectable drivers",
|
||||
decl["driver"] == f"list({'|'.join(SELECTABLE)})?")
|
||||
NEW_KEYS = ("driver", "host", "port", "unit_id", "maintenance")
|
||||
check("HIDDEN FROM CLIENTS (owner, 2026-11-07): config.yaml's per-entry schema "
|
||||
"is what it was on 23ff9d0 - the five driver keys are not in it, and "
|
||||
"setpoint_entity is still required - so the Supervisor form shows "
|
||||
"nothing new",
|
||||
not set(NEW_KEYS) & set(decl) and not decl["setpoint_entity"].endswith("?")
|
||||
and set(decl) == {"name", "setpoint_entity", "max_w", "bms_soc_floor",
|
||||
"soc_entity", "batt_entity", "batt_invert",
|
||||
"capacity_kwh"})
|
||||
_tr = {lg: io.open(HERE / "translations" / f"{lg}.yaml", encoding="utf-8").read()
|
||||
for lg in ("en", "nl")}
|
||||
from app import messages as _msgs # noqa: E402
|
||||
check("...and no translation, label or description was added for them",
|
||||
not any(f" {k}:\n" in t.split(" estop_fitted:")[0].split(" inverters:")[1]
|
||||
for t in _tr.values() for k in NEW_KEYS)
|
||||
and not set(NEW_KEYS) & (set(_msgs.LABELS) | set(_msgs.LABELS_NL)))
|
||||
|
||||
# ==============================================================================
|
||||
print()
|
||||
print("6. round 2: census parity, setters, rule 9(d), NaN ports, hidden keys")
|
||||
|
||||
import copy, itertools, math # noqa: E402
|
||||
from app import uilayout as L, uimodel # noqa: E402
|
||||
from app import uimodel # noqa: E402
|
||||
from app.validate import ACTUATOR_WRITE_KEYS # noqa: E402
|
||||
|
||||
|
||||
@@ -708,25 +715,13 @@ for key in ("port", "unit_id"):
|
||||
got, ok_ = repr(e), False
|
||||
check(f"{key} = {nm} is refused by key and does not raise", ok_)
|
||||
|
||||
keys_cfg = set(decl)
|
||||
placed = {k.split(".", 1)[1] for _g, _p, f in L.fields()
|
||||
for k in [f.key] if k.startswith("inverters.")}
|
||||
check("ROSTER_HIDDEN: every per-entry key in config.yaml is either a card "
|
||||
"field or hidden, never both and never neither",
|
||||
all((k in placed) != (k in L.ROSTER_HIDDEN) for k in keys_cfg)
|
||||
and not (placed & set(L.ROSTER_HIDDEN))
|
||||
and set(L.ROSTER_HIDDEN) <= keys_cfg)
|
||||
check("...and a per-entry key that is neither would be flagged (test_uilayout "
|
||||
"grades the same rule with a made-up key)",
|
||||
not all((k in placed) != (k in L.ROSTER_HIDDEN)
|
||||
for k in keys_cfg | {"brand_new_key"}))
|
||||
ent = dict(name="a", setpoint_entity="number.a", max_w=3000, bms_soc_floor=10,
|
||||
soc_entity="sensor.s", batt_entity="sensor.b", driver="goodwe_esphome",
|
||||
host="h", port=502, unit_id=3, maintenance=False)
|
||||
opts_rt = {"inverters": [ent, dict(ent, name="b", setpoint_entity="number.b")]}
|
||||
back = uimodel.ui_to_options(uimodel.options_to_ui(copy.deepcopy(opts_rt)))
|
||||
check("the page model carries the hidden keys through a save untouched "
|
||||
"(this is how ROSTER_HIDDEN keys survive the settings page)",
|
||||
check("an entry that carries the driver keys (from a caller that skips the "
|
||||
"schema) comes back from a save through the page model unchanged",
|
||||
back.get("inverters") == opts_rt["inverters"])
|
||||
|
||||
del REGISTRY["fake"]
|
||||
|
||||
Reference in New Issue
Block a user