Skip to content

feat(providers): Dynamic Wholesale Tariff retailer wiring (Phase 7 PR-2b)#88

Merged
Artic0din merged 2 commits into
feat/nemweb-fallbackfrom
feat/dwt-provider
May 22, 2026
Merged

feat(providers): Dynamic Wholesale Tariff retailer wiring (Phase 7 PR-2b)#88
Artic0din merged 2 commits into
feat/nemweb-fallbackfrom
feat/dwt-provider

Conversation

@Artic0din

Copy link
Copy Markdown
Owner

Summary

PR-2b — wires Dynamic Wholesale Tariff into PriceHawk's config flow as TWO retailer options (OpenElectricity, AEMO Direct) backed by ONE DynamicWholesaleTariffProvider class. Both implement the existing Provider Protocol in the same slot as Amber/Flow Power/LocalVolts. Closes the "wiring" half of v2 research PR-2 per the 2026-05-20 OE/NEMWeb-as-retailer correction.

  • DynamicWholesaleTariffProvider: self-priced; sync update(); public set_live_price(WholesalePrice) called by the coordinator's async refresh coroutine. 4-minute staleness guard dedups SDK calls against the 5-min dispatch cadence. Negative wholesale prices honoured (exporter pays during curtailment) with sign discipline matching AmberProvider. State persistence honours AEGIS rules (version field + explicit HA-tz date; no date.today() fallback).
  • coordinator.py: DWT branch in __init__ + rebuild_engine. _refresh_dwt_price coroutine hooked into _async_update_data before the per-tick provider loop. ConfigEntryNotReady raised on inconsistent config (DWT marker without enable flag).
  • config_flow.py: async_step_cdr_retailer prepends two synthetic DWT entries + dispatches to new async_step_dwt_credentials / async_step_dwt_aemo_setup steps. WEM is excluded from AEMO Direct (NEMWeb is NEM-only per PR-3); included on the OpenElectricity flavour. API key validated live against the OpenElectricity SDK before entry creation; auth failure surfaces as errors[api_key] = "invalid_api_key".
  • strings.json + translations/en.json kept byte-identical (project translation-parity invariant).
  • 29 new tests covering Protocol isinstance, cost math (positive + negative price), persistence round-trip + version mismatch + missing-today, extras, idempotency, package export, option-builder helpers, source-level routing dispatch + storage writes, and a strings byte-identical guard.

Stacked on PR #87 (NEMWeb). GitHub will auto-retarget the base to dev when PR #86 + PR #87 land.

Test plan

  • pytest --tb=short -q → 868 passed (839 baseline + 29 new)
  • ruff check → clean on every Phase 7 file
  • diff strings.json translations/en.json → byte-identical
  • Manual UAT via Playwright on homeassistant.local:8123:
    • Both DWT entries appear at the top of the retailer picker
    • DWT-AEMO end-to-end with NSW1 + 110 c/day daily supply creates an entry; sensor.pricehawk_* entities update within 5-10 minutes against wholesale rates
    • DWT-OE with invalid key surfaces the "Could not authenticate with OpenElectricity" error and does NOT create an entry
    • Multi-entry verification: second PriceHawk entry on a different region using the PR-1 sentinel still works alongside the new provider

Decisions: D-P7-10, D-P7-11 in DECISIONS.md.

…7 PR-2b)

PR-2b — Dynamic Wholesale Tariff is now a selectable retailer in PriceHawk's
config flow with TWO entries (OpenElectricity, AEMO Direct) backed by ONE
DynamicWholesaleTariffProvider class. Both implement the Provider Protocol
in the same slot as Amber/Flow Power/LocalVolts.

- DynamicWholesaleTariffProvider: self-priced; sync update(); public
  set_live_price(WholesalePrice) called by the coordinator's async refresh
  coroutine. 4-minute staleness guard dedups SDK calls against the 5-min
  dispatch cadence. Negative wholesale prices honoured (exporter pays
  during curtailment). State persistence honours AEGIS rules (version
  field + explicit HA-tz date, no date.today() fallback).
- coordinator.py: DWT branch in __init__ and rebuild_engine.
  _refresh_dwt_price coroutine hooked into _async_update_data before the
  tick loop. ConfigEntryNotReady on inconsistent config (DWT marker
  without enabled flag).
- config_flow.py: async_step_cdr_retailer prepends two synthetic DWT
  entries + dispatches to new dwt_credentials / dwt_aemo_setup steps.
  WEM excluded from AEMO Direct (NEMWeb is NEM-only per PR-3). API key
  validated live against OpenElectricity SDK before entry creation.
- strings.json + translations/en.json kept byte-identical (project
  invariant).
- 29 new tests; 868 total pass.

Decisions: DECISIONS.md > D-P7-10, D-P7-11.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Artic0din Artic0din merged commit 0dd5fcd into feat/nemweb-fallback May 22, 2026
2 of 4 checks passed
@Artic0din Artic0din deleted the feat/dwt-provider branch May 22, 2026 05:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant