forked from mseminatore/TeslaJS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
teslajs.min.js
13 lines (13 loc) · 19.4 KB
/
teslajs.min.js
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @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:!0,gzip:!0,body:{}}),Promise=require("promise"),websocket=require("ws"),streamingPortal="wss://streaming.vn.teslamotors.com/streaming/";exports.streamingPortal=streamingPortal;var streamingBaseURI=process.env.TESLAJS_STREAMING||streamingPortal,portal="https://owner-api.teslamotors.com";exports.portal=portal;var portalBaseURI=process.env.TESLAJS_SERVER||portal,API_LOG_ALWAYS=0;exports.API_LOG_ALWAYS=API_LOG_ALWAYS;var API_ERR_LEVEL=1;exports.API_ERR_LEVEL=API_ERR_LEVEL;var API_CALL_LEVEL=2;exports.API_CALL_LEVEL=API_CALL_LEVEL;var API_RETURN_LEVEL=3;exports.API_RETURN_LEVEL=API_RETURN_LEVEL;var API_BODY_LEVEL=4;exports.API_BODY_LEVEL=API_BODY_LEVEL;var API_REQUEST_LEVEL=5;exports.API_REQUEST_LEVEL=API_REQUEST_LEVEL;var API_RESPONSE_LEVEL=6;exports.API_RESPONSE_LEVEL=API_RESPONSE_LEVEL;var API_LOG_ALL=255;exports.API_LOG_ALL=API_LOG_ALL;var logLevel=process.env.TESLAJS_LOG||0;function log(e,o){logLevel<e||console.log(o)}function clamp(e,o,t){return e<o&&(e=o),t<e&&(e=t),e}function get_command(e,r,s){log(API_CALL_LEVEL,"GET call: "+r+" start."),s=s||function(e,o){};var o={method:"GET",url:portalBaseURI+"/api/1/vehicles/"+e.vehicleID+"/"+r,headers:{Authorization:"Bearer "+e.authToken,"Content-Type":"application/json; charset=utf-8"}};log(API_REQUEST_LEVEL,"\nRequest: "+JSON.stringify(o)),request(o,function(e,o,t){if(e)return log(API_ERR_LEVEL,e),s(e,null);if(200!=o.statusCode){var n="Error response: "+o.statusCode;return log(API_ERR_LEVEL,n),s(n,null)}log(API_BODY_LEVEL,"\nBody: "+JSON.stringify(t)),log(API_RESPONSE_LEVEL,"\nResponse: "+JSON.stringify(o));try{t=t.response,s(null,t)}catch(e){log(API_ERR_LEVEL,"Error parsing GET call response"),log(API_ERR_LEVEL,e),s(e,null)}log(API_RETURN_LEVEL,"\nGET request: "+r+" completed.")})}function post_command(e,r,o,s){log(API_CALL_LEVEL,"POST call: "+r+" start."),s=s||function(e,o){};var t={method:"POST",url:portalBaseURI+"/api/1/vehicles/"+e.vehicleID+"/"+r,headers:{Authorization:"Bearer "+e.authToken,"content-type":"application/json; charset=UTF-8"},body:o||null};log(API_REQUEST_LEVEL,"\nRequest: "+JSON.stringify(t)),request(t,function(e,o,t){if(e)return log(API_ERR_LEVEL,e),s(e,null);if(200!=o.statusCode){var n="Error response: "+o.statusCode;return log(API_ERR_LEVEL,n),s(n,null)}log(API_BODY_LEVEL,"\nBody: "+JSON.stringify(t)),log(API_RESPONSE_LEVEL,"\nResponse: "+JSON.stringify(o));try{t=t.response,s(null,t)}catch(e){log(API_ERR_LEVEL,"Error parsing POST call response"),s(e,null)}log(API_RETURN_LEVEL,"\nPOST command: "+r+" completed.")})}exports.setLogLevel=function(e){logLevel=e},exports.getLogLevel=function(){return logLevel},exports.setPortalBaseURI=function(e){portalBaseURI=e||portal},exports.getPortalBaseURI=function(){return portalBaseURI},exports.setStreamingBaseURI=function(e){streamingBaseURI=e||streamingPortal},exports.getStreamingBaseURI=function(){return streamingBaseURI},exports.getModel=function(e){return exports.vinDecode(e).carType},exports.vinDecode=function(e){var o={carType:"Model S",awd:!1,year:2012};if(!e||!e.vin)return o;var t=e.vin.charCodeAt(9);switch(o.year=2010+t-"A".charCodeAt(0),73<t&&o.year--,e.vin.charAt(3)){case"S":o.carType="Model S";break;case"3":o.carType="Model 3";break;case"X":o.carType="Model X";break;case"Y":o.carType="Model Y";break;case"R":o.carType="Roadster"}return"2"!=e.vin.charAt(7)&&"4"!=e.vin.charAt(7)&&"B"!=e.vin.charAt(7)&&"C"!=e.vin.charAt(7)&&"E"!=e.vin.charAt(7)||(o.awd=!0),o},exports.getPaintColor=function(e){return{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",PPSW:"pearl white",PPTI:"titanium",PMTG:"metallic grey"}[e.option_codes.match(/PBCW|PBSB|PMAB|PMBL|PMMB|PMMR|PPMR|PMNG|PMSG|PMSS|PPSB|PPSR|PPSW|PPTI|PMTG/)]||"black"},exports.getVin=function(e){if(!e||!e.vin)throw new Error("invalid parameter");return e.vin},exports.getShortVin=function(e){if(!e||!e.vin)throw new Error("invalid parameter");return e.vin.substr(11)},exports.login=function(e,r){log(API_CALL_LEVEL,"TeslaJS.login()"),"string"==typeof arguments[0]&&"string"==typeof arguments[1]&&(e={username:arguments[0],password:arguments[1]},r=arguments[2]),r=r||function(e,o){},(e=e||{}).username&&e.password?require("./src/auth").login({identity:e.username,credential:e.password,mfaPassCode:e.mfaPassCode,mfaDeviceName:e.mfaDeviceName},function(e,o,t){log(API_RESPONSE_LEVEL,"\nResponse: "+JSON.stringify(o)),log(API_RESPONSE_LEVEL,"\nBody: "+JSON.stringify(t));var n=t||{};r(e,{error:e,response:o,body:t,authToken:n.access_token,refreshToken:n.refresh_token}),log(API_RETURN_LEVEL,"TeslaJS.login() completed.")}):r("login() requires username and password",null)},exports.loginAsync=Promise.denodeify(exports.login),exports.refreshToken=function(e,n){if(log(API_CALL_LEVEL,"TeslaJS.refreshToken()"),n=n||function(e,o){},e){var o={method:"POST",url:portalBaseURI+"/oauth/token",body:{grant_type:"refresh_token",refresh_token:e}};log(API_REQUEST_LEVEL,"\nRequest: "+JSON.stringify(o)),request(o,function(e,o,t){log(API_RESPONSE_LEVEL,"\nResponse: "+t),n(e,{error:e,response:o,body:JSON.stringify(t),authToken:t.access_token,refreshToken:t.refresh_token}),log(API_RETURN_LEVEL,"TeslaJS.refreshToken() completed.")})}else n("refreshToken() requires a refresh_token",null)},exports.refreshTokenAsync=Promise.denodeify(exports.refreshToken),exports.logout=function(e,n){log(API_CALL_LEVEL,"TeslaJS.logout()"),n=n||function(e,o){},request({method:"POST",url:portalBaseURI+"/oauth/revoke",headers:{Authorization:"Bearer "+e,"Content-Type":"application/json; charset=utf-8"}},function(e,o,t){n(e,{error:e,response:o,body:JSON.stringify(t)}),log(API_RETURN_LEVEL,"TeslaJS.logout() completed.")})},exports.logoutAsync=Promise.denodeify(exports.logout),exports.vehicle=function(n,r){log(API_CALL_LEVEL,"TeslaJS.vehicle()"),r=r||function(e,o){};var e={method:"GET",url:portalBaseURI+"/api/1/vehicles",headers:{Authorization:"Bearer "+n.authToken,"Content-Type":"application/json; charset=utf-8"}};log(API_REQUEST_LEVEL,"\nRequest: "+JSON.stringify(e)),request(e,function(e,o,t){if(e)return log(API_ERR_LEVEL,e),r(e,null);if(200!=o.statusCode)return r(o.statusMessage,null);log(API_BODY_LEVEL,"\nBody: "+JSON.stringify(t)),log(API_RESPONSE_LEVEL,"\nResponse: "+JSON.stringify(o));try{(t=t.response[n.carIndex||0]).id=t.id_s,n.vehicleID=t.id,r(null,t)}catch(e){log(API_ERR_LEVEL,"Error parsing vehicles response"),r(e,null)}log(API_RETURN_LEVEL,"\nGET request: /vehicles completed.")})},exports.vehicleAsync=Promise.denodeify(exports.vehicle),exports.vehicles=function(e,n){log(API_CALL_LEVEL,"TeslaJS.vehicles()"),n=n||function(e,o){};var o={method:"GET",url:portalBaseURI+"/api/1/vehicles",headers:{Authorization:"Bearer "+e.authToken,"Content-Type":"application/json; charset=utf-8"}};log(API_REQUEST_LEVEL,"\nRequest: "+JSON.stringify(o)),request(o,function(e,o,t){if(e)return log(API_ERR_LEVEL,e),n(e,null);if(200!=o.statusCode)return n(o.statusMessage,null);log(API_BODY_LEVEL,"\nBody: "+JSON.stringify(t)),log(API_RESPONSE_LEVEL,"\nResponse: "+JSON.stringify(o));try{t=t.response,n(null,t)}catch(e){log(API_ERR_LEVEL,"Error parsing vehicles response"),n(e,null)}log(API_RETURN_LEVEL,"\nGET request: /vehicles completed.")})},exports.vehiclesAsync=Promise.denodeify(exports.vehicles),exports.get_command=get_command,exports.get_commandAsync=Promise.denodeify(exports.get_command),exports.post_command=post_command,exports.post_commandAsync=Promise.denodeify(exports.post_command),exports.vehicleData=function(e,o){get_command(e,"vehicle_data",o)},exports.vehicleDataAsync=Promise.denodeify(exports.vehicleData),exports.vehicleConfig=function(e,o){get_command(e,"data_request/vehicle_config",o)},exports.vehicleConfigAsync=Promise.denodeify(exports.vehicleConfig),exports.vehicleState=function(e,o){get_command(e,"data_request/vehicle_state",o)},exports.vehicleStateAsync=Promise.denodeify(exports.vehicleState),exports.climateState=function(e,o){get_command(e,"data_request/climate_state",o)},exports.climateStateAsync=Promise.denodeify(exports.climateState),exports.nearbyChargers=function(e,o){get_command(e,"nearby_charging_sites",o)},exports.nearbyChargersAsync=Promise.denodeify(exports.nearbyChargers),exports.driveState=function(e,o){get_command(e,"data_request/drive_state",o)},exports.driveStateAsync=Promise.denodeify(exports.driveState),exports.chargeState=function(e,o){get_command(e,"data_request/charge_state",o)},exports.chargeStateAsync=Promise.denodeify(exports.chargeState),exports.guiSettings=function(e,o){get_command(e,"data_request/gui_settings",o)},exports.guiSettingsAsync=Promise.denodeify(exports.guiSettings),exports.mobileEnabled=function(e,o){get_command(e,"mobile_enabled",o)},exports.mobileEnabledAsync=Promise.denodeify(exports.mobileEnabled),exports.honkHorn=function(e,o){post_command(e,"command/honk_horn",null,o)},exports.honkHornAsync=Promise.denodeify(exports.honkHorn),exports.flashLights=function(e,o){post_command(e,"command/flash_lights",null,o)},exports.flashLightsAsync=Promise.denodeify(exports.flashLights),exports.startCharge=function(e,o){post_command(e,"command/charge_start",null,o)},exports.startChargeAsync=Promise.denodeify(exports.startCharge),exports.stopCharge=function(e,o){post_command(e,"command/charge_stop",null,o)},exports.stopChargeAsync=Promise.denodeify(exports.stopCharge),exports.openChargePort=function(e,o){post_command(e,"command/charge_port_door_open",null,o)},exports.openChargePortAsync=Promise.denodeify(exports.openChargePort),exports.closeChargePort=function(e,o){post_command(e,"command/charge_port_door_close",null,o)},exports.closeChargePortAsync=Promise.denodeify(exports.closeChargePort),exports.scheduleSoftwareUpdate=function(e,o,t){post_command(e,"command/schedule_software_update",{offset_sec:o},t)},exports.scheduleSoftwareUpdateAsync=Promise.denodeify(exports.scheduleSoftwareUpdate),exports.cancelSoftwareUpdate=function(e,o){post_command(e,"command/cancel_software_update",null,o)},exports.cancelSoftwareUpdateAsync=Promise.denodeify(exports.cancelSoftwareUpdate),exports.navigationRequest=function(e,o,t,n,r){post_command(e,"command/navigation_request",{type:"share_ext_content_raw",value:{"android.intent.ACTION":"android.intent.action.SEND","android.intent.TYPE":"text/plain","android.intent.extra.SUBJECT":o,"android.intent.extra.TEXT":t},locale:n,timestamp_ms:Date.now()},r)},exports.navigationRequestAsync=Promise.denodeify(exports.navigationRequest),exports.mediaTogglePlayback=function(e,o){post_command(e,"command/media_toggle_playback",null,o)},exports.mediaTogglePlaybackAsync=Promise.denodeify(exports.mediaTogglePlayback),exports.mediaPlayNext=function(e,o){post_command(e,"command/media_next_track",null,o)},exports.mediaPlayNextAsync=Promise.denodeify(exports.mediaPlayNext),exports.mediaPlayPrevious=function(e,o){post_command(e,"command/media_prev_track",null,o)},exports.mediaPlayPreviousAsync=Promise.denodeify(exports.mediaPlayPrevious),exports.mediaPlayNextFavorite=function(e,o){post_command(e,"command/media_next_fav",null,o)},exports.mediaPlayNextFavoriteAsync=Promise.denodeify(exports.mediaPlayNextFavorite),exports.mediaPlayPreviousFavorite=function(e,o){post_command(e,"command/media_prev_fav",null,o)},exports.mediaPlayPreviousFavoriteAsync=Promise.denodeify(exports.mediaPlayPreviousFavorite),exports.mediaVolumeUp=function(e,o){post_command(e,"command/media_volume_up",null,o)},exports.mediaVolumeUpAsync=Promise.denodeify(exports.mediaVolumeUp),exports.mediaVolumeDown=function(e,o){post_command(e,"command/media_volume_down",null,o)},exports.mediaVolumeDownAsync=Promise.denodeify(exports.mediaVolumeDown),exports.speedLimitActivate=function(e,o,t){post_command(e,"command/speed_limit_activate",{pin:o},t)},exports.speedLimitActivateAsync=Promise.denodeify(exports.speedLimitActivate),exports.speedLimitDeactivate=function(e,o,t){post_command(e,"command/speed_limit_deactivate",{pin:o},t)},exports.speedLimitDeactivateAsync=Promise.denodeify(exports.speedLimitDeactivate),exports.speedLimitClearPin=function(e,o,t){post_command(e,"command/speed_limit_clear_pin",{pin:o},t)},exports.speedLimitClearPinAsync=Promise.denodeify(exports.speedLimitClearPin),exports.speedLimitSetLimit=function(e,o,t){post_command(e,"command/speed_limit_set_limit",{limit_mph:o},t)},exports.speedLimitSetLimitAsync=Promise.denodeify(exports.speedLimitSetLimit),exports.setSentryMode=function(e,o,t){post_command(e,"command/set_sentry_mode",{on:o},t)},exports.setSentryModeAsync=Promise.denodeify(exports.setSentryMode),exports.seatHeater=function(e,o,t,n){post_command(e,"command/remote_seat_heater_request",{heater:o,level:t},n)},exports.seatHeaterAsync=Promise.denodeify(exports.seatHeater),exports.steeringHeater=function(e,o,t){post_command(e,"command/remote_steering_wheel_heater_request",{on:o},t)},exports.steeringHeaterAsync=Promise.denodeify(exports.steeringHeater),exports.maxDefrost=function(e,o,t){post_command(e,"command/set_preconditioning_max",{on:o},t)},exports.maxDefrostAsync=Promise.denodeify(exports.maxDefrost),exports.windowControl=function(e,o,t){post_command(e,"command/window_control",{command:o,lat:0,lon:0},t)},exports.windowControlAsync=Promise.denodeify(exports.windowControl),exports.CHARGE_STORAGE=50,exports.CHARGE_DAILY=70,exports.CHARGE_STANDARD=90,exports.CHARGE_RANGE=100,exports.setChargeLimit=function(e,o,t){post_command(e,"command/set_charge_limit",{percent:o=clamp(o,exports.CHARGE_STORAGE,exports.CHARGE_RANGE)},t)},exports.setChargeLimitAsync=Promise.denodeify(exports.setChargeLimit),exports.chargeStandard=function(e,o){post_command(e,"command/charge_standard",null,o)},exports.chargeStandardAsync=Promise.denodeify(exports.chargeStandard),exports.chargeMaxRange=function(e,o){post_command(e,"command/charge_max_range",null,o)},exports.chargeMaxRangeAsync=Promise.denodeify(exports.chargeMaxRange),exports.doorLock=function(e,o){post_command(e,"command/door_lock",null,o)},exports.doorLockAsync=Promise.denodeify(exports.doorLock),exports.doorUnlock=function(e,o){post_command(e,"command/door_unlock",null,o)},exports.doorUnlockAsync=Promise.denodeify(exports.doorUnlock),exports.climateStart=function(e,o){post_command(e,"command/auto_conditioning_start",null,o)},exports.climateStartAsync=Promise.denodeify(exports.climateStart),exports.climateStop=function(e,o){post_command(e,"command/auto_conditioning_stop",null,o)},exports.climateStopAsync=Promise.denodeify(exports.climateStop),exports.SUNROOF_VENT="vent",exports.SUNROOF_CLOSED="close",exports.sunRoofControl=function(e,o,t){post_command(e,"command/sun_roof_control",{state:o},t)},exports.sunRoofControlAsync=Promise.denodeify(exports.sunRoofControl),exports.sunRoofMove=function(e,o,t){post_command(e,"command/sun_roof_control",{state:"move",percent:o},t)},exports.sunRoofMoveAsync=Promise.denodeify(exports.sunRoofMove),exports.MIN_TEMP=15,exports.MAX_TEMP=28,exports.setTemps=function(e,o,t,n){t||(t=o),post_command(e,"command/set_temps",{driver_temp:o=clamp(o,exports.MIN_TEMP,exports.MAX_TEMP),passenger_temp:t=clamp(t,exports.MIN_TEMP,exports.MAX_TEMP)},n)},exports.setTempsAsync=Promise.denodeify(exports.setTemps),exports.remoteStart=function(e,o,t){post_command(e,"command/remote_start_drive",{password:o},t)},exports.remoteStartAsync=Promise.denodeify(exports.remoteStart),exports.FRUNK="front",exports.TRUNK="rear",exports.openTrunk=function(e,o,t){post_command(e,"command/actuate_trunk",{which_trunk:o},t)},exports.openTrunkAsync=Promise.denodeify(exports.openTrunk),exports.wakeUp=function(e,o){post_command(e,"wake_up",null,o)},exports.wakeUpAsync=Promise.denodeify(exports.wakeUp),exports.setValetMode=function(e,o,t,n){post_command(e,"command/set_valet_mode",{on:o,password:t},n)},exports.setValetModeAsync=Promise.denodeify(exports.setValetMode),exports.resetValetPin=function(e,o){post_command(e,"command/reset_valet_pin",null,o)},exports.resetValetPinAsync=Promise.denodeify(exports.resetValetPin),exports.calendar=function(e,o,t){post_command(e,"command/upcoming_calendar_entries",o,t)},exports.calendarAsync=Promise.denodeify(exports.calendar),exports.makeCalendarEntry=function(e,o,t,n,r,s){return{calendar_data:{access_disabled:!1,calendars:[{color:"ff9a9cff",events:[{allday:!1,color:"ff9a9cff",end:n||(new Date).getTime(),start:t||(new Date).getTime(),cancelled:!1,tentative:!1,location:o||"",name:e||"Event name",organizer:""}],name:r||""}],phone_name:s,uuid:"333239059961778"}}},exports.homelink=function(e,o,t,n){post_command(e,"command/trigger_homelink",{lat:o,lon:t},n)},exports.homelinkAsync=Promise.denodeify(exports.homelink),exports.products=function(e,n){log(API_CALL_LEVEL,"TeslaJS.products()"),n=n||function(e,o){};var o={method:"GET",url:portalBaseURI+"/api/1/products",headers:{Authorization:"Bearer "+e.authToken,"Content-Type":"application/json; charset=utf-8"}};log(API_REQUEST_LEVEL,"\nRequest: "+JSON.stringify(o)),request(o,function(e,o,t){if(e)return log(API_ERR_LEVEL,e),n(e,null);if(200!=o.statusCode)return n(o.statusMessage,null);log(API_BODY_LEVEL,"\nBody: "+JSON.stringify(t)),log(API_RESPONSE_LEVEL,"\nResponse: "+JSON.stringify(o));try{t=t.response,n(null,t)}catch(e){console.log(e),log(API_ERR_LEVEL,"Error parsing products response"),n(e,null)}log(API_RETURN_LEVEL,"\nGET request: /products completed.")})},exports.productsAsync=Promise.denodeify(exports.products),exports.solarStatus=function(e,n){log(API_CALL_LEVEL,"TeslaJS.solarStatus()"),n=n||function(e,o){};var o={method:"GET",url:portalBaseURI+"/api/1/energy_sites/"+e.siteId+"/live_status",headers:{Authorization:"Bearer "+e.authToken,"Content-Type":"application/json; charset=utf-8"}};log(API_REQUEST_LEVEL,"\nRequest: "+JSON.stringify(o)),request(o,function(e,o,t){if(e)return log(API_ERR_LEVEL,e),n(e,null);if(200!=o.statusCode)return n(o.statusMessage,null);log(API_BODY_LEVEL,"\nBody: "+JSON.stringify(t)),log(API_RESPONSE_LEVEL,"\nResponse: "+JSON.stringify(o));try{t=t.response,n(null,t)}catch(e){log(API_ERR_LEVEL,"Error parsing solarStatus response"),n(e,null)}log(API_RETURN_LEVEL,"\nGET request: /solarStatus completed.")})},exports.solarStatusAsync=Promise.denodeify(exports.solarStatus),exports.streamingColumns=["elevation","est_heading","est_lat","est_lng","est_range","heading","odometer","power","range","shift_state","speed","soc"],exports.startStreaming=function(t,n,e){log(API_CALL_LEVEL,"TeslaJS.startStreaming()"),n=n||function(e,o,t){},e=e||function(e){},t.values=t.values||exports.streamingColumns;var r=new websocket(streamingBaseURI,{perMessageDeflate:!1});r.on("message",function(e){var o=JSON.parse(e);"control:hello"==o.msg_type?r.send(JSON.stringify({msg_type:"data:subscribe_oauth",token:t.authToken,value:t.values.join(","),tag:t.vehicle_id.toString()})):"data:error"==o.msg_type?n("Error: "+o.value):n(null,null,o)}),r.on("close",function(){n("Websocket disconnected")}),r.on("error",function(){n("Websocket error")})};var promises={};for(var name in exports)if(!name.endsWith("Async")){var nameAsync=name+"Async";nameAsync in exports?promises[name]=exports[nameAsync]:promises[name]=exports[name]}exports.promises=promises;