Files
goodwe-addon/goodwe_controller/DECISIONS/UX-13-setup-wizard.md
T
adminandClaude Opus 5.5 159d7461d8 UX-15: setup-only mode, and the wizard fixes F1, F2, meter, step 1
A new install names no inverter. When that is the startup gate's only
refusal, the add-on now serves the setup wizard in setup-only mode instead
of exiting 78. It builds no controller, MQTT client or meter task, its
HomeAssistant is read-only (every service call refuses before sending),
Controller refuses a read-only HomeAssistant, and /action answers 409.
Any other refusal still exits 78. DECISIONS/UX-15-setup-only-mode.md.

Wizard fixes from the UX-13 P4 test:
- F1: /config/validate converts what it can, so a conversion error blocks
  its own step and the live checks still run; save 422 carries steps.
- F2: saves send the model the page opened (base); only keys this page
  changed are written onto the blob stored now.
- A meter entity missing from Home Assistant is red on the last step.
- Step 1 says the reading went down after a skip that followed a fall.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 08:48:21 +02:00

5.6 KiB

UX-13 P4 — the setup wizard, and when it opens by itself

Status: DECIDED 2026-09-28 (P4 dev; the design and mockup were approved 2026-09-27). Card 6ab979852f3eca02fb40f69e. Builds on UX-13-one-layout-table. Design note: goodwe-session/UX-13-design.md §1, §3.6.

1. What the wizard is

The Setup tab draws the Installer view's page model one step at a time: a field is on step n when its uilayout.Field says wizard=n. It uses P2's controls, /config/validate and /config/save. No route was added. uilayout.py holds what a field cannot say: the kettle table (KETTLE), the optional step and the shadow switch (SHADOW). Step 5 has no battery modes yet (OPT-11); it says they come later.

A step moves on when no refusal is anchored to one of its shown fields (uipage.step_problems). A refusal on a hidden field, a field on no step or no field at all blocks the last step, which lists every refusal.

2. When it opens by itself (uipage.setup_needed)

The page opens #setup only when it is opened with no route, and only when /config/model gives a reason:

  • no_power_request: the stored options name no inverter to control.
  • first_start: this boot found no /data/state.json (Store.fresh), the Store has no setup_done and no auto key, and control is not started. auto is the key Start/Stop writes. Neither the startup gate's exit 78 nor setup-only mode (UX-15) writes the Store, so a new install's first good boot is fresh.

"Never started" alone is not enough: both TEST-23 add-ons have auto_start off and no auto key, and one has run in shadow for weeks (review of PR #146, R1). So a Store read from a file is an old site, and it is never sent to the wizard. A new install that restarts before the page is opened is not sent either, and its Setup tab still works. A site that runs control, or ever started or stopped it, is never sent. Without a Store the answer is no. The wizard's save writes setup_done (an ISO time) to the Store. A save from the Installer view does not.

Decided since, in UX-15-setup-only-mode (owner, 2026-09-28): a brand-new install ships setpoint_entity: "", and it no longer exits 78. When naming no inverter is the gate's only refusal, the add-on serves the page in setup-only mode, which commands nothing, and the wizard opens with no_power_request. Setup-only mode writes no Store file, so the first-run rule above still holds for an install set up on the Configuration tab.

3. The kettle test and the sign checks

Step 1 reads the meter's entities now (GET ha/entities?entity=, one hass.state() read, in W) before and after a kettle is switched on. The change, not the sign, decides: a rise of at least 500 W keeps meter_invert off, a fall turns it on. For a net entity or import and export, a fall cannot be fixed by an option, so the step is not passed and the page says what to check. A meter the add-on reads itself (HomeWizard, MQTT) cannot be read by the page, so the test is skipped and Home shows the direction after the restart. The installer may skip the test, because a cloud can fake a fall; the last step then warns, and after a fall it says the reading went down.

The battery and solar signs cannot be forced from the page, which never commands an inverter. The last step reports each battery's reading with its direction ("reads 800 W charging now, so check the inverter shows the same") and warns when a solar entity reads below zero without its "reads negative" switch. It also warns when meter + solar + battery, all known, add up to a house using less than -300 W: a battery sensor reversed while giving power. An idle or charging battery cannot be judged that way.

4. The last step

validate.setup_checks() sits beside the rules because it names option keys. It reads nothing itself: web.py passes a Home Assistant entity list at most 5 s old, the running options, the running meter reading and today's price count. Tiers are ok, info, warn and bad. A power request entity missing from Home Assistant is bad, because a write to it is answered 200 (SAFETY-77) and only the entity list can tell. So is Home Assistant not answering, since the list is then unknown. The wizard does not save while anything is bad. It then saves through P2's path (setup: "done") and asks for the restart as the second, confirmed request, with a dialog that names the 0 W. The shadow switch is on by default and writes shadow_mode: on, which holds every inverter at 0 W after a restart even if control is started. Off keeps the stored value, or auto if that was on. The switch goes only on the model the wizard posts, never into the page model the Installer view also saves.

5. The stale save lists only what moved (P2 test, finding a)

/config/model remembers the last 16 blobs it handed out, by fingerprint. On a stale save the add-on compares that blob with what is stored now, so the banner lists only the other surface's changes. changed (stored against the posted blob) is unchanged for the classic page's "theirs → mine" list. When the fingerprint was not handed out by this process, it falls back to changed.

6. How it is held

  • test_setup.py: the steps and tables, the kettle logic (and the page's copy of it), step blocking, the first-run rule on new and TEST-23 sites, the live checks, the save through the P2 path, the stale fix, and the words.
  • tools/ux13_wizard_blobs.py produces every blob the wizard can save from a new install and three TEST-23 sites (88 accepted by the shipped validator). UX-15 added the shipped defaults as a start (setup-only mode). At P4 all 88 were accepted by Supervisor 2026.08.0's AppOptions, offline, 78 keys each.