UX-13 P4: the setup wizard for installers
checks / unit (pull_request) Successful in 10m22s
infra-pin / fresh (pull_request) Successful in 1s

The Setup tab draws the Installer view's page model one step at a time,
from each field's `wizard` step in app/uilayout.py: meter (with the kettle
test), inverters and batteries, solar (optional), prices, peak limit
(battery modes: "comes in a later update", OPT-11), check and start.
It reuses P2's controls and saves through /config/validate and
/config/save. No route was added.

- First run: /config/model says `setup_needed` when the stored options name
  no power request entity, or on a new install (no `setup_done` and no
  `auto` in the Store, control not started). The page opens #setup only
  when opened with no route. The wizard's save writes `setup_done`.
- Kettle test: GET ha/entities?entity= reads one entity now, in W. The
  change decides: up keeps meter_invert off, down turns it on; a net or
  import/export meter that goes down blocks the step with what to check.
- Last step: validate.setup_checks() beside the refusals: the meter reads,
  each power request entity exists in HA (bad if not, SAFETY-77), battery
  levels and power with direction, solar sign, prices. Saves with
  shadow_mode on by default, then a confirmed restart naming the 0 W.
- P2 test finding (a): a stale save lists only the keys the other surface
  moved (the blob handed out on open, by fingerprint, against stored now).
- test_setup.py; tools/ux13_wizard_blobs.py makes the 88 blobs the wizard
  can save; all accepted by Supervisor 2026.08.0 AppOptions (offline).
- DECISIONS/UX-13-setup-wizard.md; DOCS "Setup, for a new install".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p
This commit is contained in:
2026-09-28 05:31:18 +02:00
co-authored by Claude Opus 5.5
parent 515c11b380
commit be57b87c34
19 changed files with 1885 additions and 59 deletions
+55 -3
View File
@@ -80,8 +80,7 @@
"toast": {"started": "Control started.", "stopped": "Control stopped.", "done": "Done.", "failed": "That did not work. Try again."},
"offline": {"name": "Cannot reach the add-on", "description": "The page tries again every 3 seconds."},
"batteries": {"name": "Batteries", "description": "Battery modes and on and off switches arrive in a later update.", "level": "Level", "now": "Now", "stored": "Stored", "mode": "Mode", "settings": "Change inverter settings"},
"settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"},
"setup": {"name": "Setup", "description": "The setup steps arrive in a later update, so use the settings page for now."}
"settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"}
},
"choices_later": {
"region": {"wallonia": "Wallonia, no preset yet", "brussels": "Brussels, no preset yet"}
@@ -148,7 +147,7 @@
"blocked": {"description": "Fix the settings marked in red, then save again."},
"restarting": {"description": "Restart requested, so this page stops answering for a moment."}
},
"tier": {"bad": "Must fix", "warn": "Check this", "info": "Note"},
"tier": {"bad": "Must fix", "warn": "Check this", "info": "Note", "ok": "Passed"},
"derive": {
"raw_roster": {"description": "This inverter list can only be changed in the Configuration tab."},
"no_inverter": {"description": "Add at least one inverter."},
@@ -157,6 +156,59 @@
"custom_profile": {"description": "Other time windows can only be changed in the Configuration tab."},
"no_price": {"description": "Enter a price per kWh."},
"unknown": {"description": "The page cannot store this choice, so reload the page."}
},
"setup": {
"name": "Setup",
"description": "For installers: six steps to a working site, and each can be changed later under Settings.",
"done_before": {"description": "This site is set up already, so a change here replaces its stored settings."},
"step": "Step {n} of {total}",
"back": "Back",
"next": "Next",
"skip": "Next, or skip",
"finish": "Save and restart",
"not_now": "Not now",
"steps": {
"1": {"name": "Your meter", "description": "The add-on steers the grid reading to zero, so it needs your meter first."},
"2": {"name": "Inverters and batteries", "description": "One card for each inverter with a battery, with its entities in Home Assistant."},
"3": {"name": "Solar", "description": "Optional, so skip this step if the add-on should not record solar production."},
"4": {"name": "Prices", "description": "What you pay per kWh, so the batteries can charge when power is cheap."},
"5": {"name": "Peak limit", "description": "The grid stays under this limit, averaged over each 15-minute period."},
"6": {"name": "Check and start", "description": "The add-on checks everything with its own start checks, then restarts."}
},
"modes_later": {"description": "Choosing a mode for each battery comes in a later update."},
"kettle": {
"name": "Check the direction",
"description": "Read the meter, switch on a kettle, then read the meter again.",
"read": "Read the meter",
"again": "Read again",
"skip": "Skip this test",
"before": {"description": "The meter reads {w} now, so switch on a kettle and press Read again."},
"unread": {"description": "The meter cannot be read now, so check the entity and try again."},
"none": {"description": "The reading moved only {d}, so switch the kettle on and read again."},
"ok": {"description": "Good, the reading went up by {d} when the kettle came on."},
"flip": {"description": "The reading went down by {d}, so the add-on flips its sign for you."},
"wrong_signed": {"description": "The reading went down by {d}, so choose “One grid power entity” above, which can flip it."},
"wrong_dsmr": {"description": "The reading went down by {d}, so check that import and export are not swapped."},
"self": {"description": "The add-on reads this meter itself, so Home shows its direction after the restart."},
"skipped": {"description": "The meter direction is not tested, so check it on Home after the restart."},
"tested": {"description": "The meter direction was tested with a kettle."},
"needed": {"description": "Do the kettle test first, or skip it."}
},
"check": {
"name": "What the add-on checked",
"running": {"description": "Checking with the add-on's own start checks."},
"pass": {"description": "The add-on's start checks pass."},
"failed": {"description": "The check did not run, so try again."},
"again": "Check again",
"blocked": {"description": "Fix the items marked in red, then check again."}
},
"shadow": {"name": "Start in shadow mode", "description": "Recommended, because every inverter then stays at 0 W until you turn shadow mode off under Settings."},
"dialog": {"name": "Save and restart?", "description": "Every inverter is set to 0 W while the add-on restarts, and shadow mode keeps them at 0 W after that.", "yes": "Save and restart"},
"dialog_live": {"name": "Save and restart?", "description": "Every inverter is set to 0 W while the add-on restarts, and then the new settings apply.", "yes": "Save and restart"},
"done": {"name": "Setup is done", "description": "The add-on restarts in shadow mode now, so open Home in a minute to see what it would do."},
"done_live": {"name": "Setup is done", "description": "The add-on restarts now, so open Home in a minute to start control."},
"restart_failed": {"name": "Saved, not running yet", "description": "The restart did not go through, so press Restart now to apply the settings."},
"home": "Open Home"
}
}
}