tesla 0.0.1 → 0.1.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 (97) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +5 -0
  3. data/CHANGELOG.md +31 -0
  4. data/CONTRIBUTING.md +45 -0
  5. data/{LICENSE.txt → LICENSE.md} +1 -1
  6. data/README.md +366 -0
  7. data/SECURITY.md +38 -0
  8. data/lib/tesla/api/alert_endpoints.rb +35 -0
  9. data/lib/tesla/api/charging_endpoints.rb +115 -0
  10. data/lib/tesla/api/climate_endpoints.rb +180 -0
  11. data/lib/tesla/api/closure_endpoints.rb +142 -0
  12. data/lib/tesla/api/command_endpoints.rb +63 -0
  13. data/lib/tesla/api/media_endpoints.rb +114 -0
  14. data/lib/tesla/api/navigation_endpoints.rb +51 -0
  15. data/lib/tesla/api/oauth_endpoints.rb +118 -0
  16. data/lib/tesla/api/partner_endpoints.rb +62 -0
  17. data/lib/tesla/api/security_endpoints.rb +123 -0
  18. data/lib/tesla/api/software_endpoints.rb +38 -0
  19. data/lib/tesla/api/user_endpoints.rb +40 -0
  20. data/lib/tesla/api/vehicle_endpoints.rb +174 -0
  21. data/lib/tesla/api.rb +39 -0
  22. data/lib/tesla/authenticator.rb +33 -0
  23. data/lib/tesla/bearer_token_authenticator.rb +38 -0
  24. data/lib/tesla/certificate_options.rb +51 -0
  25. data/lib/tesla/charge_state.rb +111 -0
  26. data/lib/tesla/charging_site.rb +67 -0
  27. data/lib/tesla/client.rb +336 -0
  28. data/lib/tesla/client_credentials.rb +230 -0
  29. data/lib/tesla/climate_state.rb +116 -0
  30. data/lib/tesla/configuration.rb +483 -0
  31. data/lib/tesla/connection.rb +361 -0
  32. data/lib/tesla/connection_pool.rb +186 -0
  33. data/lib/tesla/deep_copy.rb +41 -0
  34. data/lib/tesla/drive_state.rb +80 -0
  35. data/lib/tesla/errors/bad_gateway.rb +9 -0
  36. data/lib/tesla/errors/bad_request.rb +9 -0
  37. data/lib/tesla/errors/client_error.rb +9 -0
  38. data/lib/tesla/errors/command_failed.rb +42 -0
  39. data/lib/tesla/errors/device_unexpected_response.rb +12 -0
  40. data/lib/tesla/errors/error.rb +7 -0
  41. data/lib/tesla/errors/forbidden.rb +14 -0
  42. data/lib/tesla/errors/gateway_timeout.rb +9 -0
  43. data/lib/tesla/errors/http_error.rb +89 -0
  44. data/lib/tesla/errors/internal_server_error.rb +9 -0
  45. data/lib/tesla/errors/invalid_response.rb +33 -0
  46. data/lib/tesla/errors/locked.rb +12 -0
  47. data/lib/tesla/errors/method_not_allowed.rb +9 -0
  48. data/lib/tesla/errors/misdirected_request.rb +13 -0
  49. data/lib/tesla/errors/network_error.rb +30 -0
  50. data/lib/tesla/errors/not_acceptable.rb +9 -0
  51. data/lib/tesla/errors/not_found.rb +9 -0
  52. data/lib/tesla/errors/oauth_error.rb +53 -0
  53. data/lib/tesla/errors/payment_required.rb +12 -0
  54. data/lib/tesla/errors/precondition_failed.rb +13 -0
  55. data/lib/tesla/errors/request_timeout.rb +13 -0
  56. data/lib/tesla/errors/server_error.rb +9 -0
  57. data/lib/tesla/errors/service_unavailable.rb +9 -0
  58. data/lib/tesla/errors/too_many_redirects.rb +9 -0
  59. data/lib/tesla/errors/too_many_requests.rb +9 -0
  60. data/lib/tesla/errors/unauthorized.rb +9 -0
  61. data/lib/tesla/errors/unavailable_for_legal_reasons.rb +12 -0
  62. data/lib/tesla/errors/unprocessable_content.rb +12 -0
  63. data/lib/tesla/errors/vehicle_asleep.rb +32 -0
  64. data/lib/tesla/gui_settings.rb +60 -0
  65. data/lib/tesla/idempotence.rb +30 -0
  66. data/lib/tesla/identifiers.rb +27 -0
  67. data/lib/tesla/json_parsing.rb +38 -0
  68. data/lib/tesla/nearby_charging_sites.rb +35 -0
  69. data/lib/tesla/path_escaping.rb +30 -0
  70. data/lib/tesla/redacted_output.rb +161 -0
  71. data/lib/tesla/redirect_handler.rb +196 -0
  72. data/lib/tesla/region.rb +27 -0
  73. data/lib/tesla/request_builder.rb +138 -0
  74. data/lib/tesla/resource.rb +403 -0
  75. data/lib/tesla/response_parser.rb +92 -0
  76. data/lib/tesla/retry_after.rb +34 -0
  77. data/lib/tesla/retry_handler.rb +252 -0
  78. data/lib/tesla/settings.rb +115 -0
  79. data/lib/tesla/url_validation.rb +131 -0
  80. data/lib/tesla/user.rb +36 -0
  81. data/lib/tesla/vehicle.rb +90 -0
  82. data/lib/tesla/vehicle_config.rb +95 -0
  83. data/lib/tesla/vehicle_data.rb +67 -0
  84. data/lib/tesla/vehicle_state.rb +125 -0
  85. data/lib/tesla/version.rb +6 -0
  86. data/lib/tesla.rb +139 -0
  87. data/sig/manifest.yaml +10 -0
  88. data/sig/tesla.rbs +989 -0
  89. metadata +134 -118
  90. data/.document +0 -5
  91. data/.rvmrc +0 -1
  92. data/Gemfile +0 -13
  93. data/Gemfile.lock +0 -20
  94. data/README.rdoc +0 -19
  95. data/Rakefile +0 -47
  96. data/test/helper.rb +0 -19
  97. data/test/test_tesla.rb +0 -7
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "resource"
4
+
5
+ module Tesla
6
+ # The configuration a vehicle was built with
7
+ # @api public
8
+ class VehicleConfig < Resource
9
+ inspect_with :car_type, :trim_badging
10
+
11
+ # @!method car_type
12
+ # The model of the vehicle, such as "model3" or "modely"
13
+ # @api public
14
+ # @return [String, nil] the model of the vehicle
15
+ # @example
16
+ # vehicle_config.car_type
17
+ attribute :car_type
18
+
19
+ # @!method trim_badging
20
+ # The trim of the vehicle, such as "p90d"
21
+ # @api public
22
+ # @return [String, nil] the trim of the vehicle
23
+ # @example
24
+ # vehicle_config.trim_badging
25
+ attribute :trim_badging
26
+
27
+ # @!method exterior_color
28
+ # The color of the paint
29
+ # @api public
30
+ # @return [String, nil] the color of the paint
31
+ # @example
32
+ # vehicle_config.exterior_color
33
+ attribute :exterior_color
34
+
35
+ # @!method wheel_type
36
+ # The wheels the vehicle was built with
37
+ # @api public
38
+ # @return [String, nil] the wheels the vehicle was built with
39
+ # @example
40
+ # vehicle_config.wheel_type
41
+ attribute :wheel_type
42
+
43
+ # @!method charge_port_type
44
+ # The type of the charge port, such as "US" or "CCS"
45
+ # @api public
46
+ # @return [String, nil] the type of the charge port
47
+ # @example
48
+ # vehicle_config.charge_port_type
49
+ attribute :charge_port_type
50
+
51
+ # @!method sun_roof_installed
52
+ # The sunroof the vehicle was built with, or zero for none
53
+ # @api public
54
+ # @return [Integer, nil] the sunroof the vehicle was built with
55
+ # @example
56
+ # vehicle_config.sun_roof_installed
57
+ attribute :sun_roof_installed
58
+
59
+ # @!method can_actuate_trunks?
60
+ # Whether the trunks of the vehicle can be opened remotely
61
+ # @api public
62
+ # @return [Boolean] whether the trunks of the vehicle can be opened remotely
63
+ # @example
64
+ # vehicle_config.can_actuate_trunks?
65
+ predicate :can_actuate_trunks
66
+
67
+ # @!method power_liftgate?
68
+ # Whether the vehicle has a powered liftgate
69
+ #
70
+ # A powered liftgate can be closed as well as opened remotely.
71
+ #
72
+ # @api public
73
+ # @return [Boolean] whether the vehicle has a powered liftgate
74
+ # @example
75
+ # vehicle_config.power_liftgate?
76
+ predicate :power_liftgate, :plg
77
+
78
+ # @!method right_hand_drive?
79
+ # Whether the vehicle is right-hand drive
80
+ # @api public
81
+ # @return [Boolean] whether the vehicle is right-hand drive
82
+ # @example
83
+ # vehicle_config.right_hand_drive?
84
+ predicate :right_hand_drive, :rhd
85
+
86
+ # @!method timestamp
87
+ # The time the vehicle reported the state
88
+ # @api public
89
+ # @return [Time, nil] the time the vehicle reported the state
90
+ # @raise [InvalidResponse] if the timestamp is not a number of milliseconds
91
+ # @example
92
+ # vehicle_config.timestamp
93
+ time_attribute :timestamp
94
+ end
95
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "charge_state"
4
+ require_relative "climate_state"
5
+ require_relative "drive_state"
6
+ require_relative "gui_settings"
7
+ require_relative "vehicle"
8
+ require_relative "vehicle_config"
9
+ require_relative "vehicle_state"
10
+
11
+ module Tesla
12
+ # A vehicle and the state of its subsystems
13
+ #
14
+ # The Fleet API answers with the states it was asked for, so the reader of one it was not asked for answers nil
15
+ # (see {API::VehicleEndpoints#vehicle_data}).
16
+ #
17
+ # @api public
18
+ class VehicleData < Vehicle
19
+ # @!method charge_state
20
+ # The state of the battery and the charging
21
+ # @api public
22
+ # @return [ChargeState, nil] the state of the battery and the charging
23
+ # @example
24
+ # vehicle_data.charge_state.battery_level
25
+ resource_attribute :charge_state, ChargeState
26
+
27
+ # @!method climate_state
28
+ # The state of the climate control
29
+ # @api public
30
+ # @return [ClimateState, nil] the state of the climate control
31
+ # @example
32
+ # vehicle_data.climate_state.inside_temp
33
+ resource_attribute :climate_state, ClimateState
34
+
35
+ # @!method drive_state
36
+ # The position and the driving state
37
+ # @api public
38
+ # @return [DriveState, nil] the position and the driving state
39
+ # @example
40
+ # vehicle_data.drive_state.shift_state
41
+ resource_attribute :drive_state, DriveState
42
+
43
+ # @!method gui_settings
44
+ # The units and formats the vehicle displays
45
+ # @api public
46
+ # @return [GUISettings, nil] the units and formats the vehicle displays
47
+ # @example
48
+ # vehicle_data.gui_settings.temperature_units
49
+ resource_attribute :gui_settings, GUISettings
50
+
51
+ # @!method vehicle_config
52
+ # The configuration the vehicle was built with
53
+ # @api public
54
+ # @return [VehicleConfig, nil] the configuration the vehicle was built with
55
+ # @example
56
+ # vehicle_data.vehicle_config.car_type
57
+ resource_attribute :vehicle_config, VehicleConfig
58
+
59
+ # @!method vehicle_state
60
+ # The physical state of the vehicle
61
+ # @api public
62
+ # @return [VehicleState, nil] the physical state of the vehicle
63
+ # @example
64
+ # vehicle_data.vehicle_state.locked?
65
+ resource_attribute :vehicle_state, VehicleState
66
+ end
67
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "resource"
4
+
5
+ module Tesla
6
+ # The physical state of a vehicle, such as whether it is locked
7
+ # @api public
8
+ class VehicleState < Resource
9
+ inspect_with :car_version, :odometer
10
+
11
+ # @!method car_version
12
+ # The version of the software the vehicle runs
13
+ # @api public
14
+ # @return [String, nil] the version of the software the vehicle runs
15
+ # @example
16
+ # vehicle_state.car_version
17
+ attribute :car_version
18
+
19
+ # @!method odometer
20
+ # The odometer in miles, whatever unit the vehicle displays
21
+ # @api public
22
+ # @return [Float, nil] the odometer
23
+ # @example
24
+ # vehicle_state.odometer
25
+ attribute :odometer
26
+
27
+ # @!method vehicle_name
28
+ # The name the owner gave the vehicle
29
+ # @api public
30
+ # @return [String, nil] the name the owner gave the vehicle
31
+ # @example
32
+ # vehicle_state.vehicle_name
33
+ attribute :vehicle_name
34
+
35
+ # @!method sun_roof_state
36
+ # The state of the sunroof, such as "closed" or "vent"
37
+ # @api public
38
+ # @return [String, nil] the state of the sunroof
39
+ # @example
40
+ # vehicle_state.sun_roof_state
41
+ attribute :sun_roof_state
42
+
43
+ # @!method locked?
44
+ # Whether the vehicle is locked
45
+ # @api public
46
+ # @return [Boolean] whether the vehicle is locked
47
+ # @example
48
+ # vehicle_state.locked?
49
+ predicate :locked
50
+
51
+ # @!method sentry_mode?
52
+ # Whether Sentry Mode is on
53
+ # @api public
54
+ # @return [Boolean] whether Sentry Mode is on
55
+ # @example
56
+ # vehicle_state.sentry_mode?
57
+ predicate :sentry_mode
58
+
59
+ # @!method valet_mode?
60
+ # Whether Valet Mode is on
61
+ # @api public
62
+ # @return [Boolean] whether Valet Mode is on
63
+ # @example
64
+ # vehicle_state.valet_mode?
65
+ predicate :valet_mode
66
+
67
+ # @!method user_present?
68
+ # Whether someone is in the vehicle
69
+ # @api public
70
+ # @return [Boolean] whether someone is in the vehicle
71
+ # @example
72
+ # vehicle_state.user_present?
73
+ predicate :user_present, :is_user_present
74
+
75
+ # @!method remote_start?
76
+ # Whether the vehicle has been started remotely
77
+ # @api public
78
+ # @return [Boolean] whether the vehicle has been started remotely
79
+ # @example
80
+ # vehicle_state.remote_start?
81
+ predicate :remote_start
82
+
83
+ # @!method timestamp
84
+ # The time the vehicle reported the state
85
+ # @api public
86
+ # @return [Time, nil] the time the vehicle reported the state
87
+ # @raise [InvalidResponse] if the timestamp is not a number of milliseconds
88
+ # @example
89
+ # vehicle_state.timestamp
90
+ time_attribute :timestamp
91
+
92
+ # Whether the front trunk is open
93
+ #
94
+ # @api public
95
+ # @return [Boolean] whether the front trunk is open
96
+ # @example
97
+ # vehicle_state.frunk_open?
98
+ def frunk_open?
99
+ open?(self[:ft])
100
+ end
101
+
102
+ # Whether the rear trunk is open
103
+ #
104
+ # @api public
105
+ # @return [Boolean] whether the rear trunk is open
106
+ # @example
107
+ # vehicle_state.trunk_open?
108
+ def trunk_open?
109
+ open?(self[:rt])
110
+ end
111
+
112
+ private
113
+
114
+ # Whether a closure is open
115
+ #
116
+ # The Fleet API writes an open closure as a number other than zero.
117
+ #
118
+ # @api private
119
+ # @param value [Integer, nil] the state of the closure
120
+ # @return [Boolean] whether the closure is open, which one the response does not carry is not
121
+ def open?(value)
122
+ !(value.nil? || value.zero?)
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tesla
4
+ # The current version of the Tesla gem
5
+ VERSION = "0.1.0"
6
+ end
data/lib/tesla.rb CHANGED
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require_relative "tesla/client"
5
+ require_relative "tesla/configuration"
6
+ require_relative "tesla/version"
7
+
8
+ # A Ruby wrapper for the Tesla Fleet API
9
+ #
10
+ # Every public method of {API} is a method of this module too, delegated to {.client}: {API::VehicleEndpoints#vehicles}
11
+ # is `Tesla.vehicles`, {API::ClosureEndpoints#actuate_trunk} is `Tesla.actuate_trunk`, and so on for every endpoint.
12
+ # They are delegated as the module is loaded rather than written out, so they are not listed among the methods
13
+ # below; {API} groups them into one mixin per topic, and each is documented there.
14
+ #
15
+ # The raw request methods, {Client#get} and the rest, are on the client rather than on this module, since a request
16
+ # of your own is made with {.client}.
17
+ #
18
+ # @api public
19
+ # @see API The endpoints, grouped into one mixin per topic
20
+ module Tesla
21
+ extend Configuration
22
+ extend SingleForwardable
23
+
24
+ # The mutex that guards the client the API methods of the module delegate to
25
+ CLIENT_MUTEX = Mutex.new
26
+ private_constant :CLIENT_MUTEX
27
+
28
+ # The settings of the global configuration a client is built from, and built again for when one of them changes
29
+ CLIENT_SETTINGS = %i[host access_token refresh_token client_id client_secret].freeze
30
+ private_constant :CLIENT_SETTINGS
31
+
32
+ # The settings of the global configuration that are applied to the client the module has, rather than building
33
+ # another one from them
34
+ APPLIED_SETTINGS = %i[redirect_uri audience authorization_endpoint token_endpoint on_token_refresh user_agent
35
+ open_timeout read_timeout write_timeout keep_alive_timeout debug_output proxy_url ca_file max_redirects
36
+ max_retries max_retry_delay].freeze
37
+ private_constant :APPLIED_SETTINGS
38
+
39
+ # @!method self.new(**options)
40
+ # Alias for Tesla::Client.new
41
+ # @api public
42
+ # @param options [Hash] options passed to {Tesla::Client#initialize}
43
+ # @yield [client] the client, which is closed once the block is done with it (see {Tesla::Client.new})
44
+ # @return [Tesla::Client, Object] a new client, or what the block returned
45
+ # @example Create a client
46
+ # Tesla.new(access_token: "eyJhbGciOiJSUzI1NiIs")
47
+ # @example Close the connections of a client once a block is done with it
48
+ # Tesla.new { |client| client.vehicles }
49
+ def_delegator "Tesla::Client", :new
50
+
51
+ # The endpoints of {API}, each delegated to the client the module has. They are read from the module as it is
52
+ # loaded rather than written out one by one, so YARD has none of them to document here; {API} documents each of
53
+ # them in the mixin it belongs to.
54
+ def_delegators :client, *API.public_instance_methods
55
+
56
+ # The methods of SingleForwardable, which the module delegates with rather than offers, so that `Tesla.delegate`
57
+ # and the rest are not mistaken for methods of the API
58
+ private_class_method(*SingleForwardable.instance_methods)
59
+
60
+ # The client the API methods of the module delegate to
61
+ #
62
+ # The client is built from the global configuration, and a change to that configuration is applied to the client
63
+ # it has rather than building another one, which would throw away what the client learned: the tokens it was
64
+ # answered with when it refreshed its access token, of which the refresh token is the only one that still works.
65
+ #
66
+ # Another client is built only for the host and the credentials that tokens are issued for, since a client that
67
+ # was given other ones has nothing to keep from the ones it had.
68
+ #
69
+ # @api public
70
+ # @return [Client] the client
71
+ # @example Perform a raw request with the module's client
72
+ # Tesla.client.get("/api/1/vehicles")
73
+ def self.client
74
+ CLIENT_MUTEX.synchronize do
75
+ rebuild_client unless values_of(CLIENT_SETTINGS).eql?(@client_values)
76
+ apply_settings unless values_of(APPLIED_SETTINGS).eql?(@applied_values)
77
+ @client
78
+ end
79
+ end
80
+
81
+ # Reset the global configuration and forget the client
82
+ #
83
+ # The client is forgotten as well as the configuration it was built from, so that what it learned from
84
+ # credentials that have been reset, such as the tokens it refreshed, is not kept. Its connections are closed,
85
+ # since no request of the module will be sent on them again.
86
+ #
87
+ # The configuration is reset while the client is forgotten rather than afterwards, so that a thread asking for the
88
+ # client is given one built from the configuration as it was or as it has been reset, rather than one built from a
89
+ # configuration that is half of each.
90
+ #
91
+ # @api public
92
+ # @return [self]
93
+ # @example Reset the configuration
94
+ # Tesla.reset
95
+ def self.reset
96
+ CLIENT_MUTEX.synchronize do
97
+ @client&.close
98
+ @client_values = nil
99
+ super
100
+ end
101
+ end
102
+
103
+ # Build the client again from the global configuration
104
+ #
105
+ # The client is built from the whole of the configuration, so the settings that are applied to a client are the
106
+ # ones it already has. The client being replaced is closed once the new one has been built, since no request of
107
+ # the module will be sent on its connections again, and so that a configuration a client cannot be built from
108
+ # leaves the client the module has open rather than closing it on the way to raising.
109
+ #
110
+ # @api private
111
+ # @return [Array<Object>] the settings the client was built from
112
+ def self.rebuild_client
113
+ client = new
114
+ @client&.close
115
+ @client = client
116
+ @client_values = values_of(CLIENT_SETTINGS)
117
+ end
118
+ private_class_method :rebuild_client
119
+
120
+ # The values of settings of the global configuration
121
+ #
122
+ # @api private
123
+ # @param settings [Array<Symbol>] the names of the settings
124
+ # @return [Array<Object>] the values
125
+ def self.values_of(settings)
126
+ settings.map { |setting| public_send(setting) }
127
+ end
128
+ private_class_method :values_of
129
+
130
+ # Apply the rest of the global configuration to the client the module has
131
+ #
132
+ # @api private
133
+ # @return [Array<Object>] the configuration applied to the client
134
+ def self.apply_settings
135
+ APPLIED_SETTINGS.each { |setting| @client.public_send(:"#{setting}=", public_send(setting)) }
136
+ @applied_values = values_of(APPLIED_SETTINGS)
137
+ end
138
+ private_class_method :apply_settings
139
+ end
data/sig/manifest.yaml ADDED
@@ -0,0 +1,10 @@
1
+ # The standard libraries the signatures of tesla refer to, which rbs collection loads for code that depends on it
2
+ dependencies:
3
+ - name: forwardable
4
+ - name: json
5
+ - name: net-http
6
+ - name: openssl
7
+ - name: time
8
+ - name: timeout
9
+ - name: uri
10
+ - name: zlib