26.01.2022, 12:57
(14.01.2022, 09:29)admin Wrote: The login part has been modified so the automated way no longer works. The only way is to manually get both tokens. See this for more info: https://teslascope.com/help/generating-tokens
But in this case another script is needed to handle token refresh because they have a limited lifetime. It can be automated but if the token cannot be refreshed then it has to be updated manually again.
i installed the Auth for Tesla app and get:
- Refresh Token
- Access Token
In the old situation it generates an Api Token and thats is used in the header.
How to use above codes in my lua code to get it working again?
Code:
-- Load modules
encdec = require('encdec')
http = require('socket.http')
mime = require('mime')
ltn12 = require('ltn12')
json = require('json')
https = require('ssl.https')
-- set credentials
username = 'my@email.com'
password = 'myPassword'
client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -- default, do not change unless Tesla makes changes
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -- default, do not change unless Tesla makes changes
-- all Tesla devices
tesla = {} -- car, vehicle_id
tesla[1] = {'myCar1', 'myVehicleId'}
CarID = tesla[1][2] -- run the script once, and look in the logs you will find a string called id_s this number is your vehicle ID, this should be replaced with the 123 in this field, remember to add "", then run script again, and you will get it to work!
function GetToken()
function mt()
local ts, tu = os.microtime()
return ts .. '.' .. tu
end
function b64url(str)
return mime.b64(str):gsub('.', {
['+'] = '-',
['/'] = '_',
['='] = '',
})
end
function encodeargs(t)
local res = {}
local esc = require('socket.url').escape
for k, v in pairs(t) do
res[ #res + 1 ] = esc(k) .. '=' .. esc(v)
end
return table.concat(res, '&')
end
code_verifier = encdec.sha512(mt()):sub(1, 86)
state = b64url(encdec.sha256(mt()):sub(1, 12))
code_challenge = b64url(code_verifier)
args = encodeargs({
client_id = 'ownerapi',
code_challenge = code_challenge,
code_challenge_method = 'S256',
redirect_uri = 'https://auth.tesla.com/void/callback',
response_type = 'code',
scope = 'openid email offline_access',
state = state,
})
url = 'https://auth.tesla.com/oauth2/v3/authorize?' .. args
res, code, headers = http.request(url)
if not res or code ~= 200 then
--log('request 1 failed', res, code)
return
end
postdata = {}
regexp = '<input type="hidden" name="([^"]+)" value="([^"]*)"'
for name, value in res:gmatch(regexp) do
postdata[ name ] = value
end
postdata.identity = username
postdata.credential = password
cookie = headers['Set-Cookie'] or headers['set-cookie'] or ''
body = encodeargs(postdata)
res, code, headers = http.request({
url = url,
method = 'POST',
source = ltn12.source.string(body),
headers = {
['Content-Type'] = 'application/x-www-form-urlencoded',
['Content-Length'] = #body,
['Cookie'] = cookie,
}
})
if not res or code ~= 302 then
--log('request 2 failed', res, code)
return
end
hdr = headers.Location or headers.location
resp_code = hdr:match('code=([^&]+)')
body = json.encode({
grant_type = 'authorization_code',
client_id = 'ownerapi',
code = resp_code,
code_verifier = code_verifier,
redirect_uri = 'https://auth.tesla.com/void/callback',
})
resp = {}
res, code, headers = http.request({
url = 'https://auth.tesla.com/oauth2/v3/token',
method = 'POST',
source = ltn12.source.string(body),
sink = ltn12.sink.table(resp),
headers = {
['Content-Type'] = 'application/json',
['Accept'] = 'application/json',
['Content-Length'] = #body,
['User-Agent'] = 'Mozilla/5.0 (Linux; Android 9.0.0; VS985 4G Build/LRX21Y; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36',
['X-Tesla-User-Agent'] = 'TeslaApp/3.4.4-350/fad4a582e/android/9.0.0',
}
})
if not res or code ~= 200 then
--log('request 3 failed', res, code)
return
end
resp = table.concat(resp)
resp = json.pdecode(resp)
bearer_token = resp.access_token
refresh_token = resp.refresh_token
body = json.encode({
grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer',
client_id = client_id,
client_secret = client_secret,
})
resp = {}
res, code, headers = http.request({
url = 'https://owner-api.teslamotors.com/oauth/token',
method = 'POST',
source = ltn12.source.string(body),
sink = ltn12.sink.table(resp),
headers = {
['Content-Type'] = 'application/json',
['Authorization'] = 'Bearer ' .. bearer_token,
['Content-Length'] = #body,
}
})
--print(res, code)
if not res or code ~= 200 then
--log('request 4 failed', res, code)
return
end
resp = table.concat(resp)
resp = json.pdecode(resp)
return resp.access_token
end
-- Request token
if not API_Token then
API_Token = GetToken()
end
function RequestFromTesla(request)
request_url = 'https://owner-api.teslamotors.com/api/1/' .. request
local response_body = {}
local request_body = ""
local body, code, hdrs, stat = ssl.https.request{
url = request_url;
method = "GET";
headers =
{
["Content-Type"] = "application/json";
["Authorization"] = "Bearer " .. API_Token;
};
source = ltn12.source.string(request_body);
sink = ltn12.sink.table(response_body);
}
if code == 200 then
ret = table.concat(response_body)
ret = json.pdecode(ret)
return ret
else
API_Token = GetToken() -- request a new token
end
end
function WriteToTesla(request, request_body)
request_url = 'https://owner-api.teslamotors.com/api/1/' .. request
local response_body = {}
local content_length
if type(request_body) == "string" then
content_length = #request_body
else
request_body = ""
end
local body, code, hdrs, stat = ssl.https.request{
url = request_url;
method = "POST";
headers =
{
["Content-Type"] = "application/json";
["Authorization"] = "Bearer " .. API_Token;
["Content-Length"] = content_length;
};
source = ltn12.source.string(request_body);
sink = ltn12.sink.table(response_body);
}
if code == 200 then
ret = table.concat(response_body)
ret = json.pdecode(ret)
return ret
else
API_Token = GetToken() -- request a new token
end
end
---------------------------------------------------------------------------------------
-- Get products
function get_products()
products = RequestFromTesla('products')
return(products) -- Check here your product ID
end
-- Get vehicles
function get_vehicles()
vehicles = RequestFromTesla('vehicles')
return(vehicles) -- Check here your Vehicles
end
-- Get onboarding data
function get_onboarding_data()
onboarding_data = RequestFromTesla('users/onboarding_data')
return(onboarding_data)
end
-- Get vehicle data
function get_vehicle_data()
vehicle_data = RequestFromTesla('vehicles/' .. CarID .. '/vehicle_data')
return(vehicle_data)
end
-- Wake up car
function wake_up()
result = WriteToTesla('vehicles/' .. CarID .. '/wake_up')
debugLog(result)
end
-- Unlock car
function door_unlock()
result = WriteToTesla('vehicles/' .. CarID .. '/command/door_unlock')
return(result)
end
-- Lock car
function door_lock()
result = WriteToTesla('vehicles/' .. CarID .. '/command/door_lock')
return(result)
end
-- Honk horn
function honk_horn()
result = WriteToTesla('vehicles/' .. CarID .. '/command/honk_horn')
return(result)
end
-- Flash lights
function flash_lights()
result = WriteToTesla('vehicles/' .. CarID .. '/command/flash_lights')
return(result)
end
-- Autocondition start
function auto_conditioning_start()
result = WriteToTesla('vehicles/' .. CarID .. '/command/auto_conditioning_start')
return(result)
end
-- Autocondition stop
function auto_conditioning_stop()
result = WriteToTesla('vehicles/' .. CarID .. '/command/auto_conditioning_stop')
return(result)
end
-- Set temperature
function set_temps(iDriverTemp,iPassengerTemp)
result = WriteToTesla('vehicles/' .. CarID .. '/command/set_temps?driver_temp='..iDriverTemp..'&passenger_temp='..iPassengerTemp)
return(result)
end
-- Charge port door open
function charge_port_door_open()
result = WriteToTesla('vehicles/' .. CarID .. '/command/charge_port_door_open')
return(result)
end
-- Start charging
function charge_start()
result = WriteToTesla('vehicles/' .. CarID .. '/command/charge_start')
return(result)
end
-- Stop charging
function charge_stop()
result = WriteToTesla('vehicles/' .. CarID .. '/command/charge_stop')
return(result)
end
-- Open trunk rear
function actuate_trunk()
result = WriteToTesla('vehicles/' .. CarID .. '/command/actuate_trunk', '{"which_trunk":"rear"}')
return(result)
end
-- Open trunk front
function actuate_frunk()
result = WriteToTesla('vehicles/' .. CarID .. '/command/actuate_trunk', '{"which_trunk":"front"}')
return(result)
end