forked from jsgoecke/tesla
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommands.go
333 lines (291 loc) · 10.9 KB
/
commands.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
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
270
271
272
273
274
275
276
277
278
279
280
281
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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
package tesla
import (
"encoding/json"
"errors"
"strconv"
)
// CommandResponse represents a response from the Tesla API after POSTing a command
type CommandResponse struct {
Response struct {
Reason string `json:"reason"`
Result bool `json:"result"`
} `json:"response"`
}
// AutoParkRequest represents parameters to POST an Autopark/Summon request
type AutoParkRequest struct {
VehicleID int `json:"vehicle_id,omitempty"`
Lat float64 `json:"lat"`
Lon float64 `json:"lon"`
Action string `json:"action,omitempty"`
}
// AutoparkAbort aborts an autopark request
func (v Vehicle) AutoparkAbort() error {
return v.autoPark("abort")
}
// AutoparkForward commands the vehicle to pull forward
func (v Vehicle) AutoparkForward() error {
return v.autoPark("start_forward")
}
// AutoparkReverse commands the vehicle to go in reverse
func (v Vehicle) AutoparkReverse() error {
return v.autoPark("start_reverse")
}
// autoPark performs the auto park/summon request for the vehicle
func (v Vehicle) autoPark(action string) error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/autopark_request"
driveState, _ := v.DriveState()
autoParkRequest := &AutoParkRequest{
VehicleID: v.VehicleID,
Lat: driveState.Latitude,
Lon: driveState.Longitude,
Action: action,
}
body, _ := json.Marshal(autoParkRequest)
_, err := sendCommand(apiURL, body)
return err
}
// TBD based on Github issue #7
// Toggles defrost on and off, locations values are 'front' or 'rear'
// func (v Vehicle) Defrost(location string, state bool) error {
// command := location + "_defrost_"
// if state {
// command += "on"
// } else {
// command += "off"
// }
// apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/" + command
// fmt.Println(apiURL)
// _, err := sendCommand(apiURL, nil)
// return err
// }
// TriggerHomelink opens and closes the configured Homelink garage door of the vehicle
// This is a toggle and the garage door state is unknown
func (v Vehicle) TriggerHomelink() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/trigger_homelink"
driveState, _ := v.DriveState()
autoParkRequest := &AutoParkRequest{
Lat: driveState.Latitude,
Lon: driveState.Longitude,
}
body, _ := json.Marshal(autoParkRequest)
_, err := sendCommand(apiURL, body)
return err
}
// Wakeup wakes up the vehicle when it is powered off
func (v Vehicle) Wakeup() (*Vehicle, error) {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/wake_up"
body, err := sendCommand(apiURL, nil)
if err != nil {
return nil, err
}
vehicleResponse := &VehicleResponse{}
err = json.Unmarshal(body, vehicleResponse)
if err != nil {
return nil, err
}
return vehicleResponse.Response, nil
}
// OpenChargePort opens the vehicle's charge port
func (v Vehicle) OpenChargePort() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/charge_port_door_open"
_, err := sendCommand(apiURL, nil)
return err
}
// CloseChargePort closes the vehicle's charge port
func (v Vehicle) CloseChargePort() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/charge_port_door_close"
_, err := sendCommand(apiURL, nil)
return err
}
// ResetValetPIN resets the valet mode PIN, if set
func (v Vehicle) ResetValetPIN() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/reset_valet_pin"
_, err := sendCommand(apiURL, nil)
return err
}
// SetChargeLimitStandard sets the charge limit to the default setting
func (v Vehicle) SetChargeLimitStandard() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/charge_standard"
_, err := sendCommand(apiURL, nil)
return err
}
// SetChargeLimitMax sets the charge limit to the maximum value
func (v Vehicle) SetChargeLimitMax() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/charge_max_range"
_, err := sendCommand(apiURL, nil)
return err
}
// SetChargeLimit sets the charge limit to a supplied percent value
func (v Vehicle) SetChargeLimit(percent int) error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/set_charge_limit"
postJSON := `{"percent": ` + strconv.Itoa(percent) + `}`
_, err := ActiveClient.post(apiURL, []byte(postJSON))
return err
}
// StartCharging starts the charging of the vehicle if charging cable is inserted
func (v Vehicle) StartCharging() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/charge_start"
_, err := sendCommand(apiURL, nil)
return err
}
// StopCharging stops a vehicle's charge session
func (v Vehicle) StopCharging() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/charge_stop"
_, err := sendCommand(apiURL, nil)
return err
}
// FlashLights flashes the lights of the vehicle
func (v Vehicle) FlashLights() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/flash_lights"
_, err := sendCommand(apiURL, nil)
return err
}
// HonkHorn honks the vehicle's horn
func (v *Vehicle) HonkHorn() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/honk_horn"
_, err := sendCommand(apiURL, nil)
return err
}
// UnlockDoors unlocks the vehicle's doors
func (v Vehicle) UnlockDoors() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/door_unlock"
_, err := sendCommand(apiURL, nil)
return err
}
// LockDoors locks the vehicle's doors
func (v Vehicle) LockDoors() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/door_lock"
_, err := sendCommand(apiURL, nil)
return err
}
// SetTemperature sets the temperature of the vehicle
// Driver and passenger zones are controlled individually
func (v Vehicle) SetTemperature(driver float64, passenger float64) error {
driveTemp := strconv.FormatFloat(driver, 'f', -1, 32)
passengerTemp := strconv.FormatFloat(passenger, 'f', -1, 32)
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/set_temps"
postJSON := `{"driver_temp": "` + driveTemp + `", "passenger_temp":` + passengerTemp + `}`
_, err := ActiveClient.post(apiURL, []byte(postJSON))
return err
}
// StartAirConditioning starts the vehicle's air conditioner
func (v Vehicle) StartAirConditioning() error {
url := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/auto_conditioning_start"
_, err := sendCommand(url, nil)
return err
}
// StopAirConditioning stops the vehicle's air conditioner
func (v Vehicle) StopAirConditioning() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/auto_conditioning_stop"
_, err := sendCommand(apiURL, nil)
return err
}
// MovePanoRoof controls the state of the panoramic roof. The approximate percent open
// values for each state are open = 100%, close = 0%, comfort = 80%, vent = %15, move = set %
func (v Vehicle) MovePanoRoof(state string, percent int) error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/sun_roof_control"
postJSON := `{"state": "` + state + `", "percent":` + strconv.Itoa(percent) + `}`
_, err := ActiveClient.post(apiURL, []byte(postJSON))
return err
}
// Start starts the car by turning it on. Requires the Tesla account password
func (v Vehicle) Start(password string) error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/remote_start_drive?password=" + password
_, err := sendCommand(apiURL, nil)
return err
}
// OpenTrunk opens the trunk. Valid trunk values are 'front' and 'rear'
func (v Vehicle) OpenTrunk(trunk string) error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/trunk_open" // ?which_trunk=" + trunk
postJSON := `{"which_trunk": "` + trunk + `"}`
_, err := ActiveClient.post(apiURL, []byte(postJSON))
return err
}
// VentWindows vents the vehicle's windows
func (v Vehicle) VentWindows() error {
return v.windows("vent")
}
// CloseWindows closes the vehicle's windows (model 3 only?)
func (v Vehicle) CloseWindows() error {
return v.windows("close")
}
// windows vents or closes the windows
func (v Vehicle) windows(action string) error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/window_control"
windowRequest := struct {
VehicleID string `json:"command"`
Lat int `json:"lat"`
Lon int `json:"lon"`
}{
action, 0, 0,
}
body, _ := json.Marshal(windowRequest)
_, err := sendCommand(apiURL, body)
return err
}
// SetSentryMode controls Sentry Mode's active state (true/false)
func (v Vehicle) SetSentryMode(on bool) error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/set_sentry_mode"
postJSON := `{"on": "` + strconv.FormatBool(on) + `"}`
_, err := sendCommand(apiURL, []byte(postJSON))
return err
}
// HeatSeat sets heating for the supplied seat number (0=driver, 1=passenger, 2=rear-left...)
func (v Vehicle) HeatSeat(seat, level int) error {
//requires climate to be set first
err := v.StartAirConditioning()
if err != nil {
panic(err)
}
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/remote_seat_heater_request"
seatRequest := struct {
Heater int `json:"heater"`
Level int `json:"level"`
}{
seat, level,
}
body, _ := json.Marshal(seatRequest)
_, err = sendCommand(apiURL, body)
return err
}
// HeatWheel turns steering wheel heat on or off
func (v Vehicle) HeatWheel(on bool) error {
//requires climate to be set first
err := v.StartAirConditioning()
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/remote_steering_wheel_heater_request"
postJSON := `{"on": "` + strconv.FormatBool(on) + `"}`
_, err = sendCommand(apiURL, []byte(postJSON))
return err
}
// ScheduleSoftwareUpdate schedules the installation of the available software update.
// An update must already be available for this command to work
func (v Vehicle) ScheduleSoftwareUpdate(offset int64) error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/schedule_software_update"
theJSON := `{"offset_sec": ` + strconv.FormatInt(offset, 10) + `}`
_, err := ActiveClient.post(apiURL, []byte(theJSON))
return err
}
// CancelSoftwareUpdate cancels a previously-scheduled software update that has not yet started
func (v Vehicle) CancelSoftwareUpdate() error {
apiURL := BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/command/cancel_software_update"
_, err := sendCommand(apiURL, nil)
return err
}
// sendCommand sends a command to the vehicle
func sendCommand(url string, reqBody []byte) ([]byte, error) {
body, err := ActiveClient.post(url, reqBody)
if err != nil {
return nil, err
}
if len(body) > 0 {
response := &CommandResponse{}
err = json.Unmarshal(body, response)
if err != nil {
return nil, err
}
if response.Response.Result != true && response.Response.Reason != "" {
return nil, errors.New(response.Response.Reason)
}
}
return body, nil
}