tesla-api 0.0.1
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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +40 -0
- data/Rakefile +10 -0
- data/fixtures/vcr_cassettes/charge_state.yml +134 -0
- data/fixtures/vcr_cassettes/climate_state.yml +134 -0
- data/fixtures/vcr_cassettes/connection.yml +91 -0
- data/fixtures/vcr_cassettes/drive_state.yml +134 -0
- data/fixtures/vcr_cassettes/gui_settings.yml +134 -0
- data/fixtures/vcr_cassettes/vehicle.yml +91 -0
- data/fixtures/vcr_cassettes/vehicle_state.yml +134 -0
- data/lib/tesla-api.rb +16 -0
- data/lib/tesla-api/charge_state.rb +87 -0
- data/lib/tesla-api/climate_state.rb +55 -0
- data/lib/tesla-api/connection.rb +58 -0
- data/lib/tesla-api/data.rb +52 -0
- data/lib/tesla-api/drive_state.rb +37 -0
- data/lib/tesla-api/errors.rb +41 -0
- data/lib/tesla-api/gui_settings.rb +34 -0
- data/lib/tesla-api/private_api.rb +157 -0
- data/lib/tesla-api/tesla_api.rb +4 -0
- data/lib/tesla-api/vehicle.rb +257 -0
- data/lib/tesla-api/vehicle_state.rb +92 -0
- data/lib/tesla-api/version.rb +4 -0
- data/tesla-api.gemspec +23 -0
- data/test/helper.rb +10 -0
- data/test/test_charge_state.rb +72 -0
- data/test/test_climate_state.rb +52 -0
- data/test/test_connection.rb +32 -0
- data/test/test_drive_state.rb +36 -0
- data/test/test_gui_settings.rb +36 -0
- data/test/test_vehicle.rb +32 -0
- data/test/test_vehicle_state.rb +80 -0
- metadata +135 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
module TeslaAPI
|
2
|
+
# Defines a Model S vehicle returned from the API
|
3
|
+
class Vehicle < Data
|
4
|
+
# An array of Tesla defined option codes
|
5
|
+
attr_reader :option_codes
|
6
|
+
|
7
|
+
##
|
8
|
+
# :method: color
|
9
|
+
# Should be car color but is always nil
|
10
|
+
|
11
|
+
##
|
12
|
+
# :method: display_name
|
13
|
+
# Only observed as nil
|
14
|
+
|
15
|
+
##
|
16
|
+
# :method: id
|
17
|
+
# Vehicle ID used in other API calls
|
18
|
+
|
19
|
+
##
|
20
|
+
# :method: user_id
|
21
|
+
# Logged in user ID
|
22
|
+
|
23
|
+
##
|
24
|
+
# :method: vehicle_id
|
25
|
+
# Vehicle ID used in streaming API
|
26
|
+
|
27
|
+
##
|
28
|
+
# :method: vin
|
29
|
+
# Vehicle Identification Number
|
30
|
+
|
31
|
+
##
|
32
|
+
# :method: tokens
|
33
|
+
# API tokens (first is used for streaming API)
|
34
|
+
|
35
|
+
##
|
36
|
+
# :method: online_state
|
37
|
+
# "online" if currently online with API (streaming?)
|
38
|
+
|
39
|
+
##
|
40
|
+
# :method: option_codes
|
41
|
+
# Array of option codes defining how the vehicle is configured
|
42
|
+
|
43
|
+
def initialize(tesla, data) # :nodoc:
|
44
|
+
@tesla = tesla
|
45
|
+
|
46
|
+
ivar_from_data("color", "color", data)
|
47
|
+
ivar_from_data("display_name", "display_name", data)
|
48
|
+
ivar_from_data("id", "id", data)
|
49
|
+
ivar_from_data("user_id", "user_id", data)
|
50
|
+
ivar_from_data("vehicle_id", "vehicle_id", data)
|
51
|
+
ivar_from_data("vin", "vin", data)
|
52
|
+
ivar_from_data("tokens", "tokens", data)
|
53
|
+
ivar_from_data("online_state", "state", data)
|
54
|
+
|
55
|
+
@option_codes = data["option_codes"].split(",")
|
56
|
+
end
|
57
|
+
|
58
|
+
# true if the vehicle allows mobile access
|
59
|
+
def mobile_access?
|
60
|
+
tesla.api_mobile_access?(self)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the option codes as human readable string
|
64
|
+
def option_code_descriptions
|
65
|
+
option_codes.map { |code| codes_to_description.fetch(code, code) }.join(", ")
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns the streaming data interface
|
69
|
+
def stream
|
70
|
+
tesla.stream(self)
|
71
|
+
end
|
72
|
+
|
73
|
+
#################################
|
74
|
+
#
|
75
|
+
# Commands
|
76
|
+
#
|
77
|
+
#################################
|
78
|
+
|
79
|
+
# Wakes up the streaming API
|
80
|
+
def wake_up!
|
81
|
+
tesla.wake_up!(self)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Opens the charging port
|
85
|
+
def open_charge_port!
|
86
|
+
tesla.open_charge_port!(self)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Turns on the temperature conditioning
|
90
|
+
def auto_conditioning_start!
|
91
|
+
tesla.auto_conditioning_start!(self)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Turns off the temperature conditioning
|
95
|
+
def auto_conditioning_stop!
|
96
|
+
tesla.auto_conditioning_stop!(self)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Sets the temperature for both the driver and passenger
|
100
|
+
def set_temperature!(driver_degrees_celcius, passenger_degrees_celcius)
|
101
|
+
tesla.set_temperature!(self, driver_degrees_celcius, passenger_degrees_celcius)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Opens the panoramic roof
|
105
|
+
#
|
106
|
+
# state may be "open", "close", "comfort", or "vent"
|
107
|
+
def open_roof!(state)
|
108
|
+
tesla.open_roof!(self, state)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Locks the vehicle doors
|
112
|
+
def lock_door!
|
113
|
+
tesla.lock_door!(self)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Unlocks the vehicle doors
|
117
|
+
def unlock_door!
|
118
|
+
tesla.unlock_door!(self)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Honks the vehicles horn
|
122
|
+
def honk_horn!
|
123
|
+
tesla.honk_horn!(self)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Flashes the vehicle lights
|
127
|
+
def flash_lights!
|
128
|
+
tesla.flash_lights!(self)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Stops the vehicle charging
|
132
|
+
def charge_stop!
|
133
|
+
tesla.charge_stop!(self)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Starts the vehicle charging
|
137
|
+
def charge_start!
|
138
|
+
tesla.charge_start!(self)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Charge the vehicle for maximum range
|
142
|
+
def charge_max_range!
|
143
|
+
tesla.charge_max_range!(self)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Charge the vehicle to standard range
|
147
|
+
def charge_standard!
|
148
|
+
tesla.charge_standard!(self)
|
149
|
+
end
|
150
|
+
|
151
|
+
#################################
|
152
|
+
#
|
153
|
+
# Queries
|
154
|
+
#
|
155
|
+
#################################
|
156
|
+
|
157
|
+
# Returns the vehicles charge state
|
158
|
+
def charge_state
|
159
|
+
@charge_state ||= tesla.api_charge_state_for_vehicle(self)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns the vehicle climate state
|
163
|
+
def climate_state
|
164
|
+
@climate_state || tesla.api_climate_state_for_vehicle(self)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns the vehicle drive state
|
168
|
+
def drive_state
|
169
|
+
@drive_state ||= tesla.api_drive_state_for_vehicle(self)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns the vehicle gui settings
|
173
|
+
def gui_settings
|
174
|
+
@gui_settings ||= tesla.api_gui_settings_for_vehicle(self)
|
175
|
+
end
|
176
|
+
|
177
|
+
# Returns the vehicle state
|
178
|
+
def state
|
179
|
+
@state ||= tesla.api_get_vehicle_state_for_vehicle(self)
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
def tesla #:nodoc:
|
185
|
+
@tesla
|
186
|
+
end
|
187
|
+
|
188
|
+
def codes_to_description #:nodoc:
|
189
|
+
{
|
190
|
+
"MS01" => "base",
|
191
|
+
"RENA" => "region_us",
|
192
|
+
"RECA" => "region_canada",
|
193
|
+
"TM00" => "standard_trim",
|
194
|
+
"TM02" => "signature_trim",
|
195
|
+
"DRLH" => "left_hand_drive",
|
196
|
+
"DRRH" => "right_hand_drive",
|
197
|
+
"PF00" => "no_performance_model",
|
198
|
+
"PF01" => "performance_model",
|
199
|
+
"BT85" => "battery_85",
|
200
|
+
"BT60" => "battery_60",
|
201
|
+
"BT40" => "battery_40",
|
202
|
+
"PBSB" => "paint_black",
|
203
|
+
"PBSW" => "paint_solid_white",
|
204
|
+
"PMSS" => "paint_silver",
|
205
|
+
"PMTG" => "paint_dolphin_gray_metalic",
|
206
|
+
"PMAB" => "paint_metalic_brown",
|
207
|
+
"PMMB" => "paint_metalic_blue",
|
208
|
+
"PSW" => "paint_pearl_white",
|
209
|
+
"PSR" => "paint_signature_red",
|
210
|
+
"RFBC" => "roof_body_color",
|
211
|
+
"RFPO" => "roof_panorama",
|
212
|
+
"WT19" => "wheel_silver_19",
|
213
|
+
"WT21" => "wheel_silver_21",
|
214
|
+
"WTSP" => "wheel_gray_21",
|
215
|
+
"IBSB" => "seats_base_textile",
|
216
|
+
"IZMB" => "seats_black_leather",
|
217
|
+
"IZMG" => "seats_gray_leather",
|
218
|
+
"IPMB" => "seats_performance_black_leather",
|
219
|
+
"IDPB" => "interior_piano_black",
|
220
|
+
"IDLW" => "interior_lacewood",
|
221
|
+
"IDOM" => "interior_obeche_wood_matte",
|
222
|
+
"IDCF" => "interior_carbon_fiber",
|
223
|
+
"IPMG" => "interior_performance_leather",
|
224
|
+
"TR00" => "no_third_row_seating",
|
225
|
+
"TR01" => "third_row_seating",
|
226
|
+
"SU00" => "no_air_suspension",
|
227
|
+
"SU01" => "air_suspension",
|
228
|
+
"SC00" => "no_supercharger",
|
229
|
+
"SC01" => "supercharger",
|
230
|
+
"AU00" => "no_audio_upgrade",
|
231
|
+
"AU01" => "audio_upgrade",
|
232
|
+
"CH00" => "no_second_charger",
|
233
|
+
"CH01" => "second_charger",
|
234
|
+
"HP00" => "no_hpwc_ordered",
|
235
|
+
"HP01" => "hpwc_ordered",
|
236
|
+
"PA00" => "no_paint_armor",
|
237
|
+
"PA01" => "pait_armor",
|
238
|
+
"PS00" => "no_parcel_shelf",
|
239
|
+
"PS01" => "parcel_shelf",
|
240
|
+
"TP00" => "no_tech_package",
|
241
|
+
"TP01" => "tech_package",
|
242
|
+
"AD02" => "power_adapter_nema_14-50",
|
243
|
+
"X001" => "power_lift_gate",
|
244
|
+
"X003" => "navigation",
|
245
|
+
"X007" => "premium_exterior_lighting",
|
246
|
+
"X011" => "homelink",
|
247
|
+
"X013" => "satellite_radio",
|
248
|
+
"X014" => "standard_radio",
|
249
|
+
"X019" => "performance_exterior",
|
250
|
+
"X020" => "no_performance_exterior",
|
251
|
+
"X024" => "performance_powertrain",
|
252
|
+
"X025" => "no_performance_powertrain",
|
253
|
+
}
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module TeslaAPI
|
2
|
+
# Defines the current vehicle state
|
3
|
+
class VehicleState < Data
|
4
|
+
##
|
5
|
+
# :method: firmware_version
|
6
|
+
# Current firmware version
|
7
|
+
|
8
|
+
##
|
9
|
+
# :method: sun_roof_installed?
|
10
|
+
# true if the vehicle is configured with the panoramic sun roof
|
11
|
+
|
12
|
+
##
|
13
|
+
# :method: sun_roof_state
|
14
|
+
# Current state of the sun roof
|
15
|
+
# Potential values:
|
16
|
+
# unknown
|
17
|
+
# moving
|
18
|
+
|
19
|
+
##
|
20
|
+
# :method: sun_roof_percent_open
|
21
|
+
# Percentage the sun roof is open
|
22
|
+
|
23
|
+
##
|
24
|
+
# :method: driver_front_door_open?
|
25
|
+
# true if the driver's side front door is open
|
26
|
+
|
27
|
+
##
|
28
|
+
# :method: driver_rear_door_open?
|
29
|
+
# true if the driver's side rear door is open
|
30
|
+
|
31
|
+
##
|
32
|
+
# :method: passenger_front_door_open?
|
33
|
+
# true if the passenger's side front door is open
|
34
|
+
|
35
|
+
##
|
36
|
+
# :method: passenger_rear_door_open
|
37
|
+
# true if the passenger's side rear door is open
|
38
|
+
|
39
|
+
##
|
40
|
+
# :method: front_trunk_open?
|
41
|
+
# true if the front trunk (frunk) is open
|
42
|
+
|
43
|
+
##
|
44
|
+
# :method: rear_trunk_open?
|
45
|
+
# true if the rear trunk is open
|
46
|
+
|
47
|
+
##
|
48
|
+
# :method: locked?
|
49
|
+
# true if the doors are locked
|
50
|
+
|
51
|
+
##
|
52
|
+
# :method: dark_rims?
|
53
|
+
# true if configured with dark colored rims
|
54
|
+
|
55
|
+
##
|
56
|
+
# :method: spoiler?
|
57
|
+
# true if configured with a spoiler
|
58
|
+
|
59
|
+
##
|
60
|
+
# :method: nineteen_inch_wheels?
|
61
|
+
# true if configured with nineteen inch wheels
|
62
|
+
|
63
|
+
##
|
64
|
+
# :method: panoramic?
|
65
|
+
# true if configured with a panoramic roof
|
66
|
+
|
67
|
+
##
|
68
|
+
# :method: perf?
|
69
|
+
# true if a performance configured vehicle
|
70
|
+
|
71
|
+
def initialize(data) # :nodoc:
|
72
|
+
ivar_from_data("firmware_version", "car_version", data)
|
73
|
+
ivar_from_data("sun_roof_installed", "sun_roof_installed", data)
|
74
|
+
ivar_from_data("sun_roof_state", "sun_roof_state", data)
|
75
|
+
ivar_from_data("sun_roof_percent_open", "sun_roof_percent_open", data)
|
76
|
+
ivar_from_data("driver_front_door_open", "df", data)
|
77
|
+
ivar_from_data("driver_rear_door_open", "dr", data)
|
78
|
+
ivar_from_data("passenger_front_door_open", "pf", data)
|
79
|
+
ivar_from_data("passenger_rear_door_open", "pr", data)
|
80
|
+
ivar_from_data("front_trunk_open", "ft", data)
|
81
|
+
ivar_from_data("rear_trunk_open", "rt", data)
|
82
|
+
ivar_from_data("locked", "locked", data)
|
83
|
+
ivar_from_data("dark_rims", "dark_rims", data)
|
84
|
+
ivar_from_data("spoiler", "has_spoiler", data)
|
85
|
+
|
86
|
+
@nineteen_inch_wheels = data["wheel_type"] == "Base19"
|
87
|
+
@panoramic = data["roof_color"] == "None"
|
88
|
+
@perf = data["perf_config"] != "Base"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
data/tesla-api.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'tesla-api/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "tesla-api"
|
8
|
+
gem.version = TeslaAPI::VERSION
|
9
|
+
gem.authors = ["Gavin Stark"]
|
10
|
+
gem.email = ["gavin@gstark.com"]
|
11
|
+
gem.description = %q{Implements the Tesla Model S HTTP API}
|
12
|
+
gem.summary = %q{Implements the Tesla Model S HTTP API}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.add_dependency 'httpclient', "~> 2.3.2"
|
20
|
+
gem.add_development_dependency 'vcr', "~> 2.4.0"
|
21
|
+
gem.add_development_dependency 'webmock', "~> 1.9.1"
|
22
|
+
end
|
23
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class ChargeStateTest < Test::Unit::TestCase
|
4
|
+
USER = "user@example.com"
|
5
|
+
PASSWORD = "password"
|
6
|
+
RECORD_MODE = :new_episodes
|
7
|
+
|
8
|
+
def charge_state
|
9
|
+
@charge_state ||= begin
|
10
|
+
VCR.use_cassette('charge_state', :record => RECORD_MODE) do
|
11
|
+
TeslaAPI::Connection.new(USER, PASSWORD).vehicle.charge_state
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_charge_state
|
17
|
+
assert_equal "Disconnected", charge_state.charging_state
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_supercharging
|
21
|
+
assert !charge_state.supercharging?
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_charge_port_open
|
25
|
+
assert !charge_state.charge_port_open
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_charge_rate_miles_per_hour
|
29
|
+
assert_equal -1.0, charge_state.charge_rate_miles_per_hour
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_hours_to_full_charge
|
33
|
+
assert_equal nil, charge_state.hours_to_full_charge
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_charge_power
|
37
|
+
assert_equal 0, charge_state.charger_power
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_charger_actual_amperage
|
41
|
+
assert_equal 0, charge_state.charger_actual_amperage
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_charger_pilot_amperage
|
45
|
+
assert_equal 0, charge_state.charger_pilot_amperage
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_charger_voltage
|
49
|
+
assert_equal 0, charge_state.charger_voltage
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_battery_current_flow
|
53
|
+
assert_equal -0.2, charge_state.battery_current_flow
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_battery_percentage
|
57
|
+
assert_equal 70, charge_state.battery_percentage
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_estimated_battery_range_miles
|
61
|
+
assert_equal 143.96, charge_state.estimated_battry_range_miles
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_battery_range_miles
|
65
|
+
assert_equal 177.38, charge_state.battery_range_miles
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_charging_to_max
|
69
|
+
assert !charge_state.charging_to_max?
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|