Skip to content

fix: fill full span of mixed-granularity evcc price entries - #406

Merged
MaStr merged 2 commits into
mainfrom
copilot/bugfix-evcc-mixed-granularity-gap
Jul 28, 2026
Merged

fix: fill full span of mixed-granularity evcc price entries#406
MaStr merged 2 commits into
mainfrom
copilot/bugfix-evcc-mixed-granularity-gap

Conversation

@MaStr

@MaStr MaStr commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • evcc's tariff API sometimes mixes granularities: near-term prices are 15-min slots, but prices further out in the horizon can arrive as single hourly-width entries.
  • Evcc._get_prices_native() only wrote the price into the single 15-min index matching the entry's start time, leaving the remaining quarters of an hourly entry missing from the returned dict.
  • core.py._run_once() assumes a contiguous price_dict (for h in range(fc_period + 1): prices[h] = round(price_dict[h], ...)), and that loop is not covered by the surrounding exception handler. Hitting the gap raised an uncaught KeyError, crashing the whole batcontrol daemon (see attached startup.txt traceback that triggered this fix).
  • Fix: use each rate entry's start/end to compute how many 15-min slots it spans, and fill all of them with that entry's price instead of just the first one.

Test plan

  • uv run pytest tests/batcontrol/dynamictariff/test_evcc.py -q — 9 passed, including strengthened test_mixed_granularity_prices which now asserts the previously-missing quarters are filled and there are no gaps in the index range.
  • uv run pytest tests/ -q — full suite, 794 passed.
  • uv run pylint src/batcontrol/dynamictariff/evcc.py — 10.00/10.

🤖 Generated with Claude Code

evcc sometimes returns hourly-width rate entries for prices further out
in the forecast horizon while nearer-term prices are 15-min slots.
_get_prices_native() only wrote the price at the entry's start index,
leaving the remaining 15-min slots of an hourly entry missing from the
returned dict. core.py assumes a contiguous price dict and crashed with
an uncaught KeyError when it hit the gap, taking down the whole process.

Use each rate entry's start/end to fill every 15-min slot it actually
covers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 28, 2026 14:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a crash in the evcc dynamic tariff provider when evcc returns mixed-granularity rate entries (e.g., hourly-width entries alongside 15-minute entries), by filling the full 15-minute span covered by each entry so downstream consumers see a contiguous index sequence.

Changes:

  • Update Evcc._get_prices_native() to use each rate entry’s start/end span and populate all covered 15-minute slots.
  • Strengthen the mixed-granularity unit test to assert that hourly entries fill all four quarter-hour indices and that the produced index range has no gaps.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/batcontrol/dynamictariff/evcc.py Fill all 15-min slots spanned by a rate entry (using start/end) to prevent gaps in the returned price dict.
tests/batcontrol/dynamictariff/test_evcc.py Extend test assertions to verify hourly entries fill all quarters and the resulting index sequence is contiguous.

Comment thread src/batcontrol/dynamictariff/evcc.py Outdated
Address Copilot review feedback on PR #406: round() could undercount
the number of 15-min slots an evcc rate entry covers when its duration
isn't an exact multiple of 900 seconds (timestamp rounding, DST
transitions), silently recreating the gap this fix set out to remove.
Use math.ceil() instead so every touched slot is always filled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 28, 2026 14:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@MaStr
MaStr merged commit 68c901f into main Jul 28, 2026
14 checks passed
@MaStr
MaStr deleted the copilot/bugfix-evcc-mixed-granularity-gap branch July 28, 2026 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants