- Settings tab: the Installer view (app/static/settings.js), drawn from
app/uilayout.py through the new app/uipage.py: search, six collapsible
groups with "n to fix / n to check / n changed" badges and an "applies
after a restart" chip, radio cards, segmented choices, sliders with units
(the peak limit in kW), entity pickers with search and the live reading,
inverter cards, solar rows, locked measured values behind "Change", and
the add-on's refusals, warnings and info beside the field they name.
- Save path: the page posts its model to the existing config/validate and
config/save; uimodel turns it into options before the shipped validator,
so nothing it refuses is saved. No route added. A value equal to the
stored one is written as stored, so a save that changed nothing writes an
identical blob. Save bar, then the restart dialog that names 0 W.
- The region choice shows its preset year; Wallonia and Brussels are listed
as having no preset yet (TARIFF-22). "Classic settings" keeps /config.
- P1 test findings: (a) "Going to 0 W" until the last accepted power request
is 0 W; (b) the trade blocks and the price line name the feed's own points
("Lowest published price"), the hour bars say "hour average"; (c) the entity
list's WARNING gives a reason on a timeout.
- test_settings.py; test_home, test_haentities, test_uilayout extended.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p
149 lines
8.4 KiB
HTML
149 lines
8.4 KiB
HTML
<!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">☀</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">⌂</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">⇅</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">▮</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">
|
||
<h2 data-t="setup.name"></h2>
|
||
<p class="small muted" data-t="setup.description"></p>
|
||
<a class="btn" href="config" data-t="settings.open"></a>
|
||
</div>
|
||
</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>
|