- messages.setting() for one inverter in the list reads “Inverter rating” for inverter-b (inverters.max_w), so the config panel files per-unit reasons under `inverters`, where the value is changed. - The tariff card and plausibility reasons name “Distribution, levies and VAT” (price_taxes_eur_kwh) again. - The wrong-direction reasons say "safety stop", the sign_disagree_w option says what it protects, and the roster, price-entity, integrator_max_w and capacity_kwh texts read more plainly. - NL: stuurprint -> stuurmodule, "De piekbeperking". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
56 lines
5.2 KiB
Markdown
56 lines
5.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`. Kinds that have not been rewritten yet are on its allowlist, and that allowlist only shrinks.
|
|
|
|
## 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.
|
|
- **Log line** (WARNING/ERROR): one line, at most 25 words. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated.
|
|
- **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 |
|
|
| 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.
|