Repository navigation
Conversation
Read Ostrom's (DE) dynamic tariff from its public API with an OAuth2 client-credentials token (cached until shortly before expiry, renewed once on a 401). The contract is looked up once per run: the single active dynamic contract, or spotprice_ostrom_contract_id. Prices are requested at the contract's postcode so they carry the local taxes, levies and variable grid fees, and the documented per-kWh price (grossKwhPrice + grossKwhTaxAndLevies, VAT included) is used as-is, like Tibber. A reply with no levies at all is rejected. Suppliers now share a generic "supplier" source with its own fetch time, back-off and cache. With spotprice_provider unset, the one supplier whose credentials are set is used; credentials for several suppliers, or half an Ostrom pair, are a single configuration error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Read the active electricity agreement of an Octopus Energy Germany account from its Kraken GraphQL API (api.oeg-kraken.energy). The API key is exchanged for a JWT through obtainKrakenToken(APIKey), cached until shortly before its exp claim, sent without a Bearer prefix and replaced once when Kraken stops accepting it. The account number is looked up from the key unless spotprice_octopus_de_account is set. Rates come from the agreement under properties -> electricityMalos: a dynamic tariff's unitRateForecast slots as published, otherwise the time-of-use timeslots repeated daily in local time, or a fixed unit rate over the window, clipped to the agreement's validity. These are gross unit rates and are used as-is, like Tibber. Every query was checked against the live schema without credentials. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add provider awattar: hourly spot prices for DE-LU and AT from the public aWATTar market data API (api.awattar.de / api.awattar.at, no key), the prices tado Energy's dynamic HOURLY tariff (formerly aWATTar's) is billed on. It falls back to ENTSO-E (with a token) and then Energy-Charts; other zones go straight to the fallbacks. Add spotprice_markup_percent, a percentage of the absolute spot price added before VAT, for any spot provider. It defaults to the published 3% for awattar and to 0 otherwise. The fixed 1.5 ct/kWh and the grid fees stay in spotprice_markup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add provider ews for EWS Schönau's "Ökostrom Dynamisch": quarter-hourly gross prices for today and tomorrow from EWS's dynamic price API (api.ews-schoenau.de/v1/dynamicprices/EWS-OEKO-DYN), authenticated with an X-API-Key header. EWS issues keys on request. The totals are gross cents per kWh with grid fees and levies included and are used as-is, like Tibber. The response shape (today/tomorrow lists of startsAt/total) is only known from third-party use, so a reply whose typical value looks like euros rather than cents is rejected instead of pricing every interval a hundred times too low. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Octopus Energy Germany: - Expand a forecast entry holding several time-of-use rates by its timeslot rules instead of taking the first rate. - Price a dynamic agreement only from its forecast. With no forecast yet, record an error and publish nothing rather than a flat rate. - Require spotprice_octopus_de_malo when active agreements sit on several market locations. Hand over to the next agreement on the location when the current one ends inside the window, and skip revoked agreements. - Expand timeslot rules in Europe/Berlin, not the local timezone. - Clip forecast slots to the agreement's validity. - Retry on KT-CT-1125 (token keys rotated) rather than 1139, per the Kraken error code reference. Ostrom: price ACTIVE contracts only; with none, report an error. Cache: the name carries a digest of the configured Ostrom contract or Octopus account and market location. aWATTar: average quarter-hourly fallback prices to hourly, as the HOURLY tariff bills. Docs: an "Unverified assumptions" note under each supplier. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…licit flat rates Octopus Energy Germany: - Chain agreements one handover at a time: the single non-revoked agreement starting at, or first after, the current end. Two claiming the same start are an error, and overlapping rates are refused rather than published. - Without a forecast, price only an explicit fixed rate (Simple, not a time-of-use product) or a time-of-use rate whose every price has timeslots. Dynamic detection also reads the product's names and contract type, as the schema has no market-linked flag. - Map the repeated autumn hour to its first occurrence and skipped spring times to the jump, so rule boundaries agree. - KT-CT-1139 on a query is an auth error and is not retried. Ostrom: ACTIVE matches in any case. When no contract has a status field at all, the single dynamic contract is used with one warning. aWATTar: average fallback quarter hours to hourly for import only; export keeps the native quarter hours. Cache: cached supplier prices carry the detected contract or account and market location, and are dropped when detection finds another. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Swapping a Tibber token, Ostrom client ID, or Octopus Energy Germany or EWS API key, with no contract or market location set, kept the same cache name. The old account's prices were then restored and counted as fresh for up to six hours. The cache name now carries a salted SHA-256 of the credential and selectors, truncated to 12 hex characters. The credential itself is never written to the name or the stored data. The Kraken JWT stays bare, as the evcc project's Octopus Energy Germany tariff sends it; a test now pins that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…de error The Ostrom contract and postcode were looked up once and kept until a restart, so after a move the old postcode stayed priced. Without spotprice_ostrom_contract_id, the contract is now looked up again once a day, and straight after a 400/404/422 on /spot-prices, retrying once with the new postcode. A changed contract or postcode drops the prices held for the old one. With no active contract left, the usual "no active Ostrom contract" error is raised and nothing is kept for the old address. A configured contract is not re-checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mgazza
force-pushed
the
feat/spotprice-suppliers
branch
from
October 7, 2026 20:47
58da796 to
b3d31d1
Compare
…eat/spotprice-suppliers
This branch has not been deployed
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.
Follow-up to #5340 (stacked on
feat/spotprice-component; retarget tomainonce #5340 merges). Adds German supplier price sources to thespotpricecomponent, so users of these suppliers get their actual prices rather than spot plus an estimated markup.ostromgrossKwhPrice + grossKwhTaxAndLeviesat the contract's postcode); hourlyoctopus_deapi.oeg-kraken.energy)awattarspotprice_markup_percent(default 3%) + markup + VAT, matching the HOURLY tariff. Falls back to ENTSO-E/Energy-Charts, with import averaged to hourly and export kept at native resolutionewsBehaviour
spotprice_octopus_de_malospotprice_provideralways wins. Otherwise exactly one supplier's credentials selects it, and several is a config error.New keys:
spotprice_ostrom_client_id,spotprice_ostrom_client_secret,spotprice_ostrom_contract_id,spotprice_octopus_de_api_key,spotprice_octopus_de_account,spotprice_octopus_de_malo,spotprice_ews_api_key,spotprice_markup_percent.Tests
70 spotprice tests (29 new), fixture-based, registered in the runner and mutation-checked. Live smoke:
No real Ostrom, Octopus DE or EWS accounts were available. Each provider's docs section lists its unverified assumptions.
🤖 Generated with Claude Code