Feed-in tariffs and on-disk response caching - #5
Merged
Conversation
Two features the Planning API now supports, plus the repo's first tests. Feed-in (injection) tariffs --------------------------- api-store injects `with_feed_in` for tokens whose team carries the feature, so energy-core asks the opt-in question on its own — the integration sends nothing to trigger it. What it had to learn is how to render the sub-flow and what to do with the result: - the opt-in renders as a radio list, and question `hint`s are shown under the label (the feed-in questions lean on them); - `feed_in_price` and every other `feed_in*` decoration is carried from the price rows to the entities by prefix rather than an allow-list, so a new country decoration surfaces without a client release; - a `Feed-in Price` sensor is created only for contracts that qualified with an injection tariff. DeFeedIn is the one country sub-flow that does not echo `feed_in` back into the inputs — it resolves the opt-in to an `eeg_rate_id` instead. Since each qualification response replaces the inputs wholesale, the flow remembers the answer and re-stamps it; without that, German users would silently get no injection rates from /planning/prices. Response caching ---------------- /planning/details is kept for 48 hours, /planning/prices until the `next_update` the API returns with it. On disk rather than in memory, because the calls worth saving are the ones a restart repeats: details are fetched on every entry setup and the first price poll fires as the entry loads. Cache entries are keyed on a fingerprint of the qualification inputs, so reconfiguring fetches fresh data. Cached prices whose periods have all ended are ignored even when the deadline holds — a monthly-refreshing offer plus a multi-day outage would otherwise pin the entities to `unknown` until that deadline. Tests ----- 15 tests against real Home Assistant via pytest-homeassistant-custom-component, and a workflow to run them. Note that Home Assistant does not run on Windows (homeassistant.runner imports fcntl) — see requirements-test.txt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UKLvYuWyejP7VAZ2bxJtMt
setup-python's pip cache looks for requirements.txt or pyproject.toml and fails the job before installing anything when it finds neither. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UKLvYuWyejP7VAZ2bxJtMt
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.
Two features the Planning API now supports, plus the repo's first test suite.
Feed-in (injection) tariffs
api-storeinjectswith_feed_infor tokens whose team carries the feature, soenergy-coreasks the opt-in question on its own — the integration sends nothing to trigger it. What it had to learn is how to render the sub-flow and what to do with the result.hints are now shown under the label in the step description — the feed-in questions lean on them to explain what is being asked.Feed-in Pricesensor, created only for contracts that qualified with an injection tariff. State is the rate per kWh; the country-specific extras (grid fees, scheme, band, free-form conditions) become attributes.feed_in_priceis added to each entry of thepricesattribute onPlanned Run, so consumption and injection can be charted from the same series.strings.json,en.jsonandfr.json.Every
feed_in*key is carried from the price rows to the entities by prefix rather than an allow-list. The decorations differ per country (feed_in_extra_text,feed_in_monthly_fee,feed_in_yearly_fee_per_kw,feed_in_scheme,feed_in_band…) and the set grows, so a new country decoration surfaces without a client release.The Germany case
DeFeedInis the one country sub-flow that does not echofeed_inback into the inputs — it resolves the opt-in to aneeg_rate_idinstead. Since each qualification response replaces the inputs wholesale, the answer was being dropped, and/planning/pricesonly decorates the series when it sees the opt-in. German users would have silently got no injection rates. The flow now remembers the answer and re-stamps it, without overriding a value the API did return. Covered bytest_opt_in_is_restamped_when_the_api_drops_it.Response caching
/planning/detailsis kept for 48 hours,/planning/pricesuntil thenext_updatethe API returns with it.On disk (one Home Assistant
Storeper entry) rather than in memory, because the calls worth saving are the ones a restart repeats: details are fetched on every entry setup, and the first price poll fires as the entry loads. In-session pacing already followednext_update; this closes the restart gap..storage/.One guard worth flagging: cached prices are ignored when every period in them has already ended, even if the deadline still holds. A flat-rate offer refreshes monthly, so a multi-day outage can leave an unexpired payload with nothing left to report — serving it would have pinned the entities to
unknownuntil that deadline.Tests
The repo had none. This adds 15, running against real Home Assistant via
pytest-homeassistant-custom-component, and aTestsworkflow on push and PR:pricesattribute in both shapes;Home Assistant does not run on Windows (
homeassistant.runnerimportsfcntl);requirements-test.txtdocuments that and thelru-dictwheel gap.Verified
pytestgreen (15/15) against Home Assistant 2026.2.3, plus a manual run in a real Home Assistant instance where the feed-in question renders as intended.Not covered: a live call against a production token for every country's sub-flow. The payload shapes here were read from
energy-core(FeedInFlow, the*FeedIn/*FeedInPriceclasses,PriceResponse) rather than captured off the wire.🤖 Generated with Claude Code
https://claude.ai/code/session_01UKLvYuWyejP7VAZ2bxJtMt