Add City of Austin Utilities (COA) DSS support#190
Open
grutamu wants to merge 3 commits into
Open
Conversation
…headers The /multi-account-v1/cws/coa/customers endpoint returns 403 EMPTY_AUTHORIZED_CUSTOMERS_LIST when Opower-Selected-Entities does not include "urn:session:account:provider:dsst". Browser HAR analysis shows that every successful DSS API call includes this entity in addition to the numeric account ID. Adding it fixes the 403 for City of Austin Utilities. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The browser performs a PUT to customer-sync-v1/.../coa/sync with
{"operations":[{"type":"USER_DETAILS"}]} immediately after obtaining
the sessionToken. Without this step, the server has no customer session
context and the /customers endpoint returns 403 EMPTY_AUTHORIZED_CUSTOMERS_LIST.
Adding this call mirrors the browser flow and should unblock data fetching.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
COA uses the Opower Digital Self-Service portal (dss-coa.opower.com) with SAML-based SSO. The standard multi-account-v1/customers endpoint returns 403 EMPTY_AUTHORIZED_CUSTOMERS_LIST for Bearer token sessions because the server's authorized-customers list is only populated via SAML cookie auth. The browser avoids /customers entirely; we do the same. Changes: - Add MeterType.WATER for water/wastewater utilities - Add uses_bill_trends_for_reads() hook to UtilityBase (default False); COA overrides to True - Add _async_get_dss_customers(): discovers accounts via bill-trends-v1/serviceAgreements instead of multi-account-v1/customers; maps WATER/WASTE_WATER/ELECTRICITY/GAS service types to MeterType - Capture webUserId (UUID) from user-details after OTT exchange; use it as the customer UUID in Opower-Selected-Entities (only when UUID-format) - Add _async_fetch_dss_bills(): fetches 36 months of bill history via bill-trends-v1/billHistory; infers billing periods from consecutive bill dates; skips degenerate entries where two bills share the same date - _async_fetch(): try DataBrowser-v1 first for all utilities; on 403 fall back to _async_fetch_dss_bills() for uses_bill_trends_for_reads utilities Result: login, account discovery (WATER + WASTE_WATER), and 3-year bill history with cost data all work. Sub-bill granularity is not available via the opower portal (daily water reads live in a separate WaterSmart portal). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
Summary
City of Austin Utilities uses the Opower Digital Self-Service (DSS) portal at
dss-coa.opower.com. The existing code was unable to get past account discovery because themulti-account-v1/customersendpoint always returns403 EMPTY_AUTHORIZED_CUSTOMERS_LISTfor Bearer token sessions — the server only populates the authorized-customers list during SAML cookie authentication, which is how the browser logs in but not how the library authenticates.This PR makes COA fully functional for account discovery and bill history.
What changed
Account discovery via
bill-trends-v1/serviceAgreementsThe browser never calls
/customersat all. It usesbill-trends-v1/serviceAgreementsto discover the user's accounts. We do the same, mapping DSS service types (WATER,WASTE_WATER,ELECTRICITY,GAS, etc.) to opowerMeterTypevalues and constructing synthetic customer records the rest of the library can consume.Bill history via
bill-trends-v1/billHistoryDataBrowser-v1also requires a SAML-established server-side session and returns403for Bearer token requests. Rather than failing silently,_async_fetchnow tries DataBrowser-v1 first and falls back tobill-trends-v1/billHistoryon 403 for utilities that opt in. This provides up to 36 months of monthly billing history with cost data. Consumption values are zero because the billing API does not expose metered usage (daily water reads live in a separate WaterSmart portal outside the opower integration).New extension points
MeterType.WATERfor water/wastewater utilitiesUtilityBase.uses_bill_trends_for_reads()— utilities override this to True when DataBrowser-v1 is inaccessible; the fallback is generic and can be reused by other DSS utilities in the same situationLogin additions
After the OTT token exchange, the login flow fetches
user-detailsto capture thewebUserId(a real UUID) and callscustomer-sync-v1to establish session context on the server, mirroring what the browser does immediately after login.What is not supported
Daily and hourly water usage reads are not available through
dss-coa.opower.com. Austin Water exposes interval meter data through a separate WaterSmart portal (austintx.watersmart.com), which is outside the scope of this library.Test plan
async_get_accounts()returns WATER and WASTE_WATER accountsasync_get_cost_reads(account, AggregateType.BILL)returns up to 36 months of bill history with costsasync_get_cost_reads(account, AggregateType.DAY)falls back to bill history without crashing