PKG-18: cut 0.12.0, so TEL-12's pv_entities can reach an installed 0.11.0 (#117)
checks / unit (pull_request) Successful in 8m0s
checks / unit (pull_request) Successful in 8m0s
Reviewed at head 1ad4d3a. CI run 830 (attempt 1, pull_request, PR 117 -> release/1.0), 31/31 PASS. Review: #issuecomment-1588, #issuecomment-1589.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
This commit was merged in pull request #117.
This commit is contained in:
@@ -1,5 +1,137 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.12.0
|
||||||
|
|
||||||
|
**A MINOR BUMP FOR ONE NEW OPTION: `pv_entities` ([[TEL-12]]), for sites with
|
||||||
|
more than one PV inverter.** The option surface moves **76 keys -> 77**,
|
||||||
|
`options:` and `schema:` in step. 0.11.0's `pv_entity` takes one entity; a roof
|
||||||
|
with two or three inverters, each publishing its own power sensor into Home
|
||||||
|
Assistant, could only record one of them. `pv_entities` is a list, and the
|
||||||
|
Configuration tab renders it as a repeatable field, so you add your second and
|
||||||
|
third inverter there rather than in YAML.
|
||||||
|
|
||||||
|
⚠️ **UNSET, NOTHING CHANGES.** `pv_entities` ships as `[]`, which is what every
|
||||||
|
install that presses *Update* lands on, and empty means "use `pv_entity`" - so
|
||||||
|
an install with no PV entity still has no PV channel, and an install with one
|
||||||
|
`pv_entity` keeps exactly the single-entity channel 0.11.0 gave it. **No rule was
|
||||||
|
added to `validate.py`**, which mentions neither key, so **a stored options blob
|
||||||
|
that starts the add-on on 0.11.0 starts it on 0.12.0**. There is no
|
||||||
|
`SystemExit(78)` to plan around on this hop.
|
||||||
|
|
||||||
|
⚠️ **IT IS INSTRUMENTATION ONLY, NOT A CONTROL INPUT.** `app/control.py`,
|
||||||
|
`allocator.py`, `arbiter.py`, `peakguard.py` and the watchdogs are not in this
|
||||||
|
release's diff; the runtime files that move are `app/pv.py`, `app/main.py`,
|
||||||
|
`app/mqtt.py`, `config.yaml` and `translations/`. `tools/tel11_pv_trace.py`,
|
||||||
|
extended for this card, hashes the controller's decisions on 0.11.0 and on this
|
||||||
|
tree: the control document is **`846a10a5b89e…` with PV unset and with one
|
||||||
|
entity, on both trees** - the same hash TEL-11 recorded - and with a
|
||||||
|
three-entity roster it equals each grid world's unset document, including every
|
||||||
|
cell where one inverter is dead. Neither the total nor any partial total reaches
|
||||||
|
a decision. With PV unset or with one entity, the **telemetry** is byte-identical
|
||||||
|
to 0.11.0's as well.
|
||||||
|
|
||||||
|
Contents of this release, in merge order since 0.11.0 (`cccb2fa`):
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| `f863eca` | TEL-12 - several PV inverters, and one absent member is an absent TOTAL **⚠️ NEW OPTIONAL OPTION, EMPTY ON EVERY EXISTING INSTALL** |
|
||||||
|
|
||||||
|
### TEL-12 — `pv_entities`: the PV channel for a roof with several inverters
|
||||||
|
|
||||||
|
**WHAT TO DO ON A SITE WITH MORE THAN ONE PV INVERTER.** List every inverter's
|
||||||
|
power sensor under `pv_entities`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
pv_entities:
|
||||||
|
- sensor.pv_east_power
|
||||||
|
- sensor.pv_west_power
|
||||||
|
- sensor.pv_garage_power
|
||||||
|
```
|
||||||
|
|
||||||
|
`sensor.goodwe_pv_power` then carries the **site total**. Each entity's own
|
||||||
|
`unit_of_measurement` is read, so a kW inverter beside a W one sums correctly;
|
||||||
|
a sensor with no unit or a non-power unit is refused by name on the status
|
||||||
|
page, as in 0.11.0.
|
||||||
|
|
||||||
|
⚠️ **`pv_entities` REPLACES `pv_entity` - IT DOES NOT ADD TO IT.** When the list
|
||||||
|
is set, `pv_entity` is not read at all. **If you are upgrading from 0.11.0 with
|
||||||
|
`pv_entity` already set, the inverter it names must also be in the list**, or it
|
||||||
|
drops out of the total. Put it in the list and it is **counted once**, not
|
||||||
|
twice - that is why the rule is replacement: under a union, the natural action
|
||||||
|
(put all your inverters in the new field) would double-count the one the old
|
||||||
|
key already names. While both keys are set the status page shows a caution
|
||||||
|
saying which one won - *"`pv_entities` is set, so `pv_entity` is IGNORED - the N
|
||||||
|
entities in the list are what is summed. Clear `pv_entity` to remove this
|
||||||
|
caution"*. It is a caution, never a refusal to start and never a NOT READY row.
|
||||||
|
A repeated id inside the list is also counted once.
|
||||||
|
|
||||||
|
⚠️ **IF ANY CONFIGURED PV ENTITY IS ABSENT, THE PUBLISHED TOTAL IS `unknown` -
|
||||||
|
NOT THE SUM OF THE ONES THAT ANSWERED.** Three inverters configured and one
|
||||||
|
`unavailable`: `sensor.goodwe_pv_power` goes to `unknown` and the recorder
|
||||||
|
stores a **gap**. The sum of the other two would be a smaller number
|
||||||
|
indistinguishable from a real one, and a week later it would read as *"there
|
||||||
|
was less sun than there was"* - the conclusion this channel exists to test
|
||||||
|
rather than to manufacture. **A gap in the history, never an understated
|
||||||
|
number.** The status page, read live, still gives you the diagnostic: `PV —`
|
||||||
|
plus a caution that says there is **no site total**, names the missing entity
|
||||||
|
and its reason, and lists what the others reported. An inverter honestly
|
||||||
|
reporting **0 W** is summed, not treated as absent - shading and nightfall are
|
||||||
|
real zeros.
|
||||||
|
|
||||||
|
| what happened | `sensor.goodwe_pv_power` | the status page |
|
||||||
|
|---|---|---|
|
||||||
|
| neither key set | the entity does not exist | no row |
|
||||||
|
| all three answer, 1200 W + 2.1 kW + 450 W | `3750.0` | `PV 3 750 W` |
|
||||||
|
| all three answer, one of them `0 W` | the sum of the two others | the sum |
|
||||||
|
| one (or more) `unavailable` / missing / bad unit | `unknown` - a recorder gap | `PV —` + a caution naming what is missing |
|
||||||
|
|
||||||
|
⚠️ **THE FIX FOR A MISSING INVERTER IS NOT A TEMPLATE SENSOR THAT SUMS THEM.**
|
||||||
|
You can still point `pv_entity` at one if you prefer, but a template sensor
|
||||||
|
summing an `unavailable` source yields the partial total silently - the same
|
||||||
|
defect one layer down, where this add-on cannot see it or report it.
|
||||||
|
|
||||||
|
**WHY A SECOND KEY, RATHER THAN MAKING `pv_entity` A LIST.** Because an 0.11.0
|
||||||
|
install that has `pv_entity` set would not start. Measured against Supervisor
|
||||||
|
**2026.08.0** by `tools/supervisor_shape_probe.py` §G: with `pv_entity` declared
|
||||||
|
as a list, the string an 0.11.0 install has persisted is refused -
|
||||||
|
`Invalid list for option 'pv_entity'` - and a shipped `[]` default does not
|
||||||
|
rescue it, because the Supervisor's merge keeps your stored string. The one
|
||||||
|
single-key spelling that accepts both shapes, `match(.*)?`, validates nothing
|
||||||
|
(it accepts the integer `417`) and renders as a plain text box, so you could not
|
||||||
|
add a second inverter in the UI. So `pv_entity` stays a string, and the same
|
||||||
|
probe shows an 0.11.0 options blob - `pv_entity` set, no `pv_entities` key at
|
||||||
|
all - validating against this version untouched. ⚠️ **Rolling back to 0.11.0 is
|
||||||
|
also safe**: a schema without `pv_entities` drops the key with a warning and
|
||||||
|
leaves `pv_entity` standing.
|
||||||
|
|
||||||
|
**Why it matters now:** [[OPT-10]] needs a week of PV history to attribute the
|
||||||
|
surplus that left the reference site while the pack had room, and that site has
|
||||||
|
several PV inverters. The week starts when the site total is recorded.
|
||||||
|
|
||||||
|
**Full account: `DECISIONS/TEL-12-several-pv-inverters.md`, with the operator's
|
||||||
|
version under "Several PV inverters" in `DOCS.md`.**
|
||||||
|
|
||||||
|
### If you are crossing from a version older than 0.10.0
|
||||||
|
|
||||||
|
⚠️ **THIS SECTION IS NOT THE ONE THAT CAN REFUSE YOU - `## 0.10.0` BELOW IS.**
|
||||||
|
Updating installs 0.12.0 in one step, so every validator rule added in
|
||||||
|
0.8.0, 0.9.0 and 0.10.0 arrives at the same moment. Two of them can refuse a
|
||||||
|
config nobody has edited: [[SAFETY-39]]'s **rule 10** (added in 0.8.0) against
|
||||||
|
0.7.0's shipped default `slew_w: 1000` - the ceiling is **555.6 W** on a 5000 W
|
||||||
|
rail - and [[TARIFF-07]]'s three withdrawn `price_provider` ids,
|
||||||
|
**`engie_dynamic`, `totalenergies_dynamic` and `eneco_eddy`**, each still
|
||||||
|
refused by name at startup on 0.12.0. Neither is new here, and a site already on
|
||||||
|
0.10.0 or later has already met both. **The full account of both, including
|
||||||
|
what to set instead of each withdrawn id, is in `## 0.10.0`**, which withdrew
|
||||||
|
them and is not superseded by this section.
|
||||||
|
|
||||||
|
`tools/predeploy_check.py` checks your live options against this version's
|
||||||
|
validator before you press *Update*, and on this tree reports a real version
|
||||||
|
change from 0.11.0. ⚠️ **Pass it the bare options dict - the `data.options`
|
||||||
|
object - NOT the whole `ha apps info --raw-json` document.** Handed the wrapped
|
||||||
|
export it currently prints CLEARED while having checked nothing ([[SAFETY-60]],
|
||||||
|
open). Extract the options first, e.g. `jq '.data.options'`.
|
||||||
|
|
||||||
## 0.11.0
|
## 0.11.0
|
||||||
|
|
||||||
**A MINOR BUMP, AND ONE NEW OPTION IS THE WHOLE REASON FOR THE SECOND DIGIT:
|
**A MINOR BUMP, AND ONE NEW OPTION IS THE WHOLE REASON FOR THE SECOND DIGIT:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: GoodWe RS485 Controller
|
name: GoodWe RS485 Controller
|
||||||
version: "0.11.0"
|
version: "0.12.0"
|
||||||
slug: goodwe_controller
|
slug: goodwe_controller
|
||||||
description: >-
|
description: >-
|
||||||
Drives a GoodWe ES/BP battery inverter over RS485 by emulating its smart
|
Drives a GoodWe ES/BP battery inverter over RS485 by emulating its smart
|
||||||
|
|||||||
Reference in New Issue
Block a user