fix: implement missing "timeseries" PV forecast source dispatch - #271
Merged
Conversation
pv_forecast_source.source: timeseries was accepted by config validation
and configurable in the UI (data_url, data_path, data_token), but
PvInterface.__get_pv_forecast() had no case for it, silently falling
back to the synthetic default triangle forecast instead of fetching
data_url.
Adds __get_pv_forecast_timeseries(), reusing the same standardized
[{start, end, value}] format PriceInterface's timeseries source already
uses, with a PV-appropriate twist: 15-min-to-hourly conversion sums
(not averages, since values are energy-per-slot rather than a rate),
and incomplete data pads with 0 instead of the last known value.
Fetched once globally (not per pv_forecast.N array entry) and aligned
by absolute "start" timestamp to a midnight-anchored slot grid - both
match __get_pv_forecast_evcc_api's existing behaviour, and are required
because get_ems_data() in eos_connect.py indexes pv_forcast_array by
slots-since-midnight-today, not by position.
Tested against a self-hosted forecast service returning real
15-minute-resolution PV data; verified end to end against the running
optimizer (matching totals between the service and EOS_connect's own
computed values).
ohAnd
added a commit
that referenced
this pull request
Jul 13, 2026
Enhance timeseries PV forecast handling to be truly robust: Robustness improvement: - Timestamps now aligned to resolution boundaries before slot lookup - Handles data starting at midnight, "now", or any arbitrary time - Maintains midnight-indexed output for optimizer compatibility - Fixes silent data loss when HA templates generated "now"-aligned slots Original implementation: - HTTP fetch with Bearer token auth, 3-retry mechanism - Auto-detect 15min vs hourly resolution - 15-to-60min conversion via energy summing - Validation at startup (data_url checks, URL format) - Context-aware error messages with recovery status - Diagnostic logging (entry counts, value ranges, failure hints) Test coverage: - 15 parsing tests (format, resolution, alignment) - 8 validation tests (config scenarios, URL validation) - 45 existing PV tests (no regressions) - Full 988-test suite passing Fixes: #270 Related: #271
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
pv_forecast_source.source: timeseries was accepted by config validation and configurable in the UI (data_url, data_path, data_token), but PvInterface.__get_pv_forecast() had no case for it, silently falling back to the synthetic default triangle forecast instead of fetching data_url.
Adds __get_pv_forecast_timeseries(), reusing the same standardized [{start, end, value}] format PriceInterface's timeseries source already uses, with a PV-appropriate twist: 15-min-to-hourly conversion sums (not averages, since values are energy-per-slot rather than a rate), and incomplete data pads with 0 instead of the last known value.
Fetched once globally (not per pv_forecast.N array entry) and aligned by absolute "start" timestamp to a midnight-anchored slot grid - both match __get_pv_forecast_evcc_api's existing behaviour, and are required because get_ems_data() in eos_connect.py indexes pv_forcast_array by slots-since-midnight-today, not by position.
Tested against a self-hosted forecast service returning real 15-minute-resolution PV data; verified end to end against the running optimizer (matching totals between the service and EOS_connect's own computed values).
Fixes #270