Skip to content

Commit

Permalink
Fix access token refreshing logic
Browse files Browse the repository at this point in the history
  • Loading branch information
LeonBitCraft committed Sep 5, 2024
1 parent adf2b8a commit d8c39d6
Showing 1 changed file with 35 additions and 8 deletions.
43 changes: 35 additions & 8 deletions run/tesla_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
base_url = 'https://owner-api.teslamotors.com/api/1/vehicles'
SETTINGS = {
'DEBUG': False,
'REFRESH_TOKEN': False,
'refresh_token': False,
'tesla_email': 'dummy@local',
'tesla_password': '',
'tesla_access_token': '',
Expand Down Expand Up @@ -62,8 +62,8 @@ def _execute_request(url=None, method=None, data=None, require_vehicle_online=Tr

# Tesla REST Service sometimes misbehaves... this seems to be caused by an invalid/expired auth token
# TODO: Remove auth token and retry?
if result['response'] is None:
_error("Fatal Error: Tesla REST Service returned an invalid response")
if result.get('response') is None:
_error(f"Fatal Error: Tesla REST Service returned an invalid response: {result}")
sys.exit(1)

vehicle_online = result['response']['state'] == "online"
Expand Down Expand Up @@ -142,16 +142,43 @@ def _get_api_token():
# case, we can't accurately determine the age of the token, so we just
# use it. Later executions of the script should run after the date has
# updated correctly, at which point we can properly compare the dates.
max_retries = 24
retry_count = 0
retry_interval_s = 5
cutoff_year = 2019
# Wait for system time to be synchronized, up to max_retries times
while retry_count < max_retries:
now = datetime.now()
if now.year >= cutoff_year: # Time is correct, break the loop
break
_log(
f"System time is out of sync: {now}. Retrying in {retry_interval_s} seconds... (Attempt {retry_count + 1}/{max_retries})")
time.sleep(retry_interval_s) # Sleep for 5 seconds before checking again
retry_count += 1

now = datetime.now()
if now.year < 2019: # This script was written in 2019.
if now.year < cutoff_year: # This script was written in 2019.
_log("Time is still wrong after waiting. Using existing access token.")
return tesla_api_json['access_token']

if not SETTINGS.get('refresh_token'):
_log('No refreshing token available. Using existing access token.')
return tesla_api_json['access_token']

tesla = teslapy.Tesla(SETTINGS['tesla_email'], None)
if SETTINGS['REFRESH_TOKEN'] or 0 < tesla.expires_at < time.time():
_log('Refreshing api token')
# For some reason, the `expires_at` timestamp doesn't exactly match the `exp` field in the JWT body.
# The `expires_at` is typically about 1 minute ahead of the `exp` value in the JWT payload.
# Access token usually expires after a few hours, so refresh the token if it has less than `expiration_buffer_s` seconds remaining.
expiration_buffer_s = 60 * 30
if tesla.expires_at <= time.time() - expiration_buffer_s:
_log("Refreshing expired access token...")
tesla.token['refresh_token'] = SETTINGS.get('refresh_token')
tesla.refresh_token()
tesla_api_json['access_token'] = tesla.token.get('access_token')

if tesla_api_json['access_token'] != tesla.token.get('access_token'):
_log("Syncing access token...")
tesla_api_json['access_token'] = tesla.token.get('access_token')
_write_tesla_api_json()
return tesla_api_json['access_token']

# If the access token is not already stored in tesla_api_json AND
Expand Down Expand Up @@ -531,7 +558,7 @@ def main():
args = _get_arg_parser().parse_args()

SETTINGS['DEBUG'] = args.debug
SETTINGS['REFRESH_TOKEN'] = args.refresh_token
SETTINGS['refresh_token'] = args.refresh_token

if args.vin:
SETTINGS['tesla_vin'] = args.vin
Expand Down

0 comments on commit d8c39d6

Please sign in to comment.