Skip to content

Web plan 'History' tab: Load kWh column reads 0 from ~6am onward (self-heals the next day) #4418

Description

@chalfontchubby

Summary

The web plan tab's "History" button (data-view="yesterday", web.py:2465) shows Load kWh = 0 for a chunk of "today so far" starting around a fixed early-morning time, for the rest of the day - self-healing the next day once that day becomes a complete "yesterday" in the following day's History view.

Root cause

calculate_yesterday() (output.py:2858) builds yesterday_load_step/yesterday_pv_step via step_data_history() at output.py:2873, while self.forecast_minutes is still the live plan's normal forecast horizon.

step_data_history()'s internal loop (fetch.py:118) only populates dictionary keys from 0 up to self.forecast_minutes + plan_interval_minutes - it has no visibility into how far forward it'll later be asked to read.

But the History view needs a full "yesterday" (1440 minutes) plus "today so far" up to the current moment - i.e. offsets up to end_record + self.minutes_now = 1440 + minutes_now (the second publish_html_plan() call at output.py:3151). Whenever minutes_now > forecast_minutes - 1440, the required offset range exceeds what yesterday_load_step actually contains. Every offset past forecast_minutes is simply missing from the dict, and publish_html_plan()'s accumulation (load_forecast += load_minutes_step.get(offset, 0.0), output.py:1112) silently defaults to 0.0 for the rest of the day.

The widening fix for this is in the code, but applied far too late - self.forecast_minutes only gets set to end_record + minutes_now at output.py:3150, right before the second publish_html_plan() call, well after yesterday_load_step/yesterday_pv_step were already built too small at line 2873.

Evidence

Reproduced against a real debug.yaml capture (forecast_plan_hours: 30, forecast_minutes: 1800, minutes_now: 910 i.e. 15:10 local time):

  • yesterday_load_step.get(1800)0.0046 (real value, present)
  • yesterday_load_step.get(1860) onward → missing from the dict entirely

Offset 1800 (relative to the faked "yesterday midnight" anchor used inside calculate_yesterday()) corresponds to 06:00 the next day. This matches the reported symptom precisely: Load kWh reads 0 in the History view from ~6:00-6:30am onward, every day, self-healing the next day once that day is no longer "today" - a complete 24h "yesterday" only ever needs 1440 minutes of data, comfortably inside an 1800-minute range; it only breaks while trying to reach all the way to "now" on the same day.

Why this likely affects most installations, not just an edge-case config

The documented default for forecast_plan_hours is 24h (1440 minutes) - docs/customisation.md: "The default of 24 hours is the recommended value." At the default, the shortfall threshold is 1440 - 1440 = 0 hours, meaning this would trigger for essentially any time of day past midnight, for anyone on the default setting. A longer forecast_plan_hours (e.g. 48h) pushes the threshold later in the day but doesn't eliminate it unless forecast_plan_hours >= 48.

Suggested fix direction

Widen self.forecast_minutes to at least end_record + self.minutes_now before building yesterday_load_step/yesterday_pv_step at output.py:2873, rather than only right before the second publish_html_plan() call at line 3150. Worth double-checking nothing else in calculate_yesterday() between those two points implicitly depends on forecast_minutes staying at its original/live value in the meantime (e.g. the charge-window trimming at line 2910 explicitly checks c["start"] < 24*60, independent of forecast_minutes, so looks unaffected, but worth a careful pass).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions