Files
goodwe-addon/goodwe_controller/translations/en.yaml
T
glenn schrooyenandClaude 9ac3a9d2bc
checks / unit (pull_request) Successful in 39m31s
infra-pin / fresh (pull_request) Successful in 1s
PRICE-01: price_service provider, fallback chain, and the gate read from it
A new price source, `price_provider: price_service`: the owner's price server,
one fixed HTTPS host, a bearer token (new password option
`price_service_token`), wholesale energy only so markup and taxes are added as
for generic_dayahead.

The chain is server, then energy-charts, then the prices the history store
kept. A step counts only if it has a price for now. Each step down and back up
is one log line. With every source down a site plans from what it saved.

No price for now: one status row, one Home plan line and one notification, in
English and Dutch, cleared when a price returns. With this provider the
maintenance charge gate reads the provider's prices and keeps the Home
Assistant rule: the current 15-minute price is at or below today's average.

The token is hidden on the settings page, refused when missing, and taken out
of any error text. Other providers, `off` and the Home Assistant pair take the
road they always took (scripted-day probe against 0ce7d35: one line differs,
the refusal that lists the known providers). See
DECISIONS/PRICE-01-own-price-server.md.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
2026-10-14 16:22:24 +02:00

325 lines
20 KiB
YAML

# Home Assistant add-on translations - ENGLISH (UX-01)
#
# ⚠️ WHAT THIS FILE IS FOR, AND WHAT HOME ASSISTANT ACTUALLY DOES WITH IT.
# Without a `translations/` directory the Configuration tab renders the raw
# option KEYS - `unit_sign_disagree_w`, `saturation_cycles`, `integrator_max_w`.
# The frontend keeps a field when `e.name in options || e.required`, and all 72
# keys are in `options:` (59 of them are `required` as well), so ALL SEVENTY-TWO are
# rendered, always, in `schema:` order, with no description. This file is what
# turns that into sentences.
#
# HOW IT IS READ, measured on the Supervisor image this site runs
# (ghcr.io/home-assistant/amd64-hassio-supervisor:2026.08.0):
#
# * `supervisor/store/data.py:_read_app_translations()` reads every
# `.yaml`/`.yml`/`.json` in this directory, keyed by FILE STEM (so this file
# is the `en` translation), and validates each through
# `SCHEMA_APP_TRANSLATIONS`: `configuration: {str: {name (required),
# description, fields}}` plus `network: {str: str}`. ⚠️ A FILE THAT FAILS
# THAT SCHEMA IS DROPPED WITH A LOG WARNING AND NOTHING ELSE - the add-on
# goes on rendering raw keys and nobody is told twice. tools/
# supervisor_shape_probe.py section F is what says it loaded.
# * The frontend resolves each label as
# `translations[<user's language>]?...name || translations["en"]?...name ||
# schema.name`, and the helper text the same way with `description`. ⚠️ THE
# FALLBACK IS PER KEY, so a key missing from nl.yaml degrades to this file,
# while a key present but wrong does not degrade at all.
#
# ⚠️ ORDER IS NOT SET HERE. `App.schema_ui` is `UiOptions(...)(data["schema"])`,
# so the Configuration tab renders in the order of config.yaml's `schema:`
# block. The order below only mirrors it so the two files read alike.
#
# ⚠️ ADD-ON OPTIONS ARE A FLAT LIST. There is no section-header primitive, no
# per-option "advanced" flag, no units on the input and no sliders, so grouping
# is approximated by ORDER plus the `Group · ` prefix in each label. Do not
# promise the operator visual sections; there are none.
#
# Names and descriptions follow STYLE.md (UX-08): a short label with its unit,
# and one or two plain sentences. A measured or derived value says "leave it
# unchanged", and where it came from is in DOCS.md under "For installers:
# where the numbers come from".
configuration:
setpoint_entity:
name: "Hardware · Inverter setpoint entity"
description: "The ESPHome number entity the add-on writes the inverter's power to. Leave it empty when you fill in the inverter list."
soc_entity:
name: "Hardware · Battery level entity (%)"
description: "The sensor with the battery level in percent. Use the control board's own reading."
batt_entity:
name: "Hardware · Battery power entity (W)"
description: "The sensor with this inverter's battery power. Positive must mean the battery is giving power."
batt_invert:
name: "Hardware · Battery power sign is reversed"
description: "Switch this on only if your battery power sensor shows giving power as a negative number."
inverters:
name: "Hardware · Inverter list"
description: "Leave it empty if you have one inverter. With two or more, add one entry per inverter, which replaces the inverter settings above."
fields:
name:
name: "Name"
description: "A short, unique name for this inverter, for example inverter-a."
setpoint_entity:
name: "Setpoint entity"
description: "This inverter's own ESPHome setpoint entity. Two entries may not use the same one."
max_w:
name: "Inverter rating (W)"
description: "The most power the add-on may ask of this inverter. The site total is the sum of the list."
bms_soc_floor:
name: "Battery cut-out level (%)"
description: "The level at which this battery's own management system stops giving power. Read it off the battery that is installed."
soc_entity:
name: "Battery level entity (%) (optional)"
description: "This battery's own level sensor. Leave it empty if this inverter has none."
batt_entity:
name: "Battery power entity (W) (optional)"
description: "This inverter's own battery power sensor. Leave it empty if it has none."
batt_invert:
name: "Battery power sign is reversed (optional)"
description: "Switch this on if this inverter's sensor shows giving power as a negative number."
capacity_kwh:
name: "Usable battery capacity (kWh) (optional)"
description: "This battery's usable capacity from its datasheet. Fill it in on every inverter or on none. The add-on then shares the work by the energy each battery has left."
estop_fitted:
name: "Hardware · RS485 emergency stop is fitted"
description: "Switch this on if the emergency stop is installed. It only changes a warning on the status page."
battery_modes_enabled:
name: "Hardware · Battery modes"
description: "Give each battery an on and off switch and a mode, set on the Batteries screen."
pv_forecast_entity:
name: "Hardware · Solar forecast, today (kWh)"
description: "Optional. A forecast sensor with today's remaining solar energy, such as Forecast.Solar or Solcast. A battery then buys only what the sun will not give."
pv_forecast_tomorrow_entity:
name: "Hardware · Solar forecast, tomorrow (kWh)"
description: "Optional. The same forecast for tomorrow. It helps plan a cheap hour before midnight."
pv_forecast_entities:
name: "Hardware · Several solar forecasts, today (kWh)"
description: "Optional. One row per forecast sensor, such as one per inverter, used instead of the single one above. They are added up."
pv_forecast_tomorrow_entities:
name: "Hardware · Several solar forecasts, tomorrow (kWh)"
description: "Optional. The same list for tomorrow. If one sensor has no reading, that day's forecast is not used."
solar_trust_pct:
name: "Hardware · Trust in the forecast (%)"
description: "Forecasts are often too sunny. At 70 % the add-on plans with 7 of every 10 kWh forecast."
pv_entity:
name: "Hardware · Solar production entity (W)"
description: "Optional. Your solar inverter's power sensor, positive while producing. The add-on records it and does not use it for control."
pv_entities:
name: "Hardware · Solar production entities, per inverter (W)"
description: "Optional. Use one row per solar inverter instead of “Solar production entity” when you have several. If one stops reporting, no total is recorded."
pv_invert_entities:
name: "Hardware · Reversed-sign solar entities"
description: "Optional. Add each solar entity above that reads negative while producing, spelled the same way. Its sign is flipped before adding up."
meter_source:
name: "Meter · Where the meter reading comes from"
description: "How the add-on reads your meter. 'off' uses “Grid power entity” below, and only homewizard_local can spot a stuck meter."
meter_entity:
name: "Meter · Grid power entity (W)"
description: "Used when the meter source is 'off'. Positive must mean drawing from the grid."
meter_invert:
name: "Meter · Grid power sign is reversed"
description: "Switch this on if your grid sensor shows drawing from the grid as a negative number."
meter_phases:
name: "Meter · Number of phases (1 or 3)"
description: "Must match your grid connection. Meter readings with a different number of phases are rejected."
p1_host:
name: "Meter · HomeWizard P1 address"
description: "For homewizard_local only. The meter's address on your network, as host or host:port."
meter_poll_s:
name: "Meter · Time between meter reads (s)"
description: "For homewizard_local only. The meter updates every 5 s, so lower gains nothing. Keep it well below “Reading too old after”."
meter_max_age_s:
name: "Meter · Reading too old after (s)"
description: "After this a meter reading counts as missing. The “Missing inputs time limit” starts only after this one runs out."
meter_mqtt_topic:
name: "Meter · MQTT topic"
description: "For mqtt_p1 only. The topic your meter readings are published on."
p1_import_entity:
name: "Meter · Grid import entity (W)"
description: "The sensor for power drawn from the grid, never negative. The add-on works out the net value itself."
p1_export_entity:
name: "Meter · Grid export entity (W)"
description: "The sensor for power fed into the grid, never negative. It pairs with “Grid import entity”."
p1_net_entity:
name: "Meter · Signed net power entity (W)"
description: "For ha_signed only. One sensor that is positive when drawing from the grid and negative when feeding in."
p1_phase_import_entities:
name: "Meter · Import entities per phase (L1-L3)"
description: "Optional, in L1, L2, L3 order. Needed for the peak limit on a three-phase connection, one entry per phase."
p1_phase_export_entities:
name: "Meter · Export entities per phase (L1-L3)"
description: "Optional, in L1, L2, L3 order, next to the import entities per phase. One entry per phase."
p1_phase_net_entities:
name: "Meter · Net entities per phase (L1-L3)"
description: "For ha_signed only. Optional, in L1, L2, L3 order, signed like “Signed net power entity”, one entry per phase."
max_w:
name: "Limits · Inverter rating (W)"
description: "Your own number: the most power the add-on may ever ask of the inverter. Start low and raise it after commissioning."
bms_soc_floor:
name: "Limits · Battery cut-out level (%)"
description: "The level where the battery's own management system stops giving power. Read it off your battery rather than copying a figure."
peak_cap_w:
name: "Limits · Peak limit (W)"
description: "Your own number: the 15-minute average power the add-on keeps the grid under. Take it from your grid contract."
peak_margin_w:
name: "Limits · Margin below the peak limit (W)"
description: "The add-on aims this much below the peak limit, so a 15-minute period that ends a little high still stays under it."
peak_forecast_entity:
name: "Limits · 15-minute demand forecast entity (W)"
description: "Optional. A forecast of this 15-minute period's average power. Leave it empty and there is no peak limit."
peak_soc_floor:
name: "Limits · Peak reserve (%)"
description: "Peak limiting will not draw the battery below this level, but ordinary use can. Derived value, leave it unchanged."
price_provider:
name: "Tariff · Dynamic price source"
description: "Where prices come from. Choosing a source starts the price fetch, even with trading off."
price_markup_eur_kwh:
name: "Tariff · Supplier markup (EUR/kWh)"
description: "Your supplier's margin. It is added only when the price source does not already include it."
price_taxes_eur_kwh:
name: "Tariff · Distribution, levies and VAT (EUR/kWh)"
description: "Grid costs, levies and VAT per kWh, preset for Flanders. Check it against your own grid operator's rates."
export_price_eur_kwh:
name: "Tariff · Injection price (EUR/kWh)"
description: "What you are paid per kWh fed into the grid, all in. It may be negative."
static_profile:
name: "Tariff · Fixed or day/night tariff"
description: "Your fixed or day/night contract on one line, prices all in, as the documentation shows. Fill it in even on a dynamic contract, as the fallback."
price_taxes_profile:
name: "Tariff · Day/night levies and VAT"
description: "Leave it empty unless your grid operator charges a different day and night rate, as in Wallonia and Brussels. Set this or the flat figure above, not both."
price_formula:
name: "Tariff · Your own tariff formula"
description: "For custom_formula only. Type the numbers from your supplier's tariff card on one line, as the documentation shows. The add-on checks them against the card."
price_export_formula:
name: "Tariff · Your own injection formula"
description: "Optional. The injection formula from your tariff card, in the same shape as your own tariff formula. Leave it empty to use the flat injection price."
price_csv_path:
name: "Tariff · Price CSV file"
description: "For manual_csv only. Where in /share the add-on reads your price file."
price_feed_url:
name: "Tariff · Price feed URL override"
description: "Leave it empty to use the source's own feed. An override is sent exactly as typed and often returns only one day."
price_service_token:
name: "Tariff · Price service token"
description: "For the price service only. The token you were given for it. Leave it empty with any other price source."
price_horizon_h:
name: "Tariff · Price look-ahead (hours)"
description: "How many hours of prices to ask the source for."
price_timeout_s:
name: "Tariff · Price request timeout (s)"
description: "How long one request to the price source may take before it is given up."
price_now_entity:
name: "Tariff · Current price entity (older)"
description: "The older way to get a price, used only to charge in a cheap window during maintenance. Do not combine it with a dynamic price source."
price_avg_entity:
name: "Tariff · Average price entity (older)"
description: "The average the current price is compared with. Use it only with the current price entity, not with a dynamic price source."
arbitrage_enabled:
name: "Tariff · Trade on the price spread"
description: "Charge in the cheapest hour and draw the battery down in the dearest, when the spread covers the cost. Turning it off does not turn the price feed off."
cycle_cost_threshold_eur:
name: "Tariff · Battery cycle cost (EUR/kWh)"
description: "What one full battery cycle costs per kWh. A smaller price spread is not traded, and the value is a product choice, not a measured one."
arbitrage_soc_floor:
name: "Tariff · Trading keeps at least (%)"
description: "Price trading will not draw the battery below this level. It is separate from the maintenance settings."
arbitrage_soc_ceiling:
name: "Tariff · Trading charges at most (%)"
description: "Price trading will not charge the battery above this level."
maintenance_enabled:
name: "Maintenance · Run the monthly battery cycle"
description: "Once a month, empty the battery deeply, charge it full and hold it there, so its level reading stays accurate. Off by default."
maintenance_interval_days:
name: "Maintenance · Minimum days between cycles"
description: "The shortest gap between two maintenance cycles."
maintenance_start_hour:
name: "Maintenance · Start hour (local time)"
description: "The hour on your local clock, 0 to 23, when a due cycle starts. 19 means 19:00."
maintenance_discharge_w:
name: "Maintenance · Draw-down rate (W)"
description: "How fast the cycle empties the battery. Above “Inverter rating” it is cut back to the rating, and the cycle just takes longer."
maintenance_charge_w:
name: "Maintenance · Recharge rate (W)"
description: "How fast the cycle recharges the battery. It must be at or below “Inverter rating”, or the add-on will not start."
maintenance_soc_floor:
name: "Maintenance · Draw down to (%)"
description: "The level the monthly cycle empties the battery to. It is not the “Peak reserve”, and the two differ on purpose."
maintenance_soc_target:
name: "Maintenance · Recharge up to (%)"
description: "The level the recharge aims for before the hold starts."
maintenance_hold_min:
name: "Maintenance · Hold at full for (minutes)"
description: "How long the battery stays full so its cells can balance."
sign_disagree_w:
name: "Safety · Wrong-direction threshold (W)"
description: "Part of the safety stop for an inverter pushing the wrong way. It counts only when command and meter reading both exceed this. Measured value, leave it unchanged."
sign_disagree_s:
name: "Safety · Wrong-direction time (s)"
description: "How long a wrong direction may last before a safety stop sets every inverter to 0 W. Measured value, leave it unchanged."
unit_sign_disagree_w:
name: "Safety · Per-inverter wrong-direction threshold (W)"
description: "For two or more inverters: the wrong-direction threshold for each inverter. Derived value, leave it unchanged."
unit_sign_disagree_s:
name: "Safety · Per-inverter wrong-direction time (s)"
description: "For two or more inverters: how long one inverter may push the wrong way before it is set to 0 W. Derived value, leave it unchanged."
site_sign_disagree_w:
name: "Safety · Site wrong-direction threshold (W)"
description: "For two or more inverters: the wrong-direction threshold for the whole site. Measured value, leave it unchanged."
site_sign_disagree_s:
name: "Safety · Site wrong-direction time (s)"
description: "For two or more inverters: how long the whole site may push the wrong way before a safety stop. Derived value, leave it unchanged."
meter_freeze_s:
name: "Safety · Stuck meter alarm after (s)"
description: "An alarm when the meter repeats one reading this long while the command is at full power, with homewizard_local only. Measured value, leave it unchanged."
circulation_w:
name: "Safety · Opposing inverters threshold (W)"
description: "For two or more inverters: how much power one may push against another before it counts. Measured value, leave it unchanged."
circulation_hold_s:
name: "Safety · Opposing inverters time (s)"
description: "For two or more inverters: how long they may push against each other before a safety stop. Derived value, leave it unchanged."
delivery_hold_s:
name: "Safety · Not delivering alarm after (s)"
description: "For two or more inverters: how long one may fall short of its share before an alarm, which changes nothing. Derived value, leave it unchanged."
shadow_mode:
name: "Safety · Shadow mode"
description: "The add-on makes every decision but keeps every inverter at 0 W. 'auto' does this while control is stopped, 'on' always, 'off' never."
auto_start:
name: "Advanced · Start control on boot"
description: "Off by default. Leave it off until the site is commissioned, so someone presses Start after each restart."
gain:
name: "Advanced · Control gain"
description: "How much of the remaining error control corrects each cycle. Measured on real hardware, do not raise it."
slew_w:
name: "Advanced · Largest change per cycle (W)"
description: "How far the command may move in one cycle. 0 follows “Inverter rating” and is recommended."
deadband_w:
name: "Advanced · Ignore errors below (W)"
description: "Errors smaller than this are ignored. Keep it small, since any resting point inside it holds."
target_grid_w:
name: "Advanced · Meter resting point (W)"
description: "What the meter should show when nothing happens. A slight export avoids paying for tiny imports all day."
step_w:
name: "Advanced · Command rounding (W)"
description: "The command is rounded to a multiple of this, so noise does not change it every cycle."
saturation_w:
name: "Advanced · At-limit shortfall (W)"
description: "When an inverter delivers this much less than asked, it counts as at its limit. The per-inverter wrong-direction threshold is half of this."
saturation_cycles:
name: "Advanced · Cycles at limit before freezing"
description: "How many cycles in a row at the limit before control stops building up error. Do not set it to 1."
integrator_max_w:
name: "Advanced · Catch-up limit (W)"
description: "Limits how hard control keeps pushing while the battery falls behind. 0 means “Inverter rating”. Do not raise it above the rating."
heartbeat_s:
name: "Advanced · Command refresh interval (s)"
description: "How often the command is sent again even when unchanged. Keep it well under the control board's own 30 s limit."
stale_input_s:
name: "Advanced · Missing inputs time limit (s)"
description: "How long inputs may be missing before every inverter is set to 0 W. With a P1 meter it starts after “Reading too old after”."
cycle_floor_s:
name: "Advanced · Longest time between cycles (s)"
description: "A deadline between control cycles that a healthy meter never reaches. Raise it only for a meter slower than about 10 s."
log_level:
name: "Advanced · Log level"
description: "How much detail the add-on writes to its log. 'debug' and 'trace' are for finding a problem."