tesla_api 1.2.0 → 1.3.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.
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