kraken: add GraphQL applicableStandingCharges fallback for TOU tariff 404s#3834
kraken: add GraphQL applicableStandingCharges fallback for TOU tariff 404s#3834springfall2008 merged 2 commits intomainfrom
Conversation
Agent-Logs-Url: https://github.com/springfall2008/batpred/sessions/2aff49c8-006b-4b06-8ba4-c17dedb66f7f Co-authored-by: springfall2008 <48591903+springfall2008@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a GraphQL fallback path for Kraken standing-charge discovery to handle TOU tariffs (notably E.ON Next) where the public REST /standing-charges/ endpoint returns 404/410, aligning standing-charge handling with the existing applicableRates fallback for unit rates.
Changes:
- Introduces
KRAKEN_STANDING_CHARGES_QUERYandasync_fetch_standing_charges_graphql()to fetch standing charges via GraphQL and convert pence/day → pounds/day. - Updates
async_fetch_standing_charges()to fall back to GraphQL on REST 404/410 (but not transient errors like 429/5xx). - Adds 7 tests covering fallback behavior, guard conditions, and GraphQL parsing.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| apps/predbat/kraken.py | Adds GraphQL query + fetch method for standing charges and wires fallback into REST standing-charge fetch. |
| apps/predbat/tests/test_kraken.py | Adds test coverage for 404/410 fallback, non-fallback cases, and GraphQL standing-charge parsing. |
| # Take the first (most applicable) standing charge entry; value is pence/day inc VAT. | ||
| # Divide by 100 to match the units expected by the caller (pounds/day). | ||
| charge = applicable_charges[0] | ||
| value = charge.get("value") | ||
| if value is None: | ||
| return None | ||
| self.log(f"Kraken: Fetched standing charge via GraphQL applicableStandingCharges for MPAN {mpan}: {value}p/day") | ||
| return float(value) / 100.0 |
There was a problem hiding this comment.
async_fetch_standing_charges_graphql() requests validFrom/validTo but then always returns the first entry in applicableStandingCharges. If multiple standing charge periods are returned within the 3-day window (e.g. a rate change boundary), this can pick an arbitrary/non-current value. Consider selecting the entry that applies to now (validFrom <= now < validTo/None), or at least sorting by validFrom to make the choice deterministic.
| Falls back to GraphQL applicableStandingCharges if the REST endpoint returns a non-200 | ||
| status (e.g. 404 for TOU tariffs on E.ON Next whose product is not in the REST API) | ||
| and self.import_mpan is known. |
There was a problem hiding this comment.
The docstring says the REST call falls back to GraphQL for any non-200 status when import_mpan is known, but the implementation only falls back for permanent 404/410 responses. Please update the docstring to reflect the actual fallback conditions (404/410 only) so callers/operators aren’t misled during transient outages (429/5xx).
| Falls back to GraphQL applicableStandingCharges if the REST endpoint returns a non-200 | |
| status (e.g. 404 for TOU tariffs on E.ON Next whose product is not in the REST API) | |
| and self.import_mpan is known. | |
| Falls back to GraphQL applicableStandingCharges only when the REST endpoint returns | |
| HTTP 404 or 410 (for example, TOU tariffs on E.ON Next whose product is not in the | |
| REST API) and self.import_mpan is known. Other non-200 responses, such as transient | |
| 429/5xx errors, are treated as failures and do not trigger GraphQL fallback. |
|
|
||
| results = data.get("results", []) | ||
| if results: | ||
| # API returns pence/day; fetch.py multiplies by 100 expecting pounds/day |
There was a problem hiding this comment.
This inline comment about unit conversion appears inverted: fetch.py multiplies metric_standing_charge by 100 to convert from pounds/day to pence/day. Here you’re dividing REST/GraphQL pence/day by 100 to return pounds/day, so the comment should describe that fetch.py expects pounds/day (and converts internally) rather than “expects pounds/day” while multiplying.
| # API returns pence/day; fetch.py multiplies by 100 expecting pounds/day | |
| # API returns pence/day; convert to pounds/day here because fetch.py expects pounds/day | |
| # from this source and performs its own internal conversion to pence/day later. |
E.ON Next customers on TOU tariffs (e.g.
E-TOU-NEXT_SMART_SAVER_FIXED_12M_V8-M) get HTTP 404 from both the REST/standard-unit-rates/and/standing-charges/endpoints — the product exists for the customer but isn't exposed via the public REST API.The GraphQL
applicableRatesfallback for unit rates was already in place. This PR adds the symmetric fallback for standing charges.Changes
KRAKEN_STANDING_CHARGES_QUERY— newapplicableStandingChargesGraphQL query constant, parallel toKRAKEN_APPLICABLE_RATES_QUERYasync_fetch_standing_charges_graphql(mpan)— fetches standing charge via GraphQL; returns pounds/day (divides pence/day by 100, consistent with the REST path)async_fetch_standing_charges()— falls back to GraphQL on HTTP 404/410; transient errors (429/500/503) do not trigger the fallback, matching the behaviour ofasync_fetch_rates()async_fetch_standing_charges_graphql()coverageWarning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
api.octopus.energy/home/REDACTED/work/batpred/batpred/coverage/venv/bin/python3 python3 ../apps/predbat/unit_test.py --quick(dns block)gitlab.com/usr/lib/git-core/git-remote-https /usr/lib/git-core/git-remote-https origin REDACTED(dns block)https://api.github.com/repos/springfall2008/batpred/contents/apps/predbat/home/REDACTED/work/batpred/batpred/coverage/venv/bin/python3 python3 ../apps/predbat/unit_test.py --test kraken(http block)/home/REDACTED/work/batpred/batpred/coverage/venv/bin/python3 python3 ../apps/predbat/unit_test.py --quick(http block)/home/REDACTED/work/batpred/batpred/coverage/venv/bin/python3 python3 ../apps/predbat/unit_test.py --test kraken /home/REDACTED/work/batpred/batpred/coverage/venv(http block)If you need me to access, download, or install something from one of these locations, you can either: