tesla_api 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0a2c77105e4ceabe402f838427c9efbfb917d7f74b49d3f5f6637e3581e0678
4
- data.tar.gz: f07b11556f4d3a4a874d68ed9ced60ba40e71f759f251b0449a07fcf1513b8a0
3
+ metadata.gz: 310c9a551e9ace78ebf8eeee97d301ef30421545f0c0a876532653bad401d00f
4
+ data.tar.gz: 01344c140bec766dd95697124888b9b860d8a1a3028811d64ec41e15ff5f4adf
5
5
  SHA512:
6
- metadata.gz: ba1727791cdb0493e9a703e55d3b400d4c59dc300d5e1d463482c3622466f0f6172904c6185273405188735337b42c7ffaf055c1fe1e1b7fbd984a7894f85b34
7
- data.tar.gz: 5d73d9cf6960742d4d63b013b2ece343879a4809cb4f9dccf4ac1e1dd3f9e36f6b2e3b731bf9675d70a512f6afc6ddea9a03052ab81f65283be26e8cc6124d39
6
+ metadata.gz: 7b5c85dfc21d90bb311b8818d636d2e320aff0ca5fd5da3d6a99046c717dd91cd7b0d1ba0404d130aec49f55904442776cf1df3b78e3dfd5661aa6f92c92bfbd
7
+ data.tar.gz: 8f5bf9d04e7ee75980510f5705ecc8d1530086798a858c9a65744ac2eeb346173bbaa290898dd649c1e666e4f2b6df2f92a533f059e7f60adcbaf82afd9cb0e6
data/README.md CHANGED
@@ -36,8 +36,11 @@ Here's a quick example:
36
36
  ```ruby
37
37
  require 'tesla_api'
38
38
 
39
- tesla_api = TeslaApi::Client.new(email, client_id, client_secret)
40
- tesla_api.login!(password) # Or tesla_api.token = token if you have an existing token.
39
+ tesla_api = TeslaApi::Client.new(email: email, client_id: client_id, client_secret: client_secret)
40
+ tesla_api.login!(password)
41
+ # Or if you have an access token:
42
+ tesla_api = TeslaApi::Client.new(access_token: access_token)
43
+
41
44
  model_s = tesla_api.vehicles.first # => <TeslaApi::Vehicle>
42
45
 
43
46
  model_s.wake_up
data/Rakefile CHANGED
@@ -19,7 +19,7 @@ task :console do
19
19
  # Set up a global client
20
20
  def client
21
21
  @client ||= begin
22
- client = TeslaApi::Client.new(ENV['TESLA_EMAIL'])
22
+ client = TeslaApi::Client.new(email: ENV['TESLA_EMAIL'])
23
23
  client.login!(ENV['TESLA_PASS'])
24
24
  client
25
25
  end
@@ -30,7 +30,7 @@ appreciated!_
30
30
  | AD09 | Adapter, Swiss (1 phase, 10A) | |
31
31
  | AD10 | Adapter, Denmark (1 phase, 13A) | |
32
32
  | AD11 | Adapter, Italy (1 phase, 13A) | |
33
- | AD15 | ? | |
33
+ | AD15 | Adapter | J1772 |
34
34
  | ADPX2 | Type 2 Public Charging Connector | |
35
35
  | ADX4 | No European 3-Phase | |
36
36
  | ADX5 | European 3-Phase, IT | |
@@ -38,7 +38,7 @@ appreciated!_
38
38
  | ADX7 | No - 3-ph Red IEC309 (3 phase, 16A) | |
39
39
  | ADX9 | No - Adapter, Swiss (1 phase, 10A) | |
40
40
  | ADX8 | Blue IEC309 (1 phase, 230V 32A) | |
41
- | AF00 | No HEPA Filter | |
41
+ | AF00 | No HEPA Filter | Standard air filter, no air ionizer |
42
42
  | AF02 | HEPA Filter | |
43
43
  | AH00 | No Accessory Hitch | |
44
44
  | APE1 | Enhanced Autopilot | |
@@ -55,17 +55,19 @@ appreciated!_
55
55
  | APPB | Enhanced Autopilot | |
56
56
  | AU00 | No Audio Package | |
57
57
  | AU01 | Ultra High Fidelity Sound | |
58
+ | AU3P | Sound Studio Package | Premium audio package |
58
59
  | BC0B | Black Brake Calipers | |
59
60
  | BC0R | Red Brake Calipers | |
60
61
  | BC3B | Black Brake Calipers, Model 3 | |
61
62
  | BCMB | Black Brake Calipers | |
62
63
  | BCYR | Performance Brakes | |
64
+ | BG30 | No Badge | Model 3 |
63
65
  | BP00 | No Ludicrous | |
64
66
  | BP01 | Ludicrous Speed Upgrade | |
65
67
  | BR00 | No Battery Firmware Limit | |
66
68
  | BR03 | Battery Firmware Limit (60kWh) | |
67
69
  | BR05 | Battery Firmware Limit (75kWh) | |
68
- | BS00 | General Production Flag | |
70
+ | BS00 | Blind Spot Sensor Package | |
69
71
  | BS01 | Special Production Flag | |
70
72
  | BT37 | 75 kWh (Model 3) | |
71
73
  | BT40 | 40 kWh | |
@@ -85,7 +87,7 @@ appreciated!_
85
87
  | CF00 | High Power Charger | |
86
88
  | CF01 | 48amp charger | |
87
89
  | CH00 | Standard Charger (40 Amp) | |
88
- | CH01 | Dual Chargers (80 Amp) | |
90
+ | CH01 | Dual Chargers (80 Amp) | Twin 10kW charge config |
89
91
  | CH04 | 72 Amp Charger (Model S/X) | |
90
92
  | CH05 | 48 Amp Charger (Model S/X) | |
91
93
  | CH07 | 48 Amp Charger (Model 3) | |
@@ -96,32 +98,38 @@ appreciated!_
96
98
  | COUS | Country: United States | |
97
99
  | CONL | Country: Netherlands | |
98
100
  | CPW1 | 20" Performance Wheels | |
99
- | CW00 | No Cold Weather Package | |
100
- | CW02 | Subzero Weather Package | |
101
+ | CW00 | Weather Package | No Cold Weather Package |
102
+ | CW02 | Weather Package | Subzero Weather Package |
101
103
  | DA00 | No Autopilot | |
102
- | DA01 | Active Safety (ACC,LDW,SA) | |
104
+ | DA01 | Active Safety (ACC,LDW,SA) | Drivers Assistance Package |
103
105
  | DA02 | Autopilot Convenience Features | |
104
106
  | DCF0 | Autopilot Convenience Features (DCF0) | |
105
107
  | DRLH | Left Hand Drive | |
106
108
  | BC3R | Performance Brakes | Model 3 |
107
109
  | DRRH | Right Hand Drive | |
108
- | DSH5 | PUR Dash Pad | |
110
+ | DSH5 | Dashboard | PUR Dashboard Pad |
109
111
  | DSH7 | Alcantara Dashboard Accents | |
110
112
  | DSHG | PUR Dash Pad | |
111
113
  | DU00 | Drive Unit - IR | |
112
114
  | DU01 | Drive Unit - Infineon | |
113
115
  | DV2W | Rear-Wheel Drive | |
114
116
  | DV4W | All-Wheel Drive | |
117
+ | FC3P | Front Console Front Console (Premium) | Model 3 |
115
118
  | FG00 | No Exterior Lighting Package | |
116
- | FG01 | Exterior Lighting Package | |
117
- | FG02 | Exterior Lighting Package | |
119
+ | FG01 | Fog Lamps | Exterior Lighting Package |
120
+ | FG02 | Fog Lamps | Fog Lamps |
121
+ | FG31 | Fog Lamps | Premium Fog Lights (Model 3) |
122
+ | FM3B | Performance Package (Model 3) | |
118
123
  | FMP6 | FMP6 | |
119
124
  | FR01 | Base Front Row | |
120
125
  | FR02 | Ventilated Front Seats | |
121
126
  | FR03 | FR03 | |
122
127
  | FR04 | FR04 | |
128
+ | GLFR | Assembly | Final Assembly Fremont |
123
129
  | HC00 | No Home Charging installation | |
124
130
  | HC01 | Home Charging Installation | |
131
+ | HM31 | Teck Package - Homelink | Homelink |
132
+ | HL31 | Head Lamp (Model 3) | Uplevel Headlamps |
125
133
  | HP00 | No HPWC Ordered | |
126
134
  | HP01 | HPWC Ordered | |
127
135
  | ID3W | (Model 3) Wood Decor | |
@@ -132,7 +140,7 @@ appreciated!_
132
140
  | IDOM | Matte Obeche Wood Decor | |
133
141
  | IDOG | Gloss Obeche Wood Decor | |
134
142
  | IDLW | Lacewood Decor | |
135
- | IDPB | Piano Black Decor | |
143
+ | IDPB | Piano Black Decor | |
136
144
  | IN3BB | All Black Partial Premium Interior | |
137
145
  | IN3PB | All Black Premium Interior | |
138
146
  | INBBW | White | |
@@ -145,6 +153,7 @@ appreciated!_
145
153
  | INWPT | Tan Interior | |
146
154
  | INYPB | All Black Premium Interior | |
147
155
  | INYPW | Black and White Premium Interior | |
156
+ | IL31 | Interior Ambient Lighting | |
148
157
  | IVBPP | All Black Interior | |
149
158
  | IVBSW | Ultra White Interior | |
150
159
  | IVBTB | All Black Interior | |
@@ -153,10 +162,11 @@ appreciated!_
153
162
  | IX01 | Extended Nappa Leather Trim | |
154
163
  | LLP1 | LLP1 | |
155
164
  | LLP2 | LLP2 | |
156
- | LP01 | Premium Interior Lighting | |
165
+ | LP00 | Lighting Package | No Lighting Package |
166
+ | LP01 | Lighting Package | Premium Interior Lighting |
157
167
  | LT00 | Vegan interior | |
158
168
  | LT01 | Standard interior | |
159
- | LT1B | LT1B | |
169
+ | LT1B | Lower Trim | Lower Trim |
160
170
  | LT3W | LT3W | |
161
171
  | LT4B | LT4B | |
162
172
  | LT4C | LT4C | |
@@ -166,11 +176,13 @@ appreciated!_
166
176
  | LT6P | LT6P | |
167
177
  | LTPB | Lower Trim PUR Black | |
168
178
  | ME01 | Memory Seats | |
169
- | ME02 | Memory Seats | |
179
+ | ME02 | Seat Memory | Seat Memory LHD Driver |
170
180
  | MI00 | 2015 Production Refresh | |
181
+ | MI00 | Project/Program Code M3 | Base Manufacturing Intro Code |
171
182
  | MI01 | 2016 Production Refresh | |
172
183
  | MI02 | 2017 Production Refresh | |
173
184
  | MI03 | 201? Production Refresh | Found on Model X ordered 11/2018 delivered 3/2019 |
185
+ | MR31 | Tech Package - Mirror -YES | Uplevel Mirrors |
174
186
  | MT300 | Standard Range Rear-Wheel Drive | |
175
187
  | MT301 | Standard Range Plus Rear-Wheel Drive | |
176
188
  | MT302 | Long Range Rear-Wheel Drive | |
@@ -192,7 +204,7 @@ appreciated!_
192
204
  | PF01 | Performance Legacy Package | |
193
205
  | PI00 | No Premium Interior | |
194
206
  | PI01 | Premium Upgrades Package | |
195
- | PK00 | LEGACY No Parking Sensors | |
207
+ | PK00 | Parking Sensors | |
196
208
  | PMAB | Anza Brown Metallic Color | |
197
209
  | PMBL | Obsidian Black Multi-Coat Color | |
198
210
  | PMMB | Monterey Blue Metallic Color | |
@@ -206,6 +218,7 @@ appreciated!_
206
218
  | PPSR | Signature Red Color | |
207
219
  | PPSW | Pearl White Multi-Coat Color | |
208
220
  | PPTI | Titanium Metallic Color | |
221
+ | PL30 | No Aluminum Pedal | |
209
222
  | PL31 | Performance Pedals | Model 3 |
210
223
  | PRM30 | Partial Premium Interior | |
211
224
  | PRM31 | Premium Interior | |
@@ -213,6 +226,7 @@ appreciated!_
213
226
  | PRMY1 | Premium Interior | |
214
227
  | PS00 | No Parcel Shelf | |
215
228
  | PS01 | Parcel Shelf | |
229
+ | RS3H | Second Row Seat Rear Seats (Heated) | Model 3 |
216
230
  | PX00 | No Performance Plus Package | |
217
231
  | PX01 | Performance Plus | |
218
232
  | PX6D | Zero to 60 in 2.5 sec | |
@@ -242,32 +256,40 @@ appreciated!_
242
256
  | RCX0 | No Rear Console | |
243
257
  | RF3G | Model 3 Glass Roof | |
244
258
  | RFBK | Black Roof | |
245
- | RFBC | Body Color Roof | |
259
+ | RFBC | Body Color Roof | Roof |
246
260
  | RFFG | Glass Roof | |
247
261
  | RFP0 | All Glass Panoramic Roof | |
248
262
  | RFP2 | Sunroof | |
249
263
  | RFPX | Model X Roof | |
264
+ | S02B | Seat | BLK Leather |
250
265
  | S02P | S02P | |
251
266
  | S31B | S31B | |
252
267
  | S32C | S32C | |
253
268
  | S32P | S32P | |
254
269
  | S32W | S32W | |
270
+ | S3PB | Seat Black PUR Premium Seats | |
255
271
  | SC00 | No Supercharging | |
256
272
  | SC01 | Supercharging Enabled | |
257
273
  | SC04 | Pay Per Use Supercharging | |
258
274
  | SC05 | Free Supercharging | |
275
+ | SLR0 | No Rear Spoiler | |
259
276
  | SP00 | No Security Package | |
260
- | SR01 | Standard 2nd row | |
277
+ | SR01 | Standard 2nd row | Second Row Seat |
261
278
  | SR06 | Seven Seat Interior | |
262
279
  | SR07 | Standard 2nd row | |
263
280
  | ST00 | Non-leather Steering Wheel | |
264
281
  | ST01 | Non-heated Leather Steering Wheel | |
282
+ | ST31 | Steering Wheel | Premium Steering Wheel |
283
+ | STCP | Steering Wheel | Steering Column (Power) |
265
284
  | STY5S | Five Seat Interior | |
266
285
  | STY7S | Seven Seat Interior | |
267
286
  | SU00 | Standard Suspension | |
268
287
  | SU01 | Smart Air Suspension | |
269
- | TIC4 | All-Season Tires | |
270
- | TM00 | General Production Trim | |
288
+ | SU3C | Suspension | Coil spring suspension |
289
+ | T3MA | Tires M3 | 18 Michelin All Season, Square |
290
+ | TIC4 | Tires | All-Season Tires |
291
+ | TIMP | Tires | Michelin Primacy 19" Tire |
292
+ | TM00 | Model Trim | General Production Series Vehicle |
271
293
  | TM02 | General Production Signature Trim | |
272
294
  | TM0A | ALPHA PRE-PRODUCTION NON-SALEABLE | |
273
295
  | TM0B | BETA PRE-PRODUCTION NON-SALEABLE | |
@@ -275,22 +297,28 @@ appreciated!_
275
297
  | TP01 | Tech Package - No Autopilot | |
276
298
  | TP02 | Tech Package with Autopilot | |
277
299
  | TP03 | Tech Package with Enhanced Autopilot | |
278
- | TR00 | No Third Row Seat | |
300
+ | TR00 | No Rear Facing Seats |
279
301
  | TR01 | Third Row Seating | |
280
302
  | TRA1 | Third Row HVAC | |
281
- | TW01 | Towing Package | |
303
+ | TW00 | No Tow Package | |
304
+ | TW01 | Tow Package | |
282
305
  | UM01 | Universal Mobile Charger - US Port (Single) | |
306
+ | UT3P | Suede Grey Premium Headliner | |
283
307
  | UTAB | Black Alcantara Headliner | |
284
308
  | UTAW | Light Headliner | |
309
+ | UTMF | Headliner | |
285
310
  | UTPB | Dark Headliner | |
286
311
  | UTSB | Dark Headliner | |
287
312
  | UTZW | Light Headliner | |
313
+ | USSB | Safety | Safety US Black |
288
314
  | SLR1 | Carbon Fibre Spoiler | Model 3 |
289
315
  | SPT31 | Performance Upgrade | Model 3 |
290
316
  | SPTY1 | Performance Upgrade | Model Y |
291
317
  | W32P | 20" Performance Wheels | Model 3 |
292
318
  | W38B | 18" Aero Wheels | For the Model 3 and Model Y |
293
319
  | W39B | 19" Sport Wheels | |
320
+ | WR00 | No Wrap | |
321
+ | WT19 | 19" Wheels | |
294
322
  | WT20 | 20" Silver Slipstream Wheels | |
295
323
  | WT22 | 22" Silver Turbine Wheels | |
296
324
  | WTAB | 21" Black Arachnid Wheels | |
@@ -338,14 +366,14 @@ appreciated!_
338
366
  | X014 | Override: No Satellite Radio | |
339
367
  | X019 | Carbon Fiber Spoiler | |
340
368
  | X020 | No Performance Exterior | |
341
- | X021 | No Spoiler | |
369
+ | X021 | No Rear Carbon Fiber Spoiler | |
342
370
  | X024 | Performance Package | |
343
- | X025 | No Performance Package | |
344
- | X027 | Lighted Door Handles | |
345
- | X028 | Battery Badge | |
371
+ | X025 | Performance Powertrain | |
372
+ | X027 | Lighted Door Handles | Light handle |
373
+ | X028 | Battery Badge | Normal Badging |
346
374
  | X029 | Remove Battery Badge | |
347
375
  | X030 | Override: No Passive Entry Pkg | |
348
- | X031 | Keyless Entry | |
376
+ | X031 | Keyless Entry | Passive Entry Pkg |
349
377
  | X037 | Powerfolding Mirrors | |
350
378
  | X039 | DAB Radio | |
351
379
  | X040 | No DAB Radio | |
data/lib/tesla_api.rb CHANGED
@@ -1,5 +1,10 @@
1
- require 'httparty'
2
- require 'em-http-request'
1
+ require 'date'
2
+ require 'base64'
3
+
4
+ require 'faraday'
5
+ require 'faraday_middleware'
6
+ require 'eventmachine'
7
+ require 'faye/websocket'
3
8
 
4
9
  require 'tesla_api/version'
5
10
  require 'tesla_api/client'
@@ -1,10 +1,8 @@
1
- require 'faye/websocket'
2
-
3
1
  module TeslaApi
4
2
  module Autopark
5
3
  def start_autopark(&handler)
6
4
  EventMachine.run do
7
- socket.on(:message) do |event|
5
+ autopark_socket.on(:message) do |event|
8
6
  message = if event.data.is_a?(Array)
9
7
  JSON.parse(event.data.map(&:chr).join)
10
8
  else
@@ -15,8 +13,8 @@ module TeslaApi
15
13
  handler.call(message.delete('msg_type'), message)
16
14
  end
17
15
 
18
- socket.on(:close) do |_|
19
- @socket = nil
16
+ autopark_socket.on(:close) do |_|
17
+ @autopark_socket = nil
20
18
  @heartbeat && @heartbeat.cancel
21
19
  EventMachine.stop
22
20
  end
@@ -34,14 +32,14 @@ module TeslaApi
34
32
  msg_type: 'autopark:heartbeat_app',
35
33
  timestamp: Time.now.to_i
36
34
  }
37
- socket.send(beat.to_json)
35
+ autopark_socket.send(beat.to_json)
38
36
  end
39
37
  end
40
38
  end
41
39
 
42
- def socket
43
- @socket ||= Faye::WebSocket::Client.new(
44
- socket_endpoint,
40
+ def autopark_socket
41
+ @autopark_socket ||= Faye::WebSocket::Client.new(
42
+ autopark_socket_endpoint,
45
43
  nil,
46
44
  {
47
45
  headers: {
@@ -55,7 +53,7 @@ module TeslaApi
55
53
  Base64.strict_encode64("#{email}:#{self['tokens'].first}")
56
54
  end
57
55
 
58
- def socket_endpoint
56
+ def autopark_socket_endpoint
59
57
  "wss://streaming.vn.teslamotors.com/connect/#{self['vehicle_id']}"
60
58
  end
61
59
  end
@@ -1,12 +1,8 @@
1
1
  module TeslaApi
2
2
  class Client
3
- include HTTParty
4
- base_uri 'https://owner-api.teslamotors.com/api/1'
5
- headers 'User-Agent' => "github.com/timdorr/tesla-api v:#{VERSION}"
6
- format :json
7
- raise_on [401]
3
+ attr_reader :api, :email, :access_token, :access_token_expires_at, :refresh_token, :client_id, :client_secret
8
4
 
9
- attr_reader :email, :access_token, :access_token_expires_at, :refresh_token, :client_id, :client_secret
5
+ BASE_URI = 'https://owner-api.teslamotors.com/api/1'
10
6
 
11
7
  def initialize(
12
8
  email: nil,
@@ -21,59 +17,54 @@ module TeslaApi
21
17
  @client_id = client_id
22
18
  @client_secret = client_secret
23
19
 
24
- self.update_token(
25
- access_token: access_token,
26
- access_token_expires_at: access_token_expires_at,
27
- refresh_token: refresh_token
28
- )
29
- end
30
-
31
- def update_token(access_token:, access_token_expires_at:, refresh_token:)
32
20
  @access_token = access_token
33
21
  @access_token_expires_at = access_token_expires_at
34
22
  @refresh_token = refresh_token
35
- self.class.headers 'Authorization' => "Bearer #{access_token}" if access_token
36
23
 
37
- access_token
24
+ @api = Faraday.new(
25
+ BASE_URI,
26
+ headers: { 'User-Agent' => "github.com/timdorr/tesla-api v:#{VERSION}" }
27
+ ) do |conn|
28
+ conn.request :json
29
+ conn.response :json
30
+ conn.response :raise_error
31
+ conn.adapter Faraday.default_adapter
32
+ end
38
33
  end
39
34
 
40
35
  def refresh_access_token
41
- response = self.class.post(
42
- 'https://owner-api.teslamotors.com/oauth/token',
43
- body: {
44
- grant_type: 'refresh_token',
45
- client_id: client_id,
46
- client_secret: client_secret,
47
- refresh_token: refresh_token
48
- }
49
- )
50
-
51
- self.update_token(
52
- access_token: response['access_token'],
53
- access_token_expires_at: Time.at(response['created_at'] + response['expires_in']).to_datetime,
54
- refresh_token: response['refresh_token']
55
- )
36
+ response = api.post(
37
+ 'https://owner-api.teslamotors.com/oauth/token',
38
+ {
39
+ grant_type: 'refresh_token',
40
+ client_id: client_id,
41
+ client_secret: client_secret,
42
+ refresh_token: refresh_token
43
+ }
44
+ ).body
45
+
46
+ @access_token = response['access_token']
47
+ @access_token_expires_at = Time.at(response['created_at'].to_f + response['expires_in'].to_f).to_datetime
48
+ @refresh_token = response['refresh_token']
56
49
 
57
50
  response
58
51
  end
59
52
 
60
53
  def login!(password)
61
- response = self.class.post(
62
- 'https://owner-api.teslamotors.com/oauth/token',
63
- body: {
64
- grant_type: 'password',
65
- client_id: client_id,
66
- client_secret: client_secret,
67
- email: email,
68
- password: password
69
- }
70
- )
71
-
72
- self.update_token(
73
- access_token: response['access_token'],
74
- access_token_expires_at: Time.at(response['created_at'] + response['expires_in']).to_datetime,
75
- refresh_token: response['refresh_token']
76
- )
54
+ response = api.post(
55
+ 'https://owner-api.teslamotors.com/oauth/token',
56
+ {
57
+ grant_type: 'password',
58
+ client_id: client_id,
59
+ client_secret: client_secret,
60
+ email: email,
61
+ password: password
62
+ }
63
+ ).body
64
+
65
+ @access_token = response['access_token']
66
+ @access_token_expires_at = Time.at(response['created_at'].to_f + response['expires_in'].to_f).to_datetime
67
+ @refresh_token = response['refresh_token']
77
68
 
78
69
  response
79
70
  end
@@ -83,12 +74,20 @@ module TeslaApi
83
74
  access_token_expires_at <= DateTime.now
84
75
  end
85
76
 
86
- def vehicles
87
- self.class.get('/vehicles')['response'].map { |v| Vehicle.new(self.class, email, v['id'], v) }
77
+ def get(url)
78
+ api.get(url.sub(/^\//, ''), nil, { 'Authorization' => "Bearer #{access_token}" }).body
88
79
  end
89
80
 
90
- private
81
+ def post(url, body: nil)
82
+ api.post(url.sub(/^\//, ''), body, { 'Authorization' => "Bearer #{access_token}" }).body
83
+ end
91
84
 
92
- attr_writer :refresh_token
85
+ def vehicles
86
+ get('/vehicles')['response'].map { |v| Vehicle.new(self, email, v['id'], v) }
87
+ end
88
+
89
+ def vehicle(id)
90
+ Vehicle.new(self, email, id, self.class.get("/vehicles/#{id}")['response'])
91
+ end
93
92
  end
94
93
  end
@@ -2,10 +2,19 @@ module TeslaApi
2
2
  module Stream
3
3
  def stream(&receiver)
4
4
  EventMachine.run do
5
- http.stream do |chunk|
6
- attributes = chunk.split(",")
5
+ socket = create_streaming_socket
7
6
 
8
- receiver.call({
7
+ socket.on(:open) do |event|
8
+ socket.send(JSON.generate(stream_connect_message))
9
+ end
10
+
11
+ socket.on(:message) do |event|
12
+ data = JSON.parse(event.data.pack('c*'))
13
+
14
+ if data['msg_type'] == 'data:update'
15
+ attributes = data['value'].split(',')
16
+
17
+ receiver.call({
9
18
  time: DateTime.strptime((attributes[0].to_i/1000).to_s, '%s'),
10
19
  speed: attributes[1].to_f,
11
20
  odometer: attributes[2].to_f,
@@ -19,35 +28,33 @@ module TeslaApi
19
28
  range: attributes[10].to_f,
20
29
  est_range: attributes[11].to_f,
21
30
  heading: attributes[12].to_f
22
- })
31
+ })
32
+ end
23
33
  end
24
34
 
25
- http.callback { EventMachine.stop }
26
- http.errback { EventMachine.stop }
35
+ socket.on(:close) do |event|
36
+ EventMachine.stop
37
+ end
27
38
  end
28
39
  end
29
40
 
30
41
  private
31
42
 
32
- def request
33
- @request ||= EventMachine::HttpRequest.new(
34
- "#{stream_endpoint}/stream/#{self['vehicle_id']}/?values=#{stream_params}")
35
- end
36
-
37
- def http
38
- request.get(
39
- head: {
40
- 'authorization' => [email, self['tokens'].first]
41
- },
42
- inactivity_timeout: 15)
43
+ def create_streaming_socket
44
+ Faye::WebSocket::Client.new(streaming_endpoint)
43
45
  end
44
46
 
45
- def stream_endpoint
46
- 'https://streaming.vn.teslamotors.com'
47
+ def streaming_endpoint
48
+ 'wss://streaming.vn.teslamotors.com/streaming/'
47
49
  end
48
50
 
49
- def stream_params
50
- 'speed,odometer,soc,elevation,est_heading,est_lat,est_lng,power,shift_state,range,est_range,heading'
51
+ def stream_connect_message
52
+ {
53
+ msg_type: 'data:subscribe',
54
+ token: Base64.strict_encode64("#{email}:#{self['tokens'].first}"),
55
+ value: 'speed,odometer,soc,elevation,est_heading,est_lat,est_lng,power,shift_state,range,est_range,heading',
56
+ tag: self['vehicle_id'].to_s,
57
+ }
51
58
  end
52
59
  end
53
60
  end
@@ -2,10 +2,10 @@ module TeslaApi
2
2
  class Vehicle
3
3
  include Stream
4
4
  include Autopark
5
- attr_reader :api, :email, :id, :vehicle
5
+ attr_reader :client, :api, :email, :id, :vehicle
6
6
 
7
- def initialize(api, email, id, vehicle)
8
- @api = api
7
+ def initialize(client, email, id, vehicle)
8
+ @client = client
9
9
  @email = email
10
10
  @id = id
11
11
  @vehicle = vehicle
@@ -28,15 +28,15 @@ module TeslaApi
28
28
  # State
29
29
 
30
30
  def data
31
- api.get("/vehicles/#{id}/data")['response']
31
+ client.get("/vehicles/#{id}/data")['response']
32
32
  end
33
33
 
34
34
  def mobile_enabled
35
- api.get("/vehicles/#{id}/mobile_enabled")['response']
35
+ client.get("/vehicles/#{id}/mobile_enabled")['response']
36
36
  end
37
37
 
38
38
  def nearby_charging_sites
39
- api.get("/vehicles/#{id}/nearby_charging_sites")['response']
39
+ client.get("/vehicles/#{id}/nearby_charging_sites")['response']
40
40
  end
41
41
 
42
42
  def gui_settings
@@ -62,7 +62,7 @@ module TeslaApi
62
62
  # Commands
63
63
 
64
64
  def wake_up
65
- @vehicle = api.post("/vehicles/#{id}/wake_up")['response']
65
+ @vehicle = client.post("/vehicles/#{id}/wake_up")['response']
66
66
  end
67
67
 
68
68
  def set_valet_mode(on, password=nil)
@@ -197,11 +197,11 @@ module TeslaApi
197
197
  private
198
198
 
199
199
  def data_request(name)
200
- api.get("/vehicles/#{id}/data_request/#{name}")
200
+ client.get("/vehicles/#{id}/data_request/#{name}")
201
201
  end
202
202
 
203
203
  def command(name, body: nil)
204
- api.post("/vehicles/#{id}/command/#{name}", body: body)
204
+ client.post("/vehicles/#{id}/command/#{name}", body: body)
205
205
  end
206
206
  end
207
207
  end
@@ -1,3 +1,3 @@
1
1
  module TeslaApi
2
- VERSION = '2.0.0'
2
+ VERSION = '3.0.0'
3
3
  end
@@ -19,12 +19,7 @@ RSpec.describe TeslaApi::Client do
19
19
 
20
20
  it 'logs into the API' do
21
21
  tesla_api.login!(ENV['TESLA_PASS'])
22
- expect(a_request(:post, "https://#{URI.parse(tesla_api.class.base_uri).host}/oauth/token")).to have_been_made.once
23
- end
24
-
25
- it 'sets a Bearer token header' do
26
- tesla_api.login!(ENV['TESLA_PASS'])
27
- expect(tesla_api.class.headers).to include({'Authorization' => /Bearer [a-z0-9]{32}/})
22
+ expect(a_request(:post, "https://#{URI.parse(TeslaApi::Client::BASE_URI).host}/oauth/token")).to have_been_made.once
28
23
  end
29
24
 
30
25
  it 'obtains a Bearer token' do
@@ -63,10 +58,6 @@ RSpec.describe TeslaApi::Client do
63
58
  it 'is not expired' do
64
59
  expect(tesla_api.expired?).to eq(false)
65
60
  end
66
-
67
- it 'sets a Bearer token header' do
68
- expect(tesla_api.class.headers).to include({'Authorization' => "Bearer #{access_token}"})
69
- end
70
61
  end
71
62
 
72
63
  describe '#refresh_access_token', vcr: {cassette_name: 'client-refresh'} do
data/tesla_api.gemspec CHANGED
@@ -14,9 +14,9 @@ Gem::Specification.new do |spec|
14
14
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
15
  spec.require_paths = ['lib']
16
16
 
17
- spec.add_dependency 'httparty'
17
+ spec.add_dependency 'faraday'
18
+ spec.add_dependency 'faraday_middleware'
18
19
  spec.add_dependency 'faye-websocket'
19
- spec.add_dependency 'em-http-request'
20
20
 
21
21
  spec.add_development_dependency 'bundler', '~> 2.0'
22
22
  spec.add_development_dependency 'rake', '~> 12.0'
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tesla_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Dorr
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-23 00:00:00.000000000 Z
11
+ date: 2019-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: httparty
14
+ name: faraday
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: faye-websocket
28
+ name: faraday_middleware
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: em-http-request
42
+ name: faye-websocket
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="