R1: first_start also needs a Store created at this boot (Store.fresh), so
old never-started sites (both TEST-23 add-ons, one in shadow) stay on Home.
R2: a kettle skip after a fall says on the last step that the reading went down.
R3: the shadow switch goes only on the model the wizard posts, never into V.
R4: Home Assistant not answering is red on the last step.
R5: meter + solar + battery below -300 W flags a reversed battery sensor.
R6: the live checks say what to change and where.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
102 lines
5.6 KiB
Markdown
102 lines
5.6 KiB
Markdown
# 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. The startup gate exits 78 before the
|
|
controller 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.
|
|
|
|
**Not decided here, for the owner:** the add-on exits 78 before it serves the
|
|
page when the stored options name no power request entity, which is what a
|
|
brand-new install ships (config.yaml's `setpoint_entity: ""`). So on a truly
|
|
new install the installer fills in "Inverter setpoint entity" on the
|
|
Configuration tab first, and the wizard opens on the next page visit.
|
|
Serving a setup-only page from a refused configuration would change the CFG-01
|
|
startup gate and UX-02 §4 ("the panel is not available when it is most
|
|
needed"), so it is left as an open question.
|
|
|
|
## 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). At P4
|
|
all 88 were accepted by Supervisor 2026.08.0's `AppOptions`, offline, 78
|
|
keys each.
|