Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ PlanDetailV2 data rather than user-entered rates.
- **Universal CDR wizard.** New 4-step flow: state → distributor → retailer
(from the AER registry) → CDR plan. Replaces the bespoke GloBird-only
rate-entry form.
- **117 retailers via EME refdata2** registry (Phase 3.1 prep). Wizard
sources retailer endpoints from `api.energymadeeasy.gov.au/refdata2` with
the baked-in EME snapshot as the offline fallback.
- `RetailerEndpoint.cdr_brand` field carries the CDR-PlanDetail `brand`
discriminator. Disambiguates the 14 brands that share a base URI
(Energy Locals hosts ARCLINE / RAA / Cooperative / Indigo / Sonnen /
iO; OVO hosts MYOB + CTM; Radian hosts iO; Future X hosts Sunswitch).
- `fetch_plan_list` / `fetch_plan_detail` accept optional `brand=`
parameter and append `?brand=<cdrBrand>` so shared-base-URI plans are
correctly disambiguated.
- Baked-in EME refdata2 snapshot at
`custom_components/pricehawk/cdr/data/eme_refdata.json`.
- **8 retailer incentive parsers.** GloBird (ZEROHERO + Super Export + 3-for-Free),
AGL (Solar Savers bonus FIT + Three for Free), Origin (tiered FIT), Alinta
(stepped FiT), EnergyAustralia (Solar Max + PowerResponse VPP), Engie (free
Expand Down Expand Up @@ -90,6 +102,8 @@ PlanDetailV2 data rather than user-entered rates.
are gone.
- Skip-CDR sentinel and "enter rates manually" copy from the retailer + plan
pickers (with manual entry deleted, the affordance dead-ended on itself).
- `cdr/data/cdr_endpoints.json` (legacy jxeeno snapshot) — superseded by
the EME baked-in copy.

### Breaking Changes

Expand Down
30 changes: 22 additions & 8 deletions custom_components/pricehawk/cdr/cdr_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ async def fetch_plan_list(
*,
customer_type: str = "RESIDENTIAL",
fuel_type: str = "ELECTRICITY",
brand: str | None = None,
) -> list[dict[str, Any]]:
"""Fetch all residential-electricity MARKET plans for ``base_url``.

Expand All @@ -69,6 +70,11 @@ async def fetch_plan_list(
Filtering is done client-side because the CDR list endpoint does
not accept ``customerType`` as a query param.

``brand`` is the CDR ``brand`` discriminator for shared base URIs
(e.g. seven brands hosted on ``cdr.energymadeeasy.gov.au/energy-locals/``).
Passed as ``?brand=<brand>`` and harmlessly ignored by single-brand
endpoints.

A 404 at the list endpoint indicates a bad base URL or proxy-path
regression, not a stale plan — surfaces as ``CdrAPIError`` rather
than ``CdrPlanNotFound`` (which is reserved for the detail
Expand All @@ -78,14 +84,15 @@ async def fetch_plan_list(
seen_ids: set[str] = set()
out: list[dict[str, Any]] = []
while True:
params = urllib.parse.urlencode(
{
"type": "ALL",
"fuelType": fuel_type,
"page": page,
"page-size": _LIST_PAGE_SIZE,
}
)
query: dict[str, Any] = {
"type": "ALL",
"fuelType": fuel_type,
"page": page,
"page-size": _LIST_PAGE_SIZE,
}
if brand:
query["brand"] = brand
params = urllib.parse.urlencode(query)
url = f"{base_url.rstrip('/')}/cds-au/v1/energy/plans?{params}"
try:
body = await _get_json(session, url, x_v="1")
Expand Down Expand Up @@ -116,15 +123,22 @@ async def fetch_plan_detail(
session: aiohttp.ClientSession,
base_url: str,
plan_id: str,
*,
brand: str | None = None,
) -> dict[str, Any]:
"""Fetch PlanDetailV2 envelope for ``plan_id``.

Returns the full response body (envelope, ``data`` shape preserved)
so callers can store the raw bytes as a config-entry fixture without
losing audit fields. Raises ``CdrPlanNotFound`` on 404 — that
actually does mean a stale planId at this endpoint.

``brand`` is the CDR brand discriminator for shared base URIs — see
``fetch_plan_list`` docstring. Appended as ``?brand=<brand>`` when set.
"""
url = f"{base_url.rstrip('/')}/cds-au/v1/energy/plans/{plan_id}"
if brand:
url = f"{url}?{urllib.parse.urlencode({'brand': brand})}"
return await _get_json(session, url, x_v="3")


Expand Down
Loading
Loading