Repository navigation
fix(octopus): keep the dispatch rate on an elapsed half hour until Octopus lists it as completed (#5520) - #5533
Merged
Conversation
…h ran in until it is listed as completed (#5520) A planned Octopus Intelligent dispatch only covers what is still to come: the Octopus API component advances the start of a running one to now, and an ended one is dropped, while Octopus lists it as completed 15 to 60 minutes later. In between the half hour went back to the day rate, and as today's cost is priced from the current rates the day's cost stepped up after each half hour of car charging and fell back when the completed dispatch arrived. Each cycle, after the slot confirmation check, remember the half hour a started planned dispatch is running in unless the car was cancelled in it, and put it back into the slots as a finished dispatch until a completed dispatch overlaps it or OCTOPUS_DISPATCH_HOLD_MINUTES (90) have passed. A dispatch still to start is never held. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Ended stale planned entries can be incorrectly recorded as genuine dispatches, creating phantom cheap half-hours.
1 open finding
What changed in this PR
This PR preserves Octopus Intelligent dispatch rates while awaiting completed-dispatch confirmation.
Changes:
- Tracks eligible running dispatch half-hours for 90 minutes.
- Integrates held slots into rate calculation without forcing replans.
- Adds regression tests and documentation.
| File | Description |
|---|---|
apps/predbat/const.py |
Defines the 90-minute hold period. |
apps/predbat/predbat.py |
Initializes dispatch-hold state. |
apps/predbat/octopus.py |
Implements held-dispatch tracking and pricing. |
apps/predbat/fetch.py |
Integrates held slots into fetch cycles. |
apps/predbat/tests/test_octopus_dispatch_hold.py |
Tests dispatch-hold scenarios. |
apps/predbat/unit_test.py |
Registers the new tests. |
docs/car-charging.md |
Documents temporary rate retention. |
tools/debug-journal.md |
Adds troubleshooting guidance. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…on the exact clock (#5520) A planned entry still listed after its end passed the running check while its half hour was current, so one first seen after it ended was held without ever being seen running - and dispatch_billed_off_peak() takes an ended entry as finished, so an AWAY one became a phantom cheap half hour. Require the exact clock to be before the dispatch end as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sed-dispatch-5520
chalfontchubby
added a commit
that referenced
this pull request
Oct 15, 2026
…-planned-slots-5339 Conflicts: - apps/predbat/fetch.py (fetch_sensor_data_cars): main (#5520/#5533) now collects the planned dispatches a car uses into planned_used, inserts the held half hours from octopus_held_dispatches() ahead of them and records them in octopus_slots_planned for octopus_held_update(). This branch filtered the planned dispatches through smart_control_off_slots() while Smart Control is off. Combined: the filtered list (planned_kept) is what the plugged-in check gates, so the held dispatches, octopus_slots and octopus_slots_planned all see only the dispatches Predbat still uses. A re-tagged charger-schedule slot is not billed off-peak, so it is never held; a half hour already held from before Smart Control went off stays held until the completed list has it, as Octopus billed it off-peak. - apps/predbat/octopus.py (imports): keep both OCTOPUS_MANUAL_DISPATCH_SOURCES (this branch) and OCTOPUS_DISPATCH_HOLD_MINUTES (main). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

Fixes #5520.
Problem
A planned Octopus Intelligent dispatch only covers what is still to come. The Octopus API component advances the start of a running dispatch to now (
trim_started_dispatch()), and an ended one is dropped, while Octopus lists it incompletedDispatches15 to 60 minutes later. Since #4114 a planned dispatch is deliberately not promoted to completed, so in between nothing covers the half hour: it goes back to the day rate, and becausetoday_cost()prices every elapsed minute from the current rate table,cost_todaysteps up after each half hour of car charging and falls back when the completed dispatch arrives.Fix
Each cycle, after the slot confirmation check (
dynamic_load_car_check()), Predbat records the half hour a planned dispatch is running in. Once no planned dispatch covers that half hour any more, it goes back intooctopus_slotsas a finished dispatch, so it keeps the dispatch rate.octopus_intelligent_dynamic) has not cancelled the car. A car cancelled after it was seen charging in that half hour is still recorded, as Octopus bills that half hour whole (Partial charge from intelligent dispatch didn't treat full 30-min slot as cheap for home battery #5316).OCTOPUS_DISPATCH_HOLD_MINUTES(90), when it reverts to the day rate as now.heldand left out ofoctopus_slots_signature(), so they do not force a replan.This is done on the Predbat side (
octopus_held_update()/octopus_held_dispatches()inoctopus.py, called fromfetch.py) rather than in the Octopus API component, because that is where the cancel decision lives. It therefore also covers the Home Assistant Octopus Energy integration and Ohme sources.Points for review
Testing
octopus_dispatch_hold(11 scenarios: the report's rolling start, completed taking over, a zero-energy completed, expiry, cancelled, cancelled after charging, mid-half-hour end, not-yet-started, ineligible sources, compare runs, midnight, slot confirmation off)../run_all --quickand pre-commit pass.fetch_sensor_data()itself, and no real debug dump was replayed.Also adds a note to
docs/car-charging.mdand a row totools/debug-journal.md.🤖 Generated with Claude Code