tronikos / opower

A Python library for getting historical and forecasted usage/cost from utilities that use opower.com such as PG&E
Apache License 2.0
65 stars 59 forks source link

Request: Support opower guest accounts for coautilities #81

Open trv opened 5 months ago

trv commented 5 months ago

For coautilities (not sure about others), you can create a guest account at https://dss-coa.opower.com/dss/account/manage-web-account under "Connected accounts > + Add guest user". This allows you to set the access level to effectively read-only ("Usage & Financial Info"). It'd be nice if we could take advantage of this access control to apply the principle of least privilege.

The main login credentials work fine with demo.py (release version 0.4.6).

I can use this guest login via the browser to access usage data, but demo.py fails with:

DEBUG:/config/custom_components/opower-0.4.6/src/opower/opower.py:Fetching: https://dss-coa.opower.com/webcenter/edge/apis/dss-invite-v1/cws/v1/utilities/connectedaccounts?pageOffset=0&pageLimit=100
Level 9:/config/custom_components/opower-0.4.6/src/opower/opower.py:Fetched: {
  "accounts": [],
  "totalRecords": 0
}
Traceback (most recent call last):
  File "/config/custom_components/opower-0.4.6/src/demo.py", line 172, in <module>
    asyncio.run(_main())
  File "/usr/local/lib/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 685, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/config/custom_components/opower-0.4.6/src/demo.py", line 91, in _main
    for forecast in await opower.async_get_forecast():
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/opower-0.4.6/src/opower/opower.py", line 247, in async_get_forecast
    for customer in await self._async_get_customers():
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/opower-0.4.6/src/opower/opower.py", line 327, in _async_get_customers
    await self._async_get_user_accounts()
  File "/config/custom_components/opower-0.4.6/src/opower/opower.py", line 374, in _async_get_user_accounts
    assert self.user_accounts
AssertionError

Tracing the network calls when using the guest account from a browser session, I see

Presumably guest logins require a less-direct method to dig up the missing accounts info?

max2697 commented 3 months ago

Hello @trv. It’s a good idea. I’ll take a look at how it could be used and what changes are required.

max2697 commented 3 months ago

Hm, I tried to create a guest account, and now it wants my SSN or driver’s license number for account verification. @trv, have you also completed this step? It seems a bit excessive for a guest account just to gain access

trv commented 2 months ago

I had an existing coautilities account that I added as a guest, so I didn't go through the new account flow recently.

max2697 commented 2 months ago

Unfortunately, I can't recreate this case. I can only suggest using the main account to retrieve the information for now

jmillsy commented 1 day ago

If it helps, I tried connecting using a connected account and I get back a 500:

aiohttp.client_exceptions.ClientResponseError: 500, message='Internal Server Error', url='https://dss-coa.opower.com/webcenter/edge/apis/dss-invite-v1/cws/v1/utilities/connectedaccounts?pageOffset=0&pageLimit=100'