Files
goodwe-addon/goodwe_controller/app/static/index.html
T
adminandClaude Opus 5.5 be57b87c34
checks / unit (pull_request) Successful in 10m22s
infra-pin / fresh (pull_request) Successful in 1s
UX-13 P4: the setup wizard for installers
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
2026-09-28 05:31:18 +02:00

156 lines
9.0 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Battery add-on</title>
<style>/*APP_CSS*/</style>
</head>
<body>
<header class="top">
<div class="logo" aria-hidden="true"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="7" width="16" height="10" rx="2"/><path d="M21 11v2M8 10l-2 3h4l-2 3"/></svg></div>
<div class="grow">
<div class="app" data-t="app.name"></div>
<div class="pill" id="pill" aria-live="polite"><span class="dot warn"></span><span>…</span></div>
</div>
</header>
<nav class="tabs" role="tablist" id="tabs" data-t-label="tabs.label">
<button class="tab" role="tab" id="t-home" aria-controls="s-home" aria-selected="true" data-hash="home"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 11l9-7 9 7v9a1 1 0 0 1-1 1h-5v-6H9v6H4a1 1 0 0 1-1-1z"/></svg><span data-t="tabs.home"></span><span class="badge" id="attn-badge" hidden></span></button>
<button class="tab" role="tab" id="t-batt" aria-controls="s-batt" aria-selected="false" data-hash="batteries" tabindex="-1"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="7" width="16" height="10" rx="2"/><path d="M21 11v2"/><rect x="5.5" y="9.5" width="7" height="5" fill="currentColor" stroke="none"/></svg><span data-t="tabs.batteries"></span></button>
<button class="tab" role="tab" id="t-set" aria-controls="s-set" aria-selected="false" data-hash="settings" tabindex="-1"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M4 6h10M18 6h2M4 12h4M12 12h8M4 18h12M20 18h0"/><circle cx="16" cy="6" r="2"/><circle cx="10" cy="12" r="2"/><circle cx="18" cy="18" r="2"/></svg><span data-t="tabs.settings"></span></button>
<button class="tab" role="tab" id="t-wiz" aria-controls="s-wiz" aria-selected="false" data-hash="setup" tabindex="-1"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 7l3 3M5 19l9.5-9.5 3 3L8 22H5z"/><path d="M19 2v4M17 4h4"/></svg><span data-t="tabs.setup"></span></button>
</nav>
<main class="wrap">
<section class="screen" id="s-home" role="tabpanel" aria-labelledby="t-home">
<div id="home-banner"></div>
<div class="card" id="c-now">
<div class="row spread"><h2 data-t="now.name"></h2><span class="tiny muted" data-t="now.description"></span></div>
<div class="tiles">
<div class="tile"><div class="lab"><span class="sw-solar" aria-hidden="true">&#9728;</span><span data-t="now.solar"></span></div><div class="val" id="v-solar">–</div><div class="sub" id="sub-solar"></div></div>
<div class="tile"><div class="lab"><span class="sw-house" aria-hidden="true">&#8962;</span><span data-t="now.house"></span></div><div class="val" id="v-house">–</div><div class="sub" id="sub-house"></div></div>
<div class="tile"><div class="lab"><span class="sw-grid" aria-hidden="true">&#8645;</span><span data-t="now.grid"></span></div><div class="val" id="v-grid">–</div><div class="sub" id="sub-grid"></div></div>
<div class="tile"><div class="lab"><span class="sw-batt" aria-hidden="true">&#9646;</span><span data-t="now.batteries"></span></div><div class="val" id="v-batt">–</div><div class="sub" id="sub-batt"></div></div>
</div>
<div id="home-batts" style="margin-top:6px"></div>
</div>
<div class="card" id="c-plan">
<div class="row spread"><h2 data-t="plan.name"></h2><span class="chip tiny muted" id="verdict"></span></div>
<div class="small" id="plan-head"></div>
<div class="chart" id="chart">
<div class="bars" id="bars" role="group"></div>
<div id="lanes"></div>
<div class="nowline" id="nowline" aria-hidden="true"><span data-t="plan.now"></span></div>
<div class="axis" aria-hidden="true"><span>00:00</span><span>06:00</span><span>12:00</span><span>18:00</span><span>24:00</span></div>
</div>
<p class="tiny muted" id="no-prices" hidden data-t="plan.no_prices.description"></p>
<div class="legend" id="legend"></div>
<p class="tiny muted" style="margin:6px 0 0" data-t="plan.description"></p>
<h3 class="sr" data-t="plan.list"></h3>
<ul class="plain small" id="plan-list"></ul>
<p class="tiny muted" style="margin:8px 0 0" id="price-line"></p>
</div>
<div class="card" id="c-peak">
<div class="row spread"><h2 data-t="peak.name"></h2><span class="tiny muted" id="peak-month"></span></div>
<div class="row spread small" id="peak-figures"><span><span data-t="peak.this_month"></span>: <strong id="peak-now"></strong></span><span class="muted"><span data-t="peak.limit"></span> <span id="peak-limit"></span></span></div>
<div class="meter" id="peak-meter" role="img"><i style="width:0%"></i></div>
<div class="tiny muted" id="peak-line"></div>
</div>
<div class="card" id="c-attn">
<div class="row spread"><h2 data-t="attention.name"></h2><span class="tiny muted" id="attn-count"></span></div>
<div id="alerts"></div>
</div>
<div class="card" id="c-ctl">
<h2 data-t="control.name"></h2>
<div class="small" id="ctl-text"></div>
<div class="row" style="margin-top:10px">
<button class="btn" id="btn-ctl" type="button"></button>
<a class="small" id="docs-link" hidden target="_top" rel="noopener" data-t="control.docs"></a>
</div>
<div class="tiny muted" id="hint" aria-live="polite" style="margin-top:8px"></div>
<details class="more">
<summary data-t="control.more"></summary>
<div class="row" style="padding-bottom:6px">
<button class="btn" id="btn-maint" type="button" data-t="control.maint_start"></button>
<button class="btn danger" id="btn-abort" type="button" data-t="control.maint_abort"></button>
</div>
</details>
</div>
<details class="card more" id="c-details">
<summary data-t="details.name"></summary>
<table class="rows" id="rows"></table>
<h2 style="margin-top:12px" data-t="details.checks"></h2>
<ul class="checks" id="checks"></ul>
</details>
</section>
<section class="screen" id="s-batt" role="tabpanel" aria-labelledby="t-batt" hidden>
<div id="bcards"></div>
<div class="card">
<p class="small muted" style="margin:0 0 10px" data-t="batteries.description"></p>
<a class="btn" href="#settings" data-t="batteries.settings"></a>
</div>
</section>
<section class="screen" id="s-set" role="tabpanel" aria-labelledby="t-set" hidden>
<div class="row spread" style="margin-bottom:6px">
<h2 style="margin:0" data-s="name"></h2>
<a class="small" href="config" id="set-classic" data-s="classic"></a>
</div>
<p class="small muted" style="margin:0 0 10px" data-s="description"></p>
<div id="set-banner" aria-live="polite"></div>
<div id="set-body">
<input class="search" id="set-search" type="search" autocomplete="off" spellcheck="false" data-s-ph="search.description" data-s-label="search.name">
<div class="card" id="set-other" hidden><h2 data-s="other"></h2><ul class="plain small" id="set-other-list"></ul></div>
<div id="groups"><p class="small muted" data-s="loading"></p></div>
<p class="small muted" id="set-nomatch" hidden data-s="no_match.description"></p>
<p class="tiny muted" data-s="footer.description"></p>
</div>
</section>
<section class="screen" id="s-wiz" role="tabpanel" aria-labelledby="t-wiz" hidden>
<div class="card" id="wz">
<div class="row spread"><h2 id="wz-title" style="margin:0" data-s="setup.name"></h2><span class="tiny muted" id="wz-count"></span></div>
<div class="steps" id="wz-steps" aria-hidden="true"></div>
<p class="small muted" id="wz-desc" style="margin:0 0 6px"></p>
<div id="wz-banner" aria-live="polite"></div>
<div id="wz-body"><p class="small muted" data-s="loading"></p></div>
<div class="row spread" id="wz-nav" style="margin-top:14px">
<button class="btn" id="wz-back" type="button" data-s="setup.back"></button>
<button class="btn primary" id="wz-next" type="button" data-s="setup.next"></button>
</div>
</div>
<p class="tiny muted" data-s="setup.description"></p>
</section>
</main>
<dialog id="dlg" aria-labelledby="dlg-t" aria-describedby="dlg-b">
<h2 id="dlg-t"></h2>
<p class="small" id="dlg-b"></p>
<div class="row" style="justify-content:flex-end">
<button class="btn" id="dlg-no" type="button" data-t="dialog.cancel"></button>
<button class="btn primary" id="dlg-yes" type="button"></button>
</div>
</dialog>
<div id="savebar" role="region" hidden><div class="in">
<span class="grow" id="sb-text" aria-live="polite"></span>
<button class="btn" id="sb-discard" type="button" data-s="savebar.discard"></button>
<button class="btn primary" id="sb-save" type="button" data-s="savebar.save"></button>
</div></div>
<div id="toast" role="status" aria-live="polite"></div>
<div id="tip" class="tip" aria-hidden="true"></div>
<script type="application/json" id="ui-text">/*UI_TEXT*/</script>
<script>/*APP_JS*/</script>
<script>/*SETTINGS_JS*/</script>
</body>
</html>