v0.4.0
HAEO v0.4.0
First stable release of the 0.4 series. This is a major release that introduces the power policy pricing system, dashboard cards for forecasts and network topology, deterministic optimization, and a large internal refactor into a standalone core package.
Caution
Back up your Home Assistant configuration before upgrading. This release includes one-way schema migrations (v1.3/v1.4) that restructure element configuration data. Once migrated, you cannot downgrade back to v0.3.x without restoring a backup.
Recommended steps: Take a full Home Assistant backup, upgrade, then check Settings → Devices & Services → HAEO to verify your elements and the new Policies subentry look correct. Check the Home Assistant log for any migration warnings.
Highlights
- ⚡ Power policies — define per-source pricing rules so the optimizer distinguishes solar export earnings, battery wear costs, and grid tariffs
- 📈 Forecast & topology Lovelace cards — visualize optimization forecasts and your energy network topology directly on your dashboard
- 🎯 Deterministic optimization — calibrated multiobjective solver gives consistent dispatch schedules every run
- 🔋 Sheddable loads & battery salvage value — loads can be curtailed when cost-effective; batteries value stored energy at the horizon end
⚠️ Breaking Changes
Pricing moves to power policies
Battery discharge wear costs, charge incentives, and solar production costs have moved from individual element configuration into the new Power Policy element. Existing configurations are migrated automatically (v1.3/v1.4 migrations), but verify after upgrading:
- Open HAEO settings and confirm the new "Policies" subentry
- Check that migrated rules match your previous pricing
- Battery charge incentive prices are negated during migration — if you used entity-based incentives, check the log for warnings
Connections are now unidirectional
Connections are explicitly directional (source → target). Bidirectional paths use two connection entries. Existing bidirectional connections are migrated automatically; verify import/export paths after upgrading.
Entity unique IDs stabilized
Entity unique IDs are normalized and duplicate section-prefixed entities are cleaned up during migration. Update any automations or dashboards that reference old entity IDs.
Shadow price units changed to $/kWh (#424)
All shadow price sensors are now reported in $/kWh instead of $/kW. Entity IDs are unchanged; dashboards, templates, and automations that assumed the old unit need updating. Shadow prices now share the same unit as import/export tariffs, so no manual conversion is needed to compare them.
User-Facing Changes
New Features
- Power policy element — directional pricing rules with source/target matching and wildcard support (#369)
- HAEO forecast Lovelace card — modular forecast visualization with responsive layout and paired power limits (#352, #411, #412, #414)
- Network topology Lovelace card — interactive SVG graph of elements, connections, limits, efficiency, and policy overlays (#417, #453)
- Sheddable loads — mark loads as curtailable so the optimizer can shed them when cost-effective (#303)
- Battery salvage value — assign a terminal value ($/kWh) to stored energy, discouraging unnecessary end-of-horizon discharge (#302)
- Deterministic optimization — lexicographic, blended, and calibrated solver modes for consistent dispatch every run (#301)
- Nordpool pricing extractor — automatic extraction from Nordpool
raw_today/raw_tomorrowattributes (#367) - Volcast solar forecast extractor — use Volcast
detailedForecastdata as a solar forecast input (#440) - Shadow prices in $/kWh — shadow price sensors use the same unit as tariffs (#424)
- Historic diagnostics walkthrough guide — step through optimization diagnostics over time (#432)
- Last run timestamp — optimization status sensor exposes a
last_runattribute (#381)
Configuration Improvements
- Surfaced policy pricing on element flows — set battery/load pricing directly on element config screens without opening the standalone policy flow (#430, #442)
- Grouped UI sections — config flows organize fields into collapsible sections (#266)
- Automatic currency detection — reads the currency from your price sensor units, falling back to HA config (#368)
- Policy source/target filtering — the policy flow only shows elements that can actually source or sink power (#380)
- Unit-aware entity pickers — config entity selectors filter by unit compatibility and exclude the current hub's own entities (#446)
- Clearer battery partition names — distinct undercharge/overcharge cost and percentage labels (#428)
- Negative price entry — PRICE inputs accept negative energy prices (#415)
- Reactive policy pricing — policy price changes apply without rebuilding the network (#408)
- Tier 4 horizon alignment — half-hour horizons align to the local timezone (#463)
- Refreshed installation and comparison docs — updated installation guide and HAEO vs EMHASS comparison (#459, #464)
Bug Fixes
- Fix optimizer crash when optional efficiency is unset or cleared (#360)
- Fix battery power limits and efficiency segment ordering (#297)
- Fix network period tracking across optimization runs (#295)
- Fix recorder forecast filtering dropping valid entries (#310)
- Fix participant name resolution after Home Assistant restart (#373)
- Fix optimizer re-run race condition on concurrent subentry updates (#375)
- Fix battery charge incentive price sign in migration (#376)
- Change policy compilation from default-deny to default-allow so unpolicied flows pass freely (#379)
- Fix policy config flow UX and endpoint restore issues (#374, #382, #383, #384)
- Fix policy performance regression when policies are enabled (#387)
- Stabilize entity unique IDs across config migrations (#388)
- Fix policy and element value updates not applying (#406)
- Fix forecast card freezes and enforce strict hub scoping (#455)
- Fix intermittent Lovelace custom element registration race (#458)
- Handle policy-pruned connections in element adapters (#449)
- Scale SOC pricing cost by period duration (#439)
- Fix migration duplicate elements (#404)
- Remove null values from horizon sensor attributes (#348)
Developer-Facing Changes
Developer Highlights
- Standalone
corepackage — the model, schema, adapters, data, and context layers were extracted into a Home-Assistant-freecorepackage, enforced by an import linter (#312–#340, #320) - InputStore — a shared input-field layer (editable vs driven modes, time-series loading, readiness) unifies the optimization and surfaced-policy paths (#441)
- Versioned documentation site — published at hass-energy.github.io/haeo (#390)
uv run simrealtime simulator — boots a browsable Home Assistant instance with time-shifted scenario inputs for local development (#444)
Architecture
- Unidirectional connections and functional segment composition (#364)
- Tag infrastructure and VLAN-aware min-cut policy pricing placement (#370, #393, #394, #401)
- Topology visualization pipeline moved from matplotlib/networkx to frontend SVG rendering (#417, #453, #454)
- Config loader routed through the coordinator (#338, #339, #342)
- Snapshot dev tool and stabilized snapshot rounding (#403, #426)
- Stabilized scenario optimization SVG exports (#450)
Schema/API Changes
- v1.3 migration: typed config objects, policy restructuring, and connection split
- v1.4 migration: policy rule
enabled/pricerequirements and charge incentive negation (#376, #385, #399) - Shadow price LP formulation computed in energy-native $/kWh (#424)
- Diagnostic schema versioning (#396, #397)
Testing & Documentation
- Literate guide system with automated screenshot generation (#139, #345, #365)
- Guide test reliability improvements via event-based waiting and trusted-networks auth (#447, #448)
- Diagnostics CLI tool (#260)
- Codecov uploads via OIDC instead of a repository token (#429)
- CI accepts PEP 440
.post/.devrelease tags and gates fork-only deploy jobs (#436)
Contributors
- @TrentHouliston
- @BrendanAnnable
- @purcell-lab 🎉 (first contribution)
What's Changed
- Add grouped UI sections for config flows by @TrentHouliston in #266
- Update Open-Meteo Solar Forecast link in documentation by @purcell-lab in #290
- Remove explicit hass injection by @TrentHouliston in #294
- Reuse the group logic that's shared between elements by @TrentHouliston in #293
- Fix efficiency application order by @BrendanAnnable in #297
- Fix network period tracking by @BrendanAnnable in #295
- Swap to using objects to describe the stored data rather than simple values by @TrentHouliston in #296
- Run an audit on test files to help remove redundancy/bad tests by @TrentHouliston in #300
- Add sheddable loads by @TrentHouliston in #303
- Add battery salvage value and scalar inputs by @TrentHouliston in #302
- Add OptimizationContext by @BrendanAnnable in #291
- Use OptimizationContext for diagnostics by @BrendanAnnable in #305
- Fix input alignment test by @BrendanAnnable in #306
- Normalize SVG clip paths by @BrendanAnnable in #307
- Add diagnostics CLI tool by @BrendanAnnable in #260
- Fix recorder forecast filtering by @BrendanAnnable in #310
- Add core package with state and units by @BrendanAnnable in #312
- Remove ha dt usage by @BrendanAnnable in #313
- Add StateMachine abstraction by @BrendanAnnable in #314
- Extract schema from elements by @BrendanAnnable in #315
- Extract flows from elements by @BrendanAnnable in #316
- Extract adapters from elements by @BrendanAnnable in #317
- Cleanup elements package by @BrendanAnnable in #318
- Add ElementType enum by @BrendanAnnable in #319
- Add import linter by @BrendanAnnable in #320
- Fix adapter unit imports by @BrendanAnnable in #321
- Enrich schema to remove adapter inputs() by @BrendanAnnable in #322
- Move model to core by @BrendanAnnable in #323
- Split sections into core package by @BrendanAnnable in #324
- Move schema to core by @BrendanAnnable in #325
- Move adapters to core by @BrendanAnnable in #326
- Add core const by @BrendanAnnable in #327
- Make core standalone by @BrendanAnnable in #328
- Move data to core by @BrendanAnnable in #329
- Move more element infra to core by @BrendanAnnable in #330
- Make diag tool only use core by @BrendanAnnable in #331
- Move schema consts to core by @BrendanAnnable in #332
- Move migrations to core schema by @BrendanAnnable in #333
- Flatten common sections by @BrendanAnnable in #334
- Align tests with source by @BrendanAnnable in #335
- Colocate tests within packages by @BrendanAnnable in #336
- Update docs by @BrendanAnnable in #337
- Add config loader by @BrendanAnnable in #338
- Use config loader in coordinator by @BrendanAnnable in #339
- Move context to core by @BrendanAnnable in #340
- Improve config loader types by @BrendanAnnable in #342
- Automatically run guides and gather screenshots of the steps by @TrentHouliston in #139
- Literate guide system with automated screenshot generation by @TrentHouliston in #345
- Fix connection segment ordering by @TrentHouliston in #299
- Remove null values from horizon sensor by @BrendanAnnable in #348
- Formalize v0.3.3 migration path validation by @TrentHouliston in #359
- Fix optimizer crash when optional efficiency is unset by @TrentHouliston in #360
- Add Nordpool energy pricing data extractor by @TrentHouliston in #367
- feat: guide tooling infrastructure improvements by @TrentHouliston in #365
- Detect currency symbol from user price sensor data by @TrentHouliston in #368
- refactor: unidirectional connections and functional segment composition by @TrentHouliston in #364
- Add tag infrastructure to model layer by @TrentHouliston in #370
- Add ListFieldHints infrastructure for list-typed config fields by @TrentHouliston in #371
- Fix participant name resolution after config entry deserialisation by @TrentHouliston in #373
- Add power policy element with tagged power flow pricing by @TrentHouliston in #369
- Expose list item sibling fields in input number extra state attributes by @TrentHouliston in #377
- Fix optimizer re-run race condition in async_update_subentry_value by @TrentHouliston in #375
- Negate battery charge incentive price in v1.4 migration by @TrentHouliston in #376
- Policy config flow UX fixes by @TrentHouliston in #374
- Add lexicographic multiobjective optimization with calibrated blending by @TrentHouliston in #301
- Change policy compilation from default-deny to default-allow by @TrentHouliston in #379
- Bump version to 0.4.0b1 by @TrentHouliston in #378
- Add last_run timestamp to optimization status sensor by @TrentHouliston in #381
- Filter policy source/target by element capability by @TrentHouliston in #380
- Fix policy edit defaults and require rule price by @TrentHouliston in #382
- Fix policy endpoint choose restore ordering by @TrentHouliston in #383
- Fix policy endpoint restore value shape in UI by @TrentHouliston in #384
- Require enabled and price on policy rules, backfill in v1.4 by @TrentHouliston in #385
- Fix zip releases by @BrendanAnnable in #386
- Fix policy performance: directed reachability and objective-level calibration by @TrentHouliston in #387
- Stabilize entity unique IDs across config migrations by @TrentHouliston in #388
- Publish versioned documentation site by @TrentHouliston in #390
- Fix policy pricing placement via sink-side minimum s-t cut by @TrentHouliston in #393
- Document min-cut pricing placement and VLAN-to-all-sinks reachability by @TrentHouliston in #394
- Fix diagnostic serialization by @BrendanAnnable in #396
- Update diagnostic schema and add version by @BrendanAnnable in #397
- Migrate legacy early-charge-incentive default through to a real policy by @TrentHouliston in #399
- Absorb VLAN tags at sinks and exclude edges into a VLAN's own source by @TrentHouliston in #401
- Add snapshot dev tool by @BrendanAnnable in #403
- Fix migration duplicate elements by @BrendanAnnable in #404
- Update version to v0.4.0rc2 by @BrendanAnnable in #405
- Add HAEO forecast card with modular JSX rendering by @TrentHouliston in #352
- Fix policy and element value updates not applying by @TrentHouliston in #406
- Bump version to 0.4.0rc3 by @TrentHouliston in #407
- Make policy pricing reactively update without rebuilding network by @TrentHouliston in #408
- Deep copy subentry data and add noqa reasons by @TrentHouliston in #410
- Improve forecast card responsive layout and controls by @TrentHouliston in #411
- Show forecast card paired power limits by @TrentHouliston in #412
- Update release version command by @TrentHouliston in #413
- Render scenario visualizations with the forecast card by @TrentHouliston in #414
- Fix PRICE input bounds so negative energy prices can be entered by @TrentHouliston in #415
- Bump version to 0.4.0rc5 by @TrentHouliston in #416
- Remove DEFAULT_TAG and stabilize snapshot rounding by @TrentHouliston in #426
- Expose shadow prices in $/kWh (closes #423) by @purcell-lab in #424
- Disambiguate undercharge/overcharge partition entity names by @purcell-lab in #428
- Add network topology visualization card by @TrentHouliston in #417
- Add historic diagnostics walkthrough guide by @TrentHouliston in #432
- Surface policy pricing fields on battery and load config flows by @TrentHouliston in #430
- Add Volcast solar forecast extractor by @TrentHouliston in #440
- Apply surfaced policy defaults when frontend omits fields by @TrentHouliston in #442
- Add uv run sim realtime Home Assistant simulator by @TrentHouliston in #444
- Filter config flow entity pickers by unit compatibility by @TrentHouliston in #446
- Use trusted_networks auth for guide tests and sim by @TrentHouliston in #447
- Improve guide test reliability with event-based waiting by @TrentHouliston in #448
- Handle policy-pruned connections in element adapters by @TrentHouliston in #449
- Scale SOC pricing cost by period duration by @TrentHouliston in #439
- Stabilize scenario optimization SVG exports by @TrentHouliston in #450
- Extract InputStore and unify optimization input and surfaced policy paths by @TrentHouliston in #441
- Remove Codecov token from CI workflow by @TrentHouliston in #429
- Add HAEO network topology Lovelace card by @TrentHouliston in #453
- Remove defensive paths from topology card code by @TrentHouliston in #454
- Fix forecast card freezes and enforce strict hub scoping by @TrentHouliston in #455
- Fix intermittent Lovelace custom element registration race by @TrentHouliston in #458
- Update README and HAEO vs EMHASS documentation by @TrentHouliston in #459
- Refresh installation docs and align documentation standards by @TrentHouliston in #464
- Align tier 4 horizons to local timezone in half-hour offsets by @TrentHouliston in #463
- ci: accept PEP 440 .post/.dev release tags, gate fork-only deploy jobs by @purcell-lab in #436
Full Changelog: v0.3.3...v0.4.0