- app/static/{index.html,app.css,app.js}: tabs (Home, Batteries, Settings,
Setup), hash routes, phone bottom tabs, light/dark. Served inlined at "/";
the route list is unchanged, and every URL is relative.
- app/homeview.py: /status gains state, now, batteries, plan, attention,
month_peak and control beside the old fields. The plan is what the add-on
does today: the arbitrage verdict (the same plan.arbitrage() call as the
cycle), the monthly cycle, the peak limit, "follows the house".
- The Home plan chart has hover, tap and keyboard-focus tooltips: price bar =
hour and price; block = what, when, why, kWh and EUR.
- Region preset and year: in config/model (for P2) and on the Home price line.
- test_home.py; test_messages part 8 scans every Home sentence; STYLE plan line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p
65 lines
7.2 KiB
Markdown
65 lines
7.2 KiB
Markdown
# STYLE.md - how user-facing text is written (UX-08)
|
|
|
|
This applies to everything a home owner or installer reads: notifications, phone pushes, the add-on page, refusals, add-on log lines at WARNING and above, and the names and descriptions of options. It is enforced by `goodwe_controller/test_messages.py`. Its allowlist is empty since phase 2d and its cap is 0: a new string that breaks the rule fails the test.
|
|
|
|
## 1. Shape
|
|
- **Title**: at most 5 everyday words. It says what is wrong ("Meter reading may be stuck"). No "GoodWe:" prefix, no full stop.
|
|
- **Body**: **one sentence** of at most 25 words, saying what happened and what to do. A **red alarm** may use up to **3 sentences** (70 words, each sentence at most 30 words), so that no action a person must take is lost.
|
|
- **Details**: the last line links to the add-on documentation and names the section with the rest: `Details: add-on documentation, section "<title>" under Notifications.` Background, figures, reason codes and history go there or into the log, never into the body.
|
|
- **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label and then its key, as `messages.setting()` writes it: “Inverter rating” (max_w), or “Inverter rating” for inverter-b (inverters.max_w) for one inverter in the list. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md.
|
|
- **Plan line** (UX-13 Home screen: the plan, tooltips, a battery's "now" line): at most 2 sentences, each at most 12 words. Words from `app/homeview.py`, checked by `test_messages.py` part 8.
|
|
- **Log line** (WARNING/ERROR): one line of at most 25 words **as logged**, with any built text filled in. Log lines stay in English and are not translated. A line that reports a safety reason gives one plain sentence and the reason's code (`STALE_READING`, `OUTPUT_CLAMP`), the evidence an installer searches for. The reason itself, with its figures and limits, goes on a DEBUG line right after it and into the action log, never onto the WARNING/ERROR line. It keeps the shape of a red alarm: at most 3 sentences of at most 30 words. The line as logged has no semicolon, banned word, capitals, "1 times" or "(s)". `test_messages.py` part 6 builds every such text with the real code and checks it, and lists the few non-safety families still over 25 words. A line that repeats every cycle is DEBUG. INFO lines carry no section numbers, ISO timestamps or capitals.
|
|
- **Refusal length is counted as shown**: a setting placeholder counts as its label and key, and the long cases are driven through the validator (`test_messages.py` part 3).
|
|
- **Event line** under the buttons: the plain words of `messages.hint()`, like a green row. The add-on's own action log stays technical and is not shown on the page. Installers read it as `events` in the `status` JSON.
|
|
- **Sentences**: one idea each, active voice, present tense, with nothing nested in brackets and no semicolons (a semicolon is a second sentence in disguise). These translate well into Dutch and French.
|
|
|
|
## 2. Numbers
|
|
Use a number only if it helps the reader act, for example the peak limit, or what was asked and what was sent in a fault report. Write it the way `app/messages.py` does: `5 000 W`, `20 %`, `10 minutes`, `14:05`.
|
|
|
|
## 3. Severity
|
|
Severity is shown by the title and the colour, never by CAPITALS or by words like "BUG SIGNAL".
|
|
|
|
| Level | Colour | When |
|
|
|---|---|---|
|
|
| alarm | red | Control stopped, money or energy lost now, a fault, or a person must act now. Up to 3 sentences. |
|
|
| warning | orange | Control is still running, but something needs a look. 1 sentence. |
|
|
| info | grey | No action needed. 1 sentence. |
|
|
| resolved | green | An earlier alarm or warning has cleared. 1 sentence. |
|
|
|
|
A rewrite never changes an alarm's severity, `notification_id` or cadence.
|
|
|
|
## 4. Words - the same word for the same thing everywhere
|
|
A setting is named by its label in `translations/en.yaml`, in quotes when it sits mid-sentence (“Inverter rating”). The words below match those labels. If a label changes, change it here and in `app/messages.py` in the same change.
|
|
|
|
| Say | Not |
|
|
|---|---|
|
|
| the add-on (who decides), control (what it does: "start control", "Control: last ran …") | controller, loop, planner |
|
|
| battery | pack, BMS pack |
|
|
| inverter, or its name | unit, device, actuator |
|
|
| meter | P1 feed, telegram |
|
|
| peak limit / this month's peak | ceiling, capaciteitstarief, billed quarter |
|
|
| 15-minute period | quarter |
|
|
| battery level (setting: “Battery level entity”) | SoC, state of charge, charge level |
|
|
| battery cut-out level, or cut-out level next to "battery" (setting: “Battery cut-out level”) | BMS floor, `bms_soc_floor` |
|
|
| peak reserve (setting: “Peak reserve”) | `peak_soc_floor`, EMS floor, "peak guard will not discharge below" |
|
|
| “Inverter rating” (the setting) | `max_w`, rail, inverter rating as a fact about the hardware |
|
|
| solar production, solar entity (settings: “Solar production entity”, “Solar production entities, per inverter”, “Reversed-sign solar entities”) | PV, reversed-sign list, single sensor setting |
|
|
| “Where the meter reading comes from” | meter source |
|
|
| “Grid power entity”; entity for any Home Assistant sensor a setting points at | grid power sensor, sensor setting |
|
|
| draw the battery down, give power | discharge, discharging |
|
|
| control is stopped / every inverter is set to 0 W | failsafe, trip, latch, parked |
|
|
| safety stop (a stop that only starting control clears) | failsafe latch |
|
|
| software fault | BUG SIGNAL |
|
|
| control board | master, ESP32 |
|
|
| power request, what the add-on asks | command, setpoint (on the page) |
|
|
| the power went the wrong way | sign disagreement, command and meter point opposite ways |
|
|
| check for inverters working against each other | circulating power check |
|
|
| month peak, 15-minute periods measured | billed quarter, banked, soft limit, open block |
|
|
| shadow mode | a mode that makes every decision but commands 0 W. The name is kept. In shadow mode a text says what the add-on **would** send, never that it sent it. |
|
|
|
|
**Banned in titles and bodies** (the test fails on them): SAFETY-/TARIFF-/TEL-/CFG-/FW-/HW-nn and other card ids, integrator, anti-windup, windup, clamp, clamped, saturated, BUG SIGNAL, latch, latched, arbiter, allocator, register, `0x…`, layer 1/2/3, heartbeat, watchdog, telegram, ACK, CRC, OTA, Modbus, planner, `§n`, file names, IP addresses, option keys in snake_case, **HA entity ids**, and runs of 2 or more CAPITALISED words.
|
|
|
|
HA entity ids are allowed only in refusals and validator messages, where the installer has to find that entity. They are never allowed in alarms or status rows.
|
|
|
|
**Glossary.** DOCS.md "Words used on this page" explains, once, the words a home owner meets without context: control board, isolator, Developer Tools, shadow mode, safety stop, peak limit, peak guard, peak reserve and cut-out level. A home-owner text may use them without explaining them again. Card ids stay out of DOCS.md headings: they go on a *For installers* line under the heading.
|