Release 0.15.0 #173

Merged
admin merged 2 commits from release-0.15.0 into release/1.0 2026-10-05 01:52:41 +02:00
Owner

Cuts 0.15.0: config.yaml version 0.14.0 -> 0.15.0 and a closed ## 0.15.0 CHANGELOG section. No code change.

Version: 0.15.0 (minor). Behaviour change from SAFETY-94 + SAFETY-97 (#171), at one inverter and at two. Same rule as 0.14.0 (new behaviour, no option change = minor).

Option diff vs 0.14.0 (02ed120): none. config.yaml differs only in version (83 options, 83 schema keys). app/validate.py and translations/ are unchanged, so there are no new start-up refusals. The only new persisted state is one store key per battery, unit/<name>/idle_w (learned, not an option).

Checks run locally (offline, goodwe-addon-checks:1, --network none, nothing live touched):

  • test_version_gate.py (part 11 included), test_docs.py, test_defaults_pin.py, test_validate.py, test_tool_inputs.py: all pass.
  • tools/predeploy_check.py --deployed-version 0.14.0 --options scratch/STAGE5/settings-v4.json (bare options, the current live options incl. the two-inverter roster): REFUSED (no-op: 3 runtime commits behind an unchanged version) before the bump, CLEARED after it ("live options pass this version's validator"). The deploy step re-exports fresh options and runs it again.

Deviations from docs/RELEASE.md (same as the 0.13.0 and 0.14.0 cuts)

  1. Step 1 says "bump version: on release/1.0". release/1.0 is protected, so the bump goes through this PR (branch release-0.15.0).
  2. RELEASE.md says nothing about the CHANGELOG. The section is written to the CI gate (test_version_gate.py part 11): heading = config.yaml version, exactly one "in merge order since" table, the three withdrawn price_provider ids named.
  3. RELEASE.md says nothing about tags. No tag made; v0.15.0 is left to the manager.
  4. RELEASE.md does not ask for predeploy_check.py at cut time. It was run anyway, offline only.

What the deploy needs (separate owner go)

Same pinned-branch flow as 0.13.0 / 0.14.0, after this PR is merged into release/1.0:

  1. Create a deploy-0.15.0 branch at the release merge commit and open a PR deploy-0.15.0 -> master. No push to master.
  2. Wait for checks / unit (pull_request) to be green (a skipped is not green).
  3. Merge it, pinning head_commit_id, only after the owner's go. A merge to master is a deployment.
  4. Before the update, export fresh live data.options and run predeploy_check.py with the deployed version read from the box.
  5. ha store reload && ha addons update 68285ac7_goodwe_controller on the live HA (not local_goodwe_controller as RELEASE.md step 5 says). Needs the owner's go, which lifts the standing "no ha addons update" rule.
  6. Watchdog stays on (SAFETY-61).
  7. After the update each battery learns its rest reading after about two quiet minutes and saves it (unit/<name>/idle_w); until then the old 0 W centre applies.
  8. Rollback: revert on release/1.0, bump again, take the same path (RELEASE.md §3).

CHANGELOG section (verbatim)

0.15.0

A minor bump: changed behaviour, and no option changes. No option was
added, removed or renamed, and no default changed (83 options). Options that
start 0.14.0 also start 0.15.0. The changes below apply with one inverter and
with two.

The add-on now learns and saves, per battery, what its power reading shows
at rest (unit/<name>/idle_w). It learns it after about two quiet minutes and
uses 0 W until then, as before. There is nothing to set.

Contents of this release, in merge order since 0.14.0 (02ed120):

cf705a9 No more false "battery power reading stopped changing" errors at a new command after a rest, or at a change of phase. Each one paused control for a few seconds (several a day on a live site). A healthy battery that lags or turns around is no longer held as refusing for up to 15 min. With two inverters, a refusing battery whose reading at rest is about −100 W is now caught too. The rest value used is limited to ±75 W (SAFETY-94, SAFETY-97, also fixes SAFETY-58)
3129dae CI tests against a newer admin/goodwe (CI only) (CI-14)

Known issues

  • A false "Battery is not keeping up" can still show when the peak guard pauses a maintenance charge (SAFETY-92).
  • After a gap in the P1 meter, the peak guard is blind for the rest of that quarter hour (SAFETY-90).
  • A battery capped at a low limit with a perfectly flat reading can still trip the stale check (SAFETY-74).
  • A battery whose reading at rest is beyond about ±170 W is still not caught when it refuses, as in 0.14.0 (SAFETY-97).
  • Two inverters: if one battery's drain stops early (e.g. switched Off), the other battery can jump to about 1.6 kW at once, and the surplus goes to the grid (SAFETY-95).
  • Two inverters: after one battery's link drops, control can stall until a safety stop (SAFETY-96).
  • Two inverters: the maintenance charge can switch on and off while the house is above the peak aim (SAFETY-88).
  • Two inverters: the "circulating" figure counts a battery's reading at rest (SAFETY-98).

If you are crossing from a version older than 0.10.0

## 0.10.0 below can refuse an old config: slew_w above its limit, and the
withdrawn price_provider ids engie_dynamic, totalenergies_dynamic and
eneco_eddy. Read it before you update. Run tools/predeploy_check.py with the
bare options (jq '.data.options') first.

🤖 Generated with Claude Code

https://claude.ai/code/session_019DBUfvndgHwaV339Fvd2gr

Cuts **0.15.0**: `config.yaml` `version` 0.14.0 -> 0.15.0 and a closed `## 0.15.0` CHANGELOG section. No code change. **Version: 0.15.0 (minor).** Behaviour change from SAFETY-94 + SAFETY-97 (#171), at one inverter and at two. Same rule as 0.14.0 (new behaviour, no option change = minor). **Option diff vs 0.14.0 (`02ed120`): none.** `config.yaml` differs only in `version` (83 options, 83 schema keys). `app/validate.py` and `translations/` are unchanged, so there are no new start-up refusals. The only new persisted state is one store key per battery, `unit/<name>/idle_w` (learned, not an option). **Checks run locally (offline, `goodwe-addon-checks:1`, `--network none`, nothing live touched):** - `test_version_gate.py` (part 11 included), `test_docs.py`, `test_defaults_pin.py`, `test_validate.py`, `test_tool_inputs.py`: all pass. - `tools/predeploy_check.py --deployed-version 0.14.0 --options scratch/STAGE5/settings-v4.json` (bare options, the current live options incl. the two-inverter roster): **REFUSED** (no-op: 3 runtime commits behind an unchanged version) before the bump, **CLEARED** after it ("live options pass this version's validator"). The deploy step re-exports fresh options and runs it again. ## Deviations from docs/RELEASE.md (same as the 0.13.0 and 0.14.0 cuts) 1. Step 1 says "bump `version:` on `release/1.0`". `release/1.0` is protected, so the bump goes through this PR (branch `release-0.15.0`). 2. RELEASE.md says nothing about the CHANGELOG. The section is written to the CI gate (`test_version_gate.py` part 11): heading = config.yaml version, exactly one "in merge order since" table, the three withdrawn `price_provider` ids named. 3. RELEASE.md says nothing about tags. No tag made; `v0.15.0` is left to the manager. 4. RELEASE.md does not ask for `predeploy_check.py` at cut time. It was run anyway, offline only. ## What the deploy needs (separate owner go) Same pinned-branch flow as 0.13.0 / 0.14.0, after this PR is merged into `release/1.0`: 1. Create a `deploy-0.15.0` branch at the release merge commit and open a PR `deploy-0.15.0` -> `master`. No push to `master`. 2. Wait for `checks / unit (pull_request)` to be **green** (a `skipped` is not green). 3. Merge it, pinning `head_commit_id`, only after the owner's go. A merge to `master` is a deployment. 4. Before the update, export fresh live `data.options` and run `predeploy_check.py` with the deployed version read from the box. 5. `ha store reload && ha addons update 68285ac7_goodwe_controller` on the live HA (not `local_goodwe_controller` as RELEASE.md step 5 says). Needs the owner's go, which lifts the standing "no `ha addons update`" rule. 6. Watchdog stays on (SAFETY-61). 7. After the update each battery learns its rest reading after about two quiet minutes and saves it (`unit/<name>/idle_w`); until then the old 0 W centre applies. 8. Rollback: revert on `release/1.0`, bump again, take the same path (RELEASE.md §3). ## CHANGELOG section (verbatim) ## 0.15.0 **A minor bump: changed behaviour, and no option changes.** No option was added, removed or renamed, and no default changed (83 options). Options that start 0.14.0 also start 0.15.0. The changes below apply with one inverter and with two. The add-on now learns and saves, per battery, what its power reading shows at rest (`unit/<name>/idle_w`). It learns it after about two quiet minutes and uses 0 W until then, as before. There is nothing to set. Contents of this release, in merge order since 0.14.0 (`02ed120`): | | | |---|---| | `cf705a9` | No more false "battery power reading stopped changing" errors at a new command after a rest, or at a change of phase. Each one paused control for a few seconds (several a day on a live site). A healthy battery that lags or turns around is no longer held as refusing for up to 15 min. With two inverters, a refusing battery whose reading at rest is about −100 W is now caught too. The rest value used is limited to ±75 W ([[SAFETY-94]], [[SAFETY-97]], also fixes [[SAFETY-58]]) | | `3129dae` | CI tests against a newer `admin/goodwe` (CI only) ([[CI-14]]) | ### Known issues - A false "Battery is not keeping up" can still show when the peak guard pauses a maintenance charge ([[SAFETY-92]]). - After a gap in the P1 meter, the peak guard is blind for the rest of that quarter hour ([[SAFETY-90]]). - A battery capped at a low limit with a perfectly flat reading can still trip the stale check ([[SAFETY-74]]). - A battery whose reading at rest is beyond about ±170 W is still not caught when it refuses, as in 0.14.0 ([[SAFETY-97]]). - Two inverters: if one battery's drain stops early (e.g. switched Off), the other battery can jump to about 1.6 kW at once, and the surplus goes to the grid ([[SAFETY-95]]). - Two inverters: after one battery's link drops, control can stall until a safety stop ([[SAFETY-96]]). - Two inverters: the maintenance charge can switch on and off while the house is above the peak aim ([[SAFETY-88]]). - Two inverters: the "circulating" figure counts a battery's reading at rest ([[SAFETY-98]]). ### If you are crossing from a version older than 0.10.0 `## 0.10.0` below can refuse an old config: `slew_w` above its limit, and the withdrawn `price_provider` ids `engie_dynamic`, `totalenergies_dynamic` and `eneco_eddy`. Read it before you update. Run `tools/predeploy_check.py` with the bare options (`jq '.data.options'`) first. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019DBUfvndgHwaV339Fvd2gr
admin added 1 commit 2026-10-05 00:48:25 +02:00
Release 0.15.0: bump version and close the CHANGELOG section
checks / unit (pull_request) Successful in 29m1s
infra-pin / fresh (pull_request) Successful in 1s
f01152b113
config.yaml version 0.14.0 -> 0.15.0 (minor: behaviour change from
SAFETY-94/97, no option change). New `## 0.15.0` section with the contents
since 0.14.0 (cf705a9 #171, 3129dae #172) and the known issues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

Review round 1 (REL-0.15.0), head f01152b.

Checked and fine:

  • Minor bump is right. 02ed120 → 3129dae → f01152b: config.yaml differs only in version; app/validate.py and translations/ unchanged; no option default changed in code (the compute() change adds keyword args, not options). 83 options.
  • Contents table = exactly the two first-parent merges since 02ed120 (cf705a9 #171, 3129dae #172).
  • "up to 15 min" (PROBE_EVERY_S = 900), "about −100 W" (B −95 to −118 W), "limited to ±75 W" (IDLE_MAX_W) match the code and DECISIONS.
  • "apply with one inverter and with two": true. The stale gate (freshness._oblige) is per inverter at every roster size, and _gave_nothing plus the idle centre are used at N=1 too.
  • Known issues: SAFETY-94 is gone (fixed), SAFETY-74 (not fixed, per DECISIONS) and SAFETY-98 (review T2: B's idle counted as circulating) are added. The rest are carried over.

Findings (I push the fixes myself):

  • F1. "Each one held a battery at 0 W for about 17 s (about 4 a day)" is not true. A stale trip makes the reading a missing input: control holds its last command for stale_input_s (15 s) and goes to 0 W only after that. It clears at the next register change. The 4 live trips of 10-03 all cleared within about 1–10 s (HA history in scratch/SAFETY-94/live-history-*.json: B's command went 268 → 479 W through its 15:39:16Z trip, and B's reading changed at 15:39:21Z). Nothing went to 0 W. 17 s is RELEASE_S, which plays no part here. Also, 10-04 had 4 more trips between 08:45 and 09:45, so "about 4 a day" is low. Fix: "Each one paused control for a few seconds (several a day on a live site)."
  • F2. "a battery that refuses is still caught, now also with two inverters" reads as if no refusal was caught with two inverters before. A refusing A was caught at N=2. Only a battery whose rest reading is about −100 W was never caught at N=2 (and at N=1, 0.14.0 caught it in 17–105 s). Fix: "With two inverters, a refusing battery whose reading at rest is about −100 W is now caught too." Also add to the paragraph above the table that it learns after about two quiet minutes and uses 0 W until then. The owner will see this right after the update.
  • F3 (manager request). Add a known issue. DECISIONS/SAFETY-97 "Cost": "A battery whose idle reading is beyond about ±170 W ... behaves as in 0.14.0 (not caught by this rule)" (75 W clamp + 100 W band). Line: "A battery whose reading at rest is beyond about ±170 W is still not caught when it refuses, as in 0.14.0 (SAFETY-97)."
**Review round 1 (REL-0.15.0), head f01152b.** Checked and fine: - Minor bump is right. 02ed120 → 3129dae → f01152b: `config.yaml` differs only in `version`; `app/validate.py` and `translations/` unchanged; no option default changed in code (the `compute()` change adds keyword args, not options). 83 options. - Contents table = exactly the two first-parent merges since 02ed120 (`cf705a9` #171, `3129dae` #172). - "up to 15 min" (`PROBE_EVERY_S = 900`), "about −100 W" (B −95 to −118 W), "limited to ±75 W" (`IDLE_MAX_W`) match the code and DECISIONS. - "apply with one inverter and with two": true. The stale gate (`freshness._oblige`) is per inverter at every roster size, and `_gave_nothing` plus the idle centre are used at N=1 too. - Known issues: SAFETY-94 is gone (fixed), SAFETY-74 (not fixed, per DECISIONS) and SAFETY-98 (review T2: B's idle counted as circulating) are added. The rest are carried over. Findings (I push the fixes myself): - **F1. "Each one held a battery at 0 W for about 17 s (about 4 a day)" is not true.** A stale trip makes the reading a missing input: control holds its last command for `stale_input_s` (15 s) and goes to 0 W only after that. It clears at the next register change. The 4 live trips of 10-03 all cleared within about 1–10 s (HA history in `scratch/SAFETY-94/live-history-*.json`: B's command went 268 → 479 W through its 15:39:16Z trip, and B's reading changed at 15:39:21Z). Nothing went to 0 W. 17 s is `RELEASE_S`, which plays no part here. Also, 10-04 had 4 more trips between 08:45 and 09:45, so "about 4 a day" is low. Fix: "Each one paused control for a few seconds (several a day on a live site)." - **F2. "a battery that refuses is still caught, now also with two inverters" reads as if no refusal was caught with two inverters before.** A refusing A was caught at N=2. Only a battery whose rest reading is about −100 W was never caught at N=2 (and at N=1, 0.14.0 caught it in 17–105 s). Fix: "With two inverters, a refusing battery whose reading at rest is about −100 W is now caught too." Also add to the paragraph above the table that it learns after about two quiet minutes and uses 0 W until then. The owner will see this right after the update. - **F3 (manager request). Add a known issue.** DECISIONS/SAFETY-97 "Cost": "A battery whose idle reading is beyond about ±170 W ... behaves as in 0.14.0 (not caught by this rule)" (75 W clamp + 100 W band). Line: "A battery whose reading at rest is beyond about ±170 W is still not caught when it refuses, as in 0.14.0 ([[SAFETY-97]])."
admin added 1 commit 2026-10-05 01:23:05 +02:00
Release 0.15.0: correct the SAFETY-94/97 row, add the ±170 W known issue
checks / unit (pull_request) Successful in 29m6s
infra-pin / fresh (pull_request) Successful in 1s
8c6e5bca2e
Review round 1 (F1-F3) on PR #173.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

Round 1 fixes pushed: 8c6e5bc (CHANGELOG only; PR body's verbatim section updated to match).

  • F1 fixed: "errors ... Each one paused control for a few seconds (several a day on a live site)."
  • F2 fixed: "With two inverters, a refusing battery whose reading at rest is about −100 W is now caught too." The paragraph above the table now says it learns after about two quiet minutes and uses 0 W until then.
  • F3 fixed: known issue "A battery whose reading at rest is beyond about ±170 W is still not caught when it refuses, as in 0.14.0 (SAFETY-97)."

Offline in goodwe-addon-checks:1 (--network none): test_version_gate, test_docs, test_defaults_pin, test_validate, test_tool_inputs all pass. Waiting for checks / unit (pull_request) on 8c6e5bc.

**Round 1 fixes pushed: 8c6e5bc** (CHANGELOG only; PR body's verbatim section updated to match). - F1 fixed: "errors ... Each one paused control for a few seconds (several a day on a live site)." - F2 fixed: "With two inverters, a refusing battery whose reading at rest is about −100 W is now caught too." The paragraph above the table now says it learns after about two quiet minutes and uses 0 W until then. - F3 fixed: known issue "A battery whose reading at rest is beyond about ±170 W is still not caught when it refuses, as in 0.14.0 ([[SAFETY-97]])." Offline in `goodwe-addon-checks:1` (`--network none`): test_version_gate, test_docs, test_defaults_pin, test_validate, test_tool_inputs all pass. Waiting for `checks / unit (pull_request)` on 8c6e5bc.
admin merged commit 3ed3302d2f into release/1.0 2026-10-05 01:52:41 +02:00
Author
Owner

Merged as 3ed3302 into release/1.0, pinned head_commit_id = 8c6e5bc (checks / unit (pull_request) success, run 1174). The merged tree is identical to the PR head. No tag, nothing on master, nothing deployed.

**Merged** as 3ed3302 into `release/1.0`, pinned `head_commit_id` = 8c6e5bc (`checks / unit (pull_request)` success, run 1174). The merged tree is identical to the PR head. No tag, nothing on `master`, nothing deployed.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/goodwe-addon#173