In early August, my Tesla Access Token failed to automatically update and so days later it expired. This then stopped Inputs to emoncms from the Tesla EV – soc, battery range miles and odometer reading.
And the reason? In July, Tesla had changed things – increasing security incl adding Captcha.
With a great deal of help from others, I now have a working solution which is in two parts.
Part 1 which is described in the Python script below involves a free Android App to copy and save the data. And it is possible just to use Part 1 every 30 or so days.
I do not have an iPhone but this looks like the Apple equivalent App:
# Script name: initiate_get_access_token.py
# Introduction ...
# In July 2021, Tesla increased security re Access Tokens incl introduction of Captcha in the request
# This script is the first part of a work around
# It requires access to an Android mobile phone
# BEFORE YOU RUN THIS SCRIPT - Do Steps 1 to 3 below ...
# STEP 1 ...
# Install the Android App: Tesla Tokens
# Run the App and copy the SSO Refresh Token to the Clipboard
# Open gMail, paste the Clipboard as the message content and send it to yourself
# STEP 2 ...
# If the directory does not exist, do: mkdir /home/pi/tesla-scripts
# STEP 3 ...
# Paste the SSO Refresh Token into the line as shown below ...
sso_refresh_token = "Paste the SSO Refresh Token between these double quotes"
# NOW RUN THE SCRIPT ...
file_name = "/home/pi/tesla-scripts/sso_refresh_token.txt" # This file is read by other scripts ...
f = open(file_name, "w")
f.write(sso_refresh_token)
f.close()
"""
# For debugging only ...
# Open and read the file after the appending:
f = open(file_name, "r")
print(f.read())
f.close()
"""
print ("That's it! A lot of hassle but you only have to do it once")
print ("Now proceed to the final step which is to run the script: tesla_refresh.py")
Part 2 which is described in the Python script below, saves the key data to files – Access Token, Expiry Date and SSO Refresh Token. The script can then be set to run monthly in the background using Cron – until Tesla makes the next change, that is
# Script Name: tesla_refresh.py
# Introduction ...
# In July 2021, Tesla increased security re Access Tokens incl introduction of Captcha in the request
# This script is the second part of a work around process
# If the script is run every month as a cronjob, the Owner API Access Token will be refreshed before its 45 day expiry
# The valid Access Token is saved to file: /home/pi/tesla-scripts/access_token.txt and so can be accessed by other scripts
# Save script to: /home/pi/tesla-scripts
# Run script using: python3 /home/pi/tesla-scripts/tesla_refresh.py
# Thereafter run the script every month as a cronjob
# Due acknowledgement to Tim Dorr Ref: https://tesla-api.timdorr.com/api-basics/authentication#refreshing-an-access-token
# Due acknowledgement to themonomers Ref: https://github.com/themonomers/tesla/blob/master/python/TeslaRefreshToken.py
# And thanks to Antoine Leveugle (@denouche)
import requests
import json
import urllib
import datetime
import pathlib
import shutil
# Read existing SSO Refresh_Token from the file created by script: initiate_get_access_token.py
file_name = "/home/pi/tesla-scripts/sso_refresh_token.txt"
f = open(file_name, "r")
refresh_token = f.read()
# print (refresh_token) # Debugging only ...
f.close()
# Exchange bearer token for access token
url = 'https://auth.tesla.com/oauth2/v3/token'
payload = {
'grant_type': 'refresh_token',
'refresh_token': refresh_token,
'client_id': 'ownerapi',
'scope': 'openid email offline_access'
}
response = requests.post(
url,
json=payload
)
# Get new sso refresh token
new_sso_refresh_token = json.loads(response.text)['refresh_token']
# Get new owner api access token from sso access token
sso_access_token = json.loads(response.text)['access_token']
owner_api_url = 'https://owner-api.teslamotors.com/oauth/token'
owner_api_payload = {
'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'client_id': '81527cff06843c8634fdc09e8ac0abefb46ac849f38fe1e431c2ef2106796384'
}
owner_api_headers = {
'Authorization': 'Bearer ' + sso_access_token
}
owner_api_response = requests.post(
owner_api_url,
json=owner_api_payload,
headers=owner_api_headers
)
owner_api_access_token = json.loads(owner_api_response.text)['access_token']
# Get expiry date for new owner api access token
expiry = str(datetime.datetime.fromtimestamp(json.loads(owner_api_response.text)['created_at'] + json.loads(owner_api_response.text)['expires_in']))
# Print KEY DATA for debugging ...
"""
print (" ")
print ('Owner API access_token: ' + owner_api_access_token)
print ('Expires at: ' + expiry)
print (" ")
print ('New SSO refresh_token: ' + new_sso_refresh_token)
"""
# Write KEY DATA to files ...
file_name = "/home/pi/tesla-scripts/access_token.txt" # This file is read by other scripts ...
f = open(file_name, "w")
f.write(owner_api_access_token)
f.close()
file_name = "/home/pi/tesla-scripts/access_token_expiry.txt"
f = open(file_name, "w")
f.write(expiry)
f.close()
file_name = "/home/pi/tesla-scripts/sso_refresh_token.txt"
f = open(file_name, "w")
f.write(new_sso_refresh_token)
f.close()
# AFTER RUNNING THE SCRIPT - SET IT UP TO RUN MONTHLY USING CRON
Hope this helps