fix(octopus): treat a joined zero-reward session as free electricity - #4852
Conversation
|
Not a duplicate of #4835 / #4837 — same user-visible symptom, different feed, and #4837 does not cover this path. What the events are. Weekday Power Down participation earns a Weekend Happy Hour: Octopus offers several candidate hours at the weekend and the customer books one. All the offered hours appear in the saving-session Why #4837 does not cover it:
On Octopus Direct the free-electricity feed carries nothing for the day ( Observed dropped on at least two consecutive weekends, with a hand-typed manual import rate override as the workaround both times. |
|
How does this code know its a power up and not a power down with zero reward? |
|
It doesn't, and you're right to push on it — the change infers it from the reward being zero, and that inference isn't sound. What I actually have is correlation, not a discriminator. On the account this came from, And the failure mode is bad, not neutral. If a real Power Down did report 0, this change would zero the import rate for it, so Predbat would grid-charge through a session where the user is supposed to be reducing import — paying full price believing it's free, and losing the participation. That's worse than the bug it fixes. It shouldn't merge on an inference. There is an authoritative source already wired up. campaign_slug="octoplus-saving-sessions" # Power Down
campaign_slug="free_electricity" # Power UpNo inference needed — the API says which campaign an event belongs to. The reason it isn't already solving this is that So the correct fix looks like: find the campaign slug Happy Hours are published under, query it alongside the other two, and feed the results into I don't know the slug — I only have the two above, and the inconsistent naming ( Happy to rework this PR that way, or close it if you'd rather fold it into #4548 point 7. Either way I don't think the current version should go in as-is. |
|
Ran pr-cleanup on this PR: CI is green (kernel-binaries, pre-commit) and there are no unaddressed inline review comments — the only outstanding item is the top-level exchange between @springfall2008 and @mgazza above, which already reaches a conclusion. I checked whether the open question in that exchange (is there a way to identify the correct campaign slug for Happy Hour events without guessing) could be resolved from the codebase. That leaves mgazza's assessment as the correct read: the |
Fixes #4851. Octopus publishes Power Up and Power Down through the same savingSessions feed and distinguishes them with `eventType`: TURN_DOWN reduce consumption, rewarded in octopoints WEEKEND_HAPPY_HOUR an earned free import hour, reward 0 TURN_UP increase consumption, rewarded in octopoints Predbat's query never asked for that field, so a booked Weekend Happy Hour arrived indistinguishable from a saving session at 0 p/kWh and was dropped by `saving_rate > 0`. The free hour never reached the plan: the import rate stayed at the standard tariff rate, no charge window was planned, and the only way to use it was to enter it by hand as a manual import rate override. Request `eventType`, carry it through to the joined and available event lists, and route a joined WEEKEND_HAPPY_HOUR into octopus_free_slots at rate 0. Deliberately NOT keyed on the reward value. A zero reward looks like a free hour but a TURN_DOWN reporting 0 - an unknown reward published as 0 rather than null - would then be zeroed on IMPORT, making Predbat grid-charge through a session where the user is meant to be reducing import: full price, believing it free, and the participation lost. eventType is the only sound discriminator. TURN_UP stays on the saving path. It means import more, but it is rewarded in octopoints rather than free, so folding it in here would misprice it. An absent eventType falls through to the existing behaviour rather than guessing, so the BottleCapDave feed and older API responses are unaffected. Tests cover all four: a joined WEEKEND_HAPPY_HOUR becomes a free slot while a rewarded TURN_DOWN in the same joined_events list stays a saving slot, a TURN_DOWN reporting 0 does not become free, TURN_UP does not become free, and a missing eventType does not become free. Reverting to the reward-value test fails two of them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NnzhfR8uDgGUtYLNpDA4ka
62db9c1 to
328bf1b
Compare
|
Answered — and thank you, my original approach was wrong.
{ "id": 4809, "code": "EVENT_41_050826", "rewardPerKwhInOctoPoints": 93, "eventType": "TURN_DOWN", "status": "DONE" }
{ "id": 5144, "code": "EVENT_45_160826", "rewardPerKwhInOctoPoints": 0, "eventType": "WEEKEND_HAPPY_HOUR", "status": "UPCOMING" }with the schema description for the field being "Whether the event is a reduction event (TURN_DOWN) or an increase event (TURN_UP)." Our Reworked (force-pushed, single commit):
Your specific case is now a test: a Four cases covered, and reverting to the reward-value test fails two of them:
One thing I could use a second opinion on: I've left
|
@mgazza The changes made look to match what I understand of what the BCD integration does Answering your last point though, Octopus can and DID auto-join people to a free saving session, the one after the Eclipse power down, people were told what hour they were allocated. The events that were available that they were not allocated to still appeared in available events, the Octopus allocated event appeared in joined events. I'm not sure what the issue is you are suggesting , the Octopus selected joined events appears the same as the user selected power up free hour |
|
@gcoan thank you — that settles it, and it means my worry was unfounded. If Octopus allocates rather than the user booking, the allocated event still lands in I've taken your other point from #4851 and pushed it as a second commit: Weekend Happy Hours are no longer offered in One ordering trap worth flagging for review, because it's invisible in the diff: the reward/code/type lookup maps are built from the same Also fixed the Copilot nits on #4849 (test list numbering, docstring phrasing) and #4850 (log prefix — the new warnings now use |
Fixes #4851.
Problem
Octopus puts Power Up (free electricity) events into the Power Down / saving-session data set at
0p/kWh — the mislabelling described in #4548 point 5. The auto-join side already handles this: #4593/#4595 added a rate guard so Predbat stops trying to join events the integration will reject.Nothing was done on the side that turns those same events into rates. The
joined_eventsloop drops them:0 / 8 == 0.0, so a joined, zero-reward session fails the test and is discarded. The import rate for that period stays at the standard tariff rate and no charge window is planned.So Predbat recognises the event well enough to avoid join-spamming it, then throws it away. Observed on Octopus Intelligent Go via Octopus Energy Direct: the only way to get the free hour into the plan was to type it in by hand —
— which is exactly what the automatic path should have produced. The plan row confirmed the source, showing
import_rate_adjust_type: "manual"against a published tariff rate of 28.56p.The free-electricity feed does not cover for this either: it returned nothing for the day (also #4548 point 5, "Nothing populated in the free electricity/power up event data"), so
load_free_slot()had no current events to apply.Change
Route a joined session reporting exactly
0intooctopus_free_slotsat rate 0 instead of discarding it.Zero reward on a Power Down event means there is nothing to earn by exporting. On a Power Up event it means the opposite of "ignore this" — importing is free.
Two deliberate choices:
== 0, not onoctopus_saving_session_min_octopoints_per_kwh. That threshold exists so a user can decline low-value Power Down sessions; raising it must not also cost them free Power Up hours. The two loops are testing different things on purpose.octopus_saving_session_rateapplies if configured — and is not treated as free.This does not attempt to distinguish Power Up from Power Down by event type (#4548 point 7); that needs the upstream API change described there. It only stops a joined, zero-reward, known-duration session being silently discarded.
Tests
New
test_saving_session_zero_octopoints_joined_is_free_slot(registered inunit_test.py), covering:load_free_slot()zeroes exactly one contiguous hour and leaves every other minute untouched, with the replicate reason markedConfirmed to fail against the unfixed code (
got [],expecting 60 minutes at rate 0, got 0).unit_test.py -k savingand-k octopusboth pass in full.