Merge release/1.0 (e3e4ba6) into opt15-price-run-fixes
infra-pin / fresh (pull_request) Successful in 3s
checks / unit (pull_request) Successful in 39m30s

Conflicts (5 files, 9 hunks) resolved keeping both sides:
- p1.py: held_t (OPT-15) beside held_since (SAFETY-90).
- modetrade.py: chargers() takes targets (P4) and probe (OPT-15); decide()
  clears the chargers, a probing refuser included, while a battery drains
  (SAFETY-78); the docstring lists both rules.
- main.py: the roll goes into the SAFETY-90/91 projection chain
  (`_peak_proj`); the SAFETY-95 drain-tail grid_w keeps the run-edge hold on
  its other branch; the P4 forecast state and the hold state both stay.
- DOCS.md, DECISIONS: both lines kept, OPT-15 item refreshed.

Adaptations the merge needs:
- SAFETY-81 x F1: a rolled projection is not graded by the saturation alarm
  until the quarter's first sample, as the old edge tick was not, so a
  standing overload is still notified once per quarter.
- test_safety81, test_modes_p4: modes-on pins re-pinned (with a note), modes
  off pinned to e3e4ba6; test_price_run_fixes: identity pins on e3e4ba6,
  F1 reproduced at one inverter (SAFETY-91 already holds two), tests for the
  drain and the day plan against the probe.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
glenn schrooyen
2026-10-13 12:15:44 +02:00
co-authored by Claude
105 changed files with 17752 additions and 471 deletions
+157 -23
View File
@@ -184,6 +184,11 @@ The label and description each setting shows on the Configuration tab, in tab or
| Hardware · Inverter list | Usable battery capacity (kWh) (optional) | `inverters.capacity_kwh` | 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. |
| Hardware | RS485 emergency stop is fitted | `estop_fitted` | Switch this on if the emergency stop is installed. It only changes a warning on the status page. |
| Hardware | Battery modes | `battery_modes_enabled` | Give each battery an on and off switch and a mode, set on the Batteries screen. |
| Hardware | Solar forecast, today (kWh) | `pv_forecast_entity` | 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. |
| Hardware | Solar forecast, tomorrow (kWh) | `pv_forecast_tomorrow_entity` | Optional. The same forecast for tomorrow. It helps plan a cheap hour before midnight. |
| Hardware | Several solar forecasts, today (kWh) | `pv_forecast_entities` | Optional. One row per forecast sensor, such as one per inverter, used instead of the single one above. They are added up. |
| Hardware | Several solar forecasts, tomorrow (kWh) | `pv_forecast_tomorrow_entities` | Optional. The same list for tomorrow. If one sensor has no reading, that day's forecast is not used. |
| Hardware | Trust in the forecast (%) | `solar_trust_pct` | Forecasts are often too sunny. At 70 % the add-on plans with 7 of every 10 kWh forecast. |
| Hardware | Solar production entity (W) | `pv_entity` | Optional. Your solar inverter's power sensor, positive while producing. The add-on records it and does not use it for control. |
| Hardware | Solar production entities, per inverter (W) | `pv_entities` | Optional. Use one row per solar inverter instead of “Solar production entity” when you have several. If one stops reporting, no total is recorded. |
| Hardware | Reversed-sign solar entities | `pv_invert_entities` | Optional. Add each solar entity above that reads negative while producing, spelled the same way. Its sign is flipped before adding up. |
@@ -227,7 +232,7 @@ The label and description each setting shows on the Configuration tab, in tab or
| Tariff | Trading charges at most (%) | `arbitrage_soc_ceiling` | Price trading will not charge the battery above this level. |
| Maintenance | Run the monthly battery cycle | `maintenance_enabled` | Once a month, empty the battery deeply, charge it full and hold it there, so its level reading stays accurate. Off by default. |
| Maintenance | Minimum days between cycles | `maintenance_interval_days` | The shortest gap between two maintenance cycles. |
| Maintenance | Start hour | `maintenance_start_hour` | The local hour, 0 to 23, at which a due cycle starts. |
| Maintenance | Start hour (local time) | `maintenance_start_hour` | The hour on your local clock, 0 to 23, when a due cycle starts. 19 means 19:00. |
| Maintenance | Draw-down rate (W) | `maintenance_discharge_w` | How fast the cycle empties the battery. Above “Inverter rating” it is cut back to the rating, and the cycle just takes longer. |
| Maintenance | Recharge rate (W) | `maintenance_charge_w` | How fast the cycle recharges the battery. It must be at or below “Inverter rating”, or the add-on will not start. |
| Maintenance | Draw down to (%) | `maintenance_soc_floor` | The level the monthly cycle empties the battery to. It is not the “Peak reserve”, and the two differ on purpose. |
@@ -522,7 +527,7 @@ Off by default. Turn it on, restart the add-on, and the Batteries screen (and Se
- **On or off.** Off asks the battery for 0 W and starts no monthly cycle on it. A cycle that is running stops, and the add-on log says so. The peak limit may still use it, but only for what the other batteries cannot cover.
- **Mode.**
- *Solar first* charges from spare solar before the other batteries and covers the house at any hour. It never charges from the grid and never sells.
- *Leftover solar* charges from the solar the others cannot take, never from the grid (until the solar forecast arrives). It saves its power for the expensive hours and covers the house then.
- *Leftover solar* charges from the solar the others cannot take. With a solar forecast it may also charge from the grid, but only what the sun will not give (see below). It saves its power for the expensive hours and covers the house then.
- *Cheap hours only* charges from the grid in the cheapest hours, saves its power for the expensive hours and covers the house then.
- **Selling** is off until it can be judged on the price the grid pays (owner decision 2026-09-29, option A).
@@ -535,10 +540,24 @@ With battery modes on, these choices replace the *Charging and selling on price*
- A carried (not yet published) price is never used. A run that has started runs to its end.
- With no prices, or too small a gap, every battery follows the house.
**Solar forecast** (`pv_forecast_entity`, optional). A Home Assistant sensor with the solar energy still to come today, in kWh. These work: Forecast.Solar (`sensor.energy_production_today_remaining`), Solcast PV Forecast (`sensor.solcast_pv_forecast_forecast_remaining_today`) and Open-Meteo Solar Forecast (`sensor.energy_production_today_remaining`). Set `pv_forecast_tomorrow_entity` to the matching *tomorrow* sensor to plan a cheap run before midnight.
- **Several forecasts.** If your forecast comes as several sensors (one per inverter or roof side), list them in `pv_forecast_entities` and, for tomorrow, `pv_forecast_tomorrow_entities`, instead of the single key. They are added up, each in its own unit (Wh, kWh or MWh). Set the list or the single key for a day, not both.
- If one of them has no reading, is stale or is not in an energy unit, that day's forecast is not used at all. A part of the sun is not counted as all of it. The status page names the source by its place in the list.
- The hourly shape is kept only if every sensor has one. Otherwise the total is spread over the day as for Forecast.Solar.
- Before each cheap run the add-on asks: will the sun fill the batteries before the expensive hours? It counts on `solar_trust_pct` of the forecast (70 %), less what the house uses. Solar first batteries get that sun first.
- *Leftover solar* then charges from the grid only the shortfall: what the house will draw from it in the expensive hours, less its share of the sun. Not up to the top level.
- *Cheap hours only* ignores the forecast and fills to the top level.
- *Solar first* never charges from the grid.
- The house use is the add-on's own measurement (grid + battery power) per hour, over the last 7 days. It needs one day of it before the first plan.
- The plan is checked every 15 minutes. A planned level moves only by 1 kWh or 10 %, so a wobbling forecast does not flip it.
- No forecast, one older than 3 hours or from before midnight, or no house use yet: *Leftover solar* takes solar only and *Cheap hours only* fills to the top level. The Batteries screen says so.
- A battery needs its capacity (`inverters.capacity_kwh`) for a plan.
**What always comes first.**
- The peak limit, the safety stops and the monthly cycle come before a battery's mode.
- A grid charge is sized so the 15-minute period stays under the peak limit less its margin (`peak_margin_w`). It starts only at 500 W or more. Once the peak limit stops it, it stays off for the rest of that 15-minute period. The start of a new period does not stop it.
- While one battery charges from the grid, the others rest, and the house uses the grid.
- While one battery empties for its monthly cycle, no battery charges from the grid.
- A battery that refuses to charge or give power takes no part in a run in that direction. In a cheap run it is still tested every 15 minutes: it charges at 200 W for about half a minute while the others rest.
**In Home Assistant.** With MQTT set up, each battery also gets a *Mode* list and a *Use* switch, for example `select.goodwe_inverter_a_mode` and `switch.goodwe_inverter_a_use`. They do the same as the Batteries screen. Turn battery modes off and restart, and they are removed.
@@ -563,7 +582,7 @@ accumulator is doing:
| `Loop integrator lead` | W | that value minus **the command it was computed against**, i.e. the command the previous cycle left standing |
| `Loop reason` | — | the law's own word for this cycle |
`Loop reason` takes one of ten values:
`Loop reason` takes one of eleven values:
| value | what happened |
|---|---|
@@ -574,8 +593,9 @@ accumulator is doing:
| `slew-limited` | the command could not move as far as the integrator asked for; `slew_w` is what stopped it |
| `saturated-freeze` | the inverter is not following, so the command's magnitude may fall but not rise |
| `freeze-released` | the freeze had run out of plant-shaped explanations and the command was let move again |
| `mode-bound` | the batteries' limits set the command, not the meter: their battery modes, or, with two or more inverters, a battery in its monthly maintenance |
| `not-running` | control is stopped **and** shadow mode is off, so the loop did not run |
| `battery refuses` | the battery gave less than 100 W for 12 cycles (a minute at a 5-second meter) while asked for more than 500 W, so the add-on asks 0 W in that direction (see below) |
| `battery refuses` | the battery gave less than 100 W for 12 cycles and at least 22 s (a minute at a 5-second meter) while asked for more than 500 W, so the add-on asks 0 W in that direction (see below) |
| `battery probe` | the add-on asks 200 W to test whether a refusing battery gives power again |
**When the battery refuses.** At its cut-out level the battery gives nothing,
@@ -585,7 +605,15 @@ request, and the `Why` row reads *The battery refuses to give power: 0 W*. Every
the battery gives 100 W or more, when the grid needs charging instead, and when
control is stopped or started. 200 W is below the 250 W the stale-reading check
needs, so a test never trips it. A battery that gives some power, even 100 W,
is not refusing and keeps its request.
is not refusing and keeps its request. Nor is a battery whose reading is
still moving towards the request, such as one turning from charging to
giving (SAFETY-94). "Gives" is counted from what the battery's reading shows
at rest, which the add-on learns after two quiet minutes and keeps: some
inverters show about -100 W at rest (SAFETY-97).
While another task sets the power, such as a maintenance charge, the peak
guard or a trade, the refusal stays as long as the battery still refuses that
task's request. It is logged once, and the 200 W test waits until control sets
the power again (SAFETY-107).
**With two or more inverters** the same rule works per inverter. An inverter
whose battery gives less than 100 W for 12 cycles, and at least 22 s, while
@@ -599,7 +627,7 @@ If the battery refuses to give power while its level reads above its “Battery
cut-out level”, the log adds one warning ending in `REFUSES_ABOVE_CUT_OUT`: check that setting.
A battery that refuses is not reported as *not delivering*.
*For installers:* SAFETY-52 and SAFETY-73. The event log reads
*For installers:* SAFETY-52, SAFETY-73 and SAFETY-107. The event log reads
`BATTERY REFUSES …` and `BATTERY REFUSES ENDED …` (with the inverter's name at
N>1), and the INFO line ends in `BATTERY_REFUSES`.
`DECISIONS/SAFETY-52-a-battery-that-refuses.md` has the replay figures and
@@ -1624,13 +1652,45 @@ help - see "Why the tuning is what it is".
|---|---|---|
| `maintenance_enabled` | false | Enable the monthly cycle |
| `maintenance_interval_days` | 28 | Minimum gap between cycles |
| `maintenance_start_hour` | 10 | Hour of day a due cycle begins |
| `maintenance_discharge_w` | 2000 | Drain rate (exports the surplus). Above `max_w` it is **clamped** to `max_w` — the drain phase SETs the setpoint and the arbiter bounds it, saying so on the status page (`limited by supervised(max_w)`). Warned about, not refused: the cycle still completes, just slower |
| `maintenance_start_hour` | 19 | Local hour a due cycle begins (see below) |
| `maintenance_discharge_w` | 2000 | Drain rate (exports the surplus). The peak guard may ask for more (SAFETY-83; at N≥2 while another battery is at its peak reserve, SAFETY-87), and at N≥2 so may the house while another battery is at its peak reserve (SAFETY-91). Above `max_w` it is **clamped** to `max_w` — the drain phase SETs the setpoint and the arbiter bounds it, saying so on the status page (`limited by supervised(max_w)`). Warned about, not refused: the cycle still completes, just slower |
| `maintenance_charge_w` | 2000 | Charge ceiling, capped again by peak headroom. Must stay **at or below `max_w`** or the cheap-window shaping (`hi = -maintenance_charge_w`) contradicts the supervised limit (`lo = -max_w`), the arbiter resolves it to **0 W**, and maintenance silently never charges in a cheap window — **the add-on refuses to start** |
| `maintenance_soc_floor` | 11 | Drain target — stay just above the inverter's own floor. ⚠️ **This is not `peak_soc_floor`.** It is the depth the monthly recalibration deliberately goes to, once, on purpose; `peak_soc_floor` is the depth a money-saving discharge may never reach on any day. The right values differ (11 vs 20 as shipped), which is why they are two keys |
| `maintenance_soc_target` | 99 | Charge target |
| `maintenance_hold_min` | 120 | Hold at full so the BMS can balance |
**The start hour is local time.** The add-on reads Home Assistant's time zone
(Settings → System → General) at startup. If Home Assistant does not answer,
it uses the add-on's own time zone, and failing that UTC. The log says which
one it used, and warns if it is UTC: then restart the add-on once Home Assistant
is up. On the day the clocks go forward, a start hour that does not exist
starts at the first hour after the jump. On the day they go back, a repeated
hour starts only once, in its first pass. With two inverters both batteries use
the same local hour; one cycles at a time, and the other starts at that hour on
a later day.
**Upgrading.** The hour used to be read as UTC. An existing install keeps its
saved hour, and that hour now means local time: a saved 10 now starts at 10:00,
not 12:00 in summer. The new default, 19, only reaches installs that have no
hour saved. If you set an earlier hour to get an evening start in UTC (for
example 17 for 19:00 in summer), set it to 19. The add-on never changes a saved
value. *For installers:* DECISIONS/MAINT-10-local-start-hour.md.
**When the charge counts as done.** A battery may stop at 98 or 99 % while it
balances, so it need not reach `maintenance_soc_target`. The charge counts as
done when the battery is within 3 points of the target and has taken no more
charge for 60 minutes of charging time, or when the charging time (36 hours) runs
out within 3 points of the target. Only the minutes the cheap-hours gate let the
battery charge count, and the charge ends after 7 days at the
latest. Then the usual hold follows.
**When a cycle fails.** If the battery does not empty in 12 hours, or does not
get within 3 points of the target in 36 hours of charging time, the cycle
stops, you get the notification *Battery cycle did not finish*, and it is not
tried again for 7 days. The status page shows *Maintenance paused* with the
date. Starting a cycle by hand ignores the wait. *For installers:*
DECISIONS/MAINT-13-full-pack-is-complete.md.
### Tariff (all optional)
| option | meaning |
@@ -1647,6 +1707,30 @@ under `peak_cap_w`, and if the forecast goes over the cap the charge-only clamp
is dropped so the battery can shave the peak instead. Money outranks the
maintenance schedule.
With two or more batteries, the one being emptied gives its drain rate and the
others only add power when the house needs more; none charges while it drains
(SAFETY-78). Below the drain rate the rest is exported, as with one battery.
If the house would still go over the peak limit, the battery being emptied
gives more than its drain rate, with one battery too (SAFETY-83).
A battery at its peak reserve gives last: the others give their full power
first, and the battery being emptied rises above its drain rate before it
(SAFETY-91).
In a cheap window the battery being filled charges and the others only add
charge; none gives while it charges. The charge is cut to what keeps the
15-minute peak at the limit minus `peak_margin_w` (SAFETY-84).
While a full battery rests after its charge (the hold), it gives just enough
to keep the 15-minute peak at that aim if the house needs it; with two
batteries the other one gives first. The hold still ends on its clock
(SAFETY-86).
When a charge ends, the other batteries take over one slew step a cycle,
and none starts charging from the grid (SAFETY-93).
When a battery's link drops, the others take over one slew step a cycle,
and control does not stall on the dropped battery's power (SAFETY-96).
When a drain ends (done, Off, timeout, abort, lost link, refused), the
other batteries cover the house at once but do not export its drain; then
they move one slew step a cycle (SAFETY-95). While that battery settles,
an old battery reading does not move them (SAFETY-103).
#### Capacity-tariff exposure of the grid-following loop
⚠️ **This section described the exposure BEFORE SAFETY-07. The loop is now
@@ -1715,10 +1799,17 @@ ceiling at the cap, so a broken instrument makes the guard stricter, never loose
**When it cannot see, it forbids importing.** Three states are not evidence and
are checked before the projection is graded: no open quarter (a fresh averager
projects a confident 0 W, which is under every ceiling there is), a meter gap
longer than `meter_max_age_s`, and SAFETY-18's frozen-meter conjunction. In all
three the claim becomes a floor of **0 W**. That is the backstop for the frozen
meter: the alarm arrives at `meter_freeze_s` (300 s) of a 900 s billing quarter
and commands nothing, and this stops the import.
longer than `meter_max_age_s` while it lasts, and SAFETY-18's frozen-meter
conjunction. In all three the claim becomes a floor of **0 W**. That is the
backstop for the frozen meter: the alarm arrives at `meter_freeze_s` (300 s) of
a 900 s billing quarter and commands nothing, and this stops the import.
**After a gap it goes on (SAFETY-90).** The seconds the meter missed count at
the higher of the peak limit and the import seen just before and just after
the gap, with the batteries at 0 W. Seconds before the add-on's first reading
count the same way, at the import seen first, and the page says part of the
period was not measured. DECISIONS/SAFETY-90-peak-guard-after-a-gap.md has the
bound.
**It trips, where the freeze detector only notifies,** and the captures are why.
On the healthy reference day (2026-08-23) it engages on **zero** of 95 quarters.
@@ -1739,7 +1830,8 @@ control action and goes to the action log and the status page. A *saturated*
guard — asking for everything the inverter has while the quarter is still
projected over — raises one notification (`goodwe_peak_saturated`), because that
is the one state where the money will be spent and shedding load is the only
thing left that changes the bill.
thing left that changes the bill. SAFETY-81 keeps a 1 s meter spike, noise and
a quarter's last seconds from raising it: see `peakguard.load_too_high()`.
**And it sizes a price-driven charge, not only a forced discharge (SAFETY-45).**
The same arithmetic read the other way answers *"how hard may this site charge
@@ -1780,7 +1872,9 @@ exactly like the SoC drift the monthly maintenance cycle exists to correct.
It will discharge straight past this number and keep going until the pack's own
BMS cut-out stops it. What you are promised by `peak_soc_floor: 20` is *"the
capacity-peak guard will not spend the pack for money below 20 %"*, and
**nothing more**. See below for what that costs on a real evening.
**nothing more**. See below for what that costs on a real evening. With two
or more batteries, one under it is used last: only once the others give
their full power (SAFETY-91).
- **When it binds you are told**, once per episode, with notification
`goodwe_peak_soc_floor` and a red status-page row reading *Battery at its
peak reserve* (`PEAK_GUARD_FLOOR_LIMITED` in the log): the quarter **will**
@@ -1925,6 +2019,15 @@ over the rating is logged as a software fault, at `ERROR`, and it has its own
notification budget.
Why: [`DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md`](DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md).
The integrator bound counts only on a cycle the loop decided. While
maintenance, the peak guard or a safety limit sets a battery to discharge, the
same alarm fires only when that battery gives more than `saturation_w` less
than the least it was told over the plant's settle time (at least 23 s), for
`saturation_cycles` cycles. A charge is not graded: a full battery takes less
as it tops up. At two or more inverters the loop does not wind while
maintenance holds a battery.
Why: [`DECISIONS/SAFETY-85-no-false-not-keeping-up.md`](DECISIONS/SAFETY-85-no-false-not-keeping-up.md).
### The frozen-meter alarm
A meter that has died is easy — it stops answering, the sample age climbs past
@@ -3094,7 +3197,10 @@ The battery gives less power than the add-on asks for. This is normal for a
short time, for example just after a large load switches on or the sun comes
out. It is not a fault, and control keeps running. If it keeps coming back,
check that the battery is switched on, and that it is not empty (when it should
give power) or full (when it should charge).
give power) or full (when it should charge). During the monthly maintenance or
while the peak limit is guarded, it only shows when the battery gives
clearly less than it was told. The status page counts how many times it
happened.
### Power request too high
@@ -3129,6 +3235,10 @@ and what to do:
- **A battery cut-out level is not known.** Fill in “Battery cut-out level”
for each inverter in the settings.
With several inverters, a battery at its peak reserve does not give for the
peak and the others do. This alarm then comes only when the others cannot
keep the period under the limit alone. Control keeps running meanwhile.
The peak reserve only applies to keeping the peak down. Normal home use can
still draw the battery below it, down to the battery cut-out level, where the
battery switches itself off.
@@ -3164,6 +3274,14 @@ reading is stuck. Control keeps running and keeps following the reading, so a
stuck reading can raise this month's peak. Check the meter. If it is stuck,
stop control on the add-on page.
### Battery cycle did not finish
The monthly battery cycle stopped because the battery did not empty, or did not
fill up, in time. The battery is back under normal control. The add-on waits 7
days before it tries again, so it does not empty the battery every night. To
try sooner, start a cycle on the add-on page. If it keeps happening, check that
the battery follows its commands and that the cheap hours leave time to charge.
### For installers: notifications
This part is for installers. The texts live in `app/messages.py` and follow
@@ -3183,6 +3301,7 @@ default `info` hides it.
| Inverters working against each other | alarm | `goodwe_circulating_power` | SAFETY-31 |
| *name* is not delivering | alarm | `goodwe_not_delivering_<name>` | SAFETY-42 |
| Meter reading may be stuck | alarm | `goodwe_meter_frozen` | SAFETY-18 |
| Battery cycle did not finish | warning | `goodwe_maint_failed_<name>` | MAINT-13 |
**The Details link.** Home Assistant 2026.2 and newer show add-on pages at
`/config/app/<slug>/documentation`; 2026.5 removed the old
@@ -3195,8 +3314,9 @@ section without a link. The documentation tab adds no heading anchors, so the
link cannot jump to the section.
**Battery is not keeping up.** The grid-following loop's integrator reached its
anti-windup bound (`integrator_max_w`, SAFETY-40). No command went over the
rating. The log line is a WARNING with reason code `OUTPUT_CLAMP`. See *The
anti-windup bound (`integrator_max_w`, SAFETY-40), or a battery that another
owner set to discharge gave less than it was told (SAFETY-85). No command went
over the rating. The log line is a WARNING with reason code `OUTPUT_CLAMP`. See *The
winding-loop alarm*.
**Power request too high.** A computed command above a limit was cut before it
@@ -3211,9 +3331,12 @@ reason code `OUTPUT_CLAMP`.
**Load too high for battery.** The capacity-peak guard (SAFETY-07) asks for
everything the inverter can discharge and the running 15-minute average is
still projected over the peak limit, so the month's billed peak
(capaciteitstarief) goes up. In shadow mode the guard's projection is made on a
plant that did not respond (SAFETY-47), and the text says so. See *The
capacity-peak guard*.
(capaciteitstarief) goes up. It fires only when, for 10 s, the period would
still end more than 10 W over the real limit (not the margin's aim) with the
battery at full power. It notifies at most once per period; later overloads
in the same period go to the log (SAFETY-81). In shadow mode the
guard's projection is made on a plant that did not respond (SAFETY-47), and
the text says so. See *The capacity-peak guard*.
**Battery stopped limiting the peak.** The peak guard may not discharge below
`peak_soc_floor` (label “Peak reserve”, SAFETY-24). It also stops when the
@@ -3221,7 +3344,9 @@ state of charge is unread, or when an inverter's `bms_soc_floor` (label
“Battery cut-out level”) is missing, because the reserve is graded against it.
Charging from the grid stays blocked meanwhile. With several inverters the
notification names the battery at its limit (SAFETY-32), each graded against
its own cut-out level. ⚠️ **The reserve binds the peak guard only
its own cut-out level. That battery is held (weight 0 while the site gives)
and the guard's need goes to the others, up to their rating; the alarm fires
only if they miss the limit at full power for `ALARM_HOLD_S` (SAFETY-87). ⚠️ **The reserve binds the peak guard only
(SAFETY-25).** Self-consumption has no such floor. See *What `peak_soc_floor`
does not protect*.
@@ -3353,13 +3478,14 @@ for a new install*.
| Row starts with | What it tells you |
|---|---|
| Home Assistant is not answering | Home Assistant is not passing readings or power requests on, usually because it is still starting. The add-on cannot control until then. It resumes by itself. Nothing to do unless it lasts. |
| Control | When control last ran. Red when it has stopped running: the control board then sets the inverter to 0 W. |
| Meter | The grid reading, its age, how many readings were refused, and how long its value has not changed. Just after a start it is amber and *waiting for the first reading*. Red means no reading for longer than the limit. |
| Stuck-meter check | Whether the add-on can warn you about a stuck meter. |
| Meter reading may be stuck | See *Meter reading may be stuck* under Notifications. |
| Month peak | This month's highest 15-minute average, when it happened, and how close it is to your peak limit. Amber from 80 %. |
| 15-minute periods measured this month | How many 15-minute periods the add-on has measured and saved this month. |
| Peak guard, Load too high for battery, Battery at its peak reserve | What the add-on does to keep your peak down. *Idle, heading for …* is where this 15-minute period is heading. *Waiting for meter readings* after a restart means the battery does not charge until the add-on can measure the period again. |
| Peak guard, Load too high for battery, Battery at its peak reserve | What the add-on does to keep your peak down. *Idle, heading for …* is where this 15-minute period is heading. *Waiting for meter readings* after a restart means the battery does not charge until the add-on can measure the period again. A red peak row is an alarm while control keeps running, so the banner shows its title without *Not ready*. |
| Battery level, Battery power, Grid power | The reading of that entity. *No usable reading* means the entity is missing, or its reading is too old. Check it in Developer Tools before replacing it. |
| Inverter control | Whether the inverter can be controlled, and how much it can charge and give. |
| *name*: battery power reading stopped changing | The reading did not change while the add-on asked for a change. It may be stuck, or the battery may be refusing. The add-on sets the inverters to 0 W until it changes. |
@@ -3399,7 +3525,8 @@ reason code, and its full figures are on the DEBUG line right after it and in
…`, and the peak guard's full reason is on the DEBUG line after its ERROR.
- ***name*: battery power reading stopped changing** is SAFETY-37/56/57. The
ERROR line says when it clears and names `STALE_READING`. The full reason,
with both possible causes, is on the DEBUG line after it.
with both possible causes, is on the DEBUG line after it. The 35 s counts
only while the command asks the reading to move (SAFETY-94).
- **Meter: no reading for …** (red): the add-on logs one WARNING when the
meter goes quiet, "No meter reading for …", and an INFO line when readings
return, at most once every 10 minutes. Past `stale_input_s` the **Why**
@@ -3410,6 +3537,13 @@ reason code, and its full figures are on the DEBUG line right after it and in
(TARIFF-11), in words.
- **Solar production** reads `pv_entity` or `pv_entities` (TEL-11/12). The
*Reversed-sign solar entities* setting is `pv_invert_entities` (TEL-14).
- **Home Assistant is not answering** (SAFETY-112): the Supervisor answers
502 to every add-on read, write and websocket until Home Assistant is
RUNNING, even when its entities are already live. A slow integration at
start-up therefore holds control for as long as it holds Home Assistant's
start. The log has one WARNING, a "Still waiting" INFO line every 5
minutes and "answers again after …" at the end. See
`DECISIONS/SAFETY-112-waiting-for-home-assistant.md`.
- **Shadow mode** (SAFETY-10): the banner turns red when a latch is up
(circulating power, or a site or per-inverter sign trip), and that latch keeps
its own red row.