tesla_api 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +5 -5
  2. data/.gitbook.yml +4 -0
  3. data/.travis.yml +3 -4
  4. data/LICENSE +1 -1
  5. data/README.md +7 -3
  6. data/Rakefile +27 -1
  7. data/apiary.apib +21 -14
  8. data/docs/README.md +26 -0
  9. data/docs/SUMMARY.md +39 -0
  10. data/docs/api-basics/authentication.md +40 -0
  11. data/docs/api-basics/vehicles.md +77 -0
  12. data/docs/vehicle/autopark.md +4 -0
  13. data/docs/vehicle/commands/README.md +22 -0
  14. data/docs/vehicle/commands/alerts.md +5 -0
  15. data/docs/vehicle/commands/calendar.md +3 -0
  16. data/docs/vehicle/commands/charging.md +3 -0
  17. data/docs/vehicle/commands/climate.md +3 -0
  18. data/docs/vehicle/commands/doors.md +3 -0
  19. data/docs/vehicle/commands/media.md +3 -0
  20. data/docs/vehicle/commands/navigation.md +3 -0
  21. data/docs/vehicle/commands/remotestart.md +3 -0
  22. data/docs/vehicle/commands/softwareupdate.md +3 -0
  23. data/docs/vehicle/commands/speedlimit.md +3 -0
  24. data/docs/vehicle/commands/sunroof.md +3 -0
  25. data/docs/vehicle/commands/trunk.md +3 -0
  26. data/docs/vehicle/commands/valet.md +3 -0
  27. data/docs/vehicle/commands/wake.md +3 -0
  28. data/docs/vehicle/optioncodes.md +253 -0
  29. data/docs/vehicle/state/README.md +34 -0
  30. data/docs/vehicle/state/chargestate.md +56 -0
  31. data/docs/vehicle/state/climatestate.md +43 -0
  32. data/docs/vehicle/state/data.md +181 -0
  33. data/docs/vehicle/state/drivestate.md +27 -0
  34. data/docs/vehicle/state/guisettings.md +21 -0
  35. data/docs/vehicle/state/mobileenabled.md +14 -0
  36. data/docs/vehicle/state/vehiclestate.md +47 -0
  37. data/docs/vehicle/streaming.md +4 -0
  38. data/lib/tesla_api.rb +7 -6
  39. data/lib/tesla_api/autopark.rb +62 -0
  40. data/lib/tesla_api/client.rb +32 -11
  41. data/lib/tesla_api/stream.rb +11 -7
  42. data/lib/tesla_api/vehicle.rb +50 -30
  43. data/lib/tesla_api/version.rb +1 -1
  44. data/spec/cassettes/client-login.yml +1 -1
  45. data/spec/cassettes/vehicle-activate_speed_limit.yml +95 -0
  46. data/spec/cassettes/vehicle-clear_speed_limit_pin.yml +95 -0
  47. data/spec/cassettes/vehicle-deactivate_speed_limit.yml +95 -0
  48. data/spec/cassettes/vehicle-open_frunk.yml +40 -73
  49. data/spec/cassettes/vehicle-open_trunk.yml +40 -73
  50. data/spec/cassettes/vehicle-set_speed_limit.yml +95 -0
  51. data/spec/lib/tesla_api/client_spec.rb +42 -15
  52. data/spec/lib/tesla_api/vehicle_spec.rb +160 -136
  53. data/spec/spec_helper.rb +6 -18
  54. data/tesla_api.gemspec +20 -24
  55. metadata +67 -42
  56. data/circle.yml +0 -10
@@ -1,50 +1,5 @@
1
1
  ---
2
2
  http_interactions:
3
- - request:
4
- method: post
5
- uri: https://owner-api.teslamotors.com/oauth/token
6
- body:
7
- encoding: UTF-8
8
- string: grant_type=password&client_id=<TESLA_CLIENT_ID>&client_secret=<TESLA_CLIENT_SECRET>&email=<TESLA_EMAIL>&password=<TESLA_PASS>
9
- headers:
10
- Accept-Encoding:
11
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
- Accept:
13
- - "*/*"
14
- User-Agent:
15
- - Ruby
16
- response:
17
- status:
18
- code: 200
19
- message: OK
20
- headers:
21
- Server:
22
- - nginx
23
- Date:
24
- - Wed, 17 Dec 2014 02:02:39 GMT
25
- Content-Type:
26
- - application/json; charset=utf-8
27
- Transfer-Encoding:
28
- - chunked
29
- Connection:
30
- - keep-alive
31
- Status:
32
- - 200 OK
33
- Cache-Control:
34
- - no-store
35
- Pragma:
36
- - no-cache
37
- X-Ua-Compatible:
38
- - IE=Edge,chrome=1
39
- X-Request-Id:
40
- - 463d9f839e6eb7ccc712ec5001dfa135
41
- X-Runtime:
42
- - '0.358328'
43
- body:
44
- encoding: UTF-8
45
- string: '{"access_token":"614ac96b9d291d2af3d7bfc92e2880474afc1a7aa1c49b6df693fb1b1237c60d","token_type":"bearer","expires_in":7776000}'
46
- http_version:
47
- recorded_at: Wed, 17 Dec 2014 02:02:41 GMT
48
3
  - request:
49
4
  method: get
50
5
  uri: https://owner-api.teslamotors.com/api/1/vehicles
@@ -53,7 +8,7 @@ http_interactions:
53
8
  string: ''
54
9
  headers:
55
10
  Authorization:
56
- - Bearer 614ac96b9d291d2af3d7bfc92e2880474afc1a7aa1c49b6df693fb1b1237c60d
11
+ - Bearer <TESLA_API_TOKEN>
57
12
  response:
58
13
  status:
59
14
  code: 200
@@ -62,67 +17,79 @@ http_interactions:
62
17
  Server:
63
18
  - nginx
64
19
  Date:
65
- - Wed, 17 Dec 2014 02:02:39 GMT
20
+ - Sun, 05 Aug 2018 17:05:00 GMT
66
21
  Content-Type:
67
22
  - application/json; charset=utf-8
68
23
  Content-Length:
69
- - '446'
24
+ - '623'
70
25
  Connection:
71
26
  - keep-alive
72
- Status:
73
- - 200 OK
74
- X-Ua-Compatible:
75
- - IE=Edge,chrome=1
27
+ X-Frame-Options:
28
+ - SAMEORIGIN
29
+ - SAMEORIGIN
30
+ X-Xss-Protection:
31
+ - 1; mode=block
32
+ X-Content-Type-Options:
33
+ - nosniff
34
+ X-Txid:
35
+ - 47beb347d84e5640bf8650afc5a5d290
76
36
  Etag:
77
- - '"f75b5f2e5ddca5f7c1bf938da14972f4"'
37
+ - W/"6406a0c92e8caf93d1f9120da1610420"
78
38
  Cache-Control:
79
39
  - max-age=0, private, must-revalidate
80
40
  X-Request-Id:
81
- - f339ad32393df7d7048686949238f54c
41
+ - 00374a64-8682-4b3f-9fd3-a801f43c60b0
82
42
  X-Runtime:
83
- - '0.064041'
43
+ - '0.014727'
84
44
  body:
85
45
  encoding: UTF-8
86
46
  string: '{"response":[{"color":null,"display_name":"Nikola","id":1514029006966957156,"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,COUS","vehicle_id":490215852,"vin":"5YJSA1CN5CFP01657","tokens":["13e0ae629c708af6","156102684b1be0dd"],"state":"online","remote_start_enabled":true,"calendar_enabled":true,"notifications_enabled":true}],"count":1}'
87
47
  http_version:
88
- recorded_at: Wed, 17 Dec 2014 02:02:41 GMT
48
+ recorded_at: Sun, 05 Aug 2018 17:05:00 GMT
89
49
  - request:
90
50
  method: post
91
- uri: https://owner-api.teslamotors.com/api/1/vehicles/1514029006966957156/command/trunk_open
51
+ uri: https://owner-api.teslamotors.com/api/1/vehicles/1514029006966957156/command/actuate_trunk
92
52
  body:
93
53
  encoding: UTF-8
94
- string: which_trunk=rear
54
+ string: which_trunk=front
95
55
  headers:
96
56
  Authorization:
97
- - Bearer 614ac96b9d291d2af3d7bfc92e2880474afc1a7aa1c49b6df693fb1b1237c60d
57
+ - Bearer <TESLA_API_TOKEN>
98
58
  response:
99
59
  status:
100
- code: 400
101
- message: Bad Request
60
+ code: 200
61
+ message: OK
102
62
  headers:
103
63
  Server:
104
64
  - nginx
105
65
  Date:
106
- - Wed, 17 Dec 2014 02:02:40 GMT
66
+ - Sun, 05 Aug 2018 17:05:00 GMT
107
67
  Content-Type:
108
68
  - application/json; charset=utf-8
109
69
  Content-Length:
110
- - '66'
70
+ - '40'
111
71
  Connection:
112
72
  - keep-alive
113
- Status:
114
- - 400 Bad Request
115
- X-Ua-Compatible:
116
- - IE=Edge,chrome=1
73
+ X-Frame-Options:
74
+ - SAMEORIGIN
75
+ - SAMEORIGIN
76
+ X-Xss-Protection:
77
+ - 1; mode=block
78
+ X-Content-Type-Options:
79
+ - nosniff
80
+ X-Txid:
81
+ - 5e6adf1c1e9a73c310d45820d88451aa
82
+ Etag:
83
+ - W/"f67eec105dd6522783a1f1bacc52723a"
117
84
  Cache-Control:
118
- - no-cache
85
+ - max-age=0, private, must-revalidate
119
86
  X-Request-Id:
120
- - bc7fcff8043599002f0d44b1d3550681
87
+ - 845150c1-1b8d-4ee9-8690-65f60cfeb48f
121
88
  X-Runtime:
122
- - '0.013840'
89
+ - '0.131305'
123
90
  body:
124
91
  encoding: UTF-8
125
- string: '{"response":null,"error":"invalid_command","error_description":""}'
92
+ string: '{"response":{"reason":"","result":true}}'
126
93
  http_version:
127
- recorded_at: Wed, 17 Dec 2014 02:02:42 GMT
128
- recorded_with: VCR 2.9.3
94
+ recorded_at: Sun, 05 Aug 2018 17:05:00 GMT
95
+ recorded_with: VCR 3.0.3
@@ -0,0 +1,95 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://owner-api.teslamotors.com/api/1/vehicles
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Authorization:
11
+ - Bearer <TESLA_API_TOKEN>
12
+ response:
13
+ status:
14
+ code: 200
15
+ message: OK
16
+ headers:
17
+ Server:
18
+ - nginx
19
+ Date:
20
+ - Wed, 18 Jul 2018 23:51:18 GMT
21
+ Content-Type:
22
+ - application/json; charset=utf-8
23
+ Content-Length:
24
+ - '623'
25
+ Connection:
26
+ - keep-alive
27
+ X-Frame-Options:
28
+ - SAMEORIGIN
29
+ - SAMEORIGIN
30
+ X-Xss-Protection:
31
+ - 1; mode=block
32
+ X-Content-Type-Options:
33
+ - nosniff
34
+ X-Txid:
35
+ - 0dd1f1f026f902339fe4bb629429d653
36
+ Etag:
37
+ - W/"6958697e3e1e010f56068d8c7fa2f93d"
38
+ Cache-Control:
39
+ - max-age=0, private, must-revalidate
40
+ X-Request-Id:
41
+ - 810ad995-1c32-4527-9b55-3158ab119e1b
42
+ X-Runtime:
43
+ - '0.027684'
44
+ body:
45
+ encoding: UTF-8
46
+ string: '{"response":[{"color":null,"display_name":"Nikola","id":1514029006966957156,"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,COUS","vehicle_id":490215852,"vin":"5YJSA1CN5CFP01657","tokens":["a1f3fab6393d3a6a","91a139ce322eed65"],"state":"online","remote_start_enabled":true,"calendar_enabled":true,"notifications_enabled":true}],"count":1}'
47
+ http_version:
48
+ recorded_at: Wed, 18 Jul 2018 23:51:18 GMT
49
+ - request:
50
+ method: post
51
+ uri: https://owner-api.teslamotors.com/api/1/vehicles/1514029006966957156/command/speed_limit_set_limit
52
+ body:
53
+ encoding: UTF-8
54
+ string: limit_mph=65
55
+ headers:
56
+ Authorization:
57
+ - Bearer <TESLA_API_TOKEN>
58
+ response:
59
+ status:
60
+ code: 200
61
+ message: OK
62
+ headers:
63
+ Server:
64
+ - nginx
65
+ Date:
66
+ - Wed, 18 Jul 2018 23:51:19 GMT
67
+ Content-Type:
68
+ - application/json; charset=utf-8
69
+ Content-Length:
70
+ - '40'
71
+ Connection:
72
+ - keep-alive
73
+ X-Frame-Options:
74
+ - SAMEORIGIN
75
+ - SAMEORIGIN
76
+ X-Xss-Protection:
77
+ - 1; mode=block
78
+ X-Content-Type-Options:
79
+ - nosniff
80
+ X-Txid:
81
+ - 47cdfaf37f13879846e19ed31441ade3
82
+ Etag:
83
+ - W/"f67eec105dd6522783a1f1bacc52723a"
84
+ Cache-Control:
85
+ - max-age=0, private, must-revalidate
86
+ X-Request-Id:
87
+ - 0523f468-6cde-4ae4-8dd3-870de69ad2f4
88
+ X-Runtime:
89
+ - '0.112159'
90
+ body:
91
+ encoding: UTF-8
92
+ string: '{"response":{"reason":"","result":true}}'
93
+ http_version:
94
+ recorded_at: Wed, 18 Jul 2018 23:51:19 GMT
95
+ recorded_with: VCR 3.0.3
@@ -1,36 +1,63 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe TeslaApi::Client do
4
- subject(:tesla_api) { TeslaApi::Client.new(ENV["TESLA_EMAIL"]) }
4
+ subject(:tesla_api) { TeslaApi::Client.new(ENV['TESLA_EMAIL']) }
5
5
 
6
- describe "#token=" do
7
- it "sets a Bearer token" do
6
+ describe '#new client' do
7
+ it 'has no expiry date' do
8
+ expect(tesla_api.expired_at).to eq(nil)
9
+ end
10
+
11
+ it 'has a expiry status set to true' do
12
+ expect(tesla_api.expired?).to eq(true)
13
+ end
14
+ end
15
+
16
+ describe '#token=' do
17
+ it 'sets a Bearer token' do
8
18
  tesla_api.token = Faker::Lorem.characters(32)
9
- expect(tesla_api.class.headers).to include({"Authorization" => /Bearer [a-z0-9]{32}/})
19
+ expect(tesla_api.class.headers).to include({'Authorization' => /Bearer [a-z0-9]{32}/})
10
20
  end
11
21
  end
12
22
 
13
- describe "#login!", vcr: { cassette_name: "client-login" } do
23
+ describe '#login!', vcr: { cassette_name: 'client-login' } do
14
24
  it { is_expected.to be_a(TeslaApi::Client) }
15
25
 
16
- it "logs into the API" do
17
- tesla_api.login!(ENV["TESLA_PASS"])
26
+ it 'logs into the API' do
27
+ tesla_api.login!(ENV['TESLA_PASS'])
18
28
  expect(a_request(:post, "https://#{URI.parse(tesla_api.class.base_uri).host}/oauth/token")).to have_been_made.once
19
29
  end
20
30
 
21
- it "obtains a Bearer token" do
22
- tesla_api.login!(ENV["TESLA_PASS"])
23
- expect(tesla_api.token).to match(/[a-z0-9]{32}/)
31
+ it 'set a expiry date' do
32
+ tesla_api.login!(ENV['TESLA_PASS'])
33
+ expect(tesla_api.expired_at).to eq(Time.at(1475777133 + 7776000).to_datetime)
24
34
  end
25
35
 
26
- it "sets a Bearer token header" do
27
- tesla_api.login!(ENV["TESLA_PASS"])
28
- expect(tesla_api.class.headers).to include({"Authorization" => /Bearer [a-z0-9]{32}/})
36
+ it 'expose expiry status' do
37
+ tesla_api.login!(ENV['TESLA_PASS'])
38
+ tesla_api.created_at = (Time.now - 1).to_i
39
+ expect(tesla_api.expired?).to eq(false)
40
+ end
41
+
42
+ it 'is expired when has a 90+ days old date' do
43
+ tesla_api.login!(ENV['TESLA_PASS'])
44
+ tesla_api.created_at = (Time.now - 7776000 - 1).to_i
45
+ expect(tesla_api.expired?).to eq(true)
46
+ end
47
+
48
+ it 'sets a Bearer token header' do
49
+ tesla_api.login!(ENV['TESLA_PASS'])
50
+ expect(tesla_api.class.headers).to include({'Authorization' => /Bearer [a-z0-9]{32}/})
51
+ end
52
+
53
+ it 'obtains a Bearer token' do
54
+ tesla_api.login!(ENV['TESLA_PASS'])
55
+ expect(tesla_api.token).to match(/[a-z0-9]{32}/)
29
56
  end
30
57
  end
31
58
 
32
- describe "#vehicles", vcr: {cassette_name: "client-vehicles"} do
33
- it "lists the vehicles on the account" do
59
+ describe '#vehicles', vcr: {cassette_name: 'client-vehicles'} do
60
+ it 'lists the vehicles on the account' do
34
61
  expect(tesla_api.vehicles).to include(TeslaApi::Vehicle)
35
62
  end
36
63
  end
@@ -1,271 +1,295 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe TeslaApi::Vehicle do
4
- let(:tesla_api) { TeslaApi::Client.new(ENV["TESLA_EMAIL"]) }
4
+ let(:tesla_api) { TeslaApi::Client.new(ENV['TESLA_EMAIL']) }
5
5
 
6
6
  before do
7
- tesla_api.token = ENV["TESLA_API_TOKEN"]
7
+ tesla_api.token = ENV['TESLA_API_TOKEN']
8
8
  end
9
9
 
10
10
  subject(:vehicle) { tesla_api.vehicles.first }
11
11
 
12
- describe "#[]", vcr: { cassette_name: "vehicle" } do
13
- it "contains the vehicle name" do
14
- expect(vehicle["display_name"]).to eq("Nikola")
12
+ describe '#[]', vcr: { cassette_name: 'vehicle' } do
13
+ it 'contains the vehicle name' do
14
+ expect(vehicle['display_name']).to eq('Nikola')
15
15
  end
16
16
  end
17
17
 
18
- describe "#method_missing", vcr: {cassette_name: "vehicle"} do
19
- it "doesn't provide dynamic methods for nonexistent properties" do
18
+ describe '#method_missing', vcr: {cassette_name: 'vehicle'} do
19
+ it 'doesn\'t provide dynamic methods for nonexistent properties' do
20
20
  expect{vehicle.gas_level}.to raise_exception(NoMethodError)
21
21
  end
22
22
 
23
- it "provides a dynamic method for the display_name" do
24
- expect(vehicle.display_name).to eq("Nikola")
23
+ it 'provides a dynamic method for the display_name' do
24
+ expect(vehicle.display_name).to eq('Nikola')
25
25
  end
26
26
  end
27
27
 
28
- describe "#mobile_enabled", vcr: {cassette_name: "vehicle-mobile_enabled"} do
29
- it "indicates if mobile app access is enabled" do
28
+ describe '#mobile_enabled', vcr: {cassette_name: 'vehicle-mobile_enabled'} do
29
+ it 'indicates if mobile app access is enabled' do
30
30
  expect(vehicle.mobile_enabled).to eq(true)
31
31
  end
32
32
  end
33
33
 
34
- describe "#gui_settings", vcr: {cassette_name: "vehicle-gui_settings"} do
35
- context "details for a GUI built on the API" do
34
+ describe '#gui_settings', vcr: {cassette_name: 'vehicle-gui_settings'} do
35
+ context 'details for a GUI built on the API' do
36
36
  subject { vehicle.gui_settings }
37
37
 
38
- it { should include("gui_charge_rate_units") }
39
- it { should include("gui_distance_units") }
40
- it { should include("gui_temperature_units") }
41
- it { should include("gui_range_display") }
42
- it { should include("gui_24_hour_time") }
38
+ it { should include('gui_charge_rate_units') }
39
+ it { should include('gui_distance_units') }
40
+ it { should include('gui_temperature_units') }
41
+ it { should include('gui_range_display') }
42
+ it { should include('gui_24_hour_time') }
43
43
  end
44
44
  end
45
45
 
46
- describe "#charge_state", vcr: {cassette_name: "vehicle-charge_state"} do
47
- context "data about the vehicle's charging state" do
46
+ describe '#charge_state', vcr: {cassette_name: 'vehicle-charge_state'} do
47
+ context 'data about the vehicle\'s charging state' do
48
48
  subject { vehicle.charge_state }
49
49
 
50
- it { should include("battery_level") }
51
- it { should include("charge_rate") }
52
- it { should include("charging_state") }
53
- it { should include("est_battery_range") }
54
- it { should include("fast_charger_present") }
50
+ it { should include('battery_level') }
51
+ it { should include('charge_rate') }
52
+ it { should include('charging_state') }
53
+ it { should include('est_battery_range') }
54
+ it { should include('fast_charger_present') }
55
55
  end
56
56
  end
57
57
 
58
- describe "#climate_state", vcr: {cassette_name: "vehicle-climate_state"} do
59
- context "data about the vehicle's climate controls and internal climate" do
58
+ describe '#climate_state', vcr: {cassette_name: 'vehicle-climate_state'} do
59
+ context 'data about the vehicle\'s climate controls and internal climate' do
60
60
  subject { vehicle.climate_state }
61
61
 
62
- it { should include("inside_temp") }
63
- it { should include("outside_temp") }
64
- it { should include("driver_temp_setting") }
65
- it { should include("passenger_temp_setting") }
66
- it { should include("is_auto_conditioning_on") }
62
+ it { should include('inside_temp') }
63
+ it { should include('outside_temp') }
64
+ it { should include('driver_temp_setting') }
65
+ it { should include('passenger_temp_setting') }
66
+ it { should include('is_auto_conditioning_on') }
67
67
  end
68
68
  end
69
69
 
70
- describe "#drive_state", vcr: {cassette_name: "vehicle-drive_state"} do
71
- context "data about the vehicle's driving state" do
70
+ describe '#drive_state', vcr: {cassette_name: 'vehicle-drive_state'} do
71
+ context 'data about the vehicle\'s driving state' do
72
72
  subject { vehicle.drive_state }
73
73
 
74
- it { should include("heading") }
75
- it { should include("latitude") }
76
- it { should include("longitude") }
77
- it { should include("speed") }
74
+ it { should include('heading') }
75
+ it { should include('latitude') }
76
+ it { should include('longitude') }
77
+ it { should include('speed') }
78
78
  end
79
79
  end
80
80
 
81
- describe "#vehicle_state", vcr: {cassette_name: "vehicle-vehicle_state"} do
82
- context "data about the vehicle's overall state" do
81
+ describe '#vehicle_state', vcr: {cassette_name: 'vehicle-vehicle_state'} do
82
+ context 'data about the vehicle\'s overall state' do
83
83
  subject { vehicle.vehicle_state }
84
84
 
85
- it { should include("vehicle_name") }
86
- it { should include("exterior_color") }
87
- it { should include("wheel_type") }
88
- it { should include("has_spoiler") }
89
- it { should include("calendar_supported") }
90
- it { should include("locked") }
85
+ it { should include('vehicle_name') }
86
+ it { should include('exterior_color') }
87
+ it { should include('wheel_type') }
88
+ it { should include('has_spoiler') }
89
+ it { should include('calendar_supported') }
90
+ it { should include('locked') }
91
91
  end
92
92
  end
93
93
 
94
- describe "#wake_up", vcr: {cassette_name: "vehicle-wake_up"} do
95
- it "wakes up the car from sleep mode" do
94
+ describe '#wake_up', vcr: {cassette_name: 'vehicle-wake_up'} do
95
+ it 'wakes up the car from sleep mode' do
96
96
  vehicle.wake_up
97
- expect(vehicle.state).to eq("online")
97
+ expect(vehicle.state).to eq('online')
98
98
  end
99
99
  end
100
100
 
101
- describe "#set_valet_mode", vcr: {cassette_name: "vehicle-set_valet_mode"} do
102
- it "enables valet mode on the car" do
103
- expect(vehicle.set_valet_mode(true, 1234)["result"]).to eq(true)
101
+ describe '#set_valet_mode', vcr: {cassette_name: 'vehicle-set_valet_mode'} do
102
+ it 'enables valet mode on the car' do
103
+ expect(vehicle.set_valet_mode(true, 1234)['result']).to eq(true)
104
104
  end
105
105
 
106
- it "enables valet mode with a previous PIN" do
107
- expect(vehicle.set_valet_mode(true)["result"]).to eq(true)
106
+ it 'enables valet mode with a previous PIN' do
107
+ expect(vehicle.set_valet_mode(true)['result']).to eq(true)
108
108
  end
109
109
  end
110
110
 
111
- describe "#reset_valet_pin", vcr: {cassette_name: "vehicle-reset_valet_pin"} do
112
- it "resets the valet mode PIN" do
113
- expect(vehicle.reset_valet_pin["result"]).to eq(true)
111
+ describe '#reset_valet_pin', vcr: {cassette_name: 'vehicle-reset_valet_pin'} do
112
+ it 'resets the valet mode PIN' do
113
+ expect(vehicle.reset_valet_pin['result']).to eq(true)
114
114
  end
115
115
  end
116
116
 
117
- describe "#charge_port_door_open", vcr: {cassette_name: "vehicle-charge_port_door_open"} do
118
- it "opens the charge port door" do
119
- expect(vehicle.charge_port_door_open["result"]).to eq(true)
117
+ describe '#charge_port_door_open', vcr: {cassette_name: 'vehicle-charge_port_door_open'} do
118
+ it 'opens the charge port door' do
119
+ expect(vehicle.charge_port_door_open['result']).to eq(true)
120
120
  end
121
121
  end
122
122
 
123
- describe "#charge_standard" do
124
- it "sets the charge limit to standard (90%)", vcr: {cassette_name: "vehicle-charge_standard"} do
125
- expect(vehicle.charge_standard["result"]).to eq(true)
123
+ describe '#charge_standard' do
124
+ it 'sets the charge limit to standard (90%)', vcr: {cassette_name: 'vehicle-charge_standard'} do
125
+ expect(vehicle.charge_standard['result']).to eq(true)
126
126
  end
127
127
 
128
- it "doesn't set the charge rate to standard twice", vcr: {cassette_name: "vehicle-charge_standard-twice"} do
129
- expect(vehicle.charge_standard["result"]).to eq(true)
130
- expect(vehicle.charge_standard).to eq({"result" => false, "reason" => "already_standard"})
128
+ it 'doesn\'t set the charge rate to standard twice', vcr: {cassette_name: 'vehicle-charge_standard-twice'} do
129
+ expect(vehicle.charge_standard['result']).to eq(true)
130
+ expect(vehicle.charge_standard).to eq({'result' => false, 'reason' => 'already_standard'})
131
131
  end
132
132
  end
133
133
 
134
- describe "#charge_max_range" do
135
- it "sets the charge limit to max range (100%)", vcr: {cassette_name: "vehicle-charge_max_range"} do
136
- expect(vehicle.charge_max_range["result"]).to eq(true)
134
+ describe '#charge_max_range' do
135
+ it 'sets the charge limit to max range (100%)', vcr: {cassette_name: 'vehicle-charge_max_range'} do
136
+ expect(vehicle.charge_max_range['result']).to eq(true)
137
137
  end
138
138
 
139
- it "doesn't set the charge rate to max range twice", vcr: {cassette_name: "vehicle-charge_max_range-twice"} do
140
- expect(vehicle.charge_max_range["result"]).to eq(true)
141
- expect(vehicle.charge_max_range).to eq({"result" => false, "reason" => "already_max_range"})
139
+ it 'doesn\'t set the charge rate to max range twice', vcr: {cassette_name: 'vehicle-charge_max_range-twice'} do
140
+ expect(vehicle.charge_max_range['result']).to eq(true)
141
+ expect(vehicle.charge_max_range).to eq({'result' => false, 'reason' => 'already_max_range'})
142
142
  end
143
143
  end
144
144
 
145
- describe "#set_charge_limit" do
146
- it "sets the charge limit to 100%", vcr: {cassette_name: "vehicle-set_charge_limit-100"} do
147
- expect(vehicle.set_charge_limit(100)["result"]).to eq(true)
145
+ describe '#set_charge_limit' do
146
+ it 'sets the charge limit to 100%', vcr: {cassette_name: 'vehicle-set_charge_limit-100'} do
147
+ expect(vehicle.set_charge_limit(100)['result']).to eq(true)
148
148
  end
149
149
 
150
- it "sets the charge limit to 90%", vcr: {cassette_name: "vehicle-set_charge_limit-90"} do
151
- expect(vehicle.set_charge_limit(90)["result"]).to eq(true)
150
+ it 'sets the charge limit to 90%', vcr: {cassette_name: 'vehicle-set_charge_limit-90'} do
151
+ expect(vehicle.set_charge_limit(90)['result']).to eq(true)
152
152
  end
153
153
 
154
- it "sets the charge limit to 50%", vcr: {cassette_name: "vehicle-set_charge_limit-50"} do
155
- expect(vehicle.set_charge_limit(50)["result"]).to eq(true)
154
+ it 'sets the charge limit to 50%', vcr: {cassette_name: 'vehicle-set_charge_limit-50'} do
155
+ expect(vehicle.set_charge_limit(50)['result']).to eq(true)
156
156
  end
157
157
 
158
- it "doesn't actually set the charge limit to 1%", vcr: {cassette_name: "vehicle-set_charge_limit-1"} do
159
- expect(vehicle.set_charge_limit(1)["result"]).to eq(true)
160
- expect(vehicle.charge_state["charge_limit_soc"]).to eq(50)
158
+ it 'doesn\'t actually set the charge limit to 1%', vcr: {cassette_name: 'vehicle-set_charge_limit-1'} do
159
+ expect(vehicle.set_charge_limit(1)['result']).to eq(true)
160
+ expect(vehicle.charge_state['charge_limit_soc']).to eq(50)
161
161
  end
162
162
  end
163
163
 
164
- describe "#charge_start", vcr: {cassette_name: "vehicle-charge_start"} do
165
- it "starts charging" do
166
- expect(vehicle.charge_start["result"]).to eq(true)
164
+ describe '#charge_start', vcr: {cassette_name: 'vehicle-charge_start'} do
165
+ it 'starts charging' do
166
+ expect(vehicle.charge_start['result']).to eq(true)
167
167
  end
168
168
  end
169
169
 
170
- describe "#charge_stop", vcr: {cassette_name: "vehicle-charge_stop"} do
171
- it "stops charging" do
172
- expect(vehicle.charge_stop["result"]).to eq(true)
170
+ describe '#charge_stop', vcr: {cassette_name: 'vehicle-charge_stop'} do
171
+ it 'stops charging' do
172
+ expect(vehicle.charge_stop['result']).to eq(true)
173
173
  end
174
174
  end
175
175
 
176
- describe "#flash_lights", vcr: {cassette_name: "vehicle-flash_lights"} do
177
- it "flashes the vehicle's lights" do
178
- expect(vehicle.flash_lights["result"]).to eq(true)
176
+ describe '#flash_lights', vcr: {cassette_name: 'vehicle-flash_lights'} do
177
+ it 'flashes the vehicle\'s lights' do
178
+ expect(vehicle.flash_lights['result']).to eq(true)
179
179
  end
180
180
  end
181
181
 
182
- describe "#honk_horn", vcr: {cassette_name: "vehicle-honk_horn"} do
183
- it "honks the vehicle's horn" do
184
- expect(vehicle.honk_horn["result"]).to eq(true)
182
+ describe '#honk_horn', vcr: {cassette_name: 'vehicle-honk_horn'} do
183
+ it 'honks the vehicle\'s horn' do
184
+ expect(vehicle.honk_horn['result']).to eq(true)
185
185
  end
186
186
  end
187
187
 
188
- describe "#door_unlock", vcr: {cassette_name: "vehicle-door_unlock"} do
189
- it "unlocks the vehicle's doors" do
190
- expect(vehicle.door_unlock["result"]).to eq(true)
188
+ describe '#door_unlock', vcr: {cassette_name: 'vehicle-door_unlock'} do
189
+ it 'unlocks the vehicle\'s doors' do
190
+ expect(vehicle.door_unlock['result']).to eq(true)
191
191
  end
192
192
  end
193
193
 
194
- describe "#door_lock", vcr: {cassette_name: "vehicle-door_lock"} do
195
- it "locks the vehicle's doors" do
196
- expect(vehicle.door_lock["result"]).to eq(true)
194
+ describe '#door_lock', vcr: {cassette_name: 'vehicle-door_lock'} do
195
+ it 'locks the vehicle\'s doors' do
196
+ expect(vehicle.door_lock['result']).to eq(true)
197
197
  end
198
198
  end
199
199
 
200
- describe "#set_temps" do
201
- it "sets the desired temperature in the car to 70", vcr: {cassette_name: "vehicle-set_temps-70-70"} do
202
- expect(vehicle.set_temps(20.9, 20.9)["result"]).to eq(true)
200
+ describe '#set_temps' do
201
+ it 'sets the desired temperature in the car to 70', vcr: {cassette_name: 'vehicle-set_temps-70-70'} do
202
+ expect(vehicle.set_temps(20.9, 20.9)['result']).to eq(true)
203
203
  end
204
204
 
205
- it "sets the desired temperature in the car to 75 and 65", vcr: {cassette_name: "vehicle-set_temps-75-65"} do
206
- expect(vehicle.set_temps(23.7, 23.7)["result"]).to eq(true)
205
+ it 'sets the desired temperature in the car to 75 and 65', vcr: {cassette_name: 'vehicle-set_temps-75-65'} do
206
+ expect(vehicle.set_temps(23.7, 23.7)['result']).to eq(true)
207
207
  end
208
208
  end
209
209
 
210
- describe "#auto_conditioning_start", vcr: {cassette_name: "vehicle-auto_conditioning_start"} do
211
- it "starts the HVAC system" do
212
- expect(vehicle.auto_conditioning_start["result"]).to eq(true)
210
+ describe '#auto_conditioning_start', vcr: {cassette_name: 'vehicle-auto_conditioning_start'} do
211
+ it 'starts the HVAC system' do
212
+ expect(vehicle.auto_conditioning_start['result']).to eq(true)
213
213
  end
214
214
  end
215
215
 
216
- describe "#auto_conditioning_stop", vcr: {cassette_name: "vehicle-auto_conditioning_stop"} do
217
- it "stops the HVAC system" do
218
- expect(vehicle.auto_conditioning_stop["result"]).to eq(true)
216
+ describe '#auto_conditioning_stop', vcr: {cassette_name: 'vehicle-auto_conditioning_stop'} do
217
+ it 'stops the HVAC system' do
218
+ expect(vehicle.auto_conditioning_stop['result']).to eq(true)
219
219
  end
220
220
  end
221
221
 
222
- describe "#sun_roof_control" do
223
- it "opens the sun roof", vcr: {cassette_name: "vehicle-sun_roof_control-open"} do
224
- expect(vehicle.sun_roof_control("open")["result"]).to eq(true)
222
+ describe '#sun_roof_control' do
223
+ it 'opens the sun roof', vcr: {cassette_name: 'vehicle-sun_roof_control-open'} do
224
+ expect(vehicle.sun_roof_control('open')['result']).to eq(true)
225
225
  end
226
226
 
227
- it "closes the sun roof", vcr: {cassette_name: "vehicle-sun_roof_control-close"} do
228
- expect(vehicle.sun_roof_control("close")["result"]).to eq(true)
227
+ it 'closes the sun roof', vcr: {cassette_name: 'vehicle-sun_roof_control-close'} do
228
+ expect(vehicle.sun_roof_control('close')['result']).to eq(true)
229
229
  end
230
230
 
231
- it "vents the sun roof", vcr: {cassette_name: "vehicle-sun_roof_control-vent"} do
232
- expect(vehicle.sun_roof_control("vent")["result"]).to eq(true)
231
+ it 'vents the sun roof', vcr: {cassette_name: 'vehicle-sun_roof_control-vent'} do
232
+ expect(vehicle.sun_roof_control('vent')['result']).to eq(true)
233
233
  end
234
234
 
235
- it "sets the sun roof to the comfort (80%) setting", vcr: {cassette_name: "vehicle-sun_roof_control-comfort"} do
236
- expect(vehicle.sun_roof_control("comfort")["result"]).to eq(true)
235
+ it 'sets the sun roof to the comfort (80%) setting', vcr: {cassette_name: 'vehicle-sun_roof_control-comfort'} do
236
+ expect(vehicle.sun_roof_control('comfort')['result']).to eq(true)
237
237
  end
238
238
  end
239
239
 
240
- describe "#sun_roof_move" do
241
- it "moves the sun roof to 100% open", vcr: {cassette_name: "vehicle-sun_roof_move-100"} do
242
- expect(vehicle.sun_roof_move(100)["result"]).to eq(true)
240
+ describe '#sun_roof_move' do
241
+ it 'moves the sun roof to 100% open', vcr: {cassette_name: 'vehicle-sun_roof_move-100'} do
242
+ expect(vehicle.sun_roof_move(100)['result']).to eq(true)
243
243
  end
244
244
 
245
- it "moves the sun roof to closed", vcr: {cassette_name: "vehicle-sun_roof_move-0"} do
246
- expect(vehicle.sun_roof_move(0)["result"]).to eq(true)
245
+ it 'moves the sun roof to closed', vcr: {cassette_name: 'vehicle-sun_roof_move-0'} do
246
+ expect(vehicle.sun_roof_move(0)['result']).to eq(true)
247
247
  end
248
248
 
249
- it "moves the sun roof to 50% open", vcr: {cassette_name: "vehicle-sun_roof_move-50"} do
250
- expect(vehicle.sun_roof_move(50)["result"]).to eq(true)
249
+ it 'moves the sun roof to 50% open', vcr: {cassette_name: 'vehicle-sun_roof_move-50'} do
250
+ expect(vehicle.sun_roof_move(50)['result']).to eq(true)
251
251
  end
252
252
  end
253
253
 
254
- describe "#remote_start_drive", vcr: {cassette_name: "vehicle-remote_start_drive"} do
255
- it "starts the vehicle's keyless driving mode" do
256
- expect(vehicle.remote_start_drive("elon4eva")["result"]).to eq(true)
254
+ describe '#remote_start_drive', vcr: {cassette_name: 'vehicle-remote_start_drive'} do
255
+ it 'starts the vehicle\'s keyless driving mode' do
256
+ expect(vehicle.remote_start_drive('elon4eva')['result']).to eq(true)
257
257
  end
258
258
  end
259
259
 
260
- describe "#open_trunk", vcr: {cassette_name: "vehicle-open_trunk"} do
261
- it "opens the trunk" do
262
- expect(vehicle.open_trunk["error"]).to eq("invalid_command")
260
+ describe '#open_trunk', vcr: {cassette_name: 'vehicle-open_trunk'} do
261
+ it 'opens the trunk' do
262
+ expect(vehicle.open_frunk['result']).to eq(true)
263
263
  end
264
264
  end
265
265
 
266
- describe "#open_frunk", vcr: {cassette_name: "vehicle-open_frunk"} do
267
- it "opens the frunk" do
268
- expect(vehicle.open_frunk["error"]).to eq("invalid_command")
266
+ describe '#open_frunk', vcr: {cassette_name: 'vehicle-open_frunk'} do
267
+ it 'opens the frunk' do
268
+ expect(vehicle.open_frunk['result']).to eq(true)
269
+ end
270
+ end
271
+
272
+ describe '#activate_speed_limit', vcr: {cassette_name: 'vehicle-activate_speed_limit'} do
273
+ it 'activates the speed limit' do
274
+ expect(vehicle.activate_speed_limit('1234')['result']).to eq(true)
275
+ end
276
+ end
277
+
278
+ describe '#deactivate_speed_limit', vcr: {cassette_name: 'vehicle-deactivate_speed_limit'} do
279
+ it 'deactivates the speed limit' do
280
+ expect(vehicle.deactivate_speed_limit('1234')['result']).to eq(true)
281
+ end
282
+ end
283
+
284
+ describe '#set_speed_limit', vcr: {cassette_name: 'vehicle-set_speed_limit'} do
285
+ it 'sets the speed limit' do
286
+ expect(vehicle.set_speed_limit(65)['result']).to eq(true)
287
+ end
288
+ end
289
+
290
+ describe '#clear_speed_limit_pin', vcr: {cassette_name: 'vehicle-clear_speed_limit_pin'} do
291
+ it 'clears the speed limit pin' do
292
+ expect(vehicle.clear_speed_limit_pin('1234')['result']).to eq(true)
269
293
  end
270
294
  end
271
295
  end