Repository navigation
E.ON Next Drive Smart bills the whole planned dispatch window off-peak, but Predbat prices it at day rate unless the car charges #5521
Description
Summary
On E.ON Next Drive Smart (Kraken, built-in Octopus API / Kraken component), E.ON appears to bill every half hour in which a smart-charging planned dispatch was in force at the off-peak rate, whether or not the car drew any power. Predbat only keeps the off-peak rate for elapsed time that completedDispatches confirms, and since #5229 / #5248 it also strips the rate from a dispatch when the car is seen not charging. Both follow Octopus Intelligent Go's billing. On E.ON they make Predbat price cheap energy at the day rate.
The effect on one account: cost_today_import overstated the supplier's own figure by about £19.75 over nine days, and by £5.05 on the worst day. The plan is affected too, because Predbat treats periods the supplier bills at 6.57p as 27.7p.
Evidence is from one account over 13 days, using E.ON's estimated half-hourly costs rather than a bill. It needs confirming on another E.ON account before the rule is treated as settled.
Evidence
Tariff E-TOU-NEXT_DRIVE_SMART_V7_1-B: 6.571p from 00:00 to 06:00, 27.70p otherwise. myenergi Zappi under E.ON smart charging.
E.ON's Kraken measurements query (half-hourly, metaData.statistics[].costInclTax.estimatedAmount) gives a cost per half hour. Dividing by the energy gives exactly 6.571p or 27.70p, so each half hour can be classed as billed cheap or billed at day rate.
Billed cheap matches the planned dispatch, not the car
| Day | What Predbat logged | What E.ON billed |
|---|---|---|
| 1 Oct | One planned dispatch open for almost the whole day from 09:00. No completed dispatch ever listed for the day. House load 0.6 to 1.4 kW in the evening, so the car was not charging. | 25.3 kWh at 6.571p outside 00:00–06:00, including all of 19:00–24:00 (17.8 kWh). Only 0.38 kWh at 27.70p. |
| 3 Oct | Planned dispatches 17:00–18:00, then none until 19:30, then 19:30 onwards. | 18:00–19:30 billed at 27.70p (1.65 kWh). The half hours either side billed at 6.571p. |
| 6 Oct | Planned dispatch 18:00–06:00 present at 18:20, gone by 18:25 ("no charging is planned"). | 18:00–18:30 billed at 6.571p. 18:30–19:30 billed at 27.70p. |
Daily import cost, E.ON's figure against Predbat's final cost_today_import (pence)
| Day | E.ON | Predbat | Engine behaviour |
|---|---|---|---|
| 28 Sep | 497.7 | 677.6 | before #5229 |
| 29 Sep | 338.2 | 705.3 | |
| 30 Sep | 285.0 | 643.0 | |
| 1 Oct | 220.7 | 725.7 | |
| 2 Oct | 259.4 | 401.6 | |
| 3 Oct | 259.1 | 353.0 | "car 0 is in a dispatch but not charging, cancelling its slots" first logged |
| 4 Oct | 316.6 | 510.5 | |
| 5 Oct | 286.8 | 361.6 | |
| 6 Oct | 355.9 | 416.2 |
Metered energy agrees (1 Oct: 32.36 kWh at the meter, 31.9 kWh in import_energy_h0), so the gap is rate, not energy.
Why Predbat gets it wrong here
- Elapsed time. A running planned dispatch has its start trimmed to now (
trim_started_dispatch()), and in-progress dispatches are not promoted to completed (Octopus Intelligent: in-progress flexPlannedDispatches promoted to completed creates phantom cheap slots when EV unplugged #4114). An elapsed half hour only keeps the off-peak rate ifcompletedDispatcheslists it. E.ON'scompletedDispatchesonly lists half hours in which the charger delivered energy, but E.ON bills the rest of the window cheap as well. Octopus API: a just-finished half hour of a running Intelligent dispatch is re-priced at day rate until completedDispatches lists it #5520 covers the delay before a completed dispatch arrives; this is the case where it never arrives and the half hour was still cheap. - Future time.
dynamic_load_car_check()/dynamic_load_car_strip_from()remove the off-peak rate from a dispatch while the car is in it and not charging. That is right for Octopus, which bills per half hour on the car actually charging. On E.ON it marks billed-cheap time as day rate, so the plan avoids importing in it.
Suggested direction
Make the billing rule depend on the supplier rather than assuming Octopus's:
- For
kraken_provider: eon, record each half hour in which a planned dispatch was observed in force, and price elapsed minutes from that record. This is the short-lived record suggested in Octopus API: a just-finished half hour of a running Intelligent dispatch is re-priced at day rate until completedDispatches lists it #5520, without the "car was charging" condition and without the timeout. - For the same provider, do not strip the off-peak rate when the car is not charging.
- Keep Octopus's behaviour unchanged. IOG future planned dispatches treated as cheap home rate before EV charging earns the slot #4516 and Octopus Intelligent: in-progress flexPlannedDispatches promoted to completed creates phantom cheap slots when EV unplugged #4114 show why planned dispatches cannot be trusted there.
Open questions a maintainer may know the answer to:
- Is this E.ON's intended rule or an artefact of the Drive Smart beta? The estimate could be revised before billing.
- Does EDF's Kraken tariff behave like E.ON or like Octopus?
- Would turning
octopus_intelligent_dynamicoff be a safe interim workaround for E.ON users? It would address point 2 only. Not tested.
Related
- Octopus API: a just-finished half hour of a running Intelligent dispatch is re-priced at day rate until completedDispatches lists it #5520: just-finished half hour re-priced until
completedDispatcheslists it. - feat(dynamic-load): cancel a car's slots and IOG cheap rate while it is not charging, with an option to distrust Intelligent slots until seen charging #5229 / feat(octopus): octopus_intelligent_dynamic - confirm Intelligent slots only well inside a dispatch #5248: cancel a car's slots and cheap rate when it is in a slot and not charging.
- IOG future planned dispatches treated as cheap home rate before EV charging earns the slot #4516, Octopus Intelligent: in-progress flexPlannedDispatches promoted to completed creates phantom cheap slots when EV unplugged #4114: planned dispatches treated as firm on Octopus.
Activity
springfall2008 commentedon Oct 12, 2026
🤖 Automated first-pass triage — a maintainer will review before any action is taken.
Classification: bug. Predbat applies Octopus Intelligent Go's billing rule to E.ON Next Drive Smart dispatches: it prices a dispatch half hour at the day rate unless the car is seen charging in it or the supplier's completed feed lists it, while on your evidence (Kraken
measurementshalf-hourly estimates, one account over 13 days) E.ON bills every half hour a planned dispatch was in force at the off-peak rate — socost_today_importoverstates the supplier's own figure and the plan avoids hours E.ON would bill at 6.571p. Priority: low (the Kraken component with a SmartFlex EV device is still a small population, there is a partial workaround for the future-side half, and the supplier-side rule itself is unconfirmed beyond this account — your open question. A maintainer may raise it if the rule is confirmed as intended and uptake grows.)Verified in the code (main at 40b9ce2, just past v9.3.8 — the mechanisms you cite are all merged and live; the report states no Predbat version, but #5229/#5248, #5319 are on main):
No provider distinction. The Kraken component wires its SmartFlex dispatches into Predbat through the Octopus path —
kraken.py:1363publishesoctopus_intelligent_slot"exactly like Octopus IOG" sofetch.pyconsumes it identically — andkraken_provider(edf/eon,kraken.py:271-274) only selects the API base URL. The sharedrate_add_io_slots()/dispatch_billed_off_peak()machinery therefore applies Octopus's rule to E.ON. This is the root cause.Elapsed side (your point 1). An in-progress dispatch's start is advanced to
noweach cycle (trim_started_dispatch(),octopus.py:2763), so elapsed half hours are covered by neither the planned nor the completed list until the completed feed lists them (Octopus API: a just-finished half hour of a running Intelligent dispatch is re-priced at day rate until completedDispatches lists it #5520's mechanism); a finished dispatch withkwh <= 0is dropped outright (octopus.py:3965, "a zero-kWh past dispatch is treated as never having happened"); and the ended-dispatch exemption (octopus.py:3445-3446,dispatch_billed_off_peak()→end_minutes <= self.minutes_now) revives minutes only when the feed lists them.today_cost()(output.py:2017) then prices every elapsed minute from the live tariff table. On E.ON, if the car never charges in the window (1 Oct) or the dispatch is withdrawn mid-window (6 Oct), those half hours never get it back. Whether E.ON'scompletedDispatchestruly omits zero-energy half hours is your account-side observation — the code side confirms Predbat would honour a listed one.Future side (your point 2).
dynamic_load_car_check()cancels a car's slots when it is "is in a dispatch but not charging, cancelling its slots" (plan.py:836) anddynamic_load_car_strip_from()(plan.py:572-577) feedsrate_add_io_slots()(octopus.py:3988— skips minutes ≥ strip_from) anddynamic_load_car_strip_feed_rates()(octopus.py:4173— overwrites feed-delivered discounts back torate_max_base). All Octopus-rule decisions, applied to E.ON.Your open questions:
octopus_intelligent_dynamicOff as interim workaround — verified for point 2: plan.py:872 gates the whole cancel/strip mechanism on that switch, so Off disables the not-charging cancellation and restores pre-feat(dynamic-load): cancel a car's slots and IOG cheap rate while it is not charging, with an option to distrust Intelligent slots until seen charging #5229 trust in future dispatches, which matches E.ON's rule (and it does not touch point 1). One interplay to know about:octopus_intelligent_trust_slotsOff as well gets warned as "no effect" (plan.py:773-777), so leave trust_slots at its default. Whether it is safe is a maintainer call — it forgoes the feat(dynamic-load): cancel a car's slots and IOG cheap rate while it is not charging, with an option to distrust Intelligent slots until seen charging #5229-style planning benefit Octopus users get.On the suggested direction — consistent with the #4114 constraint (Octopus pricing unchanged; provider-dependent record is pricing-only), and the gate already exists:
kraken_provideris in the shared arg store (kraken.pyuses the sameget_arg/set_argas Predbat), soself.get_arg("kraken_provider")can branch without new config. One extra thing a fix should settle: the daily cheap-slot cap keys on "IOG-SMB" only (has_six_hour_cap(),octopus.py:1881-1885), so an E.ON daily/rolling cheap-window cap is currently unmodelled — if E.ON imposes one, the provider-dependent rule needs an answer for it too (1 Oct shows 25.3 kWh cheap outside 00:00–06:00 with no cap visible in the data).Related, none a duplicate:
No files needed from you — the Predbat-side behaviour is fully code-verified above, and the supplier-side claim rests on your Kraken
measurementsexport, which no Predbat file would settle.