Skip to content

Commit

Permalink
Tesla API separation
Browse files Browse the repository at this point in the history
  • Loading branch information
ngardiner committed Oct 12, 2019
1 parent 39c00a9 commit fbf7f43
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 27 deletions.
38 changes: 17 additions & 21 deletions TWCManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ def load_settings():
global config, nonScheduledAmpsMax, scheduledAmpsMax, \
scheduledAmpsStartHour, scheduledAmpsEndHour, \
scheduledAmpsDaysBitmap, hourResumeTrackGreenEnergy, kWhDelivered, \
carapi, carApiRefreshToken, carApiTokenExpireTime, \
homeLat, homeLon
carapi, carApiTokenExpireTime, homeLat, homeLon

try:
fh = open(config['config']['settingsPath'] + "/TWCManager.settings", 'r')
Expand Down Expand Up @@ -185,9 +184,9 @@ def load_settings():

m = re.search(r'^\s*carApiRefreshToken\s*=\s*(.+)', line, re.MULTILINE)
if(m):
carApiRefreshToken = m.group(1)
carapi.setCarApiRefreshToken(m.group(1))
if(config['config']['debugLevel'] >= 10):
print("load_settings: carApiRefreshToken set to " + str(carApiRefreshToken))
print("load_settings: carApiRefreshToken set to " + str(m.group(1)))
continue

m = re.search(r'^\s*carApiTokenExpireTime\s*=\s*(.+)', line, re.MULTILINE)
Expand Down Expand Up @@ -222,8 +221,7 @@ def save_settings():
global config, nonScheduledAmpsMax, scheduledAmpsMax, \
scheduledAmpsStartHour, scheduledAmpsEndHour, \
scheduledAmpsDaysBitmap, hourResumeTrackGreenEnergy, kWhDelivered, \
carapi, carApiRefreshToken, carApiTokenExpireTime, \
homeLat, homeLon
carapi, carApiTokenExpireTime, homeLat, homeLon

fh = open(config['config']['settingsPath'] + "/TWCManager.settings", 'w')
fh.write('nonScheduledAmpsMax=' + str(nonScheduledAmpsMax) +
Expand All @@ -234,7 +232,7 @@ def save_settings():
'\nhourResumeTrackGreenEnergy=' + str(hourResumeTrackGreenEnergy) +
'\nkWhDelivered=' + str(kWhDelivered) +
'\ncarApiBearerToken=' + str(carapi.getCarApiBearerToken()) +
'\ncarApiRefreshToken=' + str(carApiRefreshToken) +
'\ncarApiRefreshToken=' + str(carapi.getCarApiRefreshToken()) +
'\ncarApiTokenExpireTime=' + str(int(carApiTokenExpireTime)) +
'\nhomeLat=' + str(homeLat) +
'\nhomeLon=' + str(homeLon)
Expand Down Expand Up @@ -503,13 +501,12 @@ def total_amps_actual_all_twcs():


def car_api_available(email = None, password = None, charge = None):
global config, carApiLastErrorTime, carApiErrorRetryMins, \
carapi, carApiRefreshToken, carApiTokenExpireTime
global config, carApiLastErrorTime, carapi, carApiTokenExpireTime

now = time.time()
apiResponseDict = {}

if(now - carApiLastErrorTime < carApiErrorRetryMins*60):
if(now - carApiLastErrorTime < (carapi.getCarApiErrorRetryMins()*60)):
# It's been under carApiErrorRetryMins minutes since the car API
# generated an error. To keep strain off Tesla's API servers, wait
# carApiErrorRetryMins mins till we try again. This delay could be
Expand All @@ -523,7 +520,7 @@ def car_api_available(email = None, password = None, charge = None):
# automatically.
if(config['config']['debugLevel'] >= 11):
print(time_now() + ': Car API disabled for ' +
str(int(carApiErrorRetryMins*60 - (now - carApiLastErrorTime))) +
str(int(carapi.getCarApiErrorRetryMins()*60 - (now - carApiLastErrorTime))) +
' more seconds due to recent error.')
return False

Expand All @@ -535,12 +532,12 @@ def car_api_available(email = None, password = None, charge = None):
# If we don't have a bearer token or our refresh token will expire in
# under 30 days, get a new bearer token. Refresh tokens expire in 45
# days when first issued, so we'll get a new token every 15 days.
if(carApiRefreshToken != ''):
if(carapi.getCarApiRefreshToken() != ''):
cmd = 'curl -s -m 60 -X POST -H "accept: application/json" -H "Content-Type: application/json" -d \'' + \
json.dumps({'grant_type': 'refresh_token', \
'client_id': '81527cff06843c8634fdc09e8ac0abefb46ac849f38fe1e431c2ef2106796384', \
'client_secret': 'c7257eb71a564034f9419ee651c7d0e5f7aa6bfbd18bafb5c5c033b093bb2fa3', \
'refresh_token': carApiRefreshToken }) + \
'refresh_token': carapi.getCarApiRefreshToken() }) + \
'\' "https://owner-api.teslamotors.com/oauth/token"'
elif(email != None and password != None):
cmd = 'curl -s -m 60 -X POST -H "accept: application/json" -H "Content-Type: application/json" -d \'' + \
Expand Down Expand Up @@ -568,7 +565,7 @@ def car_api_available(email = None, password = None, charge = None):
if(config['config']['debugLevel'] >= 4):
print(time_now() + ': Car API auth response', apiResponseDict, '\n')
carapi.setCarApiBearerToken(apiResponseDict['access_token'])
carApiRefreshToken = apiResponseDict['refresh_token']
carapi.setCarApiRefreshToken(apiResponseDict['refresh_token'])
carApiTokenExpireTime = now + apiResponseDict['expires_in']
except KeyError:
print(time_now() + ": ERROR: Can't access Tesla car via API. Please log in again via web interface.")
Expand All @@ -579,7 +576,7 @@ def car_api_available(email = None, password = None, charge = None):
# ten minutes with a bad token because Tesla might decide to block
# remote access to your car after too many authorization errors.
carapi.setCarApiBearerToken()
carApiRefreshToken = ''
carapi.setCarApiRefreshToken()

save_settings()

Expand All @@ -606,7 +603,7 @@ def car_api_available(email = None, password = None, charge = None):
# apiResponseDict['response'] when 'response' doesn't exist in
# apiResponseDict.
print(time_now() + ": ERROR: Can't get list of vehicles via Tesla car API. Will try again in "
+ str(carApiErrorRetryMins) + " minutes.")
+ str(carapi.getCarApiErrorRetryMins()) + " minutes.")
carApiLastErrorTime = now
return False

Expand All @@ -620,14 +617,14 @@ def car_api_available(email = None, password = None, charge = None):
+ " because vehicle.stopAskingToStartCharging == True")
continue

if(now - vehicle.lastErrorTime < carApiErrorRetryMins*60):
if(now - vehicle.lastErrorTime < (carapi.getCarApiErrorRetryMins()*60)):
# It's been under carApiErrorRetryMins minutes since the car
# API generated an error on this vehicle. Don't send it more
# commands yet.
if(config['config']['debugLevel'] >= 8):
print(time_now() + ": Don't send commands to vehicle " + str(vehicle.ID)
+ " because it returned an error in the last "
+ str(carApiErrorRetryMins) + " minutes.")
+ str(carapi.getCarApiErrorRetryMins()) + " minutes.")
continue

if(vehicle.ready()):
Expand Down Expand Up @@ -810,7 +807,7 @@ def car_api_available(email = None, password = None, charge = None):
((now - vehicle.firstWakeAttemptTime) / 60 / 60),
str(apiResponseDict)))

if(now - carApiLastErrorTime < carApiErrorRetryMins*60 or carapi.getCarApiBearerToken() == ''):
if(now - carApiLastErrorTime < (carapi.getCarApiErrorRetryMins()*60) or carapi.getCarApiBearerToken() == ''):
if(config['config']['debugLevel'] >= 8):
print(time_now() + ": car_api_available returning False because of recent carApiLasterrorTime "
+ str(now - carApiLastErrorTime) + " or empty carApiBearerToken '"
Expand Down Expand Up @@ -839,8 +836,7 @@ def car_api_available(email = None, password = None, charge = None):
def car_api_charge(charge):
# Do not call this function directly. Call by using background thread:
# queue_background_task({'cmd':'charge', 'charge':<True/False>})
global carApiLastErrorTime, carApiErrorRetryMins, \
carapi, homeLat, homeLon, config
global carApiLastErrorTime, carapi, homeLat, homeLon, config

now = time.time()
apiResponseDict = {}
Expand Down
34 changes: 28 additions & 6 deletions lib/TWCManager/Vehicle/TeslaAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ class CarApi:
import time

carApiLastErrorTime = 0
carApiBearerToken = ''
carApiRefreshToken = ''
carApiBearerToken = ''
carApiRefreshToken = ''
carApiTokenExpireTime = time.time()
carApiLastStartOrStopChargeTime = 0
carApiVehicles = []
config = None
carApiVehicles = []
config = None

# Transient errors are ones that usually disappear if we retry the car API
# command a minute or less later.
Expand All @@ -33,6 +33,15 @@ def addVehicle(self, json):
self.carApiVehicles.append(CarApiVehicle(json, self, self.config))
return True

def getCarApiBearerToken(self):
return self.carApiBearerToken

def getCarApiErrorRetryMins(self):
return self.carApiErrorRetryMins

def getCarApiRefreshToken(self):
return self.carApiRefreshToken

def getCarApiTransientErrors(self):
return self.carApiTransientErrors

Expand All @@ -43,8 +52,21 @@ def getVehicleCount(self):
# Returns the number of currently tracked vehicles
return int(len(self.carApiVehicles))

def setCarApiBearerToken(self, token):
self.carApiBearerToken = token
return True

def setCarApiErrorRetryMins(self, mins):
self.carApiErrorRetryMins = mins
return True

def setCarApiRefreshToken(self, token):
self.carApiRefreshToken = token
return True

def updateLastStartOrStopChargeTime(self):
self.carApiLastStartOrStopChargeTime = now
return True

class CarApiVehicle:

Expand Down Expand Up @@ -74,9 +96,9 @@ def debugLog(self, minlevel, message):
print("TeslaAPI: (" + str(minlevel) + ") " + message)

def ready(self):
global carApiLastErrorTime, carApiErrorRetryMins
global carApiLastErrorTime

if(self.time.time() - self.lastErrorTime < carApiErrorRetryMins*60):
if(self.time.time() - self.lastErrorTime < (self.carApiErrorRetryMins*60)):
# It's been under carApiErrorRetryMins minutes since the car API
# generated an error on this vehicle. Return that car is not ready.
debugLog(8, ': Vehicle ' + str(self.ID)
Expand Down

0 comments on commit fbf7f43

Please sign in to comment.