Skip to content

10%, 90%, and Calibrated PV values are out by a factor of 2 when using open-meteo #3806

@DFEvans

Description

@DFEvans

Describe the bug
My 10%, 90%, and CL PV values are coming out a factor of 2x too low compared to the forecast since converting to open-meteo.

Predbat is suggesting reasonable scaling factors in the logs:

 PV Calibration: Worst day scaling factor 0.85, best day scaling factor 1.25 average day scaling factor 0.99 max historical power 14.76 max future predicted power 12.23

But when it applies them, the 0.99 average scaling factor x 73.04 kWh is somehow giving 33.6 kWh calibrated:

PV Forecast for today is 73.04 (28.53 10%, 41.87 90%, 33.6 calibrated) kWh, and PV left today is 0.0 (0.0 10%, 0.0 90%, 0.0 calibrated) kWh

Expected behaviour
The values are comparable to the forecast if the scaling factors are ~= 1

Predbat version

v8.37.0

Environment details

Standard HAOS setup

Debug thoughts

This feels like it's a 30 min vs. 60 min forecast slot issue, which is referenced in a lot of the new code.

Adding some debug logging, I can see the issue has been introduced into the 10/90/CL fields added to pv_forecast_data by pv_calibration(). Knowing the adjustment factors are good, I suspect the issue is hiding in this section:

for minute in range(0, max(pv_forecast_minute.keys()) + 1, self.plan_interval_minutes):
pv_value = 0
for offset in range(0, self.plan_interval_minutes, 1):
pv_value += pv_forecast_minute_adjusted.get(minute + offset, 0)
# Force timezone to UTC
pv_estimateCL[minute] = dp4(min(pv_value, capped_data)) # Clamp to max_kwh scaled to 30 minute slots
pv_estimate10[minute] = dp4(min(pv_value * worst_day_scaling, capped_data))
pv_estimate90[minute] = dp4(min(pv_value * best_day_scaling, capped_data))
for entry in pv_forecast_data:
period_start = entry.get("period_start", "")
if period_start:
minutes_since_midnight = (datetime.strptime(period_start, TIME_FORMAT) - self.midnight_utc).total_seconds() / 60
slot = int(minutes_since_midnight / self.plan_interval_minutes) * self.plan_interval_minutes
calibrated = pv_estimateCL.get(slot, None)
calibrated10 = pv_estimate10.get(slot, None)
calibrated90 = pv_estimate90.get(slot, None)
# When we store the data we have to reverse the divide_by factor
if calibrated is not None:
entry["pv_estimateCL"] = calibrated * divide_by
if create_pv10 and (calibrated10 is not None):
entry["pv_estimate10"] = calibrated10 * divide_by
if create_pv10 and (calibrated90 is not None):
entry["pv_estimate90"] = calibrated90 * divide_by

If I'm reading correctly, what happens is:

  • For each slot in the plan (as determined by self.plan_interval_minutes), sum up the solar PV values for 10/90/CL
  • Then, for each slot in the forecast, annotate the pv_forecast_data entries with the 10/90/CL values from forecast slot starting at the same time

This is fine when the plan slots are the default 30 minutes and the forecasts slots are also 30 minutes, but this is not the case for OpenMeteo - the calibrated PV values for the first half of each 60 minute forecast slot are being output as the 10/90/CL values for the entire slot.

Metadata

Metadata

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions