tesla_api 2.0.0 → 3.0.0

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 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
  - - ">="