Repository navigation
fix(output): savings_today_predbat feeds the total with the same figure the sensor state shows (#3894) - #5061
chalfontchubby wants to merge 3 commits into
Conversation
…re the sensor state shows (#3894) self.savings_today_predbat = saving used the unadjusted (real) figure, but it feeds three things that should all track the same quantity sensor.predbat_savings_yesterday_predbat's own *state* already publishes - saving_adjusted: - savings_total_predbat (predbat.py), the running total sensor - the predbat_savings_today_predbat Prometheus gauge - the metrics dashboard's "Savings Yesterday (PredBat)" tile So the running total accumulated positive real savings while the daily HA chart showed the adjusted (frequently negative) figure - a real, climbing total coexisting with daily bars sitting below zero, exactly the reported symptom. The sibling metric, savings_today_pvbat, already used the adjusted figure correctly (self.savings_today_pvbat = saving_no_pvbat_adjusted, matching its own sensor's state=saving_no_pvbat_adjusted) - this was the one inconsistent case. Scoped to this one root cause. The triage identified a second, larger defect - the battery-value adjustment bills the counterfactual battery's closing SoC *level* against the real one every day in perpetuity, rather than the day's *change* in level, so any export strategy that empties the battery overnight sees a permanent ~100p+/day penalty - plus two secondary issues (savings_total_soc unclamped to soc_max; a one-off wrong-baseline window in the first ~2h after midnight). None of those are addressed here; they need a redesign of the adjustment term rather than a one-line fix and are left for a separate PR. Verified with mutation testing: the new test forces a real saving_real/saving_adjusted divergence (soc_kwh_history set to a closing SoC that differs from the mocked prediction's final SoC, since the default fixture has no adjustment to diverge on) and reproduces the reported shape numerically - savings_today_predbat reads 400.0 (real) against a published 315.0 (adjusted) with the bug reintroduced, matching only with the fix in place. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Address persisted-total migration and align the test’s SoC injection key with production lookup.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
This PR aligns PredBat savings accumulation with the adjusted daily sensor value and adds regression coverage.
Changes:
- Uses
saving_adjustedfor savings totals and metrics. - Adds real-versus-adjusted savings regression coverage.
File summaries
| File | Summary |
|---|---|
apps/predbat/output.py |
Uses adjusted savings for downstream totals and metrics; persisted totals are not migrated. |
apps/predbat/tests/test_calculate_yesterday.py |
Adds regression coverage, but the injected SoC uses a key production does not read. |
Review details
Suppressed comments (1)
apps/predbat/output.py:3497
- This changes the addend for future updates, but the total is persisted across upgrades:
predbat.pyloads the existingsavings_total_predbatand then adds this value without any migration or reset. Users upgrading from the old code will therefore retain a total accumulated from unadjustedsavingand append adjusted values afterward, so the total still does not represent the sum of the published daily states. Please either migrate/rebuild the persisted total (or explicitly start a new total at this definition change) before claiming the quantities are aligned.
self.savings_today_predbat = saving_adjusted
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…pilot review on #5061) calculate_yesterday() reads battery_soc_yesterday from soc_kwh_history at key minutes_now + 1 (output.py: "minutes_back = self.minutes_now + 1"), not minutes_now. The new test keyed its injected closing SoC at minutes_now, so the lookup silently fell through to the 0.0 default instead of the injected 2.0 - the test still passed, but against the divergence that fallback produced against the mock's 5.0 final_soc, not the soc_kwh_history-driven divergence the docstring describes. Confirmed directly: with the wrong key, actual_final_soc published 0.0; with minutes_now + 1, it correctly publishes the injected 2.0. Re-verified the corrected test still fails when the #3894 fix is reverted, now via the intended path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
Address persisted-total migration and restore shared test history safely.
Review details
Suppressed comments (2)
apps/predbat/output.py:3497
- This only changes future increments; it does not repair an existing installation's persisted total.
predbat.py:1196loads the oldsavings_total_predbat, and:1249only adds the new daily value, so a total accumulated under the oldsaving_realsemantics remains mixed with adjusted daily history and can continue showing the reported mismatch after upgrade. Please add a one-time rebaseline/reset or otherwise explicitly handle totals created before this change.
self.savings_today_predbat = saving_adjusted
apps/predbat/tests/test_calculate_yesterday.py:414
- This test runs on the single
my_predbatinstance shared by the test registry (apps/predbat/unit_test.py:818-823), so replacing the history with{}on cleanup can discard history that existed before this test and make later tests order-dependent. Save the pre-testsoc_kwh_historybefore injecting the fixture and restore that object here (preferably from afinallyblock).
my_predbat.soc_kwh_history = {}
- Files reviewed: 2/2 changed files
- Comments generated: 0 new
- Review effort level: Lite
…h_history (Copilot review on #5061) unit_test.py runs every registered test against one shared PredBat instance, but this test's cleanup reset soc_kwh_history to {} unconditionally rather than restoring whatever an earlier test may have left there - the same state-leak pattern already fixed in the #5052 review. Snapshot before mutating, restore what was actually there on cleanup. Verified directly: seeded soc_kwh_history with unrelated data before running the test, confirmed it comes back unchanged afterward. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
(Posted by Rik; written by Claude.) Copilot flagged two further findings that did not surface as inline review comments (GitHub marked them "suppressed" - visible in the review body, not as separate threads). Both real.
Persisted The honest options are a one-time reset (loses the historical figure, but is exact from that point on), leaving it to self-correct gradually as new adjusted daily values dilute the old mixed total, or something in between (e.g. a changelog note telling anyone who cares to reset it by hand). All three are visible, somewhat irreversible changes to a number users see, and I don't think it's my call to make unprompted - flagging for @springfall2008 to decide the shape of, separately from this PR's actual bug fix. |
|
@springfall2008 If the patch makes sense - thn we need to decide what to do about old data |
|
The total savings is meant to be based on real data, if you use adjusted its not a true savings. This however sounds like something to look into "The original triage on this issue identified a second, larger defect: the battery-value adjustment bills the counterfactual battery's closing SoC level against the real one every day in perpetuity, rather than the day's change in level - so any export strategy that empties the battery overnight sees a permanent ~100p+/day penalty. That needs a redesign of the adjustment term (opening->closing delta on both sides), not a one-line fix, and is left for a separate PR. Two secondary issues from the same triage (savings_total_soc never clamped to soc_max; a stale-baseline window in the first ~2h after midnight) are likewise out of scope here." |
springfall2008
left a comment
There was a problem hiding this comment.
Changed the total which isn't desirable, at least not without good reason?
|
Ok - so this PR is the wrong shape - close it? |
|
(Posted by Rik; written by Claude.) Closing this - the premise doesn't hold up. @springfall2008's answer above is that The actual root of #3894 looks like a documentation gap rather than a calculation bug: |
Posted by Claude on behalf of @chalfontchubby.
Fixes #3894.
Problem
self.savings_today_predbat = savingused the unadjusted (real) figure, but it feeds three things that should all track the same quantitysensor.predbat_savings_yesterday_predbat's own state already publishes (saving_adjusted):savings_total_predbat(predbat.py), the running total sensorpredbat_savings_today_predbatPrometheus gaugeSo the running total accumulated positive real savings while the daily HA chart showed the adjusted (frequently negative) figure - a real, climbing total coexisting with daily bars sitting below zero, exactly the reported symptom.
The sibling metric,
savings_today_pvbat, already used the adjusted figure correctly (self.savings_today_pvbat = saving_no_pvbat_adjusted, matching its own sensor'sstate=saving_no_pvbat_adjusted) - this was the one inconsistent case, not a deliberate distinction.Scope
This PR is scoped to that one root cause. The original triage on this issue identified a second, larger defect: the battery-value adjustment bills the counterfactual battery's closing SoC level against the real one every day in perpetuity, rather than the day's change in level - so any export strategy that empties the battery overnight sees a permanent ~100p+/day penalty. That needs a redesign of the adjustment term (opening->closing delta on both sides), not a one-line fix, and is left for a separate PR. Two secondary issues from the same triage (
savings_total_socnever clamped tosoc_max; a stale-baseline window in the first ~2h after midnight) are likewise out of scope here.Verification
The new test forces a real
saving_real/saving_adjusteddivergence (the default fixture has no battery-value adjustment to diverge on, sosoc_kwh_historyis set to a closing SoC that differs from the mocked prediction'sfinal_soc) and reproduces the reported shape numerically:savings_today_predbatreads400.0(real) against a published315.0(adjusted) with the bug reintroduced, matching only with the fix in place. Confirmed with mutation testing - reverting the fix reliably fails the new test with that exact mismatch../run_all --quickgreen (310 tests)./run_pre_commitgreen🤖 Generated with Claude Code