teslajs
Version:
Full-featured Tesla REST API NodeJS package
2,156 lines • 68.1 kB
JavaScript
/**
* @file This is a Node.js module encapsulating the unofficial Tesla API set
*
* Github: https://github.com/mseminatore/TeslaJS
* NPM: https://www.npmjs.com/package/teslajs
*
* @copyright Copyright (c) 2016 Mark Seminatore
*
* @license MIT
*
* Refer to included LICENSE file for usage rights and restrictions
*/
"use strict";
var request = require('request').defaults({
headers: {
"x-tesla-user-agent": "TeslaApp/3.4.4-350/fad4a582e/android/8.1.0",
"user-agent": "Mozilla/5.0 (Linux; Android 8.1.0; Pixel XL Build/OPM4.171019.021.D1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36"
},
json: true,
gzip: true,
body: {}
});
var Promise = require('promise');
var websocket = require('ws');
//=======================
// Streaming API portal
//=======================
/**
* @global
* @default
*/
var streamingPortal = "wss://streaming.vn.teslamotors.com/streaming/";
exports.streamingPortal = streamingPortal;
var streamingBaseURI = process.env.TESLAJS_STREAMING || streamingPortal;
//===========================
// New OAuth-based API portal
//===========================
/**
* @global
* @default
*/
var portal = "https://owner-api.teslamotors.com";
exports.portal = portal;
var portalBaseURI = process.env.TESLAJS_SERVER || portal;
//=======================
// Log levels
//=======================
/**
* @global
* @default
*/
var API_LOG_ALWAYS = 0;
exports.API_LOG_ALWAYS = API_LOG_ALWAYS;
/**
* @global
* @default
*/
var API_ERR_LEVEL = 1;
exports.API_ERR_LEVEL = API_ERR_LEVEL;
/**
* @global
* @default
*/
var API_CALL_LEVEL = 2;
exports.API_CALL_LEVEL = API_CALL_LEVEL;
/**
* @global
* @default
*/
var API_RETURN_LEVEL = 3;
exports.API_RETURN_LEVEL = API_RETURN_LEVEL;
/**
* @global
* @default
*/
var API_BODY_LEVEL = 4;
exports.API_BODY_LEVEL = API_BODY_LEVEL;
/**
* @global
* @default
*/
var API_REQUEST_LEVEL = 5;
exports.API_REQUEST_LEVEL = API_REQUEST_LEVEL;
/**
* @global
* @default
*/
var API_RESPONSE_LEVEL = 6;
exports.API_RESPONSE_LEVEL = API_RESPONSE_LEVEL;
/**
* @global
* @default
*/
var API_LOG_ALL = 255; // this value must be the last
exports.API_LOG_ALL = API_LOG_ALL;
var logLevel = process.env.TESLAJS_LOG || 0;
/**
* Node-style callback function
* @callback nodeBack
* @param {function} error - function which receives the error result
* @param {function} data - function which receives the data result
*/
/**
* TeslaJS options parameter
* @typedef optionsType
* @type {object}
* @property {string} authToken - Tesla provided OAuth token
* @property {string} vehicleID - Tesla provided long vehicle id
* @property {?int} [carIndex] - index of vehicle within vehicles JSON
*/
/*
* Adjustable console logging
* @param {int} level - logging level
* @param {string} str - text to log
*/
function log(level, str) {
if (logLevel < level) {
return;
}
// console.log("[" + new Date().toISOString() + "] " + str);
console.log(str);
}
/*
* Ensure value is within [min..max]
*/
function clamp(value, min, max) {
if (value < min) {
value = min;
}
if (value > max) {
value = max;
}
return value;
}
/**
* Set the current logging level
* @param {int} level - logging level
*/
exports.setLogLevel = function setLogLevel(level) {
logLevel = level;
}
/**
* Get the current logging level
* @return {int} the current logging level
*/
exports.getLogLevel = function getLogLevel() {
return logLevel;
}
/**
* Set the portal base URI
* @param {string} uri - URI for Tesla servers
*/
exports.setPortalBaseURI = function setPortalBaseURI(uri) {
if (!uri) {
portalBaseURI = portal; // reset to the default Tesla servers
} else {
portalBaseURI = uri;
}
}
/**
* Get the portal base URI
* @return {string} URI for Tesla servers
*/
exports.getPortalBaseURI = function getPortalBaseURI() {
return portalBaseURI;
}
/**
* Set the streaming base URI
* @param {string} uri - URI for Tesla streaming servers
*/
exports.setStreamingBaseURI = function setStreamingBaseURI(uri) {
if (!uri) {
streamingBaseURI = streamingPortal; // reset to the default Tesla servers
} else {
streamingBaseURI = uri;
}
}
/**
* Get the streaming base URI
* @return {string} URI for Tesla streaming servers
*/
exports.getStreamingBaseURI = function getStreamingBaseURI() {
return streamingBaseURI;
}
/**
* Return the car model from vehicle JSON information
* @param {object} vehicle - vehicle JSON
* @return {string} vehicle model string
*/
exports.getModel = function getModel(vehicle) {
var result = exports.vinDecode(vehicle);
return result.carType;
}
/**
* Return an object containing properties decoded from the vehicle VIN
* @param {object} vehicle - vehicle JSON
* @return {object} vehicle properties
*/
exports.vinDecode = function vinDecode(vehicle) {
var result = {
carType: "Model S",
awd: false,
year: 2012
};
if (!vehicle || !vehicle.vin) {
return result;
}
var dateCode = vehicle.vin.charCodeAt(9);
result.year = 2010 + dateCode - 'A'.charCodeAt(0);
// handle the skipped 'I' code. We may also need to skip 'O'
if (dateCode > 73) {
result.year--;
}
var model = vehicle.vin.charAt(3);
switch (model) {
case "S":
result.carType = "Model S";
break;
case "3":
result.carType = "Model 3";
break;
case "X":
result.carType = "Model X";
break;
case "Y":
result.carType = "Model Y";
break;
case "R":
result.carType = "Roadster";
break;
}
// Check for AWD config 2, 4 or B
if (
vehicle.vin.charAt(7) == "2" || // Dual Motor (standard) (Designated for Model S & Model X)
vehicle.vin.charAt(7) == "4" || // Dual Motor (performance) (Designated for Model S & Model X)
vehicle.vin.charAt(7) == "B" || // Dual motor - standard Model 3
vehicle.vin.charAt(7) == "C" || // Dual motor - performance Model 3
vehicle.vin.charAt(7) == "E" // Dual motor - Model Y
) {
result.awd = true;
}
return result;
}
/**
* Return the paint color from vehicle JSON information
* @param {object} vehicle - vehicle JSON
* @return {string} the vehicle paint color
*/
exports.getPaintColor = function getPaintColor(vehicle) {
var colors = {
"PBCW": "white",
"PBSB": "black",
"PMAB": "metallic brown",
"PMBL": "metallic black",
"PMMB": "metallic blue",
"PMMR": "multi-coat red",
"PPMR": "multi-coat red",
"PMNG": "steel grey",
"PMSG": "metallic green",
"PMSS" : "metallic silver",
"PPSB": "ocean blue",
"PPSR" : "signature red", //premium signature red"
"PPSW": "pearl white",
"PPTI": "titanium",
"PMTG": "metallic grey" // dolphin grey
};
var paintColor = vehicle.option_codes.match(/PBCW|PBSB|PMAB|PMBL|PMMB|PMMR|PPMR|PMNG|PMSG|PMSS|PPSB|PPSR|PPSW|PPTI|PMTG/);
return colors[paintColor] || "black";
}
/**
* Return the vehicle VIN from vehicle JSON information
* @param {object} vehicle - vehicle JSON
* @return {string} the vehicle VIN
*/
exports.getVin = function getVin(vehicle) {
if (!vehicle || !vehicle.vin) {
throw new Error("invalid parameter");
}
return vehicle.vin;
}
/**
* Return the vehicle VIN from vehicle JSON information
* @param {object} vehicle - vehicle JSON
* @return {string} the short version of the vehicle VIN
*/
exports.getShortVin = function getShortVin(vehicle) {
if (!vehicle || !vehicle.vin) {
throw new Error("invalid parameter");
}
return vehicle.vin.substr(11);
}
/**
* Login to the server and receive OAuth tokens
* @function login
* @param {Object} credentials - object of Tesla credentials
* @param {string} credentials.username - email address used on Tesla.com
* @param {string} credentials.password - password used on Tesla.command
* @param {string} credentials.mfaPassCode - MFA password
* @param {string} credentials.mfaDeviceName - MFA device name
* @param {nodeBack} callback - Node-style callback
* @returns {object} {response, body, authToken, refreshToken}
*/
exports.login = function login(credentials, callback) {
log(API_CALL_LEVEL, "TeslaJS.login()");
// Compatibility with old username/password API
if (typeof arguments[0] == 'string' && typeof arguments[1] == 'string') {
credentials = {username: arguments[0], password: arguments[1]};
callback = arguments[2];
}
credentials = credentials || {};
callback = callback || function (err, result) { /* do nothing! */ }
if (!credentials.username || !credentials.password) {
callback("login() requires username and password", null);
return;
}
require('./src/auth').login({identity: credentials.username, credential: credentials.password, mfaPassCode: credentials.mfaPassCode, mfaDeviceName: credentials.mfaDeviceName}, function (error, response, body) {
log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response));
log(API_RESPONSE_LEVEL, "\nBody: " + JSON.stringify(body));
var loginResult = body || {};
callback(error, { error: error, response: response, body: body, authToken: loginResult.access_token, refreshToken: loginResult.refresh_token });
log(API_RETURN_LEVEL, "TeslaJS.login() completed.");
});
}
/**
* Login to the server and receive OAuth tokens
* @function loginAsync
* @param {Object} credentials - object of Tesla credentials
* @param {string} credentials.username - email address used on Tesla.com
* @param {string} credentials.password - password used on Tesla.command
* @param {string} credentials.mfaPassCode - MFA password
* @param {string} credentials.mfaDeviceName - MFA device name
* @returns {Promise} {response, body, authToken, refreshToken}
*/
exports.loginAsync = Promise.denodeify(exports.login);
/**
* Retrieve new OAuth and refresh tokens using a refresh_token
* @param {string} refresh_token - a valid OAuth refresh_token from a previous login
* @param {nodeBack} callback - Node-style callback
* @returns {object} {response, body, authToken, refreshToken}
*/
exports.refreshToken = function refreshToken(refresh_token, callback) {
log(API_CALL_LEVEL, "TeslaJS.refreshToken()");
callback = callback || function (err, result) { /* do nothing! */ }
if (!refresh_token) {
callback("refreshToken() requires a refresh_token", null);
return;
}
var req = {
method: 'POST',
url: portalBaseURI + '/oauth/token',
body: {
"grant_type": "refresh_token",
"refresh_token": refresh_token
}
};
log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req));
request(req, function (error, response, body) {
log(API_RESPONSE_LEVEL, "\nResponse: " + body);
callback(error, { error: error, response: response, body: JSON.stringify(body), authToken: body.access_token, refreshToken: body.refresh_token });
log(API_RETURN_LEVEL, "TeslaJS.refreshToken() completed.");
});
}
/**
* Async call to retrieve new OAuth and refresh tokens using a refresh_token
* @function refreshTokenAsync
* @param {string} refresh_token - a valid OAuth refresh_token from a previous login
* @returns {Promise} {response, body, authToken, refreshToken}
*/
exports.refreshTokenAsync = Promise.denodeify(exports.refreshToken);
/**
* Logout and invalidate the current auth token
* @param {string} authToken - Tesla provided OAuth token
* @param {nodeBack} callback - Node-style callback
*/
exports.logout = function logout(authToken, callback) {
log(API_CALL_LEVEL, "TeslaJS.logout()");
callback = callback || function (err, result) { /* do nothing! */ }
request({
method: 'POST',
url: portalBaseURI + '/oauth/revoke',
headers: { Authorization: "Bearer " + authToken, 'Content-Type': 'application/json; charset=utf-8' }
}, function (error, response, body) {
callback(error, { error: error, response: response, body: JSON.stringify(body) });
log(API_RETURN_LEVEL, "TeslaJS.logout() completed.");
});
}
/**
* Logout and invalidate the current auth token
* @function logoutAsync
* @param {string} authToken - Tesla provided OAuth token
* @returns {Promise} result
*/
exports.logoutAsync = Promise.denodeify(exports.logout);
/**
* Return vehicle information on the requested vehicle
* @function vehicle
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {Vehicle} vehicle JSON data
*/
exports.vehicle = function vehicle(options, callback) {
log(API_CALL_LEVEL, "TeslaJS.vehicle()");
callback = callback || function (err, vehicle) { /* do nothing! */ }
var req = {
method: 'GET',
url: portalBaseURI + '/api/1/vehicles',
headers: { Authorization: "Bearer " + options.authToken, 'Content-Type': 'application/json; charset=utf-8' }
};
log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req));
request(req, function (error, response, body) {
if (error) {
log(API_ERR_LEVEL, error);
return callback(error, null);
}
if (response.statusCode != 200) {
return callback(response.statusMessage, null);
}
log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body));
log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response));
try {
body = body.response[options.carIndex || 0];
body.id = body.id_s;
options.vehicleID = body.id;
callback(null, body);
} catch (e) {
log(API_ERR_LEVEL, 'Error parsing vehicles response');
callback(e, null);
}
log(API_RETURN_LEVEL, "\nGET request: " + "/vehicles" + " completed.");
});
}
/**
* Return vehicle information on the requested vehicle
* @function vehicleAsync
* @param {optionsType} options - options object
* @returns {Promise} vehicle JSON data
*/
exports.vehicleAsync = Promise.denodeify(exports.vehicle);
/**
* Return vehicle information on the requested vehicle. Uses options.vehicleID
* to determine which vehicle to fetch data for.
* @function vehicleById
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {Vehicle} vehicle JSON data
*/
exports.vehicleById = function vehicle(options, callback) {
log(API_CALL_LEVEL, "TeslaJS.vehicleById()");
callback = callback || function (err, vehicle) { /* do nothing! */ }
var req = {
method: 'GET',
url: portalBaseURI + '/api/1/vehicles/' + options.vehicleID,
headers: { Authorization: "Bearer " + options.authToken, 'Content-Type': 'application/json; charset=utf-8' }
};
log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req));
request(req, function (error, response, body) {
if (error) {
log(API_ERR_LEVEL, error);
return callback(error, null);
}
if (response.statusCode != 200) {
return callback(response.statusMessage, null);
}
log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body));
log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response));
try {
body = body.response;
callback(null, body);
} catch (e) {
log(API_ERR_LEVEL, 'Error parsing vehicle response');
callback(e, null);
}
log(API_RETURN_LEVEL, "\nGET request: " + "/vehicles/" + options.vehicleID + " completed.");
});
}
/**
* Return vehicle information on the requested vehicle. Uses options.vehicleID
* to determine which vehicle to fetch data for.
* @function vehicleByIdAsync
* @param {optionsType} options - options object
* @returns {Promise} vehicle JSON data
*/
exports.vehicleByIdAsync = Promise.denodeify(exports.vehicleById);
/**
* Return vehicle information on ALL vehicles
* @function vehicles
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {Vehicles[]} array of vehicle JSON data
*/
exports.vehicles = function vehicles(options, callback) {
log(API_CALL_LEVEL, "TeslaJS.vehicles()");
callback = callback || function (err, vehicle) { /* do nothing! */ }
var req = {
method: 'GET',
url: portalBaseURI + '/api/1/vehicles',
headers: { Authorization: "Bearer " + options.authToken, 'Content-Type': 'application/json; charset=utf-8' }
};
log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req));
request(req, function (error, response, body) {
if (error) {
log(API_ERR_LEVEL, error);
return callback(error, null);
}
if (response.statusCode != 200) {
return callback(response.statusMessage, null);
}
log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body));
log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response));
try {
body = body.response;
callback(null, body);
} catch (e) {
log(API_ERR_LEVEL, 'Error parsing vehicles response');
callback(e, null);
}
log(API_RETURN_LEVEL, "\nGET request: " + "/vehicles" + " completed.");
});
}
/**
* Return vehicle information on ALL vehicles
* @function vehiclesAsync
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {Promise} array of vehicle JSON data
*/
exports.vehiclesAsync = Promise.denodeify(exports.vehicles);
/**
* Generic REST call for GET commands
* @function get_command
* @param {optionsType} options - options object
* @param {string} command - REST command
* @param {nodeBack} callback - Node-style callback
*/
exports.get_command = get_command;
function get_command(options, command, callback) {
log(API_CALL_LEVEL, "GET call: " + command + " start.");
callback = callback || function (err, data) { /* do nothing! */ }
var req = {
method: "GET",
url: portalBaseURI + "/api/1/vehicles/" + options.vehicleID + "/" + command,
headers: { Authorization: "Bearer " + options.authToken, 'Content-Type': 'application/json; charset=utf-8'}
};
log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req));
request(req, function (error, response, body) {
if (error) {
log(API_ERR_LEVEL, error);
return callback(error, null);
}
if (response.statusCode != 200) {
var str = "Error response: " + response.statusCode;
log(API_ERR_LEVEL, str);
return callback(str, null);
}
log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body));
log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response));
try {
body = body.response;
callback(null, body);
} catch (e) {
log(API_ERR_LEVEL, 'Error parsing GET call response');
log(API_ERR_LEVEL, e);
callback(e, null);
}
log(API_RETURN_LEVEL, "\nGET request: " + command + " completed.");
});
}
/**
* Generic Async REST call for GET commands
* @function get_commandAsync
* @param {optionsType} options - options object
* @param {string} command - REST command
* @returns {Promise} result
*/
exports.get_commandAsync = Promise.denodeify(exports.get_command);
/**
* Generic REST call for POST commands
* @function
* @param {optionsType} options - options object
* @param {string} command - REST command
* @param {object} body - JSON payload
* @param {nodeBack} callback - Node-style callback
*/
exports.post_command = post_command;
function post_command(options, command, body, callback) {
log(API_CALL_LEVEL, "POST call: " + command + " start.");
callback = callback || function (err, data) { /* do nothing! */ }
var cmd = {
method: "POST",
url: portalBaseURI + "/api/1/vehicles/" + options.vehicleID + "/" + command,
headers: { Authorization: "Bearer " + options.authToken, 'content-type': 'application/json; charset=UTF-8' },
body: body || null
};
log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(cmd));
request(cmd, function (error, response, body) {
if (error) {
log(API_ERR_LEVEL, error);
return callback(error, null);
}
if (response.statusCode != 200) {
var str = "Error response: " + response.statusCode;
log(API_ERR_LEVEL, str);
return callback(str, null);
}
log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body));
log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response));
try {
body = body.response;
callback(null, body);
} catch (e) {
log(API_ERR_LEVEL, 'Error parsing POST call response');
callback(e, null);
}
log(API_RETURN_LEVEL, "\nPOST command: " + command + " completed.");
});
}
/**
* Generic Async REST call for POST commands
* @function post_commandAsync
* @param {optionsType} options - options object
* @param {string} command - REST command
* @param {object} body - JSON payload
* @returns {Promise} result
*/
exports.post_commandAsync = Promise.denodeify(exports.post_command);
/**
* GET all vehicle data in a single call
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} vehicle_data object
*/
exports.vehicleData = function vehicleData(options, callback){
get_command(options, "vehicle_data", callback);
}
/**
* Async version to GET all vehicle data in a single call
* @function vehicleDataAsync
* @param {optionsType} options - options object
* @returns {Promise} vehicle_data object
*/
exports.vehicleDataAsync = Promise.denodeify(exports.vehicleData);
/**
* GET the vehicle config
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} vehicle_config object
*/
exports.vehicleConfig = function vehicleConfig(options, callback) {
get_command(options, "data_request/vehicle_config", callback);
}
/**
* Async version to GET the vehicle config
* @function vehicleConfigAsync
* @param {optionsType} options - options object
* @returns {Promise} vehicle_config object
*/
exports.vehicleConfigAsync = Promise.denodeify(exports.vehicleConfig);
/**
* GET the vehicle state
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} vehicle_state object
*/
exports.vehicleState = function vehicleState(options, callback) {
get_command(options, "data_request/vehicle_state", callback);
}
/**
* Async version to GET the vehicle state
* @function vehicleStateAsync
* @param {optionsType} options - options object
* @returns {Promise} vehicle_state object
*/
exports.vehicleStateAsync = Promise.denodeify(exports.vehicleState);
/**
* GET the climate state
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} climate_state object
*/
exports.climateState = function climateState(options, callback) {
get_command(options, "data_request/climate_state", callback);
}
/**
* GET the climate state
* @function climateStateAsync
* @param {optionsType} options - options object
* @returns {Promise} climate_state object
*/
exports.climateStateAsync = Promise.denodeify(exports.climateState);
/**
* GET nearby charging sites
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} climate_state object
*/
exports.nearbyChargers = function nearbyChargers(options, callback) {
get_command(options, "nearby_charging_sites", callback);
}
/**
* @function nearbyChargersAsync
* @param {optionsType} options - options object
* @returns {Promise} climate_state object
*/
exports.nearbyChargersAsync = Promise.denodeify(exports.nearbyChargers);
/**
* GET the drive state
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} drive_state object
*/
exports.driveState = function driveState(options, callback) {
get_command(options, "data_request/drive_state", callback);
}
/**
* @function driveStateAsync
* @param {optionsType} options - options object
* @returns {Promise} drive_state object
*/
exports.driveStateAsync = Promise.denodeify(exports.driveState);
/**
* GET the charge state
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} charge_state object
*/
exports.chargeState = function chargeState(options, callback) {
get_command(options, "data_request/charge_state", callback);
}
/**
* @function chargeStateAsync
* @param {optionsType} options - options object
* @returns {Promise} charge_state object
*/
exports.chargeStateAsync = Promise.denodeify(exports.chargeState);
/**
* GET the GUI settings
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} gui_settings object
*/
exports.guiSettings = function guiSettings(options, callback) {
get_command(options, "data_request/gui_settings", callback);
}
/**
* @function guiSettingsAsync
* @param {optionsType} options - options object
* @returns {Promise} gui_settings object
*/
exports.guiSettingsAsync = Promise.denodeify(exports.guiSettings);
/**
* GET the mobile enabled status
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} mobile_enabled object
*/
exports.mobileEnabled = function mobileEnabled(options, callback) {
get_command(options, "mobile_enabled", callback);
}
/**
* @function mobileEnabledAsync
* @param {optionsType} options - options object
* @returns {Promise} mobile_enabled object
*/
exports.mobileEnabledAsync = Promise.denodeify(exports.mobileEnabled);
/**
* Honk the horn
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.honkHorn = function honk(options, callback) {
post_command(options, "command/honk_horn", null, callback);
}
/**
* @function honkHornAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.honkHornAsync = Promise.denodeify(exports.honkHorn);
/**
* Flash the lights
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.flashLights = function flashLights(options, callback) {
post_command(options, "command/flash_lights", null, callback);
}
/**
* @function flashLightsAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.flashLightsAsync = Promise.denodeify(exports.flashLights);
/**
* Start charging the car
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.startCharge = function startCharge(options, callback) {
post_command(options, "command/charge_start", null, callback);
}
/**
* Start charging the car
* @function startChargeAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.startChargeAsync = Promise.denodeify(exports.startCharge);
/**
* Stop charging the car
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.stopCharge = function stopCharge(options, callback) {
post_command(options, "command/charge_stop", null, callback);
}
/**
* Stop charging the car
* @function stopChargeAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.stopChargeAsync = Promise.denodeify(exports.stopCharge);
/**
* Open the charge port, or releases the latch if the charge port is open, a cable is plugged in, and charging is stopped
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.openChargePort = function openChargePort(options, callback) {
post_command(options, "command/charge_port_door_open", null, callback);
}
/**
* Open the charge port, or releases the latch if the charge port is open, a cable is plugged in, and charging is stopped
* @function openChargePortAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.openChargePortAsync = Promise.denodeify(exports.openChargePort);
/**
* Close the charge port for appropriately equipped vehicles
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.closeChargePort = function closeChargePort(options, callback) {
post_command(options, "command/charge_port_door_close", null, callback);
}
/**
* Close the charge port for appropriately equipped vehicles
* @function closeChargePortAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.closeChargePortAsync = Promise.denodeify(exports.closeChargePort);
/**
* Schedule a firmware update
* @function scheduleSoftwareUpdate
* @param {optionsType} options - options object
* @param {number} offset - delay in ms before installation begins
* @returns {object} result
*/
exports.scheduleSoftwareUpdate = function scheduleSoftwareUpdate(options, offset, callback) {
post_command(options, "command/schedule_software_update", { "offset_sec": offset }, callback);
}
/**
* Schedule a firmware update
* @function scheduleSoftwareUpdateAsync
* @param {optionsType} options - options object
* @param {number} offset - delay in ms before installation begins
* @returns {Promise} result
*/
exports.scheduleSoftwareUpdateAsync = Promise.denodeify(exports.scheduleSoftwareUpdate);
/**
* Cancel a scheduled software update
* @function cancelSoftwareUpdate
* @param {optionsType} options - options object
* @returns {object} result
*/
exports.cancelSoftwareUpdate = function cancelSoftwareUpdate(options, callback) {
post_command(options, "command/cancel_software_update", null, callback);
}
/**
* Cancel a scheduled software update
* @function cancelSoftwareUpdateAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.cancelSoftwareUpdateAsync = Promise.denodeify(exports.cancelSoftwareUpdate);
/**
* Send a navigation request to the car
* @function navigationRequest
* @param {optionsType} options - options object
* @param {string} subject - short-hand name for the destination
* @param {string} text - address details including things like name, address, map link
* @param {string} locale - the language locale, for example "en-US"
* @returns {object} result
*/
exports.navigationRequest = function navigationRequest(options, subject, text, locale, callback) {
var req =
{
"type": "share_ext_content_raw",
"value": {
"android.intent.ACTION": "android.intent.action.SEND",
"android.intent.TYPE": "text\/plain",
"android.intent.extra.SUBJECT": subject,
"android.intent.extra.TEXT": text
},
"locale": locale,
"timestamp_ms": Date.now()
};
post_command(options, "command/navigation_request", req, callback);
}
/**
* Send a navigation request to the car
* @function navigationRequestAsync
* @param {optionsType} options - options object
* @param {string} subject - short-hand name for the destination
* @param {string} text - address details including things like name, address, map link
* @param {string} locale - the language locale, for example "en-US"
* @returns {Promise} result
*/
exports.navigationRequestAsync = Promise.denodeify(exports.navigationRequest);
/**
* Toggle media playback
* @function mediaTogglePlayback
* @param {optionsType} options - options object
* @returns {object} result
*/
exports.mediaTogglePlayback = function mediaTogglePlayback(options, callback) {
post_command(options, "command/media_toggle_playback", null, callback);
}
/**
* Toggle media playback
* @function mediaTogglePlaybackAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.mediaTogglePlaybackAsync = Promise.denodeify(exports.mediaTogglePlayback);
/**
* Media play next track
* @function mediaPlayNext
* @param {optionsType} options - options object
* @returns {object} result
*/
exports.mediaPlayNext = function mediaPlayNext(options, callback) {
post_command(options, "command/media_next_track", null, callback);
}
/**
* Media play next track
* @function mediaPlayNextAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.mediaPlayNextAsync = Promise.denodeify(exports.mediaPlayNext);
/**
* Media play previous track
* @function mediaPlayPrevious
* @param {optionsType} options - options object
* @returns {object} result
*/
exports.mediaPlayPrevious = function mediaPlayPrevious(options, callback) {
post_command(options, "command/media_prev_track", null, callback);
}
/**
* Media play previous track
* @function mediaPlayPreviousAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.mediaPlayPreviousAsync = Promise.denodeify(exports.mediaPlayPrevious);
/**
* Media play next favorite
* @function mediaPlayNextFavorite
* @param {optionsType} options - options object
* @returns {object} result
*/
exports.mediaPlayNextFavorite = function mediaPlayNextFavorite(options, callback) {
post_command(options, "command/media_next_fav", null, callback);
}
/**
* Media play next favorite
* @function mediaPlayNextFavoriteAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.mediaPlayNextFavoriteAsync = Promise.denodeify(exports.mediaPlayNextFavorite);
/**
* Media play previous favorite
* @function mediaPlayPreviousFavorite
* @param {optionsType} options - options object
* @returns {object} result
*/
exports.mediaPlayPreviousFavorite = function mediaPlayPreviousFavorite(options, callback) {
post_command(options, "command/media_prev_fav", null, callback);
}
/**
* Media play previous favorite
* @function mediaPlayPreviousFavoriteAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.mediaPlayPreviousFavoriteAsync = Promise.denodeify(exports.mediaPlayPreviousFavorite);
/**
* Media volume up
* @function mediaVolumeUp
* @param {optionsType} options - options object
* @returns {object} result
*/
exports.mediaVolumeUp = function mediaVolumeUp(options, callback) {
post_command(options, "command/media_volume_up", null, callback);
}
/**
* Media volume up
* @function mediaVolumeUpAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.mediaVolumeUpAsync = Promise.denodeify(exports.mediaVolumeUp);
/**
* Media volume down
* @function mediaVolumeDown
* @param {optionsType} options - options object
* @returns {object} result
*/
exports.mediaVolumeDown = function mediaVolumeDown(options, callback) {
post_command(options, "command/media_volume_down", null, callback);
}
/**
* Media volume down
* @function mediaVolumeDownAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.mediaVolumeDownAsync = Promise.denodeify(exports.mediaVolumeDown);
/**
* Activate speed limitation
* @function speedLimitActivate
* @param {optionsType} options - options object
* @param {number} pin - Activation pin code. Not the same as valet pin
* @returns {object} result
*/
exports.speedLimitActivate = function speedLimitActivate(options, pin, callback) {
post_command(options, "command/speed_limit_activate", { pin: pin }, callback);
}
/**
* Activate speed limitation
* @function speedLimitActivateAsync
* @param {optionsType} options - options object
* @param {number} pin - Activation pin code. Not the same as valet pin
* @returns {Promise} result
*/
exports.speedLimitActivateAsync = Promise.denodeify(exports.speedLimitActivate);
/**
* Deactivate speed limitation
* @function speedLimitDeactivate
* @param {optionsType} options - options object
* @param {number} pin - Activation pin code. Not the same as valet pin
* @returns {object} result
*/
exports.speedLimitDeactivate = function speedLimitDeactivate(options, pin, callback) {
post_command(options, "command/speed_limit_deactivate", { pin: pin }, callback);
}
/**
* Deactivate speed limitation
* @function speedLimitDeactivateAsync
* @param {optionsType} options - options object
* @param {number} pin - Activation pin code. Not the same as valet pin
* @returns {Promise} result
*/
exports.speedLimitDeactivateAsync = Promise.denodeify(exports.speedLimitDeactivate);
/**
* Clear speed limitation pin
* @function speedLimitClearPin
* @param {optionsType} options - options object
* @param {number} pin - Activation pin code. Not the same as valet pin
* @returns {object} result
*/
exports.speedLimitClearPin = function speedLimitClearPin(options, pin, callback) {
post_command(options, "command/speed_limit_clear_pin", { pin: pin }, callback);
}
/**
* Clear speed limitation pin
* @function speedLimitClearPinAsync
* @param {optionsType} options - options object
* @param {number} pin - Activation pin code. Not the same as valet pin
* @returns {Promise} result
*/
exports.speedLimitClearPinAsync = Promise.denodeify(exports.speedLimitClearPin);
/**
* Set speed limit
* @function speedLimitSetLimit
* @param {optionsType} options - options object
* @param {number} limit - Speed limit in mph
* @returns {object} result
*/
exports.speedLimitSetLimit = function speedLimitSetLimit(options, limit, callback) {
post_command(options, "command/speed_limit_set_limit", { limit_mph: limit }, callback);
}
/**
* Set speed limit
* @function speedLimitSetLimitAsync
* @param {optionsType} options - options object
* @param {number} limit - Speed limit in mph
* @returns {Promise} result
*/
exports.speedLimitSetLimitAsync = Promise.denodeify(exports.speedLimitSetLimit);
/**
* Enable or disable sentry mode
* @function setSentryMode
* @param {optionsType} options - options object
* @param {boolean} onoff - true to turn on sentry mode, false to turn off
* @returns {object} result
*/
exports.setSentryMode = function setSentryMode(options, onoff, callback) {
post_command(options, "command/set_sentry_mode", { on: onoff }, callback);
}
/**
* Enable or disable sentry mode
* @function setSentryModeAsync
* @param {boolean} onoff - true to turn on sentry mode, false to turn off
* @returns {Promise} result
*/
exports.setSentryModeAsync = Promise.denodeify(exports.setSentryMode);
/**
* Remote seat heater
* @function seatHeater
* @param {optionsType} options - options object
* @param {number} heater - Which heater to adjust (0-5)
* @param {number} level - Level for the heater (0-3)
* @returns {object} result
*/
exports.seatHeater = function seatHeater(options, heater, level, callback) {
post_command(options, "command/remote_seat_heater_request", { "heater": heater, "level": level }, callback);
}
/**
* Remote seat heater
* @function seatHeaterAsync
* @param {optionsType} options - options object
* @param {number} heater - Which heater to adjust (0-5)
* @param {number} level - Level for the heater (0-3)
* @returns {Promise} result
*/
exports.seatHeaterAsync = Promise.denodeify(exports.seatHeater);
/**
* Remote steering heater
* @function steeringHeater
* @param {optionsType} options - options object
* @param {number} level - Level for the heater (0-3)
* @returns {object} result
*/
exports.steeringHeater = function steeringHeater(options, level, callback) {
post_command(options, "command/remote_steering_wheel_heater_request", { "on": level }, callback);
}
/**
* Remote steering heater
* @function seatHeaterAsync
* @param {optionsType} options - options object
* @param {number} level - Level for the heater (0-3)
* @returns {Promise} result
*/
exports.steeringHeaterAsync = Promise.denodeify(exports.steeringHeater);
/**
* Max Defrost
* @function maxDefrost
* @param {optionsType} options - options object
* @param {boolean} onoff - true for on, false for off
* @returns {object} result
*/
exports.maxDefrost = function maxDefrost(options, onoff, callback) {
post_command(options, "command/set_preconditioning_max", { "on": onoff }, callback);
}
/**
* Remote steering heater
* @function maxDefrostAsync
* @param {optionsType} options - options object
* @param {boolean} onoff - true for on, false for off
* @returns {Promise} result
*/
exports.maxDefrostAsync = Promise.denodeify(exports.maxDefrost);
/**
* Window control
* @function windowControl
* @param {optionsType} options - options object
* @param {string} command - Allowable values are 'vent' and 'close'
* @param {number} lat - User latitude (can be 0 if not 'close' command)
* @param {number} lon - User longitude (can be 0 if not 'close' command)
* @returns {object} result
*/
exports.windowControl = function windowControl(options, command, lat, lon, callback) {
post_command(options, "command/window_control", { "command": command, "lat":lat || 0, "lon":lon || 0 }, callback);
}
/**
* Window control
* @function windowControlAsync
* @param {optionsType} options - options object
* @param {string} command - Allowable values are 'vent' and 'close'
* @param {number} lat - User latitude (can be 0 if not 'close' command)
* @param {number} lon - User longitude (can be 0 if not 'close' command)
* @returns {Promise} result
*/
exports.windowControlAsync = Promise.denodeify(exports.windowControl);
//=====================
// Charge limit constants
//=====================
/**
* @global
* @default
*/
exports.CHARGE_STORAGE = 50;
/**
* @global
* @default
*/
exports.CHARGE_DAILY = 70;
/**
* @global
* @default
*/
exports.CHARGE_STANDARD = 90;
/**
* @global
* @default
*/
exports.CHARGE_RANGE = 100;
/**
* Set the charge limit.
* Note: charging to 100% frequently is NOT recommended for long-term battery health!
* @param {optionsType} options - options object
* @param {int} amt - charge limit in percent
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.setChargeLimit = function setChargeLimit(options, amt, callback) {
amt = clamp(amt, exports.CHARGE_STORAGE, exports.CHARGE_RANGE);
post_command(options, "command/set_charge_limit", { percent: amt }, callback);
}
/**
* Set the charge limit async and return Promise.
* Note: charging to 100% frequently is NOT recommended for long-term battery health!
* @function setChargeLimitAsync
* @param {optionsType} options - options object
* @param {int} amt - charge limit in percent
* @returns {Promise} result
*/
exports.setChargeLimitAsync = Promise.denodeify(exports.setChargeLimit);
/**
* Set the charge limit to (standard) 90%
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.chargeStandard = function chargeStandard(options, callback) {
post_command(options, "command/charge_standard", null, callback);
}
/**
* @function chargeStandardAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.chargeStandardAsync = Promise.denodeify(exports.chargeStandard);
/**
* Set charge limit to 100%
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.chargeMaxRange = function chargeMaxRange(options, callback) {
post_command(options, "command/charge_max_range", null, callback);
}
/**
* @function chargeMaxRangeAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.chargeMaxRangeAsync = Promise.denodeify(exports.chargeMaxRange);
/**
* Set the charging amps.
* @param {optionsType} options - options object
* @param {int} amps - charging amps
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.setChargingAmps = function setChargingAmps(options, amps, callback) {
post_command(options, "command/set_charging_amps", { charging_amps: amps }, callback);
}
/**
* Set the charging amps async and return Promise.
* @function setChargingAmpsAsync
* @param {optionsType} options - options object
* @param {int} amps - charging amps
* @returns {Promise} result
*/
exports.setChargingAmpsAsync = Promise.denodeify(exports.setChargingAmps);
/**
* Set the scheduled charging time.
* @param {optionsType} options - options object
* @param {boolean} enable - true for on, false for off
* @param {int} time - time in minutes since midnight, 15min step
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.setScheduledCharging = function setScheduledCharging(options, enable, time, callback) {
post_command(options, "command/set_scheduled_charging", { enable: enable, time: time }, callback);
}
/**
* Set the scheduled charging time async and return Promise.
* @function setScheduledCharging
* @param {optionsType} options - options object
* @param {boolean} enable - true for on, false for off
* @param {int} time - time in minutes since midnight, 15min step
* @returns {Promise} result
*/
exports.setScheduledChargingAsync = Promise.denodeify(exports.setScheduledCharging);
/**
* Set the scheduled departure.
* @param {optionsType} options - options object
* @param {boolean} enable - true if (preconditioning_enabled || off_peak_charging_enabled), false otherwise (this condition may change in the future)
* @param {int} departure_time - time in minutes since midnight, 15min step
* @param {boolean} preconditioning_enabled - true for on, false for off
* @param {boolean} preconditioning_weekdays_only - true for on, false for off
* @param {boolean} off_peak_charging_enabled - true for on, false for off
* @param {boolean} off_peak_charging_weekdays_only - true for on, false for off
* @param {int} end_off_peak_time - time in minutes since midnight, 15min step
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.setScheduledDeparture = function setScheduledDeparture(options, enable, departure_time, preconditioning_enabled, preconditioning_weekdays_only, off_peak_charging_enabled, off_peak_charging_weekdays_only, end_off_peak_time, callback) {
post_command(options, "command/set_scheduled_departure", {
"enable":enable,
"departure_time":departure_time,
"preconditioning_enabled":preconditioning_enabled,
"preconditioning_weekdays_only":preconditioning_weekdays_only,
"off_peak_charging_enabled":off_peak_charging_enabled,
"off_peak_charging_weekdays_only":off_peak_charging_weekdays_only,
"end_off_peak_time":end_off_peak_time }, callback);
}
/**
* Set the scheduled departure async and return Promise.
* @function setScheduledDeparture
* @param {optionsType} options - options object
* @param {boolean} enable - true if (preconditioning_enabled || off_peak_charging_enabled), false otherwise (this condition may change in the future)
* @param {int} departure_time - time in minutes since midnight, 15min step
* @param {boolean} preconditioning_enabled - true for on, false for off
* @param {boolean} preconditioning_weekdays_only - true for on, false for off
* @param {boolean} off_peak_charging_enabled - true for on, false for off
* @param {boolean} off_peak_charging_weekdays_only - true for on, false for off
* @param {int} end_off_peak_time - time in minutes since midnight, 15min step
* @returns {Promise} result
*/
exports.setScheduledDepartureAsync = Promise.denodeify(exports.setScheduledDeparture);
/**
* Lock the car doors
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.doorLock = function doorLock(options, callback) {
post_command(options, "command/door_lock", null, callback);
}
/**
* @function doorLockAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.doorLockAsync = Promise.denodeify(exports.doorLock);
/**
* Unlock the car doors
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.doorUnlock = function doorUnlock(options, callback) {
post_command(options, "command/door_unlock", null, callback);
}
/**
* @function doorUnlockAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.doorUnlockAsync = Promise.denodeify(exports.doorUnlock);
/**
* Turn on HVAC system
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.climateStart = function climateStart(options, callback) {
post_command(options, "command/auto_conditioning_start", null, callback);
}
/**
* @function climateStartAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.climateStartAsync = Promise.denodeify(exports.climateStart);
/**
* Turn off HVAC system
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.climateStop = function climateStop(options, callback) {
post_command(options, "command/auto_conditioning_stop", null, callback);
}
/**
* @function climateStopAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.climateStopAsync = Promise.denodeify(exports.climateStop);
//==================================
// Set the sun roof to specific mode
//==================================
/**
* @global
* @default
*/
exports.SUNROOF_VENT = "vent";
/**
* @global
* @default
*/
exports.SUNROOF_CLOSED = "close";
/**
* Set sun roof mode
* @param {optionsType} options - options object
* @param {string} state - one of "vent", "close"
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.sunRoofControl = function sunRoofControl(options, state, callback) {
post_command(options, "command/sun_roof_control", { "state": state }, callback);
}
/**
* @function sunRoofControlAsync
* @param {optionsType} options - options object
* @param {string} state - one of "vent", "close"
* @returns {Promise} result
*/
exports.sunRoofControlAsync = Promise.denodeify(exports.sunRoofControl);
/**
* Set sun roof position
* @param {optionsType} options - options object
* @param {int} percent - position in percent
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.sunRoofMove = function sunRoofMove(options, percent, callback) {
post_command(options, "command/sun_roof_control", { "state": "move", "percent": percent }, callback);
}
/**
* @function sunRoofMoveAsync
* @param {optionsType} options - options object
* @param {int} percent - position in percent
* @returns {Promise} result
*/
exports.sunRoofMoveAsync = Promise.denodeify(exports.sunRoofMove);
//==============================================
// Temperature Limits
//==============================================
/**
* @global
* @default
*/
exports.MIN_TEMP = 15; // 59 Deg.F
/**
* @global
* @default
*/
exports.MAX_TEMP = 28; // 82.4 Deg.F
/**
* Set the driver/passenger climate temperatures
* @param {optionsType} options - options object
* @param {number} driver - driver temp in Deg.C
* @param {number} pass - passenger temp in Deg.C
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.setTemps = function setTemps(options, driver, pass, callback) {
if (!pass) {
pass = driver;
}
// ensure valid temp range
driver = clamp(driver, exports.MIN_TEMP, exports.MAX_TEMP);
pass = clamp(pass, exports.MIN_TEMP, exports.MAX_TEMP);
post_command(options, "command/set_temps", { driver_temp: driver, passenger_temp: pass }, callback);
}
/**
* @function setTempsAsync
* @param {optionsType} options - options object
* @param {number} driver - driver temp in Deg.C
* @param {number} pass - passenger temp in Deg.C
* @returns {Promise} result
*/
exports.setTempsAsync = Promise.denodeify(exports.setTemps);
/**
* Remote start the car
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.remoteStart = function remoteStartDrive(options, callback) {
post_command(options, "command/remote_start_drive", null, callback);
}
/**
* @function remoteStartAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.remoteStartAsync = Promise.denodeify(exports.remoteStart);
//=====================
// Trunk/Frunk constants
//=====================
/**
* @global
* @default
*/
exports.FRUNK = "front";
/**
* @global
* @default
*/
exports.TRUNK = "rear";
/**
* Open the trunk/frunk
* @param {optionsType} options - options object
* @param {string} which - FRUNK or TRUNK constant
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.openTrunk = function openTrunk(options, which, callback) {
post_command(options, "command/actuate_trunk", { which_trunk: which }, callback);
}
/**
* @function openTrunkAsync
* @param {optionsType} options - options object
* @param {string} which - one of "trunk", "frunk"
* @returns {Promise} result
*/
exports.openTrunkAsync = Promise.denodeify(exports.openTrunk);
/**
* Wake up a car that is sleeping
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.wakeUp = function wakeUp(options, callback) {
post_command(options, "wake_up", null, callback);
}
/**
* @function wakeUpAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.wakeUpAsync = Promise.denodeify(exports.wakeUp);
/**
* Turn valet mode on/off
* @param {optionsType} options - options object
* @param {boolean} onoff - true for on, false for off
* @param {int} pin - pin code
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.setValetMode = function setValetMode(options, onoff, pin, callback) {
post_command(options, "command/set_valet_mode", { on : onoff, password : pin }, callback);
}
/**
* @function setValetModeAsync
* @param {optionsType} options - options object
* @param {boolean} onoff - true for on, false for off
* @param {int} pin - pin code
* @returns {Promise} result
*/
exports.setValetModeAsync = Promise.denodeify(exports.setValetMode);
/**
* Reset the valet pin
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.resetValetPin = function resetValetPin(options, callback) {
post_command(options, "command/reset_valet_pin", null, callback);
}
/**
* @function resetValetPinAsync
* @param {optionsType} options - options object
* @returns {Promise} result
*/
exports.resetValetPinAsync = Promise.denodeify(exports.resetValetPin);
/**
* Set a calendar entry
* @param {optionsType} options - options object
* @param {object} entry - calendar entry object
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.calendar = function calendar(options, entry, callback) {
post_command(options, "command/upcoming_calendar_entries", entry, callback);
}
/**
* @function calendarAsync
* @param {optionsType} options - options object
* @param {object} entry - calendar entry object
* @returns {Promise} result
*/
exports.calendarAsync = Promise.denodeify(exports.calendar);
/**
* Create a calendar entry
* @param {string} eventName - name of the event
* @param {string} location - location of the event
* @param {number} startTime - Javascript timestamp for start of event
* @param {number} endTime - Javascript timestamp for end of event
* @param {string} accountName - name of the calendar account
* @param {string} phoneName - phone bluetooth name
* @returns {object} result
*/
exports.makeCalendarEntry = function makeCalendarEntry(eventName, location, startTime, endTime, accountName, phoneName) {
var entry = {
"calendar_data": {
"access_disabled": false,
"calendars": [
{
"color": "ff9a9cff",
"events": [
{
"allday": false,
"color": "ff9a9cff",
"end": endTime || new Date().getTime(),
"start": startTime || new Date().getTime(),
"cancelled": false,
"tentative": false,
"location": location || "",
"name": eventName || "Event name",
"organizer": ""
}
],
"name": accountName || "" // calendar account name?
}
],
"phone_name": phoneName, // Bluetooth name of phone
"uuid": "333239059961778" // any random value OK?
}
};
return entry;
}
/**
* Trigger homelink
* @param {optionsType} options - options object
* @param {number} lat - vehicle GPS latitude
* @param {number} long - vehicle GPS longitude
* @param {string} string - one of the tokens from vehicle JSON
* @param {nodeBack} callback - Node-style callback
* @returns {object} result
*/
exports.homelink = function homelink(options, lat, long, callback) {
post_command(options, "command/trigger_homelink", { lat: lat, lon: long } , callback);
}
/**
* @function homelinkAsync
* @param {optionsType} options - options object
* @param {number} lat - vehicle GPS latitude
* @param {number} long - vehicle GPS longitude
* @param {string} string - one of the tokens from vehicle JSON
* @returns {Promise} result
*/
exports.homelinkAsync = Promise.denodeify(exports.homelink);
/**
* Return list of products
* @function products
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {products[]} array of products JSON data
*/
exports.products = function products(options, callback) {
log(API_CALL_LEVEL, "TeslaJS.products()");
callback =
callback ||
function(err, products) {
/* do nothing! */
};
var req = {
method: "GET",
url: portalBaseURI + "/api/1/products",
headers: {
Authorization: "Bearer " + options.authToken,
"Content-Type": "application/json; charset=utf-8"
}
};
log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req));
request(req, function(error, response, body) {
if (error) {
log(API_ERR_LEVEL, error);
return callback(error, null);
}
if (response.statusCode != 200) {
return callback(response.statusMessage, null);
}
log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body));
log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response));
try {
body = body.response;
callback(null, body);
} catch (e) {
console.log(e);
log(API_ERR_LEVEL, "Error parsing products response");
callback(e, null);
}
log(API_RETURN_LEVEL, "\nGET request: " + "/products" + " completed.");
});
};
/**
* Return list of products
* @function productsAsync
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {Promise} array of products JSON data
*/
exports.productsAsync = Promise.denodeify(exports.products);
/**
* Return live status from solar installation
* @function solarStatus
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {solarStatus} solarStatus JSON data
*/
exports.solarStatus = function solarStatus(options, callback) {
log(API_CALL_LEVEL, "TeslaJS.solarStatus()");
callback =
callback ||
function(err, solarStatus) {
/* do nothing! */
};
var req = {
method: "GET",
url: portalBaseURI + "/api/1/energy_sites/" + options.siteId + "/live_status",
headers: {
Authorization: "Bearer " + options.authToken,
"Content-Type": "application/json; charset=utf-8"
}
};
log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req));
request(req, function(error, response, body) {
if (error) {
log(API_ERR_LEVEL, error);
return callback(error, null);
}
if (response.statusCode != 200) {
return callback(response.statusMessage, null);
}
log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body));
log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response));
try {
body = body.response;
callback(null, body);
} catch (e) {
log(API_ERR_LEVEL, "Error parsing solarStatus response");
callback(e, null);
}
log(API_RETURN_LEVEL, "\nGET request: " + "/solarStatus" + " completed.");
});
};
/**
* Return solar status information
* @function solarStatusAsync
* @param {optionsType} options - options object
* @param {nodeBack} callback - Node-style callback
* @returns {Promise} solar JSON data
*/
exports.solarStatusAsync = Promise.denodeify(exports.solarStatus);
/*
//
// [Alpha impl] Not yet supported
//
exports.frontDefrostOn = function frontDefrostOn(options, callback) {
post_command(options, "command/front_defrost_on", null, callback);
}
//
// [Alpha impl] Not yet supported
//
exports.frontDefrostOff = function frontDefrostOff(options, callback) {
post_command(options, "command/front_defrost_off", null, callback);
}
//
// [Alpha impl] Not yet supported
//
exports.rearDefrostOn = function rearDefrostOn(options, callback) {
post_command(options, "command/rear_defrost_on", null, callback);
}
//
// [Alpha impl] Not yet supported
//
exports.rearDefrostOff = function rearDefrostOff(options, callback) {
post_command(options, "command/rear_defrost_off", null, callback);
}
*/
//
// [Alpha impl] Auto Park
//
/*
exports.autoParkForward = function autoParkForward(options, lat, long, callback) {
autoPark(options, lat, long, "start_forward", callback);
}
exports.autoParkBackward = function autoParkBackward(options, lat, long, callback) {
autoPark(options, lat, long, "start_reverse", callback);
}
exports.autoPark = function autoPark(options, lat, long, action, callback) {
post_command(options, "command/autopark_request", { lat: lat, long: long, action: action}, callback);
}
*/
//=================================
// Available streaming data options
//=================================
/**
* @global
* @default
*/
exports.streamingColumns = ['elevation', 'est_heading', 'est_lat', 'est_lng', 'est_range', 'heading', 'odometer', 'power', 'range', 'shift_state', 'speed', 'soc'];
/**
* Start streaming car data
* @param {object} options - {username, token, vehicle_id, columns[]}
* @param {nodeBack} callback - Node-style callback
* @param {nodeBack} onDataCb - Node-style callback
* @returns {object} result
*/
exports.startStreaming = function startStreaming(options, callback, onDataCb) {
log(API_CALL_LEVEL, "TeslaJS.startStreaming()");
callback = callback || function (error, response, body) { /* do nothing! */ }
onDataCb = onDataCb || function (data) { /* do nothing! */ }
options.values = options.values || exports.streamingColumns;
var ws = new websocket(streamingBaseURI, {
perMessageDeflate: false
});
ws.on('message', function incoming(data) {
var d = JSON.parse(data);
if (d.msg_type == 'control:hello') {
ws.send(JSON.stringify({
msg_type: 'data:subscribe_oauth',
token: options.authToken,
value: options.values.join(','),
tag: options.vehicle_id.toString()
}));
} else if (d.msg_type == 'data:error') {
callback('Error: ' + d.value);
} else {
callback(null, null, d);
}
});
ws.on('close', function close() {
callback('Websocket disconnected');
});
ws.on('error', function error() {
callback('Websocket error');
});
}
var promises = {};
for (var name in exports) {
if (name.endsWith('Async')) {
continue;
}
var nameAsync = name + 'Async';
if (nameAsync in exports) {
promises[name] = exports[nameAsync];
} else {
promises[name] = exports[name];
}
}
exports.promises = promises;