Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any suggestions? #44

Open
jackkorber opened this issue May 29, 2021 · 17 comments
Open

Any suggestions? #44

jackkorber opened this issue May 29, 2021 · 17 comments

Comments

@jackkorber
Copy link

jackkorber commented May 29, 2021

I am getting the error below. Any suggestions?

Traceback (most recent call last):
File "/Users/jackkorber/Desktop/Python/GetPowerwallCapacity/powerwallCapacity.py", line 31, in
asyncio.run(main())
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/runners.py", line 43, in run
return loop.run_until_complete(main)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/base_events.py", line 608, in run_until_complete
return future.result()
File "/Users/jackkorber/Desktop/Python/GetPowerwallCapacity/powerwallCapacity.py", line 12, in main
energy_sites = await client.list_energy_sites()
File "/Users/jackkorber/Desktop/Python/GetPowerwallCapacity/tesla_api/init.py", line 123, in list_energy_sites
for product in await self.get("products") if "energy_site_id" in product]
File "/Users/jackkorber/Desktop/Python/GetPowerwallCapacity/tesla_api/init.py", line 91, in get
await self.authenticate()
File "/Users/jackkorber/Desktop/Python/GetPowerwallCapacity/tesla_api/init.py", line 81, in authenticate
expiry_time = timedelta(seconds=self._token["expires_in"])
KeyError: 'expires_in'
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x7fa22a881ac0>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x7fa22a8a5520>, 0.69530855)]']
connector: <aiohttp.connector.TCPConnector object at 0x7fa22a881af0>

@jackkorber
Copy link
Author

<ClientResponse(https://owner-api.teslamotors.com/oauth/token) [400 Bad Request]>

@jakkaj
Copy link

jakkaj commented May 29, 2021

In my experience, errors like this come and go. They seem to play with the API from time to time.

I think there is a new problem now though with Captcha being added as discussed here: timdorr/tesla-api#390

@jakkaj
Copy link

jakkaj commented May 29, 2021

I managed to work around the captcha by grabbing a token in Postman using the built in authentication stuff, then popping it in a json file and removing direct user and pass. Works for MFA too as you're just logging in a browser as you would in the app - and the tokens refresh anyway, so should never have to do it again hypothetically.

Settings for Postman that worked:

Client secret:c7257eb71a564034f9419ee651c7d0e5f7aa6bfbd18bafb5c5c033b093bb2fa3

t1

t2

@jakkaj
Copy link

jakkaj commented May 29, 2021

This is the rest.

The START_TOKEN variable is a json token from .env to get things started (the one manually generated in postman)

It looks like this:

{"resfresh_token": "", "access_token": "", "expires_in": 28800, "created_at": 1622326394.014721}
async def save_token(token):
    open("token_file.json", "w").write(token)

async def load_token():
    try:
        with open('token_file.json', "r") as f:
            return f.read()        
    except IOError:
        await save_token(START_TOKEN)
        return await load_token()    
    


async def getreserve():
    token = await load_token()
    client = TeslaApiClient(token=token, on_new_token=save_token) 

@jakkaj
Copy link

jakkaj commented Jun 1, 2021

Just create a new request and switch to the authorization tab and you should see it. BTW you don't need an account in Postman!

Capture

@bchristian14
Copy link

Just create a new request and switch to the authorization tab and you should see it. BTW you don't need an account in Postman!

I deleted my previous response out of embarrassment but thank very much for holding my hand. I don't know why I couldn't fumble my way through the UI to find this!

@jakkaj
Copy link

jakkaj commented Jun 1, 2021

I find it to be unintuitive... could be a better UI .

There is a problem I've come across now that the code does not refresh the tokens properly, gives an invalid_grant error with a grant type of refresh_token. Have not had time to really pull it apart yet. Will create a new issue.

@bchristian14
Copy link

the code does not refresh the tokens properly

well that's unfortunate. I think I maybe saw this when I first wrote my script, but probably just attributed to my lack of understanding/knowledge, and just pass the credentials each time (the script only has 1 user - me!)

@jakkaj
Copy link

jakkaj commented Jun 1, 2021

The auth token works fine, just when it expires the refresh step fails.

@fracai
Copy link

fracai commented Aug 30, 2021

Thanks @jakkaj, your token suggestion is working for me and but I'm also seeing the refresh step failing.
The error I get is:

...
  File ".../.venv/lib/python3.8/site-packages/tesla_api/__init__.py", line 61, in _get_token
    raise AuthenticationError(response_json)
tesla_api.exceptions.AuthenticationError: Authentication to the Tesla API failed: {'error': 'invalid_grant', 'error_description': 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.'}

The "issued to another client" makes me wonder if the OAUTH_CLIENT_ID is the problem. I note that tesla_api uses 81527cff…, but the Postman process uses ownerapi. I tried getting a token using the 81527cff… ID, but that resulted in an error in the authorization popup. I tried changing OAUTH_CLIENT_ID to ownerapi for just the _get_token method, but resulted in the same error response.

@fracai
Copy link

fracai commented Aug 30, 2021

I was able to refresh the token!

I used ownerapi for the client id, https://auth.tesla.com/oauth2/v3/token for the URL, and added "scope": "openid email offline_access" to the refresh data. I'm not sure if scope is actually required here. I saw it used in a refresh on another project and haven't tried it without. I then also added created_at to the response_json to support the refresh check.

I can make a proper PR, but for now my changes are below:

diff --git a/tesla_api/__init__.py b/tesla_api/__init__.py
index 6d5ab02..775a18d 100644
--- a/tesla_api/__init__.py
+++ b/tesla_api/__init__.py
@@ -9,9 +9,11 @@ from .exceptions import ApiError, AuthenticationError, VehicleUnavailableError
 from .vehicle import Vehicle
 
 TESLA_API_BASE_URL = "https://owner-api.teslamotors.com/"
-TOKEN_URL = TESLA_API_BASE_URL + "oauth/token"
+TESLA_TOKEN_BASE_URL = "https://auth.tesla.com/"
+TOKEN_URL = TESLA_TOKEN_BASE_URL + "oauth2/v3/token"
 API_URL = TESLA_API_BASE_URL + "api/1"
 
+TOKEN_CLIENT_ID = "ownerapi"
 OAUTH_CLIENT_ID = "81527cff06843c8634fdc09e8ac0abefb46ac849f38fe1e431c2ef2106796384"
 OAUTH_CLIENT_SECRET = "c7257eb71a564034f9419ee651c7d0e5f7aa6bfbd18bafb5c5c033b093bb2fa3"
 
@@ -50,7 +52,7 @@ class TeslaApiClient:
 
     async def _get_token(self, data):
         request_data = {
-            "client_id": OAUTH_CLIENT_ID,
+            "client_id": TOKEN_CLIENT_ID,
             "client_secret": OAUTH_CLIENT_SECRET,
         }
         request_data.update(data)
@@ -60,6 +62,7 @@ class TeslaApiClient:
             if resp.status == 401:
                 raise AuthenticationError(response_json)
 
+        response_json['created_at'] = datetime.now().timestamp()
         # Send token to application via callback.
         if self._new_token_callback:
             asyncio.create_task(self._new_token_callback(json.dumps(response_json)))
@@ -71,7 +74,7 @@ class TeslaApiClient:
         return await self._get_token(data)
 
     async def _refresh_token(self, refresh_token):
-        data = {"grant_type": "refresh_token", "refresh_token": refresh_token}
+        data = {"grant_type": "refresh_token", "refresh_token": refresh_token, "scope": "openid email offline_access"}
         return await self._get_token(data)
 
     async def authenticate(self):

@fracai
Copy link

fracai commented Aug 30, 2021

Looks like some of my changes are covered by the v3 PRs that already exist.
#38
#39

@jcam
Copy link

jcam commented Sep 27, 2021

This project seems to handle the captcha pretty well, might be useful to lift some of their work:
tdorssers/TeslaPy@22540ab

@jakkaj
Copy link

jakkaj commented Sep 27, 2021

@fracai sweet!

@jakkaj
Copy link

jakkaj commented Sep 27, 2021

@jcam Seems like a lot of extra work around to handle Capcha. This really looks like a lot of work when perhaps a one time interactive login is needed + decent token refreshing.

@jcam
Copy link

jcam commented Sep 27, 2021

Yeah it is a lot. Probably way more than needed. The built in interactive login (kicks out to system web browser) and token refresh handling seems pretty solid though. Not really suggesting to duplicate all the work, but since it all works it might be a useful resource for getting the flows right.

@jakkaj
Copy link

jakkaj commented Sep 27, 2021 via email

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

No branches or pull requests

5 participants