This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Help with Tesla Powerwall API V3
#21
(26.01.2022, 13:00)admin Wrote: Specify API_Token = 'xyz' together with other credentials then you should be able to use the RequestFromTesla/WriteToTesla functions. Keep in mind that the token has expiration time and has to be refreshed.

I received an 401 error if i do what you suggested.

API_Token is the Refresh Token?

But why the other credentials? they are only used in the GetToken function and never used if you hardcoded the api_token.
Reply
#22
Refresh token is what you use to get a new access and refresh token pair. Access token is used for API calls. It might have already expired so you need to generate a new token pair.
You will need a scheduled script to refresh the token periodically. See this for more info: https://tesla-api.timdorr.com/api-basics...cess-token
Reply
#23
(27.01.2022, 07:26)admin Wrote: Refresh token is what you use to get a new access and refresh token pair. Access token is used for API calls. It might have already expired so you need to generate a new token pair.
You will need a scheduled script to refresh the token periodically. See this for more info: https://tesla-api.timdorr.com/api-basics...cess-token

i changed the code a little bit, but always received a deny from the webservice

Code:
function GetToken()
  body = json.encode({
    grant_type = 'authorization_code',
    client_id = 'ownerapi',
    refresh_token = refreshToken,
    scope = 'openid email offline_access'
  })

  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
    }
  })
 
  log(res, code, headers)
end

As refreshToken i used the Refresh Token from the Auth for Tesla app.

When i hardcoded the Access Token in the code it works, but this code expires in 8 hours
Code:
function GetToken()
  return accessToken --from the Auth for Tesla app
end
Reply
#24
Try adding User-Agent/X-Tesla-User-Agent headers as in previous examples. Also try adding client_secret field to the JSON body. You might also need an additional request to exchange bearer token for access token.
Reply
#25
(27.01.2022, 09:41)admin Wrote: Try adding User-Agent/X-Tesla-User-Agent headers as in previous examples. Also try adding client_secret field to the JSON body. You might also need an additional request to exchange bearer token for access token.

I already tried that, but same 400 deny error

Code:
function GetToken()
  body = json.encode({
    grant_type = 'authorization_code',
    client_id = 'ownerapi',
    client_secret = client_secret,
    refresh_token = refreshToken,
    scope = 'openid email offline_access'     
  })

  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'
    }
  })
 
  log(res, code, headers)
end
Reply
#26
problem found, grant_type incorrect transfered

Code:
function GetToken()
  body = json.encode({
    grant_type = 'refresh_token',
    client_id = 'ownerapi',
    refresh_token = refreshToken,
    scope = 'openid email offline_access'     
  })

  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   
      }
  })
  if not res or code ~= 200 then
    return
  end
  resp = table.concat(resp)
  resp = json.pdecode(resp)
 
  bearer_token = resp.access_token
  --refresh_token = resp.refresh_token
 
    return bearer_token
end

And next? do i need to refresh some tokens?
Reply
#27
When you get new bearer token you need to exchange it for an access token as described here: https://tesla-api.timdorr.com/api-basics...cess-token

Your scheduled refresh script should work like this:
1. get current refresh_token from storage (you will have to store it manually once)
2. request new bearer_token and refresh_token using current refresh_token
3. exchange bearer_token for new access_token
4. save new access_token and new refresh_token to storage

All other API calls should use access_token from storage.
Reply
#28
this is great in that we seemed to have got to a solution but in the meantime, I have become confused. the most recent post explains how to obtain and maintain access tokens. Can someone provide a working example of the LUA code to set the backup reserve % in my battery and the mode (self-powered vs time-based control)? I'd really like to access the State of Charge and other parameters too if that is possible. My knowledge is scant but I am good at trial and error! with thanks
Reply
#29
Has anybody got working scripts for Tesla? Both to get token and to use API calls and want to share?
Reply
#30
Hi, I finally got these working by following the different advices in this thread and some googling. I especially wanted to control the rate of charge and charging limit. After some fiddling, I found out that these needs the arguments in the body.

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 = 'some@email.com'
password = 'somepwd'
client_id = "replace" -- default, do not change unless Tesla makes changes
client_secret = "replace" -- default, do not change unless Tesla makes changes

-- all Tesla devices
tesla =    {} -- car, vehicle_id
tesla[1] = {'myCar1', 'id_s'}
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!

--Update using the Auth for Tesla app:
RefreshToken_App= "ey...XYZ"
AccessToken_App = "ey...123"

function GetToken()
 
-- 1. get current refresh_token from storage (you will have to store it manually once)
    RefreshToken = storage.get('TeslaRefresh')

-- 2. request new access_token and refresh_token using current refresh_token
  body = json.encode({
    grant_type = 'refresh_token',
    client_id = 'ownerapi',
    refresh_token = RefreshToken,
    scope = 'openid email offline_access'     
  })
  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('Failed to Tesla API tokens', resp, res, code)
    return
  end
  resp = table.concat(resp)
  resp = json.pdecode(resp)
 
  -- 3. save new access_token and new refresh_token to storage

  storage.set('TeslaAccess', resp.access_token)
  storage.set('TeslaRefresh', resp.refresh_token)
  log('Tesla tokens successfully updated')
  log('New access token:  ' .. resp.access_token)
  log('New refresh token: ' .. resp.refresh_token)
end

function RequestFromTesla(request)
  API_Token = storage.get('TeslaAccess')
  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
    GetToken() -- request a new token
    log('Request from Tesla API failed ', code, ret)
  end
end

function WriteToTesla(request, request_body)
  API_Token = storage.get('TeslaAccess')
  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
    log('Write to Tesla API failed ', code, ret)
    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
-- Get vehicle charge state
function get_charge_state()
    charge_state = RequestFromTesla('vehicles/' .. CarID .. '/data_request/charge_state')
    return(charge_state)
end
-- Get vehicle state
function get_vehicle_state()
    vehicle_state = RequestFromTesla('vehicles/' .. CarID .. '/data_request/vehicle_state')
    return(vehicle_state)
end
-- Get drive state
function get_drive_state()
    drive_state = RequestFromTesla('vehicles/' .. CarID .. '/data_request/drive_state')
    return(drive_state)
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
-- Set charging current: PS needs argument in body
function set_charging_current(iChargingAmps)
      result = WriteToTesla('vehicles/' .. CarID .. '/command/set_charging_amps', '{"charging_amps":"'..iChargingAmps..'"}')
    return(result)
end
-- Set charging limit:
function set_charge_limit(iChargingLimit)
      result = WriteToTesla('vehicles/' .. CarID .. '/command/set_charge_limit', '{"percent":"'..iChargingLimit..'"}')
    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
-- Charge to standard limit (90%)
function charge_standard()
    result = WriteToTesla('vehicles/' .. CarID .. '/command/charge_standard')
    return(result)
end
-- Charge to max range (100%)
function charge_standard()
    result = WriteToTesla('vehicles/' .. CarID .. '/command/charge_max_range')
    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
Reply


Forum Jump: