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.
- checksums.yaml +5 -5
- data/.gitbook.yml +4 -0
- data/.travis.yml +3 -4
- data/LICENSE +1 -1
- data/README.md +7 -3
- data/Rakefile +27 -1
- data/apiary.apib +21 -14
- data/docs/README.md +26 -0
- data/docs/SUMMARY.md +39 -0
- data/docs/api-basics/authentication.md +40 -0
- data/docs/api-basics/vehicles.md +77 -0
- data/docs/vehicle/autopark.md +4 -0
- data/docs/vehicle/commands/README.md +22 -0
- data/docs/vehicle/commands/alerts.md +5 -0
- data/docs/vehicle/commands/calendar.md +3 -0
- data/docs/vehicle/commands/charging.md +3 -0
- data/docs/vehicle/commands/climate.md +3 -0
- data/docs/vehicle/commands/doors.md +3 -0
- data/docs/vehicle/commands/media.md +3 -0
- data/docs/vehicle/commands/navigation.md +3 -0
- data/docs/vehicle/commands/remotestart.md +3 -0
- data/docs/vehicle/commands/softwareupdate.md +3 -0
- data/docs/vehicle/commands/speedlimit.md +3 -0
- data/docs/vehicle/commands/sunroof.md +3 -0
- data/docs/vehicle/commands/trunk.md +3 -0
- data/docs/vehicle/commands/valet.md +3 -0
- data/docs/vehicle/commands/wake.md +3 -0
- data/docs/vehicle/optioncodes.md +253 -0
- data/docs/vehicle/state/README.md +34 -0
- data/docs/vehicle/state/chargestate.md +56 -0
- data/docs/vehicle/state/climatestate.md +43 -0
- data/docs/vehicle/state/data.md +181 -0
- data/docs/vehicle/state/drivestate.md +27 -0
- data/docs/vehicle/state/guisettings.md +21 -0
- data/docs/vehicle/state/mobileenabled.md +14 -0
- data/docs/vehicle/state/vehiclestate.md +47 -0
- data/docs/vehicle/streaming.md +4 -0
- data/lib/tesla_api.rb +7 -6
- data/lib/tesla_api/autopark.rb +62 -0
- data/lib/tesla_api/client.rb +32 -11
- data/lib/tesla_api/stream.rb +11 -7
- data/lib/tesla_api/vehicle.rb +50 -30
- data/lib/tesla_api/version.rb +1 -1
- data/spec/cassettes/client-login.yml +1 -1
- data/spec/cassettes/vehicle-activate_speed_limit.yml +95 -0
- data/spec/cassettes/vehicle-clear_speed_limit_pin.yml +95 -0
- data/spec/cassettes/vehicle-deactivate_speed_limit.yml +95 -0
- data/spec/cassettes/vehicle-open_frunk.yml +40 -73
- data/spec/cassettes/vehicle-open_trunk.yml +40 -73
- data/spec/cassettes/vehicle-set_speed_limit.yml +95 -0
- data/spec/lib/tesla_api/client_spec.rb +42 -15
- data/spec/lib/tesla_api/vehicle_spec.rb +160 -136
- data/spec/spec_helper.rb +6 -18
- data/tesla_api.gemspec +20 -24
- metadata +67 -42
- 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
|
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
|
-
-
|
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
|
-
- '
|
24
|
+
- '623'
|
70
25
|
Connection:
|
71
26
|
- keep-alive
|
72
|
-
|
73
|
-
-
|
74
|
-
|
75
|
-
-
|
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
|
-
-
|
37
|
+
- W/"6406a0c92e8caf93d1f9120da1610420"
|
78
38
|
Cache-Control:
|
79
39
|
- max-age=0, private, must-revalidate
|
80
40
|
X-Request-Id:
|
81
|
-
-
|
41
|
+
- 00374a64-8682-4b3f-9fd3-a801f43c60b0
|
82
42
|
X-Runtime:
|
83
|
-
- '0.
|
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:
|
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/
|
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=
|
54
|
+
string: which_trunk=front
|
95
55
|
headers:
|
96
56
|
Authorization:
|
97
|
-
- Bearer
|
57
|
+
- Bearer <TESLA_API_TOKEN>
|
98
58
|
response:
|
99
59
|
status:
|
100
|
-
code:
|
101
|
-
message:
|
60
|
+
code: 200
|
61
|
+
message: OK
|
102
62
|
headers:
|
103
63
|
Server:
|
104
64
|
- nginx
|
105
65
|
Date:
|
106
|
-
-
|
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
|
-
- '
|
70
|
+
- '40'
|
111
71
|
Connection:
|
112
72
|
- keep-alive
|
113
|
-
|
114
|
-
-
|
115
|
-
|
116
|
-
-
|
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
|
-
-
|
85
|
+
- max-age=0, private, must-revalidate
|
119
86
|
X-Request-Id:
|
120
|
-
-
|
87
|
+
- 845150c1-1b8d-4ee9-8690-65f60cfeb48f
|
121
88
|
X-Runtime:
|
122
|
-
- '0.
|
89
|
+
- '0.131305'
|
123
90
|
body:
|
124
91
|
encoding: UTF-8
|
125
|
-
string: '{"response":
|
92
|
+
string: '{"response":{"reason":"","result":true}}'
|
126
93
|
http_version:
|
127
|
-
recorded_at:
|
128
|
-
recorded_with: VCR
|
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[
|
4
|
+
subject(:tesla_api) { TeslaApi::Client.new(ENV['TESLA_EMAIL']) }
|
5
5
|
|
6
|
-
describe
|
7
|
-
it
|
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({
|
19
|
+
expect(tesla_api.class.headers).to include({'Authorization' => /Bearer [a-z0-9]{32}/})
|
10
20
|
end
|
11
21
|
end
|
12
22
|
|
13
|
-
describe
|
23
|
+
describe '#login!', vcr: { cassette_name: 'client-login' } do
|
14
24
|
it { is_expected.to be_a(TeslaApi::Client) }
|
15
25
|
|
16
|
-
it
|
17
|
-
tesla_api.login!(ENV[
|
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
|
22
|
-
tesla_api.login!(ENV[
|
23
|
-
expect(tesla_api.
|
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
|
27
|
-
tesla_api.login!(ENV[
|
28
|
-
|
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
|
33
|
-
it
|
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[
|
4
|
+
let(:tesla_api) { TeslaApi::Client.new(ENV['TESLA_EMAIL']) }
|
5
5
|
|
6
6
|
before do
|
7
|
-
tesla_api.token = ENV[
|
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
|
13
|
-
it
|
14
|
-
expect(vehicle[
|
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
|
19
|
-
it
|
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
|
24
|
-
expect(vehicle.display_name).to eq(
|
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
|
29
|
-
it
|
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
|
35
|
-
context
|
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(
|
39
|
-
it { should include(
|
40
|
-
it { should include(
|
41
|
-
it { should include(
|
42
|
-
it { should include(
|
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
|
47
|
-
context
|
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(
|
51
|
-
it { should include(
|
52
|
-
it { should include(
|
53
|
-
it { should include(
|
54
|
-
it { should include(
|
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
|
59
|
-
context
|
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(
|
63
|
-
it { should include(
|
64
|
-
it { should include(
|
65
|
-
it { should include(
|
66
|
-
it { should include(
|
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
|
71
|
-
context
|
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(
|
75
|
-
it { should include(
|
76
|
-
it { should include(
|
77
|
-
it { should include(
|
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
|
82
|
-
context
|
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(
|
86
|
-
it { should include(
|
87
|
-
it { should include(
|
88
|
-
it { should include(
|
89
|
-
it { should include(
|
90
|
-
it { should include(
|
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
|
95
|
-
it
|
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(
|
97
|
+
expect(vehicle.state).to eq('online')
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
describe
|
102
|
-
it
|
103
|
-
expect(vehicle.set_valet_mode(true, 1234)[
|
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
|
107
|
-
expect(vehicle.set_valet_mode(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
|
112
|
-
it
|
113
|
-
expect(vehicle.reset_valet_pin[
|
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
|
118
|
-
it
|
119
|
-
expect(vehicle.charge_port_door_open[
|
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
|
124
|
-
it
|
125
|
-
expect(vehicle.charge_standard[
|
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
|
129
|
-
expect(vehicle.charge_standard[
|
130
|
-
expect(vehicle.charge_standard).to eq({
|
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
|
135
|
-
it
|
136
|
-
expect(vehicle.charge_max_range[
|
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
|
140
|
-
expect(vehicle.charge_max_range[
|
141
|
-
expect(vehicle.charge_max_range).to eq({
|
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
|
146
|
-
it
|
147
|
-
expect(vehicle.set_charge_limit(100)[
|
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
|
151
|
-
expect(vehicle.set_charge_limit(90)[
|
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
|
155
|
-
expect(vehicle.set_charge_limit(50)[
|
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
|
159
|
-
expect(vehicle.set_charge_limit(1)[
|
160
|
-
expect(vehicle.charge_state[
|
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
|
165
|
-
it
|
166
|
-
expect(vehicle.charge_start[
|
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
|
171
|
-
it
|
172
|
-
expect(vehicle.charge_stop[
|
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
|
177
|
-
it
|
178
|
-
expect(vehicle.flash_lights[
|
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
|
183
|
-
it
|
184
|
-
expect(vehicle.honk_horn[
|
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
|
189
|
-
it
|
190
|
-
expect(vehicle.door_unlock[
|
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
|
195
|
-
it
|
196
|
-
expect(vehicle.door_lock[
|
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
|
201
|
-
it
|
202
|
-
expect(vehicle.set_temps(20.9, 20.9)[
|
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
|
206
|
-
expect(vehicle.set_temps(23.7, 23.7)[
|
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
|
211
|
-
it
|
212
|
-
expect(vehicle.auto_conditioning_start[
|
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
|
217
|
-
it
|
218
|
-
expect(vehicle.auto_conditioning_stop[
|
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
|
223
|
-
it
|
224
|
-
expect(vehicle.sun_roof_control(
|
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
|
228
|
-
expect(vehicle.sun_roof_control(
|
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
|
232
|
-
expect(vehicle.sun_roof_control(
|
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
|
236
|
-
expect(vehicle.sun_roof_control(
|
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
|
241
|
-
it
|
242
|
-
expect(vehicle.sun_roof_move(100)[
|
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
|
246
|
-
expect(vehicle.sun_roof_move(0)[
|
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
|
250
|
-
expect(vehicle.sun_roof_move(50)[
|
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
|
255
|
-
it
|
256
|
-
expect(vehicle.remote_start_drive(
|
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
|
261
|
-
it
|
262
|
-
expect(vehicle.
|
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
|
267
|
-
it
|
268
|
-
expect(vehicle.open_frunk[
|
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
|