fix(home-assistant): EPEX/Spotty consumer price broken by epex_spot 4.x rename + add future-price chart #217
Labels
No labels
bug
enhancement
in-progress
needs-info
needs-triage
p0
ready-for-agent
ready-for-human
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/nixos#217
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Home Assistant (host
fw,hasscontainer) shows a constant, wrong consumer electricity price. Root cause: theepex_spotcustom component was updated to 4.x, which renamed its sensors (price→market_price,net_price→total_price) and switched units (ct/kWh → €/kWh). The template inhosts/fw/modules/home-assistant/electricity.nixstill references the now-orphanedsensor.epex_spot_data_price(permanentlyunavailable):Two defects, really: the dead entity reference and the original formula never applied 20% VAT (so it read ~20% low even when it worked). Note the
epex_spotcomponent itself loads fine — the aggregate sensors (average/median/lowest/highest/rank/quantile) work; only the current-intervalprice/net_priceentities are orphaned.Rebuild the price sensor declaratively in Nix (design option C) sourced from
sensor.epex_spot_data_market_price, applying the full Spotty + grid + tax fee model incl. VAT, and exposing aforecastattribute so a future-price ApexCharts chart can render (option X: card installed in Nix, chart placed via the UI).Fee model (from the June 2026 Spotty invoice — reconciles to the cent)
Marginal consumer price =
(market_price + fees_net) × 1.20, withfees_netin net €/kWh:Model as named
letconstants, one per line, each commented with its invoice line + effective date (so the 2027 Abgabe revert is a one-line edit). Fixed monthly costs (Grundgebühr, Messpreis, Netzleistung, Pauschalen) are excluded — this sensor is marginal €/kWh, which is exactly what a "when is it cheap" chart wants.Historical anchor: the old hardcoded
0.1039was ~ the correct net offset (0.1010) — the original bug was forgetting× 1.20.Plan
electricity.nix: replace the legacyplatform: templatesensor with a moderntemplate:/sensor:sensor (also removes the HA 2026.6 legacy-template-entity breakage thedefault.nixpin is deliberately holding below). Keep the entity idsensor.electricity_priceso nothing downstream breaks.state=(market_price + fees_net) × 1.20.forecastattribute =market_price'sdatalist mapped to[{start, price: (market + fees_net) × 1.20}, ...]. Exclude this attribute from the recorder (DB bloat: up to ~192 entries at 15-min × 2 days).pkgs.home-assistant-custom-lovelace-modules.apexcharts-cardtoservices.home-assistant.customLovelaceModules(nixpkgs ships it; auto-registers as a Lovelace resource). Pattern mirrorsac.nix+custom-components/lovelace-scheduler.nix.sensor.electricity_price'sforecast, today + tomorrow (tomorrow appears after ~14:00), cheap→expensive coloring, "now" marker, optional raw-spot overlay to show the tax wedge. Placed on a dashboard via the UI (dashboards are storage-mode). Capture the YAML in the PR for reproducibility.origin/main-> pre-commit dry-buildsfw->tea pr create-> merge -> bento pulls (~5 min) and HA restarts.Acceptance criteria
sensor.electricity_pricetracks live(market_price + fees) × 1.20, updates each interval, no longer constant.template:syntax (not legacyplatform: template).letconstants matching the invoice; 20% VAT applied.sensor.electricity_priceexposes aforecastattribute:{start, price}consumer prices for all known future intervals (today + tomorrow), excluded from the recorder.apexcharts-cardinstalled declaratively viacustomLovelaceModules.forecastattribute; card YAML recorded in the PR.sensor.epex_spot_data_price/sensor.epex_spot_data_net_priceentities deleted (cosmetic).fwpre-commit dry-build green; verified on the running instance.Open question (acceptance-blocker for the forecast mapping)
The exact localized price-key inside
sensor.epex_spot_data_market_price'sdataentries — it isself._localized.attr_name_per_kwhin the 4.x source, not literallyprice. Read it (and confirm hourly vs 15-min resolution) from Developer Tools -> States. TheforecastJinja mapping can't be finalized until this key is known. Once provided, this issue isready-for-agent.References
hosts/fw/modules/home-assistant/electricity.nixhosts/fw/modules/home-assistant/ac.nix(customLovelaceModules)price->market_price,net_price->total_price, ct/kWh -> €/kWh)Blocked by
None — can start immediately (modulo the forecast-key lookup above).
Agent Brief
Category: bug
Summary: Rebuild
sensor.electricity_priceon the epex_spot 4.x entities with the full Spotty fee model incl. 20% VAT, expose a consumer-priceforecastattribute, and install apexcharts-card declaratively.Current behavior (reproduced live during triage):
The fw Home Assistant instance (hass container) defines
sensor.electricity_priceas a legacyplatform: templatesensor readingsensor.epex_spot_data_price— an entity orphaned by the epex_spot 4.x rename. Deployed component version is 4.1.0 (nixpkgs 26.05); HA itself is 2026.5.4 via the dedicated pin. The container journal shows a recurring error on every render:Note this corrects the issue body: on HA 2026.5,
| floatwithout a default raises, so the entity goes stale/unavailable rather than reading a constant 0.1039. Additionally the old formula never applied 20% VAT. The epex_spot integration itself loads fine; its aggregate sensors work.Resolved during triage (was the open question):
Read from the deployed 4.1.0 source in fw's nix store:
sensor.epex_spot_data_market_price'sdataattribute is the literal stringprice_per_kwh(EUR mapping →ATTR_PRICE_PER_KWH).dataentry is{"start_time": <local ISO8601>, "end_time": <local ISO8601>, "price_per_kwh": <float, €/kWh>}. The sensor also exposes a top-levelprice_per_kwhequal to its state..storage). Non-blocking: write the forecast mapping and chartdata_generatorto iterate entries generically usingstart_time, so either resolution works. Confirm actual resolution after deploy.Desired behavior:
sensor.electricity_price(keep this entity id — downstream consumers depend on it) is a moderntemplate:-style sensor: state = (sensor.epex_spot_data_market_price+ fees_net) × 1.20, unit €/kWh, updating each market interval.forecastattribute: thedatalist mapped to[{start, price}]where price = (price_per_kwh+ fees_net) × 1.20, covering all known future intervals. This attribute is excluded from the recorder (DB bloat).apexcharts-cardis installed declaratively viaservices.home-assistant.customLovelaceModules(nixpkgs attrhome-assistant-custom-lovelace-modules.apexcharts-card, verified present in 26.05 at v2.2.3). Pattern: same as the existing lovelace-scheduler module install.forecastattribute, today + tomorrow, now-marker) is authored and captured in the PR description for the human to paste into the storage-mode dashboard.Key interfaces:
services.home-assistant.configin the fw hass container config — replace the legacysensor = [{platform = "template"; ...}]block with moderntemplatesyntax; this also removes one blocker for the HA 2026.6 pin bump tracked separately.sensor.epex_spot_data_market_price(source),sensor.electricity_price(must survive unchanged).recorder.excludeconfig or template attribute exclusion — whichever HA 2026.5 supports for attributes.journalctl -D /var/lib/nixos-containers/hass/var/log/journalon fw.Acceptance criteria:
sensor.electricity_pricestate = (market_price + fees_net) × 1.20, updates each interval; the recurringTemplateErrorfor this entity no longer appears in the hass container journal after HA restarts post-deploy.template:syntax; no legacyplatform: templatesensor remains in the electricity module.forecastattribute exposes{start, price}consumer prices for all future intervals present in the sourcedataattribute, and is excluded from the recorder.customLovelaceModules; card YAML included in the PR.Out of scope (human follow-ups after merge):
sensor.epex_spot_data_price/sensor.epex_spot_data_net_priceregistry entries (UI cosmetic cleanup).