Skip to content

Instantly share code, notes, and snippets.

@emily-pesce
Last active January 24, 2021 12:39
Show Gist options
  • Save emily-pesce/69f8ada9494daee82d2d5fe3a92e32cc to your computer and use it in GitHub Desktop.
Save emily-pesce/69f8ada9494daee82d2d5fe3a92e32cc to your computer and use it in GitHub Desktop.
Google Sheet Data Logger for Teslas
function getData() {
var id = 'REPLACE_WITH_GOOGLE_SHEET_ID';
var sheet = SpreadsheetApp.openById(id);
var today = Utilities.formatDate(new Date(), 'America/New_York', "MM/dd/yy hh:mm:ss a");
var base_url = 'https://owner-api.teslamotors.com/api/1/vehicles/'
var auth_token = "Bearer REPLACE_WITH_AUTHORIZATION_STRING"
var response = UrlFetchApp.fetch(base_url, {
'headers':{
Authorization:auth_token
},
muteHttpExceptions:true
});
if (response.getResponseCode() == 401) {
MailApp.sendEmail('REPLACE_WITH_YOUR_EMAIL', 'tesla api auth failed', 'tesla api auth failed');
}
var data = JSON.parse(response.getContentText());
data.response.forEach(function( d ) {
var name = d.display_name
//***VEHICLE STATE***
var url = base_url + d.id_s + '/data_request/vehicle_state';
var vehicle_response = UrlFetchApp.fetch(url, {
'headers':{
Authorization:auth_token
},
muteHttpExceptions:true
});
var vehicle_data = JSON.parse(vehicle_response);
//var name = vehicle_data.response.display_name;
var version = vehicle_data.response.car_version;
var miles = vehicle_data.response.odometer;
var timestamp = new Date(parseInt(vehicle_data.response.timestamp));
//***DRIVE STATE***
var url = base_url + d.id_s + '/data_request/drive_state';
var drive_response = UrlFetchApp.fetch(url, {
'headers':{
Authorization:auth_token
},
muteHttpExceptions:true
});
var drive_data = JSON.parse(drive_response);
var drive_speed = drive_data.response.speed;
var drive_power = drive_data.response.power;
var drive_lat = drive_data.response.latitude;
var drive_lon = drive_data.response.longitude;
var drive_shift_state = drive_data.response.shift_state;
var drive_heading = drive_data.response.heading;
//***CLIMATE STATE***
var url = base_url + d.id_s + '/data_request/climate_state';
var climate_response = UrlFetchApp.fetch(url, {
'headers':{
Authorization:auth_token
},
muteHttpExceptions:true
});
var climate_data = JSON.parse(climate_response);
var climate_inside = climate_data.response.inside_temp;
var climate_outside = climate_data.response.outside_temp;
var climate_battery_heater = climate_data.response.battery_heater;
//*** START CHARGE STATE ***
var url = base_url + d.id_s + '/data_request/charge_state';
var charge_response = UrlFetchApp.fetch(url, {
'headers':{
Authorization:auth_token
},
muteHttpExceptions:true
});
var charge_data = JSON.parse(charge_response);
var charging_state = charge_data.response.charging_state;
var battery_level = charge_data.response.battery_level;
//var battery_current = ""; //charge_data.battery_current;
var charger_voltage = charge_data.response.charger_voltage;
var charger_actual_current = charge_data.response.charger_actual_current;
var charger_power = charge_data.response.charger_power;
var charge_energy_added = charge_data.response.charge_energy_added;
var charge_miles_added_rated = charge_data.response.charge_miles_added_rated;
var charge_miles_added_ideal = charge_data.response.charge_miles_added_ideal;
var rated_range = charge_data.response.battery_range
var est_range = charge_data.response.est_battery_range;
var ideal_range = charge_data.response.ideal_battery_range;
var implied_max_rated_range = rated_range / (battery_level / 100);
var implied_estimated_kwh_mi = ((battery_level / 100) * 72600) / est_range;
var max_range_cycles = charge_data.response.max_range_charge_counter;
var battery_heater_on = charge_data.response.battery_heater_on;
var trip_charging = charge_data.response.trip_charging;
var fast_charger = charge_data.response.fast_charger_present;
var usable_battery_level = charge_data.response.usable_battery_level;
var not_enough_power_to_heat = charge_data.response.not_enough_power_to_heat;
var time_to_full_charge = charge_data.response.time_to_full_charge;
var charge_limit_soc = charge_data.response.charge_limit_soc;
//*** END CHARGE STATE ***
//Create new sheet for new Car Name if it doesn't already exist
try {
sheet.setActiveSheet(sheet.getSheetByName(name));
} catch (e) {
sheet.insertSheet(name);
}
var data_sheet = sheet.getSheetByName(name);
data_sheet.appendRow([today,
timestamp,
name,
miles,
version,
rated_range,
est_range,
ideal_range,
charging_state,
battery_level,
//battery_current,
charger_voltage,
charger_actual_current,
charger_power,
charge_energy_added,
charge_miles_added_rated,
charge_miles_added_ideal,
battery_heater_on,
max_range_cycles,
charge_limit_soc,
trip_charging,
fast_charger,
usable_battery_level,
not_enough_power_to_heat,
time_to_full_charge,
implied_max_rated_range,
implied_estimated_kwh_mi,
drive_shift_state,
drive_speed,
drive_power,
drive_lat,
drive_lon,
drive_heading,
climate_inside,
climate_outside,
climate_battery_heater
]);
});
}
@k-hos
Copy link

k-hos commented Dec 28, 2020

Have you confirmed that this script does not actually wake the vehicle if it is sleeping and that it doesn't keep the vehicle awake if it's not already asleep (I suppose an hourly trigger should be sufficiently slow to deal with this 2nd case)

@Woekje
Copy link

Woekje commented Jan 20, 2021

I have the same problem, getting a 401 when getting the vehicle list. The token seems to be valid. I think the car doesn't need to be awake for the vehicle list, but in any case I made sure it was awake.
Any ideas?

Update, I added User-Agent and X-Tesla-User-Agent headers, and also used a different too4l to get a token, and now it works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment