tesla_api 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +46 -0
- data/Rakefile +2 -0
- data/apiary.apib +433 -0
- data/lib/tesla_api.rb +172 -0
- data/lib/tesla_api/version.rb +3 -0
- data/logs/login.GET.log +44 -0
- data/logs/login.POST.log +29 -0
- data/logs/root.GET.log +50 -0
- data/tesla_api.gemspec +22 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 20e84c22651e2f1856d02fc5288277ec8ec512cc
|
4
|
+
data.tar.gz: b4a0471a5d0ca51c0974071b0ef526d7603a531c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6b0fc114f6cd257b6d52dbcc6aa6d3902a4241fd536cc39c75554ba96b5a88d56dc69e6076d15479c30e4133a1ca24573224daa054222dc04c7843a0a2f1ae17
|
7
|
+
data.tar.gz: f6f63dc83fd699d418c3f2702cf612f772c16a6a4980765a57d254eded2ded59a6cd065b3ed70762dc589464844720a2859d48b861bfa9b1c6b6ffd1da7e4902
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Tim Dorr
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Tesla JSON API
|
2
|
+
|
3
|
+
[View Documentation](http://docs.timdorr.apiary.io/)
|
4
|
+
|
5
|
+
This is unofficial documentation of the Tesla Model S JSON API used by the iOS and Android apps.
|
6
|
+
The API provides functionality to monitor and control the Model S (and future Tesla vehicles) remotely.
|
7
|
+
The project provides both a documention of the API and a Ruby library to for accessing it.
|
8
|
+
|
9
|
+
## Ruby Library
|
10
|
+
|
11
|
+
This gem provides a basic wrapper around the API to easily query and command the car remotely.
|
12
|
+
It also provides access to the streaming API and a means to process data coming from it.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
```ruby
|
18
|
+
gem 'tesla_api'
|
19
|
+
```
|
20
|
+
|
21
|
+
Or install it yourself:
|
22
|
+
```sh
|
23
|
+
gem install tesla_api
|
24
|
+
```
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
Here's a quick example:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'tesla_api'
|
32
|
+
|
33
|
+
tesla_api = TeslaApi.new(email, password, client_id, client_secret)
|
34
|
+
model_s = tesla_api.vehicles.first
|
35
|
+
|
36
|
+
model_s.wake_up
|
37
|
+
model_s.auto_conditioning_start unless model_s.climate_state["is_auto_conditioning_on"]
|
38
|
+
|
39
|
+
model_s.set_charge_limit(90)
|
40
|
+
model_s.charge_start
|
41
|
+
|
42
|
+
charge_state = model_s.charge_state
|
43
|
+
puts "Your Model S is #{charge_state["charging_state"]} " +
|
44
|
+
"with a SOC of #{charge_state["battery_level"]}% " +
|
45
|
+
"and an estimate range of #{charge_state["est_battery_range"]} miles"
|
46
|
+
```
|
data/Rakefile
ADDED
data/apiary.apib
ADDED
@@ -0,0 +1,433 @@
|
|
1
|
+
FORMAT: 1A
|
2
|
+
HOST: https://portal.vn.teslamotors.com
|
3
|
+
|
4
|
+
# Tesla Model S JSON API
|
5
|
+
This is unofficial documentation of the Tesla Model S JSON API used by the iOS and Android apps. It features functionality to monitor and control the Model S remotely.
|
6
|
+
|
7
|
+
# Group Authentication Flow
|
8
|
+
These endpoints handle login and session management
|
9
|
+
|
10
|
+
## GET /login
|
11
|
+
Returns the login form. Sets a `_s_portal_session` cookie for the session
|
12
|
+
+ Response 200
|
13
|
+
|
14
|
+
+ Headers
|
15
|
+
|
16
|
+
Set-Cookie: _s_portal_session={cookie}; path=/; secure; HttpOnly
|
17
|
+
|
18
|
+
+ Body
|
19
|
+
|
20
|
+
Login Screen HTML
|
21
|
+
|
22
|
+
## POST /login
|
23
|
+
Performs the login. Takes in an plain text email and password, matching the owner's login from [http://teslamotors.com/mytesla](http://teslamotors.com/mytesla).
|
24
|
+
|
25
|
+
Sets a `user_credentials` cookie that expires in 3 months, which is passed along with all future requests to authenticate the user.
|
26
|
+
|
27
|
+
Redirects back to a dummy welcome page. This page is ignored by the smartphone app and can be ignored by your API client.
|
28
|
+
+ Request (application/x-www-form-urlencoded)
|
29
|
+
|
30
|
+
+ Body
|
31
|
+
|
32
|
+
user_session%5Bemail%5D=string&user_session%5Bpassword%5D=string
|
33
|
+
|
34
|
+
+ Response 302
|
35
|
+
|
36
|
+
+ Headers
|
37
|
+
|
38
|
+
Set-Cookie: _s_portal_session={cookie}; path=/; secure; HttpOnly
|
39
|
+
Set-Cookie: user_credentials=x; path=/; expires=Fri, 03-May-2013 03:01:54 GMT; secure; HttpOnly
|
40
|
+
Location: https://portal.vn.teslamotors.com/
|
41
|
+
|
42
|
+
|
43
|
+
+ Body
|
44
|
+
|
45
|
+
Dummy Welcome Page
|
46
|
+
|
47
|
+
|
48
|
+
# Group Vehicle List
|
49
|
+
A logged in user can have multiple vehicles under their account. This resource is primarily responsible for listing the vehicles and the basic details about them.
|
50
|
+
|
51
|
+
Must have a `_s_portal_session` and `user_credentials` cookie set for all requests.
|
52
|
+
|
53
|
+
## GET /vehicles
|
54
|
+
Retrieve a list of your owned vehicles (includes vehicles not yet shipped!)
|
55
|
+
+ Response 200 (application/json)
|
56
|
+
|
57
|
+
+ Body
|
58
|
+
|
59
|
+
[{
|
60
|
+
"color": null,
|
61
|
+
"display_name": null,
|
62
|
+
"id": 321,
|
63
|
+
"option_codes": "MS01,RENA,TM00,DRLH,PF00,BT85,PBCW,RFPO,WT19,IBMB,IDPB,TR00,SU01,SC01,TP01,AU01,CH00,HP00,PA00,PS00,AD02,X020,X025,X001,X003,X007,X011,X013",
|
64
|
+
"user_id": 123,
|
65
|
+
"vehicle_id": 1234567890,
|
66
|
+
"vin": "5YJSA1CN5CFP01657",
|
67
|
+
"tokens": ["x", "x"],
|
68
|
+
"state": "online"
|
69
|
+
}]
|
70
|
+
|
71
|
+
|
72
|
+
# Group Vehicle Status
|
73
|
+
These resources are read-only and determine the state of the vehicle's various sub-systems.
|
74
|
+
|
75
|
+
Must have a `_s_portal_session` and `user_credentials` cookie set for all requests.
|
76
|
+
|
77
|
+
## GET /vehicles/{id}/mobile_enabled
|
78
|
+
Determines if mobile access to the vehicle is enabled.
|
79
|
+
+ Parameters
|
80
|
+
|
81
|
+
+ id (number) ... The ID number of the car
|
82
|
+
|
83
|
+
+ Response 200 (application/json)
|
84
|
+
|
85
|
+
+ Body
|
86
|
+
|
87
|
+
{
|
88
|
+
"reason":"",
|
89
|
+
"result":true
|
90
|
+
}
|
91
|
+
|
92
|
+
## GET /vehicles/{id}/command/charge_state
|
93
|
+
Returns the state of charge in the battery.
|
94
|
+
+ Parameters
|
95
|
+
|
96
|
+
+ id (number) ... The ID number of the car
|
97
|
+
|
98
|
+
+ Response 200 (application/json)
|
99
|
+
|
100
|
+
+ Body
|
101
|
+
|
102
|
+
{
|
103
|
+
"charging_state": "Complete", // "Charging", ??
|
104
|
+
"charge_to_max_range": false, // current std/max-range setting
|
105
|
+
"max_range_charge_counter": 0,
|
106
|
+
"fast_charger_present": false, // connected to Supercharger?
|
107
|
+
"battery_range": 239.02, // rated miles
|
108
|
+
"est_battery_range": 155.79, // range estimated from recent driving
|
109
|
+
"ideal_battery_range": 275.09, // ideal miles
|
110
|
+
"battery_level": 91, // integer charge percentage
|
111
|
+
"battery_current": -0.6, // current flowing into battery
|
112
|
+
"charge_starting_range": null,
|
113
|
+
"charge_starting_soc": null,
|
114
|
+
"charger_voltage": 0, // only has value while charging
|
115
|
+
"charger_pilot_current": 40, // max current allowed by charger & adapter
|
116
|
+
"charger_actual_current": 0, // current actually being drawn
|
117
|
+
"charger_power": 0, // kW (rounded down) of charger
|
118
|
+
"time_to_full_charge": null, // valid only while charging
|
119
|
+
"charge_rate": -1.0, // float mi/hr charging or -1 if not charging
|
120
|
+
"charge_port_door_open": true
|
121
|
+
}
|
122
|
+
|
123
|
+
## GET /vehicles/{id}/command/climate_state
|
124
|
+
Returns the current temperature and climate control state.
|
125
|
+
+ Parameters
|
126
|
+
|
127
|
+
+ id (number) ... The ID number of the car
|
128
|
+
|
129
|
+
+ Response 200 (application/json)
|
130
|
+
|
131
|
+
+ Body
|
132
|
+
|
133
|
+
{
|
134
|
+
"inside_temp": 17.0, // degC inside car
|
135
|
+
"outside_temp": 9.5, // degC outside car or null
|
136
|
+
"driver_temp_setting": 22.6, // degC of driver temperature setpoint
|
137
|
+
"passenger_temp_setting": 22.6, // degC of passenger temperature setpoint
|
138
|
+
"is_auto_conditioning_on": false, // apparently even if on
|
139
|
+
"is_front_defroster_on": null, // null or boolean as integer?
|
140
|
+
"is_rear_defroster_on": false,
|
141
|
+
"fan_status": 0 // fan speed 0-6 or null
|
142
|
+
}
|
143
|
+
|
144
|
+
## GET /vehicles/{id}/command/drive_state
|
145
|
+
Returns the driving and position state of the vehicle.
|
146
|
+
+ Parameters
|
147
|
+
|
148
|
+
+ id (number) ... The ID number of the car
|
149
|
+
|
150
|
+
+ Response 200 (application/json)
|
151
|
+
|
152
|
+
+ Body
|
153
|
+
|
154
|
+
{
|
155
|
+
"shift_state": null, //
|
156
|
+
"speed": null, //
|
157
|
+
"latitude": 33.794839, // degrees N of equator
|
158
|
+
"longitude": -84.401593, // degrees W of the prime meridian
|
159
|
+
"heading": 4, // integer compass heading, 0-359
|
160
|
+
"gps_as_of": 1359863204 // Unix timestamp of GPS fix
|
161
|
+
}
|
162
|
+
|
163
|
+
## GET /vehicles/{id}/command/gui_settings
|
164
|
+
Returns various information about the GUI settings of the car, such as unit format and range display.
|
165
|
+
+ Parameters
|
166
|
+
|
167
|
+
+ id (number) ... The ID number of the car
|
168
|
+
|
169
|
+
+ Response 200 (application/json)
|
170
|
+
|
171
|
+
+ Body
|
172
|
+
|
173
|
+
{
|
174
|
+
"gui_distance_units": "mi/hr",
|
175
|
+
"gui_temperature_units": "F",
|
176
|
+
"gui_charge_rate_units": "mi/hr",
|
177
|
+
"gui_24_hour_time": false,
|
178
|
+
"gui_range_display": "Rated"
|
179
|
+
}
|
180
|
+
|
181
|
+
## GET /vehicles/{id}/command/vehicle_state
|
182
|
+
Returns the vehicle's physical state, such as which doors are open.
|
183
|
+
+ Parameters
|
184
|
+
|
185
|
+
+ id (number) ... The ID number of the car
|
186
|
+
|
187
|
+
+ Response 200 (application/json)
|
188
|
+
|
189
|
+
+ Body
|
190
|
+
|
191
|
+
{
|
192
|
+
"df": false, // driver's side front door open
|
193
|
+
"dr": false, // driver's side rear door open
|
194
|
+
"pf": false, // passenger's side front door open
|
195
|
+
"pr": false, // passenger's side rear door open
|
196
|
+
"ft": false, // front trunk is open
|
197
|
+
"rt": false, // rear trunk is open
|
198
|
+
"car_verson": "1.19.42", // car firmware version
|
199
|
+
"locked": true, // car is locked
|
200
|
+
"sun_roof_installed": false, // panoramic roof is installed
|
201
|
+
"sun_roof_state": "unknown",
|
202
|
+
"sun_roof_percent_open": 0, // null if not installed
|
203
|
+
"dark_rims": false, // gray rims installed
|
204
|
+
"wheel_type": "Base19", // wheel type installed
|
205
|
+
"has_spoiler": false, // spoiler is installed
|
206
|
+
"roof_color": "Colored", // "None" for panoramic roof
|
207
|
+
"perf_config": "Base"
|
208
|
+
}
|
209
|
+
|
210
|
+
# Group Vehicle Commands
|
211
|
+
These commands alter the vehicles state, and return result (true/false) to indicate success, and if failure reason contains the cause of failure.
|
212
|
+
|
213
|
+
Must have a `_s_portal_session` and `user_credentials` cookie set for all requests.
|
214
|
+
|
215
|
+
## GET /vehicles/{id}/command/charge_port_door_open
|
216
|
+
Open the charge port.
|
217
|
+
+ Parameters
|
218
|
+
|
219
|
+
+ id (number) ... The ID number of the car
|
220
|
+
|
221
|
+
+ Response 200 (application/json)
|
222
|
+
|
223
|
+
+ Body
|
224
|
+
|
225
|
+
{
|
226
|
+
"result": false,
|
227
|
+
"reason": "failure reason"
|
228
|
+
}
|
229
|
+
|
230
|
+
## GET /vehicles/{id}/command/charge_standard
|
231
|
+
Set the charge mode to standard (~90% under the new percentage system introduced in 4.5).
|
232
|
+
+ Parameters
|
233
|
+
|
234
|
+
+ id (number) ... The ID number of the car
|
235
|
+
|
236
|
+
+ Response 200 (application/json)
|
237
|
+
|
238
|
+
+ Body
|
239
|
+
|
240
|
+
{
|
241
|
+
"result": false,
|
242
|
+
"reason": "failure reason"
|
243
|
+
}
|
244
|
+
|
245
|
+
## GET /vehicles/{id}/command/charge_max_range
|
246
|
+
Set the charge mode to max range (100% under the new percentage system introduced in 4.5).
|
247
|
+
+ Parameters
|
248
|
+
|
249
|
+
+ id (number) ... The ID number of the car
|
250
|
+
|
251
|
+
+ Response 200 (application/json)
|
252
|
+
|
253
|
+
+ Body
|
254
|
+
|
255
|
+
{
|
256
|
+
"result": false,
|
257
|
+
"reason": "failure reason"
|
258
|
+
}
|
259
|
+
|
260
|
+
## GET /vehicles/{id}/command/set_charge_limit?percent={limit_value}
|
261
|
+
Set the charge limit to a custom percentage.
|
262
|
+
+ Parameters
|
263
|
+
|
264
|
+
+ id (number) ... The ID number of the car
|
265
|
+
+ limit_value (number) ... The percentage value
|
266
|
+
|
267
|
+
+ Response 200 (application/json)
|
268
|
+
|
269
|
+
+ Body
|
270
|
+
|
271
|
+
{
|
272
|
+
"result": false,
|
273
|
+
"reason": "failure reason"
|
274
|
+
}
|
275
|
+
|
276
|
+
## GET /vehicles/{id}/command/charge_start
|
277
|
+
Start charging.
|
278
|
+
+ Parameters
|
279
|
+
|
280
|
+
+ id (number) ... The ID number of the car
|
281
|
+
|
282
|
+
+ Response 200 (application/json)
|
283
|
+
|
284
|
+
+ Body
|
285
|
+
|
286
|
+
{
|
287
|
+
"result": false,
|
288
|
+
"reason": "failure reason" // "already started" if a charge is in progress
|
289
|
+
}
|
290
|
+
|
291
|
+
## GET /vehicles/{id}/command/charge_stop
|
292
|
+
Stop charging.
|
293
|
+
+ Parameters
|
294
|
+
|
295
|
+
+ id (number) ... The ID number of the car
|
296
|
+
|
297
|
+
+ Response 200 (application/json)
|
298
|
+
|
299
|
+
+ Body
|
300
|
+
|
301
|
+
{
|
302
|
+
"result": false,
|
303
|
+
"reason": "failure reason" // "not_charging" if a charge was not in progress
|
304
|
+
}
|
305
|
+
|
306
|
+
## GET /vehicles/{id}/command/flash_lights
|
307
|
+
Flash the lights once.
|
308
|
+
+ Parameters
|
309
|
+
|
310
|
+
+ id (number) ... The ID number of the car
|
311
|
+
|
312
|
+
+ Response 200 (application/json)
|
313
|
+
|
314
|
+
+ Body
|
315
|
+
|
316
|
+
{
|
317
|
+
"result": false,
|
318
|
+
"reason": "failure reason"
|
319
|
+
}
|
320
|
+
|
321
|
+
## GET /vehicles/{id}/command/honk_horn
|
322
|
+
Honk the horn once.
|
323
|
+
+ Parameters
|
324
|
+
|
325
|
+
+ id (number) ... The ID number of the car
|
326
|
+
|
327
|
+
+ Response 200 (application/json)
|
328
|
+
|
329
|
+
+ Body
|
330
|
+
|
331
|
+
{
|
332
|
+
"result": false,
|
333
|
+
"reason": "failure reason"
|
334
|
+
}
|
335
|
+
|
336
|
+
## GET /vehicles/{id}/command/door_unlock
|
337
|
+
Unlock the car's doors.
|
338
|
+
+ Parameters
|
339
|
+
|
340
|
+
+ id (number) ... The ID number of the car
|
341
|
+
|
342
|
+
+ Response 200 (application/json)
|
343
|
+
|
344
|
+
+ Body
|
345
|
+
|
346
|
+
{
|
347
|
+
"result": false,
|
348
|
+
"reason": "failure reason"
|
349
|
+
}
|
350
|
+
|
351
|
+
## GET /vehicles/{id}/command/door_lock
|
352
|
+
Lock the car's doors.
|
353
|
+
+ Parameters
|
354
|
+
|
355
|
+
+ id (number) ... The ID number of the car
|
356
|
+
|
357
|
+
+ Response 200 (application/json)
|
358
|
+
|
359
|
+
+ Body
|
360
|
+
|
361
|
+
{
|
362
|
+
"result": false,
|
363
|
+
"reason": "failure reason"
|
364
|
+
}
|
365
|
+
|
366
|
+
## GET /vehicles/{id}/command/set_temps?driver_temp={driver_degC}&passenger_temp={pass_degC}
|
367
|
+
Set the temperature target for the HVAC system.
|
368
|
+
+ Parameters
|
369
|
+
|
370
|
+
+ id (number) ... The ID number of the car
|
371
|
+
+ driver_degC (number) ... The desired temperature on the driver's side in celcius.
|
372
|
+
+ pass_degC (number) ... The desired temperature on the passenger's side in celcius.
|
373
|
+
|
374
|
+
+ Response 200 (application/json)
|
375
|
+
|
376
|
+
+ Body
|
377
|
+
|
378
|
+
{
|
379
|
+
"result": false,
|
380
|
+
"reason": "failure reason"
|
381
|
+
}
|
382
|
+
|
383
|
+
## GET /vehicles/{id}/command/auto_conditioning_start
|
384
|
+
Start the HVAC system. Will cool or heat automatically, depending on set temperature.
|
385
|
+
+ Parameters
|
386
|
+
|
387
|
+
+ id (number) ... The ID number of the car
|
388
|
+
|
389
|
+
+ Response 200 (application/json)
|
390
|
+
|
391
|
+
+ Body
|
392
|
+
|
393
|
+
{
|
394
|
+
"result": false,
|
395
|
+
"reason": "failure reason"
|
396
|
+
}
|
397
|
+
|
398
|
+
## GET /vehicles/{id}/command/auto_conditioning_stop
|
399
|
+
Stop the HVAC system.
|
400
|
+
+ Parameters
|
401
|
+
|
402
|
+
+ id (number) ... The ID number of the car
|
403
|
+
|
404
|
+
+ Response 200 (application/json)
|
405
|
+
|
406
|
+
+ Body
|
407
|
+
|
408
|
+
{
|
409
|
+
"result": false,
|
410
|
+
"reason": "failure reason"
|
411
|
+
}
|
412
|
+
|
413
|
+
## GET /vehicles/{id}/command/sun_roof_control?state={state}
|
414
|
+
Controls the car's panoramic roof, if installed.
|
415
|
+
+ Parameters
|
416
|
+
|
417
|
+
+ id (number) ... The ID number of the car
|
418
|
+
+ state (string)
|
419
|
+
The desired state of the panoramic roof. The approximate percent open values for each state are `open` = 100%, `close` = 0%, `comfort` = 80%, and `vent` = ~15%
|
420
|
+
+ Values
|
421
|
+
+ `open`
|
422
|
+
+ `close`
|
423
|
+
+ `comfort`
|
424
|
+
+ `vent`
|
425
|
+
|
426
|
+
+ Response 200 (application/json)
|
427
|
+
|
428
|
+
+ Body
|
429
|
+
|
430
|
+
{
|
431
|
+
"result": false,
|
432
|
+
"reason": "failure reason"
|
433
|
+
}
|
data/lib/tesla_api.rb
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
require "tesla_api/version"
|
2
|
+
|
3
|
+
class TeslaApi
|
4
|
+
include HTTParty
|
5
|
+
base_uri "https://owner-api.teslamotors.com/api/1"
|
6
|
+
format :json
|
7
|
+
|
8
|
+
attr_reader :email
|
9
|
+
|
10
|
+
def initialize(email, password, client_id, client_secret)
|
11
|
+
@email = email
|
12
|
+
response = self.class.post(
|
13
|
+
"https://owner-api.teslamotors.com/oauth/token",
|
14
|
+
body: {
|
15
|
+
"grant_type" => "password",
|
16
|
+
"client_id" => client_id,
|
17
|
+
"client_secret" => client_secret,
|
18
|
+
"email" => email,
|
19
|
+
"password" => password
|
20
|
+
}
|
21
|
+
)
|
22
|
+
self.class.headers "Authorization" => "Bearer #{response["access_token"]}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def vehicles
|
26
|
+
self.class.get("/vehicles")["response"].map { |v| Vehicle.new(self.class, email, v["id"], v) }
|
27
|
+
end
|
28
|
+
|
29
|
+
class Vehicle
|
30
|
+
attr_reader :api, :email, :id, :vehicle
|
31
|
+
|
32
|
+
def initialize(api, email, id, vehicle)
|
33
|
+
@api = api
|
34
|
+
@email = email
|
35
|
+
@id = id
|
36
|
+
@vehicle = vehicle
|
37
|
+
end
|
38
|
+
|
39
|
+
def [](key)
|
40
|
+
vehicle[key]
|
41
|
+
end
|
42
|
+
|
43
|
+
# State
|
44
|
+
|
45
|
+
def mobile_enabled
|
46
|
+
api.get("/vehicles/#{id}/mobile_enabled")["response"]
|
47
|
+
end
|
48
|
+
|
49
|
+
def charge_state
|
50
|
+
api.get("/vehicles/#{id}/data_request/charge_state")["response"]
|
51
|
+
end
|
52
|
+
|
53
|
+
def climate_state
|
54
|
+
api.get("/vehicles/#{id}/data_request/climate_state")["response"]
|
55
|
+
end
|
56
|
+
|
57
|
+
def drive_state
|
58
|
+
api.get("/vehicles/#{id}/data_request/drive_state")["response"]
|
59
|
+
end
|
60
|
+
|
61
|
+
def gui_settings
|
62
|
+
api.get("/vehicles/#{id}/data_request/gui_settings")["response"]
|
63
|
+
end
|
64
|
+
|
65
|
+
def vehicle_state
|
66
|
+
api.get("/vehicles/#{id}/data_request/vehicle_state")["response"]
|
67
|
+
end
|
68
|
+
|
69
|
+
# Commands
|
70
|
+
|
71
|
+
def wake_up
|
72
|
+
api.post("/vehicles/#{id}/wake_up")
|
73
|
+
end
|
74
|
+
|
75
|
+
def charge_port_door_open
|
76
|
+
api.post("/vehicles/#{id}/command/charge_port_door_open")
|
77
|
+
end
|
78
|
+
|
79
|
+
def charge_standard
|
80
|
+
api.post("/vehicles/#{id}/command/charge_standard")
|
81
|
+
end
|
82
|
+
|
83
|
+
def charge_max_range
|
84
|
+
api.post("/vehicles/#{id}/command/charge_max_range")
|
85
|
+
end
|
86
|
+
|
87
|
+
def set_charge_limit(percent)
|
88
|
+
api.post("/vehicles/#{id}/command/set_charge_limit", query: {state: "set", percent: percent})
|
89
|
+
end
|
90
|
+
|
91
|
+
def charge_start
|
92
|
+
api.post("/vehicles/#{id}/command/charge_start")
|
93
|
+
end
|
94
|
+
|
95
|
+
def charge_stop
|
96
|
+
api.post("/vehicles/#{id}/command/charge_stop")
|
97
|
+
end
|
98
|
+
|
99
|
+
def flash_lights
|
100
|
+
api.post("/vehicles/#{id}/command/flash_lights")
|
101
|
+
end
|
102
|
+
|
103
|
+
def honk_horn
|
104
|
+
api.post("/vehicles/#{id}/command/honk_horn")
|
105
|
+
end
|
106
|
+
|
107
|
+
def door_unlock
|
108
|
+
api.post("/vehicles/#{id}/command/door_unlock")
|
109
|
+
end
|
110
|
+
|
111
|
+
def door_lock
|
112
|
+
api.post("/vehicles/#{id}/command/door_lock")
|
113
|
+
end
|
114
|
+
|
115
|
+
def set_temps(driver_temp, passenger_temp)
|
116
|
+
api.post("/vehicles/#{id}/command/set_temps", query: {driver_temp: driver_temp, passenger_temp: passenger_temp})
|
117
|
+
end
|
118
|
+
|
119
|
+
def auto_conditioning_start
|
120
|
+
api.post("/vehicles/#{id}/command/auto_conditioning_start")
|
121
|
+
end
|
122
|
+
|
123
|
+
def auto_conditioning_stop
|
124
|
+
api.post("/vehicles/#{id}/command/auto_conditioning_stop")
|
125
|
+
end
|
126
|
+
|
127
|
+
def sun_roof_control(state)
|
128
|
+
api.post("/vehicles/#{id}/command/sun_roof_control", query: {state: state})
|
129
|
+
end
|
130
|
+
|
131
|
+
def sun_roof_move(percent)
|
132
|
+
api.post("/vehicles/#{id}/command/sun_roof_control", query: {state: "move", percent: percent})
|
133
|
+
end
|
134
|
+
|
135
|
+
# Streaming
|
136
|
+
|
137
|
+
def stream(&reciever)
|
138
|
+
EventMachine.run do
|
139
|
+
request = EventMachine::HttpRequest.new(
|
140
|
+
"https://streaming.vn.teslamotors.com/stream/#{self["vehicle_id"]}/" +
|
141
|
+
"?values=speed,odometer,soc,elevation,est_heading,est_lat,est_lng,power")
|
142
|
+
|
143
|
+
http = request.get(
|
144
|
+
head: {
|
145
|
+
"authorization" => [
|
146
|
+
email,
|
147
|
+
self["tokens"].first
|
148
|
+
]
|
149
|
+
},
|
150
|
+
inactivity_timeout: 15)
|
151
|
+
|
152
|
+
http.stream do |chunk|
|
153
|
+
attributes = chunk.split(",")
|
154
|
+
reciever.call({
|
155
|
+
time: DateTime.strptime((attributes[0].to_i/1000).to_s, "%s"),
|
156
|
+
speed: attributes[1].to_f,
|
157
|
+
odometer: attributes[2].to_f,
|
158
|
+
soc: attributes[3].to_f,
|
159
|
+
elevation: attributes[4].to_f,
|
160
|
+
est_heading: attributes[5].to_f,
|
161
|
+
est_lat: attributes[6].to_f,
|
162
|
+
est_lng: attributes[7].to_f,
|
163
|
+
power: attributes[8].to_f
|
164
|
+
})
|
165
|
+
end
|
166
|
+
|
167
|
+
http.callback { EventMachine.stop }
|
168
|
+
http.errback { EventMachine.stop }
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
data/logs/login.GET.log
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
GET /login HTTP/1.1
|
2
|
+
Host: portal.vn.teslamotors.com
|
3
|
+
Connection: Keep-Alive
|
4
|
+
Accept-Encoding: gzip deflate
|
5
|
+
|
6
|
+
|
7
|
+
HTTP/1.1 200 OK
|
8
|
+
Content-Type: text/html; charset=utf-8
|
9
|
+
X-UA-Compatible: IE=Edge,chrome=1
|
10
|
+
ETag: "68693d0c80ee503a112cafc18a273525"
|
11
|
+
Cache-Control: max-age=0, private, must-revalidate
|
12
|
+
Set-Cookie: _s_portal_session=x; path=/; secure; HttpOnly
|
13
|
+
X-Request-Id: 80985fcba166592ed09cce956fd395d6
|
14
|
+
X-Runtime: 0.006161
|
15
|
+
Date: Sun, 03 Feb 2013 03:01:52 GMT
|
16
|
+
X-Rack-Cache: miss
|
17
|
+
Server: thin 1.4.1 codename Chromeo
|
18
|
+
Transfer-Encoding: chunked
|
19
|
+
|
20
|
+
205
|
21
|
+
<!DOCTYPE html>
|
22
|
+
<html>
|
23
|
+
<head>
|
24
|
+
<title>Portal</title>
|
25
|
+
<script src="/assets/application-a5592d882a1bdc39d6b26c108a8ffbe0.js" type="text/javascript"></script>
|
26
|
+
<meta content="authenticity_token" name="csrf-param" />
|
27
|
+
<meta content="kOHBAsesbSMy0AJKsPC7f9aI/QgE9g4SxbUcfZAhvdg=" name="csrf-token" />
|
28
|
+
<meta name="csrf-token" content="kOHBAsesbSMy0AJKsPC7f9aI/QgE9g4SxbUcfZAhvdg=">
|
29
|
+
|
30
|
+
<link href='/images/favicon.ico' rel='shortcut icon'>
|
31
|
+
|
32
|
+
</head>
|
33
|
+
<body>
|
34
|
+
<header>
|
35
|
+
<li><a href="/login">Login</a></li>
|
36
|
+
</header>
|
37
|
+
|
38
|
+
|
39
|
+
</body>
|
40
|
+
</html>
|
41
|
+
|
42
|
+
0
|
43
|
+
|
44
|
+
|
data/logs/login.POST.log
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
POST /login HTTP/1.1
|
2
|
+
Content-Length: 81
|
3
|
+
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
|
4
|
+
Host: portal.vn.teslamotors.com
|
5
|
+
Connection: Keep-Alive
|
6
|
+
Cookie: _s_portal_session=BAh7B0kiD3Nlc3Npb25faWQGOgZFRkkiJWI2YzM0ZTJkMzZkMTk4ZWVkYjkzYzBiYWNmMzI3MTZkBjsAVEkiEF9jc3JmX3Rva2VuBjsARkkiMWtPSEJBc2VzYlNNeTBBSktzUEM3ZjlhSS9RZ0U5ZzRTeGJVY2ZaQWh2ZGc9BjsARg%3D%3D--da659682afba93065edfe2932903edc6eb16d0ac
|
7
|
+
Cookie2: $Version=1
|
8
|
+
Accept-Encoding: gzip deflate
|
9
|
+
|
10
|
+
user_session%5Bpassword%5D=xxx&user_session%5Bemail%5D=xxx%40xxx.com
|
11
|
+
HTTP/1.1 302 Found
|
12
|
+
Location: https://portal.vn.teslamotors.com/
|
13
|
+
Content-Type: text/html; charset=utf-8
|
14
|
+
X-UA-Compatible: IE=Edge,chrome=1
|
15
|
+
Cache-Control: no-cache
|
16
|
+
Set-Cookie: user_credentials=x; path=/; expires=Fri, 03-May-2013 03:01:54 GMT; secure; HttpOnly
|
17
|
+
Set-Cookie: _s_portal_session=x; path=/; secure; HttpOnly
|
18
|
+
X-Request-Id: a1c6e1dc7d2ba9c1c8cdec6ad536b2e4
|
19
|
+
X-Runtime: 1.129245
|
20
|
+
Date: Sun, 03 Feb 2013 03:01:54 GMT
|
21
|
+
X-Rack-Cache: invalidate, pass
|
22
|
+
Server: thin 1.4.1 codename Chromeo
|
23
|
+
Transfer-Encoding: chunked
|
24
|
+
|
25
|
+
64
|
26
|
+
<html><body>You are being <a href="https://portal.vn.teslamotors.com/">redirected</a>.</body></html>
|
27
|
+
0
|
28
|
+
|
29
|
+
|
data/logs/root.GET.log
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
GET / HTTP/1.1
|
2
|
+
Host: portal.vn.teslamotors.com
|
3
|
+
Connection: Keep-Alive
|
4
|
+
Cookie: _s_portal_session=x; user_credentials=x
|
5
|
+
Cookie2: $Version=1
|
6
|
+
Accept-Encoding: gzip deflate
|
7
|
+
|
8
|
+
|
9
|
+
HTTP/1.1 200 OK
|
10
|
+
Content-Type: text/html; charset=utf-8
|
11
|
+
X-UA-Compatible: IE=Edge,chrome=1
|
12
|
+
ETag: "389b2980d80c9fac569172b31c06dddb"
|
13
|
+
Cache-Control: must-revalidate, private, max-age=0
|
14
|
+
Set-Cookie: _s_portal_session=x; path=/; secure; HttpOnly
|
15
|
+
X-Request-Id: 2c54d0edded8b93de51a3cbf8a5dd3e9
|
16
|
+
X-Runtime: 0.007121
|
17
|
+
Date: Sun, 03 Feb 2013 03:01:54 GMT
|
18
|
+
X-Rack-Cache: miss
|
19
|
+
Server: thin 1.4.1 codename Chromeo
|
20
|
+
Transfer-Encoding: chunked
|
21
|
+
|
22
|
+
249
|
23
|
+
<!DOCTYPE html>
|
24
|
+
<html>
|
25
|
+
<head>
|
26
|
+
<title>Portal</title>
|
27
|
+
<script src="/assets/application-a5592d882a1bdc39d6b26c108a8ffbe0.js" type="text/javascript"></script>
|
28
|
+
<meta content="authenticity_token" name="csrf-param" />
|
29
|
+
<meta content="6/1QjgCk7xTyDJGAK8xIpCNAShD8a6NSco4rbEyz6bw=" name="csrf-token" />
|
30
|
+
<meta name="csrf-token" content="6/1QjgCk7xTyDJGAK8xIpCNAShD8a6NSco4rbEyz6bw=">
|
31
|
+
|
32
|
+
<link href='/images/favicon.ico' rel='shortcut icon'>
|
33
|
+
|
34
|
+
</head>
|
35
|
+
<body>
|
36
|
+
<header>
|
37
|
+
|
38
|
+
<li>
|
39
|
+
<a href="/logout" data-method="delete" rel="nofollow">Logout</a>
|
40
|
+
</li>
|
41
|
+
</header>
|
42
|
+
|
43
|
+
Welcome to the portal app.
|
44
|
+
|
45
|
+
</body>
|
46
|
+
</html>
|
47
|
+
|
48
|
+
0
|
49
|
+
|
50
|
+
|
data/tesla_api.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'tesla_api/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "tesla_api"
|
7
|
+
spec.version = TeslaApi::VERSION
|
8
|
+
spec.authors = ["Tim Dorr"]
|
9
|
+
spec.email = ["timdorr@timdorr.com"]
|
10
|
+
spec.summary = %q{A wrapper for the Tesla API}
|
11
|
+
spec.description = %q{Check the state of your Tesla Model S and issue basic commands. Stream data from the car's telematics system.}
|
12
|
+
spec.homepage = "https://github.com/timdorr/model-s-api"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tesla_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tim Dorr
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Check the state of your Tesla Model S and issue basic commands. Stream
|
42
|
+
data from the car's telematics system.
|
43
|
+
email:
|
44
|
+
- timdorr@timdorr.com
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- apiary.apib
|
55
|
+
- lib/tesla_api.rb
|
56
|
+
- lib/tesla_api/version.rb
|
57
|
+
- logs/login.GET.log
|
58
|
+
- logs/login.POST.log
|
59
|
+
- logs/root.GET.log
|
60
|
+
- tesla_api.gemspec
|
61
|
+
homepage: https://github.com/timdorr/model-s-api
|
62
|
+
licenses:
|
63
|
+
- MIT
|
64
|
+
metadata: {}
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 2.2.2
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: A wrapper for the Tesla API
|
85
|
+
test_files: []
|