Skip to content

Predbat Savings #3894

Description

@markbw999

See #3872 and #3881. I tried to reopen my original issue as I don't believe it is fixed but I don't have permission.

From the release notes it appears 3881 was packaged in v8.38.0 which I have been running for a couple days. My daily savings chart still shows negative values...

Image

Here are the total and daily savings for the last three days. The daily values are still fultuating and (IMHO) shouldn't be negative if the total is steadily increasing...

Image

Debug and log files...

predbat.log
predbat_debug.yaml.txt

Please can you have another look.

Activity

  1. springfall2008 commented on Aug 25, 2026

    @springfall2008
    Owner

    🤖 Automated first-pass triage. A maintainer will review this before any action is taken.

    Classification: bug — Priority: priority_medium

    What I checked

    Version confirmed as v8.38.0 from your predbat_debug.yaml (installed_version: v8.38.0), investigated against current main (v8.53.2-37-g12412a7e). Both attachments were used; nothing further is needed from you.

    #3881 did do its job. Your log shows the baseline is now stable — rate_low no longer drifts, and across the 8 recalculations from 02:09 to 09:05 on 05-09 the baseline is identical every time (metric 59.2p, charge window {0–330} + {1410–…}). The oscillation #3872 was about is gone.

    The value you are still seeing is a separate defect, and it's the one that produces exactly your symptom: total rising, daily negative.

    Root cause 1 — the total and the daily sensor publish two different numbers

    From your debug file, for 05-08:

    attribute value
    saving_real +86.14p
    saving_adjusted −25.66p
    sensor state −25.66

    savings_yesterday_predbat publishes saving_adjusted, but the running total accumulates saving (the unadjusted figure):

    • apps/predbat/output.py:3350 — self.savings_today_predbat = saving ← real
    • apps/predbat/output.py:3388 — sensor state=dp2(saving_adjusted) ← adjusted
    • apps/predbat/predbat.py:1184 — savings_total_predbat += self.savings_today_predbat

    So savings_total_predbat (£740.72 in your dump) is a running sum of the positive real savings, while the daily bar chart shows the adjusted ones. The two series are not the same quantity, which is why the total climbs while the daily bars sit below zero. The savings_yesterday_pvbat pair does not have this mismatch — output.py:3425 and :3458 both use the adjusted value. This is unchanged on current main.

    Root cause 2 — the battery-value adjustment charges the SoC level, not the day's change

    output.py:3129 and :3219 subtract the closing stored-energy value from each side:

    cost_yesterday_adjusted   = cost_yesterday   - battery_value_yesterday
    metric_baseline_adjusted  = metric_baseline  - battery_value_baseline
    saving_adjusted           = metric_baseline_adjusted - cost_yesterday_adjusted   # :3326
    

    For 05-08:

    • Actual: cost −26.94p, closing SoC 2.67 kWh → battery value 19.75p → adjusted −46.69p
    • Baseline: cost +59.20p, closing SoC 17.75 kWh → battery value 131.56p → adjusted −72.35p
    • −72.35 − (−46.69) = −25.66p

    The 2.67 kWh is genuine — Predbat was force-exporting straight through midnight (00:03:19: Exporting now - current SoC 2.666kWh and target 1.52kWh). But both sides were energy-neutral across the day: the baseline started and ended at 17.75 kWh (log: start_soc 17.75kWh, final_soc 17.75kWh), and the real system started 05-08 at ~2.6 kWh (implied by the previous day's battery_value_yesterday of 19p) and ended at 2.67 kWh. Neither consumed any net stored energy, so neither should attract a battery-value correction at all.

    Because the adjustment uses the closing level rather than the change over the day, the constant 15 kWh level difference between the counterfactual battery and the real one is billed as a ~112p penalty every single day, in perpetuity — which is what flips a real +86p saving to −26p. The counterfactual's SoC chains from its own previous close (predbat.py:1186, savings_total_soc), so it stays parked near full forever while a system that profitably exports overnight sits near empty. Any user whose export strategy empties the battery over midnight will see this permanently.

    A day-over-day comparison would need the battery-value term applied as (closing − opening) on each side; today only the closing term exists.

    Secondary observations

    1. savings_total_soc is never clamped to soc_max. Your dump has soc_max: 19.04 kWh (2 × 9.52), but the 05-08 20:35 run started the baseline at 26.54 kWh — 39% above the battery's capacity. It is read straight from the sensor at output.py:3043 with no bound. That inflates the baseline's starting energy and depresses the apparent saving.
    2. Residual once-a-day step. The 05-09 figure was −57p at 00:06 and −56p at 01:09, then settled at −25.66p from 02:09 onward. That single jump is soc_yesterday rolling from the stale 26.54 to 17.75 when the 1am total-increment runs (predbat.py:1183, gated on minutes_now > 60). Small compared to the above, but it does mean the value published in the first ~2 hours after midnight is computed from the wrong starting SoC.

    Test

    Ran calculate_yesterday (the only test module that maps cleanly here) against current main — passes (exit 0). Neither the total-vs-daily consistency nor the level-vs-delta adjustment is covered by it, so a green suite is expected and doesn't contradict the above.

    Related

    Possibly related; not closing this as a duplicate of any of them.

  2. added
    bugSomething isn't working
    BOT_TRIAGEDHas been through the triage bot
    and removed
    BOT_REVIEWTrigger an autotriage
    on Aug 25, 2026
  3. added 2 commits that reference this issue on Sep 11, 2026
  4. chalfontchubby commented on Sep 14, 2026

    @chalfontchubby
    Collaborator

    (Posted by Rik; written by Claude.)

    @springfall2008 Closed #5061 given your answer - the total is correctly real, not adjusted, and I'd left that PR pointed the wrong way.

    The docs were the actual bug: output-data.md described savings_total_predbat as a running total of savings_yesterday_predbat's own state, which it never has been - the sensor's displayed state is the adjusted figure, the total accumulates the real one. Fixed that description separately so it says what's actually true.

    One open question that description-fix doesn't answer: should savings_yesterday_predbat's own displayed state switch from adjusted to real, so the daily bars visibly reconcile with the (real) running total - i.e. non-negative days that add up to the total actually rising, rather than a daily figure that can legitimately dip below zero next to a total that keeps climbing? saving_adjusted would stay available as an attribute either way. That's the original reporter's actual complaint (daily negative, total positive, 'shouldn't the total be the sum'), and it's a call about what the daily sensor is for rather than a bug fix, so I didn't want to make it without you weighing in.

  5. added a commit that references this issue on Sep 14, 2026
  6. chalfontchubby commented on Sep 16, 2026

    @chalfontchubby
    Collaborator

    After going round in circles with patches for a while, the conclusion seems to be this is behaving as intended, but the docs were poor.

    Docs are updated. No intention to actually change the code at this point.

  7. chalfontchubby commented on Sep 16, 2026

    @chalfontchubby
    Collaborator

    We will close this ticket shortly unless you push back

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

AUTOCLOSE_CANDIDATEIf we don't hear back, this issue will be autoclosed in around a week.BOT_TRIAGEDHas been through the triage botbugSomething isn't workingpriority_medium

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions