Module: Smartcar

Extended by:
Utils
Defined in:
lib/smartcar.rb,
lib/smartcar/base.rb,
lib/smartcar/utils.rb,
lib/smartcar/vehicle.rb,
lib/smartcar/version.rb,
lib/smartcar/auth_client.rb

Overview

Main Smartcar umbrella module

Defined Under Namespace

Modules: Utils Classes: AuthClient, Base, ConfigNotFound, Vehicle

Constant Summary collapse

API_ORIGIN =

Host to connect to smartcar

'https://api.smartcar.com/'
VEHICLE_API_ORIGIN =
'https://vehicle.api.smartcar.com'
MANAGEMENT_API_ORIGIN =
'https://management.smartcar.com'
PATHS =
{
  compatibility: '/compatibility',
  user: '/user',
  vehicles: '/vehicles',
  connections: '/management/connections'
}.freeze
CONNECT_ORIGIN =

Path for smartcar oauth

'https://connect.smartcar.com'
AUTH_ORIGIN =
'https://auth.smartcar.com'
UNITS =

Constant for units

[IMPERIAL, METRIC].freeze
DEFAULT_REQUEST_TIMEOUT =

Number of seconds to wait for responses

310
VERSION =

Gem current version number

'3.9.5'

Class Method Summary collapse

Methods included from Utils

build_aliases, build_error, build_meta, build_response, build_v3_response, convert_path_to_attribute, convert_to_ostruct_recursively, deep_transform_keys_to_snake_case, determine_mode, get_config, handle_error, initialize, json_to_ostruct, parse_date_safely, process_batch_response, stringify_params, to_snake_case

Class Method Details

.delete_connections(amt:, filter: {}, options: {}) ⇒ Object



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/smartcar.rb', line 244

def delete_connections(amt:, filter: {}, options: {})
  user_id = filter[:user_id]
  vehicle_id = filter[:vehicle_id]
  error_message = nil
  error_message = 'Filter can contain EITHER user_id OR vehicle_id, not both.' if user_id && vehicle_id
  error_message = 'Filter needs one of user_id OR vehicle_id.' unless user_id || vehicle_id

  raise Base::InvalidParameterValue.new, error_message if error_message

  query_params = {}
  query_params['user_id'] = user_id if user_id
  query_params['vehicle_id'] = vehicle_id if vehicle_id

  base_object = Base.new(
    url: ENV['SMARTCAR_MANAGEMENT_API_ORIGIN'] || MANAGEMENT_API_ORIGIN,
    auth_type: Base::BASIC,
    token: generate_basic_management_auth(amt, options),
    version: options[:version] || Smartcar.get_api_version,
    service: options[:service]
  )

  base_object.build_response(*base_object.delete(
    PATHS[:connections],
    query_params
  ))
end

.generate_basic_management_auth(amt, options = {}) ⇒ String

returns auth token for Basic vehicle management auth



313
314
315
316
# File 'lib/smartcar.rb', line 313

def generate_basic_management_auth(amt, options = {})
  username = options[:username] || 'default'
  Base64.strict_encode64("#{username}:#{amt}")
end

.get_api_versionString

Module method Used to get api version to be used. This is the getter for the class instance variable @api_version



59
60
61
# File 'lib/smartcar.rb', line 59

def get_api_version
  instance_variable_get('@api_version')
end

.get_compatibility(vin:, scope:, country: 'US', options: {}) ⇒ OpenStruct

Module method Used to check compatiblity for VIN and scope

API Documentation - https://smartcar.com/docs/api#compatibility-api. Options Hash ISO 3166-1 alpha-2. Defaults to US. Launch Smartcar Connect in test mode(https://smartcar.com/docs/guides/testing/). Should be one of test, live or simulated. test mode with a real vin. For more information refer to docs.

Options Hash (options:):

  • :client_id (String)

    Client ID that overrides ENV

  • :client_secret (String)

    Client Secret that overrides ENV

  • :version (String)

    API version to use, defaults to what is globally set

  • :flags (Hash)

    A hash of flag name string as key and a string or boolean value.

  • :mode (String)

    Determine what mode Smartcar Connect should be launched in.

  • :test_mode_compatibility_level (String)

    this is required argument while using

  • :service (Faraday::Connection)

    Optional connection object to be used for requests

Raises:



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/smartcar.rb', line 85

def get_compatibility(vin:, scope:, country: 'US', options: {})
  raise Base::InvalidParameterValue.new, 'vin is a required field' if vin.nil?
  raise Base::InvalidParameterValue.new, 'scope is a required field' if scope.nil? || scope.empty?

  base_object = Base.new(
    {
      version: options[:version] || Smartcar.get_api_version,
      auth_type: Base::BASIC,
      service: options[:service]
    }
  )

  base_object.token = generate_basic_auth(options, base_object)

  base_object.build_response(*base_object.get(
    PATHS[:compatibility],
    build_compatibility_params(vin, scope, country, options)
  ))
end

.get_compatibility_matrix(region, options = {}) ⇒ OpenStruct

Module method to retrieve the Smartcar compatibility matrix for a given region. Provides the ability to filter by scope, make, and type.

A compatible vehicle is a vehicle that:

  1. has the hardware required for internet connectivity,
  2. belongs to the makes and models Smartcar supports, and
  3. supports the permissions.

API Documentation - https://smartcar.com/docs/api-reference/compatibility/by-region-and-make

Options Hash (options):

  • :scope (Array<String>)

    List of permissions to filter the matrix by

  • :make (String, Array<String>)

    List of makes to filter the matrix by (space-separated string or array)

  • :type (String)

    Engine type to filter the matrix by (e.g., "ICE", "HEV", "PHEV", "BEV")

  • :client_id (String)

    Client ID that overrides ENV

  • :client_secret (String)

    Client Secret that overrides ENV

  • :version (String)

    API version to use, defaults to what is globally set

  • :mode (String)

    Determine what mode Smartcar Connect should be launched in. Should be one of test, live or simulated.

  • :service (Faraday::Connection)

    Optional connection object to be used for requests

Raises:



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/smartcar.rb', line 129

def get_compatibility_matrix(region, options = {})
  raise Base::InvalidParameterValue.new, 'region is a required field' if region.nil? || region.empty?

  base_object = Base.new(
    {
      version: options[:version] || Smartcar.get_api_version,
      auth_type: Base::BASIC,
      service: options[:service]
    }
  )

  base_object.token = generate_basic_auth(options, base_object)

  base_object.build_response(*base_object.get(
    "#{PATHS[:compatibility]}/matrix",
    build_compatibility_matrix_params(region, options)
  ))
end

.get_connections(amt:, filter: {}, paging: {}, options: {}) ⇒ OpenStruct

Module method Returns a paged list of all vehicle connections connected to the application.

API Documentation - https://smartcar.com/docs/api#get-connections

Options Hash (options:):

  • :service (Faraday::Connection)

    Optional connection object to be used for requests

  • :version (String)

    Optional API version to use, defaults to what is globally set



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/smartcar.rb', line 227

def get_connections(amt:, filter: {}, paging: {}, options: {})
  paging[:limit] ||= 10
  base_object = Base.new(
    token: generate_basic_management_auth(amt, options),
    version: options[:version] || Smartcar.get_api_version,
    service: options[:service],
    auth_type: Base::BASIC,
    url: ENV['SMARTCAR_MANAGEMENT_API_ORIGIN'] || MANAGEMENT_API_ORIGIN
  )
  query_params = filter.merge(paging).compact

  base_object.build_response(*base_object.get(
    PATHS[:connections],
    query_params
  ))
end

.get_user(token:, version: Smartcar.get_api_version, options: {}) ⇒ OpenStruct

Module method Used to get user id

API Documentation - https://smartcar.com/docs/api#get-user

Options Hash (options:):

  • :service (Faraday::Connection)

    Optional connection object to be used for requests



158
159
160
161
162
163
164
165
166
167
# File 'lib/smartcar.rb', line 158

def get_user(token:, version: Smartcar.get_api_version, options: {})
  base_object = Base.new(
    {
      token: token,
      version: version,
      service: options[:service]
    }
  )
  base_object.build_response(*base_object.get(PATHS[:user]))
end

.get_vehicle(vehicle_id:, token:, options: {}) ⇒ OpenStruct

Module method to retrieve vehicle information using the v3 API.

API Documentation - https://smartcar.com/docs/api-reference/get-vehicle

Options Hash (options:):

  • :flags (Hash)

    A hash of flag name string as key and a string or boolean value.

  • :service (Faraday::Connection)

    Optional connection object to be used for requests

Raises:



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/smartcar.rb', line 282

def get_vehicle(vehicle_id:, token:, options: {})
  raise Base::InvalidParameterValue.new, 'vehicle_id is a required field' if vehicle_id.nil? || vehicle_id.empty?
  raise Base::InvalidParameterValue.new, 'token is a required field' if token.nil? || token.empty?

  vehicle_service = Faraday.new(
    url: ENV['SMARTCAR_VEHICLE_API_ORIGIN'] || VEHICLE_API_ORIGIN,
    request: { timeout: DEFAULT_REQUEST_TIMEOUT }
  )

  query_params = { flags: stringify_params(options[:flags]) }

  response = vehicle_service.get do |request|
    request.headers['Authorization'] = "Bearer #{token}"
    request.headers['Content-Type'] = 'application/json'
    request.headers['User-Agent'] =
      "Smartcar/#{VERSION} (#{RbConfig::CONFIG['host_os']}; #{RbConfig::CONFIG['arch']}) Ruby v#{RUBY_VERSION}"

    complete_path = "/v3/vehicles/#{vehicle_id}"
    complete_path += "?#{URI.encode_www_form(query_params.compact)}" unless query_params.empty?
    request.url complete_path
  end

  raise build_error(response.status, response.body, response.headers) unless [200, 204].include?(response.status)

  body = response.body.empty? ? '{}' : response.body
  build_v3_response(body, response.headers.to_h)
end

.get_vehicles(token:, paging: {}, version: Smartcar.get_api_version, options: {}) ⇒ OpenStruct

Module method Returns a paged list of all vehicles connected to the application for the current authorized user.

API Documentation - https://smartcar.com/docs/api#get-all-vehicles

Options Hash (options:):

  • :service (Faraday::Connection)

    Optional connection object to be used for requests



180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/smartcar.rb', line 180

def get_vehicles(token:, paging: {}, version: Smartcar.get_api_version, options: {})
  base_object = Base.new(
    {
      token: token,
      version: version,
      service: options[:service]
    }
  )
  base_object.build_response(*base_object.get(
    PATHS[:vehicles],
    paging
  ))
end

.hash_challenge(amt, challenge) ⇒ String

Module method to generate hash challenge for webhooks. It does HMAC_SHA256(amt, challenge)



200
201
202
# File 'lib/smartcar.rb', line 200

def hash_challenge(amt, challenge)
  OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), amt, challenge)
end

.set_api_version(version) ⇒ Object

Module method Used to set api version to be used. This method can be used at the top to set the version and any following request will use the version set here unless overridden separately.



51
52
53
# File 'lib/smartcar.rb', line 51

def set_api_version(version)
  instance_variable_set('@api_version', version)
end

.verify_payload(amt, signature, body) ⇒ true, false

Module method used to verify webhook payload with AMT and signature.



211
212
213
# File 'lib/smartcar.rb', line 211

def verify_payload(amt, signature, body)
  hash_challenge(amt, body.to_json) == signature
end