smartcar 2.4.0 → 3.0.2
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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +32 -0
- data/.travis.yml +1 -2
- data/Gemfile +4 -2
- data/Gemfile.lock +78 -16
- data/README.md +38 -36
- data/Rakefile +11 -3
- data/bin/console +4 -3
- data/lib/smartcar.rb +167 -55
- data/lib/smartcar/auth_client.rb +154 -0
- data/lib/smartcar/base.rb +18 -26
- data/lib/smartcar/utils.rb +102 -20
- data/lib/smartcar/vehicle.rb +183 -249
- data/lib/smartcar/version.rb +3 -1
- data/lib/smartcar_error.rb +49 -0
- data/ruby-sdk.gemspec +28 -21
- metadata +84 -24
- data/lib/smartcar/battery.rb +0 -13
- data/lib/smartcar/battery_capacity.rb +0 -9
- data/lib/smartcar/charge.rb +0 -13
- data/lib/smartcar/engine_oil.rb +0 -12
- data/lib/smartcar/fuel.rb +0 -15
- data/lib/smartcar/location.rb +0 -10
- data/lib/smartcar/oauth.rb +0 -119
- data/lib/smartcar/odometer.rb +0 -9
- data/lib/smartcar/permissions.rb +0 -9
- data/lib/smartcar/tire_pressure.rb +0 -19
- data/lib/smartcar/user.rb +0 -35
- data/lib/smartcar/vehicle_attributes.rb +0 -12
- data/lib/smartcar/vin.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e822148047b9ffd85867b85f13eec9bbba7785424d7c98982a65657f24b02019
|
4
|
+
data.tar.gz: 1322fbc3a032a209bdd8b7101e0e3e8baf2113972586399edb292ca82879a967
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e99928f83946aa9a62b48a0f920c1571442545b5320d2b5d3c9e0195a6b0835748ef54d9335bf6f29f2ffa47b60dab6e24ffd576af885dd37d6b1bfa1c35214
|
7
|
+
data.tar.gz: 48df4fe316d3eb55ca38630345f35f00ebec59d984d63854e03810d0dbde2e12ae9768fda8d6ec5d24911d7c82fa2be7844427d0390f50927a6ce88aa61d4f79
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Prevent messages for libraries of rubocop
|
2
|
+
AllCops:
|
3
|
+
NewCops: enable
|
4
|
+
SuggestExtensions: false
|
5
|
+
|
6
|
+
# Disabling ABC size for now as refactoring few places seems pointless for now
|
7
|
+
Metrics/AbcSize:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
# Disabling this becuase we are using `set` and `get` prefixed methods to keep some commonality across SDKs
|
11
|
+
Naming/AccessorMethodName:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
Metrics/BlockLength:
|
15
|
+
Exclude:
|
16
|
+
- '**/*.gemspec'
|
17
|
+
- 'spec/**/*'
|
18
|
+
|
19
|
+
# Just ignoring test helper for headless auth.
|
20
|
+
Metrics/MethodLength:
|
21
|
+
Max: 20
|
22
|
+
Exclude:
|
23
|
+
- 'spec/smartcar/helpers/auth_helper.rb'
|
24
|
+
|
25
|
+
# Parameters in data from json API comes in as camelCase, ignoring those files to avoid snake_case enforcement
|
26
|
+
Naming/MethodName:
|
27
|
+
Exclude:
|
28
|
+
- 'lib/smartcar/battery.rb'
|
29
|
+
- 'lib/smartcar/charge.rb'
|
30
|
+
- 'lib/smartcar/engine_oil.rb'
|
31
|
+
- 'lib/smartcar/fuel.rb'
|
32
|
+
- 'lib/smartcar/tire_pressure.rb'
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
6
|
|
5
7
|
# Specify your gem's dependencies in smartcar.gemspec
|
6
8
|
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,21 +1,44 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
smartcar (
|
4
|
+
smartcar (3.0.2)
|
5
5
|
oauth2 (~> 1.4)
|
6
|
+
recursive-open-struct (~> 1.1.3)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
9
10
|
specs:
|
11
|
+
addressable (2.8.0)
|
12
|
+
public_suffix (>= 2.0.2, < 5.0)
|
13
|
+
ast (2.4.2)
|
14
|
+
backport (1.1.2)
|
10
15
|
byebug (11.1.3)
|
11
16
|
childprocess (3.0.0)
|
12
|
-
|
13
|
-
|
17
|
+
codecov (0.5.2)
|
18
|
+
simplecov (>= 0.15, < 0.22)
|
19
|
+
crack (0.4.5)
|
20
|
+
rexml
|
21
|
+
diff-lcs (1.4.4)
|
22
|
+
docile (1.4.0)
|
23
|
+
faraday (1.5.1)
|
24
|
+
faraday-em_http (~> 1.0)
|
25
|
+
faraday-em_synchrony (~> 1.0)
|
26
|
+
faraday-excon (~> 1.1)
|
27
|
+
faraday-httpclient (~> 1.0.1)
|
14
28
|
faraday-net_http (~> 1.0)
|
29
|
+
faraday-net_http_persistent (~> 1.1)
|
30
|
+
faraday-patron (~> 1.0)
|
15
31
|
multipart-post (>= 1.2, < 3)
|
16
|
-
ruby2_keywords
|
32
|
+
ruby2_keywords (>= 0.0.4)
|
33
|
+
faraday-em_http (1.0.0)
|
34
|
+
faraday-em_synchrony (1.0.0)
|
35
|
+
faraday-excon (1.1.0)
|
36
|
+
faraday-httpclient (1.0.1)
|
17
37
|
faraday-net_http (1.0.1)
|
18
|
-
|
38
|
+
faraday-net_http_persistent (1.2.0)
|
39
|
+
faraday-patron (1.0.0)
|
40
|
+
hashdiff (1.0.1)
|
41
|
+
jwt (2.2.3)
|
19
42
|
multi_json (1.15.0)
|
20
43
|
multi_xml (0.6.0)
|
21
44
|
multipart-post (2.1.1)
|
@@ -25,27 +48,62 @@ GEM
|
|
25
48
|
multi_json (~> 1.3)
|
26
49
|
multi_xml (~> 0.5)
|
27
50
|
rack (>= 1.2, < 3)
|
51
|
+
parallel (1.20.1)
|
52
|
+
parser (3.0.1.1)
|
53
|
+
ast (~> 2.4.1)
|
54
|
+
public_suffix (4.0.6)
|
28
55
|
rack (2.2.3)
|
56
|
+
rainbow (3.0.0)
|
29
57
|
rake (12.3.3)
|
58
|
+
readapt (1.3.0)
|
59
|
+
backport (~> 1.1)
|
60
|
+
thor (~> 1.0)
|
61
|
+
recursive-open-struct (1.1.3)
|
30
62
|
redcarpet (3.5.1)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
rspec-
|
35
|
-
|
36
|
-
rspec-
|
37
|
-
rspec-
|
63
|
+
regexp_parser (2.1.1)
|
64
|
+
rexml (3.2.5)
|
65
|
+
rspec (3.10.0)
|
66
|
+
rspec-core (~> 3.10.0)
|
67
|
+
rspec-expectations (~> 3.10.0)
|
68
|
+
rspec-mocks (~> 3.10.0)
|
69
|
+
rspec-core (3.10.1)
|
70
|
+
rspec-support (~> 3.10.0)
|
71
|
+
rspec-expectations (3.10.1)
|
38
72
|
diff-lcs (>= 1.2.0, < 2.0)
|
39
|
-
rspec-support (~> 3.
|
40
|
-
rspec-mocks (3.
|
73
|
+
rspec-support (~> 3.10.0)
|
74
|
+
rspec-mocks (3.10.2)
|
41
75
|
diff-lcs (>= 1.2.0, < 2.0)
|
42
|
-
rspec-support (~> 3.
|
43
|
-
rspec-support (3.
|
76
|
+
rspec-support (~> 3.10.0)
|
77
|
+
rspec-support (3.10.2)
|
78
|
+
rubocop (1.16.1)
|
79
|
+
parallel (~> 1.10)
|
80
|
+
parser (>= 3.0.0.0)
|
81
|
+
rainbow (>= 2.2.2, < 4.0)
|
82
|
+
regexp_parser (>= 1.8, < 3.0)
|
83
|
+
rexml
|
84
|
+
rubocop-ast (>= 1.7.0, < 2.0)
|
85
|
+
ruby-progressbar (~> 1.7)
|
86
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
87
|
+
rubocop-ast (1.7.0)
|
88
|
+
parser (>= 3.0.1.1)
|
89
|
+
ruby-progressbar (1.11.0)
|
44
90
|
ruby2_keywords (0.0.4)
|
45
91
|
rubyzip (2.3.0)
|
46
92
|
selenium-webdriver (3.142.7)
|
47
93
|
childprocess (>= 0.5, < 4.0)
|
48
94
|
rubyzip (>= 1.2.2)
|
95
|
+
simplecov (0.21.2)
|
96
|
+
docile (~> 1.1)
|
97
|
+
simplecov-html (~> 0.11)
|
98
|
+
simplecov_json_formatter (~> 0.1)
|
99
|
+
simplecov-html (0.12.3)
|
100
|
+
simplecov_json_formatter (0.1.3)
|
101
|
+
thor (1.1.0)
|
102
|
+
unicode-display_width (2.0.0)
|
103
|
+
webmock (3.13.0)
|
104
|
+
addressable (>= 2.3.6)
|
105
|
+
crack (>= 0.3.2)
|
106
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
49
107
|
|
50
108
|
PLATFORMS
|
51
109
|
ruby
|
@@ -53,11 +111,15 @@ PLATFORMS
|
|
53
111
|
DEPENDENCIES
|
54
112
|
bundler (~> 2.0)
|
55
113
|
byebug (~> 11.0)
|
114
|
+
codecov (~> 0.5.2)
|
56
115
|
rake (~> 12.3, >= 12.3.3)
|
116
|
+
readapt (~> 1.3)
|
57
117
|
redcarpet (~> 3.5.0)
|
58
118
|
rspec (~> 3.0)
|
119
|
+
rubocop (~> 1.12)
|
59
120
|
selenium-webdriver (~> 3.142)
|
60
121
|
smartcar!
|
122
|
+
webmock (~> 3.13)
|
61
123
|
|
62
124
|
BUNDLED WITH
|
63
125
|
2.1.4
|
data/README.md
CHANGED
@@ -29,28 +29,28 @@ not have access to the dashboard, please
|
|
29
29
|
|
30
30
|
### Flow
|
31
31
|
|
32
|
-
- Create a new `AuthClient` object with your `
|
33
|
-
`
|
34
|
-
- Redirect the user to Smartcar Connect using `
|
32
|
+
- Create a new `AuthClient` object with your `client_id`, `client_secret`,
|
33
|
+
`redirect_uri`.
|
34
|
+
- Redirect the user to Smartcar Connect using `get_auth_url` with required `scope` or with one
|
35
35
|
of our frontend SDKs.
|
36
36
|
- The user will login, and then accept or deny your `scope`'s permissions.
|
37
|
-
- Handle the get request to `
|
37
|
+
- Handle the get request to `redirect_uri`.
|
38
38
|
- If the user accepted your permissions, `req.query.code` will contain an
|
39
39
|
authorization code.
|
40
|
-
- Use `
|
40
|
+
- Use `exchange_code` with this code to obtain an access object
|
41
41
|
containing an access token (lasting 2 hours) and a refresh token
|
42
42
|
(lasting 60 days).
|
43
43
|
- Save this access object.
|
44
44
|
- If the user denied your permissions, `req.query.error` will be set
|
45
45
|
to `"access_denied"`.
|
46
|
-
- If you passed a state parameter to `
|
46
|
+
- If you passed a state parameter to `get_auth_url`, `req.query.state` will
|
47
47
|
contain the state value.
|
48
|
-
- Get the user's vehicles with `
|
49
|
-
- Create a new `Vehicle` object using a `
|
48
|
+
- Get the user's vehicles with `getVehicles`.
|
49
|
+
- Create a new `Vehicle` object using a `vehicle_id` from the previous response,
|
50
50
|
and the `access_token`.
|
51
51
|
- Make requests to the Smartcar API.
|
52
|
-
- Use `
|
53
|
-
when your `
|
52
|
+
- Use `exchange_refresh_token` on your saved `refresh_token` to retrieve a new token
|
53
|
+
when your `access_token` expires.
|
54
54
|
|
55
55
|
## Installation
|
56
56
|
|
@@ -70,53 +70,47 @@ Or install it yourself as:
|
|
70
70
|
|
71
71
|
## Usage
|
72
72
|
|
73
|
-
Setup the environment variables for
|
73
|
+
Setup the environment variables for SMARTCAR_CLIENT_ID, SMARTCAR_CLIENT_SECRET and SMARTCAR_REDIRECT_URI.
|
74
74
|
```bash
|
75
75
|
# Get your API keys from https://dashboard.smartcar.com/signup
|
76
|
-
export
|
77
|
-
export
|
76
|
+
export SMARTCAR_CLIENT_ID=<client id>
|
77
|
+
export SMARTCAR_CLIENT_SECRET=<client secret>
|
78
|
+
export SMARTCAR_REDIRECT_URI=<redirect URI>
|
78
79
|
```
|
79
80
|
|
80
81
|
Example Usage for calling the reports API with oAuth token
|
81
82
|
```ruby
|
82
83
|
2.5.7 :001 > require 'smartcar'
|
83
84
|
=> true
|
84
|
-
2.5.7 :003 > ids = Smartcar
|
85
|
+
2.5.7 :003 > ids = Smartcar.get_vehicles(token: token).vehicles
|
85
86
|
=> ["4bb777b2-bde7-4305-8952-25956f8c0868"]
|
86
87
|
2.5.7 :004 > vehicle = Smartcar::Vehicle.new(token: token, id: ids.first)
|
87
|
-
=> #<Smartcar::Vehicle:
|
88
|
+
=> #<Smartcar::Vehicle:0x0000558dcd7ee608 @token="c900e00e-ee8e-403d-a7bf-f992bc0ad302", @id="e31c9de6-1332-472b-b648-5d74b05b7fda", @options={:unit_system=>"metric", :version=>"2.0"}, @unit_system="metric", @version="2.0", @service=#<Faraday::Connection:0x0000558dcd7d63f0 @parallel_manager=nil, @headers={"User-Agent"=>"Faraday v1.4.2"}, @params={}, @options=#<Faraday::RequestOptions timeout=310>, @ssl=#<Faraday::SSLOptions verify=true>, @default_parallel_manager=nil, @builder=#<Faraday::RackBuilder:0x0000558dcd7c1bf8 @adapter=Faraday::Adapter::NetHttp, @handlers=[Faraday::Request::UrlEncoded], @app=#<Faraday::Request::UrlEncoded:0x0000558dcd7af048 @app=#<Faraday::Adapter::NetHttp:0x0000558dcd7af390 @ssl_cert_store=#<OpenSSL::X509::Store:0x0000558dcd7a36a8 @verify_callback=nil, @error=nil, @error_string=nil, @chain=nil, @time=nil>, @app=#<Proc:0x0000558dcd7af278 /home/ashwinsubramanian/.rvm/gems/ruby-2.7.2/gems/faraday-1.4.2/lib/faraday/adapter.rb:37 (lambda)>, @connection_options={}, @config_block=nil>, @options={}>>, @url_prefix=#<URI::HTTPS https://api.smartcar.com/>, @proxy=nil, @manual_proxy=false>>
|
88
89
|
2.5.7 :006 > vehicle.odometer
|
89
|
-
=> #<
|
90
|
+
=> #<OpenStruct distance=39685.33984375, meta=#<OpenStruct data_age=#<DateTime: 2021-06-24T22:28:39+00:00 ((2459390j,80919s,95000000n),+0s,2299161j)>, unit_system="metric", request_id="4962ba7f-5c94-48ab-9955-4e2b101c7b8a">>
|
90
91
|
2.5.7 :007 > vehicle.battery
|
91
|
-
=> #<
|
92
|
+
=> #<OpenStruct range=208.82, percentRemaining=0.31, meta=#<OpenStruct data_age=#<DateTime: 2021-06-24T22:28:54+00:00 ((2459390j,80934s,855000000n),+0s,2299161j)>, unit_system="metric", request_id="a88b95ec-b10f-4fc8-979b-5d95fe40d925">, percentage_remaining=0.31>
|
92
93
|
2.5.7 :009 > vehicle.lock!
|
93
|
-
=>
|
94
|
-
2.5.7 :010 > vehicle.batch(["charge","battery"])
|
95
|
-
=>
|
96
|
-
2.5.7 :011 >
|
97
|
-
|
98
|
-
5: from /usr/share/rvm/rubies/ruby-2.5.7/bin/irb:11:in `<main>'
|
99
|
-
4: from (irb):5
|
100
|
-
3: from /home/st-2vgpnn2/.rvm/gems/ruby-2.5.7/gems/smartcar-1.0.0/lib/smartcar/vehicle.rb:118:in `start_charge!'
|
101
|
-
2: from /home/st-2vgpnn2/.rvm/gems/ruby-2.5.7/gems/smartcar-1.0.0/lib/smartcar/vehicle.rb:290:in `start_or_stop_charge!'
|
102
|
-
1: from /home/st-2vgpnn2/.rvm/gems/ruby-2.5.7/gems/smartcar-1.0.0/lib/smartcar/base.rb:39:in `block (2 levels) in <class:Base>'
|
103
|
-
Smartcar::ExternalServiceError (API error - {"error":"vehicle_state_error","message":"Charging plug is not connected to the vehicle.","code":"VS_004"})
|
104
|
-
|
94
|
+
=> #<OpenStruct status="success", message="Successfully sent request to vehicle", meta=#<OpenStruct request_id="0c90918f-a9cc-405c-839f-7d9b70e249c4">>
|
95
|
+
2.5.7 :010 > batch_response = vehicle.batch(["/charge","/battery"])
|
96
|
+
=> #<OpenStruct>
|
97
|
+
2.5.7 :011 > batch_response.charge()
|
98
|
+
=> #<OpenStruct state="NOT_CHARGING", isPluggedIn=false, meta=#<OpenStruct data_age=#<DateTime: 2021-06-24T22:30:20+00:00 ((2459390j,81020s,892000000n),+0s,2299161j)>, request_id="29a66280-8685-4a57-9733-daa3dfb9970f">, is_plugged_in?=false>
|
105
99
|
```
|
106
100
|
|
107
101
|
Example Usage for oAuth -
|
108
102
|
```ruby
|
109
103
|
# To get the redirect URL :
|
110
|
-
2.5.5 :002 > options = {test_mode: true
|
104
|
+
2.5.5 :002 > options = {test_mode: true}
|
111
105
|
2.5.5 :003 > require 'smartcar'
|
112
|
-
2.5.5 :004 > client = Smartcar::
|
113
|
-
2.5.5 :005 > url = client.
|
106
|
+
2.5.5 :004 > client = Smartcar::AuthClient.new(options)
|
107
|
+
2.5.5 :005 > url = client.get_auth_url(["read_battery","read_charge","read_fuel","read_location","control_security","read_odometer","read_tires","read_vin","read_vehicle_info"], {flags: ["country:DE"]})
|
114
108
|
=> "https://connect.smartcar.com/oauth/authorize?approval_prompt=auto&client_id=<client id>&mode=test&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fcallback&response_type=code&scope=read_battery+read_charge+read_fuel+read_location+control_security+read_odometer+read_tires+read_vin+read_vehicle_info&flags=country%3ADE"
|
115
109
|
# Redirect user to the above URL.
|
116
110
|
# After authentication user control reaches the callback URL with code.
|
117
111
|
# Use the code from the parameters and request a token
|
118
|
-
2.5.5 :006 > token_hash = client.
|
119
|
-
=>
|
112
|
+
2.5.5 :006 > token_hash = client.exchange_code(code)
|
113
|
+
=> #<OpenStruct token_type="Bearer", access_token="20e24b4a-3055-4cc8-9cf3-2b3c5afba3e6", refresh_token="cf89c62e-7b36-4e13-a9df-d9c2a5296280", expires_at=1624581588>
|
120
114
|
# This access_token can be used to call the Smartcar APIs as given above.
|
121
115
|
# Store this hash and if it expired refresh the token OR use the code again to
|
122
116
|
# get a new token or use .
|
@@ -128,8 +122,10 @@ To install this gem onto your local machine, run `bundle exec rake install`.
|
|
128
122
|
|
129
123
|
To run tests, make sure you have the env variables setup for client id and secret.
|
130
124
|
```shell
|
131
|
-
export
|
132
|
-
export
|
125
|
+
export E2E_SMARTCAR_CLIENT_ID=<client id>
|
126
|
+
export E2E_SMARTCAR_CLIENT_SECRET=<client secret>
|
127
|
+
export E2E_SMARTCAR_AMT=<amt from dashboard for webhooks>
|
128
|
+
export E2E_SMARTCAR_WEBHOOK_ID=<webhook id to use for tests>
|
133
129
|
```
|
134
130
|
|
135
131
|
Tests can be run using either default rake command OR specific rspec command.
|
@@ -164,3 +160,9 @@ To contribute, please:
|
|
164
160
|
|
165
161
|
[gem-image]: https://badge.fury.io/rb/smartcar
|
166
162
|
[gem-url]: https://badge.fury.io/rb/smartcar.svg
|
163
|
+
|
164
|
+
## Supported Ruby Branches
|
165
|
+
|
166
|
+
Smartcar aims to support the SDK on all Ruby branches that have a status of "normal maintenance" or "security maintenance" as defined in the [Ruby Branches documentation](https://www.ruby-lang.org/en/downloads/branches/).
|
167
|
+
|
168
|
+
In accordance with the Semantic Versioning specification, the addition of support for new Ruby branches would result in a MINOR version bump and the removal of support for Ruby branches would result in a MAJOR version bump.
|
data/Rakefile
CHANGED
@@ -1,6 +1,14 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
3
5
|
|
4
6
|
RSpec::Core::RakeTask.new(:spec)
|
5
7
|
|
6
|
-
|
8
|
+
require 'rubocop/rake_task'
|
9
|
+
|
10
|
+
RuboCop::RakeTask.new(:rubocop) do |t|
|
11
|
+
t.options = ['--display-cop-names']
|
12
|
+
end
|
13
|
+
|
14
|
+
task default: %i[rubocop spec]
|
data/bin/console
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
require
|
4
|
-
require
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'smartcar'
|
5
6
|
|
6
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
8
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +11,5 @@ require "smartcar"
|
|
10
11
|
# require "pry"
|
11
12
|
# Pry.start
|
12
13
|
|
13
|
-
require
|
14
|
+
require 'irb'
|
14
15
|
IRB.start(__FILE__)
|
data/lib/smartcar.rb
CHANGED
@@ -1,73 +1,185 @@
|
|
1
|
-
|
2
|
-
require "smartcar/version"
|
3
|
-
require "smartcar/base"
|
4
|
-
require "smartcar/oauth"
|
5
|
-
require "smartcar/permissions"
|
6
|
-
require "smartcar/battery"
|
7
|
-
require "smartcar/battery_capacity"
|
8
|
-
require "smartcar/charge"
|
9
|
-
require "smartcar/engine_oil"
|
10
|
-
require "smartcar/fuel"
|
11
|
-
require "smartcar/location"
|
12
|
-
require "smartcar/odometer"
|
13
|
-
require "smartcar/tire_pressure"
|
14
|
-
require "smartcar/vin"
|
15
|
-
require "smartcar/vehicle_attributes"
|
16
|
-
require "smartcar/vehicle"
|
17
|
-
require "smartcar/user"
|
1
|
+
# frozen_string_literal: true
|
18
2
|
|
3
|
+
require 'recursive_open_struct'
|
4
|
+
require 'smartcar_error'
|
5
|
+
require 'smartcar/utils'
|
6
|
+
require 'smartcar/version'
|
7
|
+
require 'smartcar/base'
|
8
|
+
require 'smartcar/auth_client'
|
9
|
+
require 'smartcar/vehicle'
|
19
10
|
|
20
11
|
# Main Smartcar umbrella module
|
21
12
|
module Smartcar
|
22
13
|
# Error raised when a config is not found
|
23
14
|
class ConfigNotFound < StandardError; end
|
24
|
-
# Error raised when Smartcar returns non 400, 404, 401, 200 or 204 response
|
25
|
-
class ExternalServiceError < StandardError; end
|
26
|
-
# Error raised when Smartcar returns 404
|
27
|
-
class ServiceUnavailableError < ExternalServiceError; end
|
28
|
-
# Error raised when Smartcar returns Authentication Error with status 401
|
29
|
-
class AuthenticationError < ExternalServiceError; end
|
30
|
-
# Error raised when Smartcar returns 400 response
|
31
|
-
class BadRequestError < ExternalServiceError; end
|
32
15
|
|
33
16
|
# Host to connect to smartcar
|
34
|
-
|
17
|
+
API_ORIGIN = 'https://api.smartcar.com/'
|
18
|
+
PATHS = {
|
19
|
+
compatibility: '/compatibility',
|
20
|
+
user: '/user',
|
21
|
+
vehicles: '/vehicles'
|
22
|
+
}.freeze
|
35
23
|
|
36
24
|
# Path for smartcar oauth
|
37
|
-
|
38
|
-
%w
|
25
|
+
AUTH_ORIGIN = 'https://connect.smartcar.com'
|
26
|
+
%w[success code test live force auto metric imperial].each do |constant|
|
39
27
|
# Constant to represent the value
|
40
28
|
const_set(constant.upcase, constant.freeze)
|
41
29
|
end
|
42
30
|
|
43
|
-
# Lock value sent in request body
|
44
|
-
LOCK = "LOCK".freeze
|
45
|
-
# Unlock value sent in request body
|
46
|
-
UNLOCK = "UNLOCK".freeze
|
47
|
-
# Start charge value sent in request body
|
48
|
-
START_CHARGE = "START".freeze
|
49
|
-
# Stop charge value sent in request body
|
50
|
-
STOP_CHARGE = "STOP".freeze
|
51
31
|
# Constant for units
|
52
|
-
UNITS = [IMPERIAL,METRIC]
|
53
|
-
|
54
|
-
# Smartcar API version variable - defaulted to
|
55
|
-
@api_version =
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
32
|
+
UNITS = [IMPERIAL, METRIC].freeze
|
33
|
+
|
34
|
+
# Smartcar API version variable - defaulted to 2.0
|
35
|
+
@api_version = '2.0'
|
36
|
+
|
37
|
+
class << self
|
38
|
+
# Module method Used to set api version to be used.
|
39
|
+
# This method can be used at the top to set the version and any
|
40
|
+
# following request will use the version set here unless overridden
|
41
|
+
# separately.
|
42
|
+
# @param version [String] version to be set without 'v' prefix.
|
43
|
+
def set_api_version(version)
|
44
|
+
instance_variable_set('@api_version', version)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Module method Used to get api version to be used.
|
48
|
+
# This is the getter for the class instance variable @api_version
|
49
|
+
#
|
50
|
+
# @return [String] api version number without 'v' prefix
|
51
|
+
def get_api_version
|
52
|
+
instance_variable_get('@api_version')
|
53
|
+
end
|
54
|
+
|
55
|
+
# Module method Used to check compatiblity for VIN and scope
|
56
|
+
#
|
57
|
+
# API Documentation - https://smartcar.com/docs/api#connect-compatibility
|
58
|
+
# @param vin [String] VIN of the vehicle to be checked
|
59
|
+
# @param scope [Array of Strings] - array of scopes
|
60
|
+
# @param country [String] An optional country code according to
|
61
|
+
# [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2).
|
62
|
+
# Defaults to US.
|
63
|
+
# @param options [Hash] Other optional parameters including overrides
|
64
|
+
# @option options [String] :client_id Client ID that overrides ENV
|
65
|
+
# @option options [String] :client_secret Client Secret that overrides ENV
|
66
|
+
# @option options [String] :version API version to use, defaults to what is globally set
|
67
|
+
# @option options [Hash] :flags A hash of flag name string as key and a string or boolean value.
|
68
|
+
# @option options [Boolean] :test_mode Wether to use test mode or not.
|
69
|
+
# @option options [String] :test_mode_compatibility_level this is required argument while using
|
70
|
+
# test mode with a real vin. For more information refer to docs.
|
71
|
+
#
|
72
|
+
# @return [OpenStruct] And object representing the JSON response mentioned in https://smartcar.com/docs/api#connect-compatibility
|
73
|
+
# and a meta attribute with the relevant items from response headers.
|
74
|
+
def get_compatibility(vin:, scope:, country: 'US', options: {})
|
75
|
+
raise InvalidParameterValue.new, 'vin is a required field' if vin.nil?
|
76
|
+
raise InvalidParameterValue.new, 'scope is a required field' if scope.nil?
|
77
|
+
|
78
|
+
base_object = Base.new(
|
79
|
+
{
|
80
|
+
version: options[:version] || Smartcar.get_api_version,
|
81
|
+
auth_type: Base::BASIC
|
82
|
+
}
|
83
|
+
)
|
84
|
+
|
85
|
+
base_object.token = generate_basic_auth(options, base_object)
|
86
|
+
|
87
|
+
base_object.build_response(*base_object.fetch(
|
88
|
+
{
|
89
|
+
path: PATHS[:compatibility],
|
90
|
+
query_params: build_compatibility_params(vin, scope, country, options)
|
91
|
+
}
|
92
|
+
))
|
93
|
+
end
|
94
|
+
|
95
|
+
# Module method Used to get user id
|
96
|
+
#
|
97
|
+
# API Documentation - https://smartcar.com/docs/api#get-user
|
98
|
+
# @param token [String] Access token
|
99
|
+
#
|
100
|
+
# @return [OpenStruct] And object representing the JSON response mentioned in https://smartcar.com/docs/api#get-user
|
101
|
+
# and a meta attribute with the relevant items from response headers.
|
102
|
+
def get_user(token:, version: Smartcar.get_api_version)
|
103
|
+
base_object = Base.new(
|
104
|
+
{
|
105
|
+
token: token,
|
106
|
+
version: version
|
107
|
+
}
|
108
|
+
)
|
109
|
+
base_object.build_response(*base_object.fetch({ path: PATHS[:user] }))
|
110
|
+
end
|
111
|
+
|
112
|
+
# Module method Returns a paged list of all vehicles connected to the application for the current authorized user.
|
113
|
+
#
|
114
|
+
# API Documentation - https://smartcar.com/docs/api#get-all-vehicles
|
115
|
+
# @param token [String] - Access token
|
116
|
+
# @param paging [Hash] - Optional filter parameters (check documentation)
|
117
|
+
#
|
118
|
+
# @return [OpenStruct] And object representing the JSON response mentioned in https://smartcar.com/docs/api#get-all-vehicles
|
119
|
+
# and a meta attribute with the relevant items from response headers.
|
120
|
+
def get_vehicles(token:, paging: {}, version: Smartcar.get_api_version)
|
121
|
+
base_object = Base.new(
|
122
|
+
{
|
123
|
+
token: token,
|
124
|
+
version: version
|
125
|
+
}
|
126
|
+
)
|
127
|
+
base_object.build_response(*base_object.fetch(
|
128
|
+
{
|
129
|
+
path: PATHS[:vehicles],
|
130
|
+
query_params: paging
|
131
|
+
}
|
132
|
+
))
|
133
|
+
end
|
134
|
+
|
135
|
+
# Module method to generate hash challenge for webhooks. It does HMAC_SHA256(amt, challenge)
|
136
|
+
#
|
137
|
+
# @param amt [String] - Application Management Token
|
138
|
+
# @param challenge [String] - Challenge string
|
139
|
+
#
|
140
|
+
# @return [String] String representing the hex digest
|
141
|
+
def hash_challenge(amt, challenge)
|
142
|
+
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), amt, challenge)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Module method used to verify webhook payload with AMT and signature.
|
146
|
+
#
|
147
|
+
# @param amt [String] - Application Management Token
|
148
|
+
# @param signature [String] - sc-signature header value
|
149
|
+
# @param body [Object] - webhook response body
|
150
|
+
#
|
151
|
+
# @return [true, false] - true if signature matches the hex digest of amt and body
|
152
|
+
def verify_payload(amt, signature, body)
|
153
|
+
hash_challenge(amt, body.to_json) == signature
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
def build_compatibility_params(vin, scope, country, options)
|
159
|
+
query_params = {
|
160
|
+
vin: vin,
|
161
|
+
scope: scope.join(' '),
|
162
|
+
country: country
|
163
|
+
}
|
164
|
+
query_params[:flags] = options[:flags].map { |key, value| "#{key}:#{value}" }.join(' ') if options[:flags]
|
165
|
+
query_params[:mode] = options[:test_mode].is_a?(TrueClass) ? 'test' : 'live' unless options[:test_mode].nil?
|
166
|
+
|
167
|
+
if options[:test_mode_compatibility_level]
|
168
|
+
query_params[:test_mode_compatibility_level] =
|
169
|
+
options[:test_mode_compatibility_level]
|
170
|
+
query_params[:mode] = 'test'
|
171
|
+
end
|
172
|
+
|
173
|
+
query_params
|
174
|
+
end
|
65
175
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
176
|
+
# returns auth token for Basic auth
|
177
|
+
#
|
178
|
+
# @return [String] Base64 encoding of CLIENT:SECRET
|
179
|
+
def generate_basic_auth(options, base_object)
|
180
|
+
client_id = options[:client_id] || base_object.get_config('SMARTCAR_CLIENT_ID')
|
181
|
+
client_secret = options[:client_secret] || base_object.get_config('SMARTCAR_CLIENT_SECRET')
|
182
|
+
Base64.strict_encode64("#{client_id}:#{client_secret}")
|
183
|
+
end
|
72
184
|
end
|
73
185
|
end
|