mlowijs/tesla_api

Cope with tesla API errors

one4many opened this issue · 7 comments

From time to time Tesla-API servers return text/html instead of application/json.
Which results in a rather nasty Exception (Some information is obfuscated):

File "/home/....../tesla_api/__init__.py", line 154, in get
    response_json = await resp.json()
  File "/home/....../lib/python3.8/site-packages/aiohttp/client_reqrep.py", line 1026, in json
    raise ContentTypeError(
aiohttp.client_exceptions.ContentTypeError: 0, message='Attempt to decode JSON with unexpected mimetype: text/html', url=URL('https://owner-api.teslamotors.com/api/1/vehicles/21212121212121/data_request/charge_state')
    raise ContentTypeError(

Handling this is the app seems too complicated, as this error could occur at any point the app code (and api call) and just generate a lot of copy & paste code for exception handling. Or a 2nd api layer around the lib just to handle those rare hick-ups.

The lib could retry to send the command for a defined number of times or raise a CommunicationError Exception of some sort.

That must be another recent change, I've not seen these before.

I'll try and reproduce soon, but if you could debug and get the resp.text() that would help figure out exactly what is happening.

I will add a resp.text() and log the output. I happens very rarely though. I hope I can catch it in the future.

Tesla changed to v3 oauth api about last Friday so all their auth basically broke I have a work around in my python code 👍
https://github.com/fkhera/powerwallCloud/blob/abd0daa069888e68b346201464ec5dfcda771144/powerwallBackup.py#L132

Just found another Tesla Server oddity. I get an response with the correct header (and mimetype) but no body data at all. This causes a None response in await resp.json() and finally results in an exception like this:

Traceback (most recent call last):
  File "pcase.py", line 32, in <module>
    asyncio.run(main())
  File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py", line 587, in run_until_complete
    return future.result()
  File "pcase.py", line 10, in main
    energy_sites = await client.list_energy_sites()
  File "/Users/......../tesla_api/__init__.py", line 183, in list_energy_sites
    for product in await self.get("products") if "energy_site_id" in product]
  File "/Users/......./tesla_api/__init__.py", line 157, in get
    if "error" in response_json:
TypeError: argument of type 'NoneType' is not iterable
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x10eabf390>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x10eadaa60>, 0.923982764)]']
connector: <aiohttp.connector.TCPConnector object at 0x10eabf3d0>

The Tesla servers don't respond to this account/token with any valid response. No data or not even a authentication error.
So I'm not sure if we can assume the account is intact and we just don't get any data at the moment or the account is blocked/disabled/temporarily disabled for now.

Maybe raising a 'No data' exception is ok for now and if it turns out to be a authentication problem changing it into a 'Authentication Error' exception.

Thanks Tesla... :P

OK, sounds like the latter issue may be a WAF?
timdorr/tesla-api#260 (comment)

Hmmm, not sure if it is a WAF. WAFs typically block IP addresses and not single sessions. All other connections my servers hold (talking to the API-Servers) work without a problem. In theory it is possible to block a single session because it is identifiable via the auth-header but WAFs can't do that (at least none of the ones I know).

I just retried the account in question with the same result, just no data from the Tesla API servers. This account had no requests for at least 4 hrs.

Just to be clear: This is just a request to retrieve data from the API and not a request to authenticate via user/pass/MFA token.