From addd9c02cf92f4358f8f9f9373a86eb1cb8534aa Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 28 Apr 2023 16:07:18 +0200 Subject: [PATCH 1/5] Use vehicle_data api --- cmd/login/main.go | 3 +- commands.go | 12 ++--- states.go | 113 +++++----------------------------------------- states_test.go | 91 ++++++++++++++++++------------------- 4 files changed, 63 insertions(+), 156 deletions(-) diff --git a/cmd/login/main.go b/cmd/login/main.go index a55ffc7..cdc3010 100644 --- a/cmd/login/main.go +++ b/cmd/login/main.go @@ -7,7 +7,6 @@ import ( "flag" "fmt" "io" - "io/ioutil" "log" "os" "path/filepath" @@ -87,7 +86,7 @@ func getUsernameAndPassword() (string, string, error) { } func solveCaptcha(ctx context.Context, svg io.Reader) (string, error) { - tmpFile, err := ioutil.TempFile(os.TempDir(), "captcha-*.svg") + tmpFile, err := io.TempFile(os.TempDir(), "captcha-*.svg") if err != nil { return "", fmt.Errorf("cannot create temp file: %w", err) } diff --git a/commands.go b/commands.go index 2571b4b..14ee127 100644 --- a/commands.go +++ b/commands.go @@ -46,11 +46,11 @@ func (v *Vehicle) AutoparkReverse() error { // Performs the actual auto park/summon request for the vehicle func (v *Vehicle) autoPark(action string) error { apiURL := v.commandPath("autopark_request") - driveState, _ := v.DriveState() + data, _ := v.Data() autoParkRequest := &AutoParkRequest{ VehicleID: v.VehicleID, - Lat: driveState.Latitude, - Lon: driveState.Longitude, + Lat: data.Response.DriveState.Latitude, + Lon: data.Response.DriveState.Longitude, Action: action, } body, _ := json.Marshal(autoParkRequest) @@ -91,10 +91,10 @@ func (v *Vehicle) EnableSentry() error { // a major limitation of Homelink. func (v *Vehicle) TriggerHomelink() error { apiURL := v.commandPath("trigger_homelink") - driveState, _ := v.DriveState() + data, _ := v.Data() autoParkRequest := &AutoParkRequest{ - Lat: driveState.Latitude, - Lon: driveState.Longitude, + Lat: data.Response.DriveState.Latitude, + Lon: data.Response.DriveState.Longitude, } body, _ := json.Marshal(autoParkRequest) diff --git a/states.go b/states.go index 7ef39c1..aa7be0d 100644 --- a/states.go +++ b/states.go @@ -193,8 +193,8 @@ type ServiceData struct { ServiceStatus string `json:"service_status"` } -// StateRequest represents the request to get the states of the vehicle. -type StateRequest struct { +// VehicleData represents the states of the vehicle. +type VehicleData struct { Response struct { Timestamp timeMsec `json:"timestamp"` *ChargeState @@ -287,61 +287,7 @@ func (v *Vehicle) NearbyChargingSites() (*NearbyChargingSitesResponse, error) { return resp, nil } -// ChargeState returns the charge state of the vehicle. -func (v *Vehicle) ChargeState() (*ChargeState, error) { - stateRequest, err := v.c.fetchState("charge_state", v.ID) - if err != nil { - return nil, err - } - return stateRequest.Response.ChargeState, nil -} - -// ClimateState returns the climate state of the vehicle. -func (v Vehicle) ClimateState() (*ClimateState, error) { - stateRequest, err := v.c.fetchState("climate_state", v.ID) - if err != nil { - return nil, err - } - return stateRequest.Response.ClimateState, nil -} - -// DriveState returns the drive state of the vehicle. -func (v Vehicle) DriveState() (*DriveState, error) { - stateRequest, err := v.c.fetchState("drive_state", v.ID) - if err != nil { - return nil, err - } - return stateRequest.Response.DriveState, nil -} - -// GuiSettings returns the GUI settings of the vehicle. -func (v Vehicle) GuiSettings() (*GuiSettings, error) { - stateRequest, err := v.c.fetchState("gui_settings", v.ID) - if err != nil { - return nil, err - } - return stateRequest.Response.GuiSettings, nil -} - -// VehicleState returns the state of the vehicle. -func (v Vehicle) VehicleState() (*VehicleState, error) { - stateRequest, err := v.c.fetchState("vehicle_state", v.ID) - if err != nil { - return nil, err - } - return stateRequest.Response.VehicleState, nil -} - -// ServiceData returns the service data for the vehicle. -func (v Vehicle) ServiceData() (*ServiceData, error) { - stateRequest, err := v.c.fetchState("service_data", v.ID) - if err != nil { - return nil, err - } - return stateRequest.Response.ServiceData, nil -} - -func stateError(sr *StateRequest) error { +func stateError(sr *VehicleData) error { if sr.Error == "" { return nil } @@ -353,56 +299,19 @@ func stateError(sr *StateRequest) error { } // A utility function to fetch the appropriate state of the vehicle -func (c *Client) fetchState(resource string, id int64) (*StateRequest, error) { - stateRequest := &StateRequest{} - path := strings.Join([]string{c.baseURL, "vehicles", strconv.FormatInt(id, 10), "data_request", resource}, "/") - if err := c.getJSON(path, stateRequest); err != nil { +func (c *Client) fetchState(id int64) (*VehicleData, error) { + var res VehicleData + path := strings.Join([]string{c.baseURL, "vehicles", strconv.FormatInt(id, 10), "vehicle_data"}, "/") + if err := c.getJSON(path, &res); err != nil { return nil, err } - if err := stateError(stateRequest); err != nil { + if err := stateError(&res); err != nil { return nil, err } - return stateRequest, nil + return &res, nil } // Data : Get data of the vehicle (calling this will not permit the car to sleep) -func (v Vehicle) Data(vid int64) (*StateRequest, error) { - stateRequest := &StateRequest{} - - // climate_state - stateRequestClimate, err := v.c.fetchState("climate_state", v.ID) - if err != nil { - return nil, fmt.Errorf("getting climate_state failed: %w", err) - } - stateRequest.Response.ClimateState = stateRequestClimate.Response.ClimateState - - // drive_state - stateRequestGui, err := v.c.fetchState("drive_state", v.ID) - if err != nil { - return nil, fmt.Errorf("getting drive_state failed: %w", err) - } - stateRequest.Response.DriveState = stateRequestGui.Response.DriveState - - // gui_settings - stateRequestSettings, err := v.c.fetchState("gui_settings", v.ID) - if err != nil { - return nil, fmt.Errorf("getting gui_settings failed: %w", err) - } - stateRequest.Response.GuiSettings = stateRequestSettings.Response.GuiSettings - - // vehicle_state - stateRequestVehicle, err := v.c.fetchState("vehicle_state", v.ID) - if err != nil { - return nil, fmt.Errorf("getting vehicle_state failed: %w", err) - } - stateRequest.Response.VehicleState = stateRequestVehicle.Response.VehicleState - - // charge_state - stateRequestCharge, err := v.c.fetchState("charge_state", v.ID) - if err != nil { - return nil, fmt.Errorf("getting charge_state failed: %w", err) - } - stateRequest.Response.ChargeState = stateRequestCharge.Response.ChargeState - - return stateRequest, nil +func (v Vehicle) Data() (*VehicleData, error) { + return v.c.fetchState(v.ID) } diff --git a/states_test.go b/states_test.go index f785877..f69eb86 100644 --- a/states_test.go +++ b/states_test.go @@ -4,7 +4,6 @@ import ( "net/http" "net/http/httptest" "testing" - "time" . "github.com/smartystreets/goconvey/convey" ) @@ -37,61 +36,61 @@ func TestStatesSpec(t *testing.T) { So(status, ShouldBeTrue) }) - Convey("Should get charge state", t, func() { - status, err := vehicle.ChargeState() - So(err, ShouldBeNil) - So(status.BatteryLevel, ShouldEqual, 90) - So(status.ChargeRate, ShouldEqual, 0) - So(status.ChargingState, ShouldEqual, "Complete") - }) + // Convey("Should get charge state", t, func() { + // status, err := vehicle.ChargeState() + // So(err, ShouldBeNil) + // So(status.BatteryLevel, ShouldEqual, 90) + // So(status.ChargeRate, ShouldEqual, 0) + // So(status.ChargingState, ShouldEqual, "Complete") + // }) - Convey("Should get climate state", t, func() { - status, err := vehicle.ClimateState() - So(err, ShouldBeNil) - So(status.DriverTempSetting, ShouldEqual, 22.0) - So(status.PassengerTempSetting, ShouldEqual, 22.0) - So(status.IsRearDefrosterOn, ShouldBeFalse) - }) + // Convey("Should get climate state", t, func() { + // status, err := vehicle.ClimateState() + // So(err, ShouldBeNil) + // So(status.DriverTempSetting, ShouldEqual, 22.0) + // So(status.PassengerTempSetting, ShouldEqual, 22.0) + // So(status.IsRearDefrosterOn, ShouldBeFalse) + // }) - Convey("Should get drive state", t, func() { - status, err := vehicle.DriveState() - So(err, ShouldBeNil) - So(status.Latitude, ShouldEqual, 35.1) - So(status.Longitude, ShouldEqual, 20.2) - }) + // Convey("Should get drive state", t, func() { + // status, err := vehicle.DriveState() + // So(err, ShouldBeNil) + // So(status.Latitude, ShouldEqual, 35.1) + // So(status.Longitude, ShouldEqual, 20.2) + // }) - Convey("Should get GUI settings", t, func() { - status, err := vehicle.GuiSettings() - So(err, ShouldBeNil) - So(status.GuiDistanceUnits, ShouldEqual, "mi/hr") - So(status.GuiTemperatureUnits, ShouldEqual, "F") - }) + // Convey("Should get GUI settings", t, func() { + // status, err := vehicle.GuiSettings() + // So(err, ShouldBeNil) + // So(status.GuiDistanceUnits, ShouldEqual, "mi/hr") + // So(status.GuiTemperatureUnits, ShouldEqual, "F") + // }) - Convey("Should get Vehicle state", t, func() { - status, err := vehicle.VehicleState() - So(err, ShouldBeNil) - So(status.APIVersion, ShouldEqual, 3) - So(status.CalendarSupported, ShouldBeTrue) - So(status.RearTrunk, ShouldEqual, 0) - }) + // Convey("Should get Vehicle state", t, func() { + // status, err := vehicle.VehicleState() + // So(err, ShouldBeNil) + // So(status.APIVersion, ShouldEqual, 3) + // So(status.CalendarSupported, ShouldBeTrue) + // So(status.RearTrunk, ShouldEqual, 0) + // }) - Convey("Should get service data", t, func() { - status, err := vehicle.ServiceData() - So(err, ShouldBeNil) - So(status.ServiceStatus, ShouldEqual, "in_service") - wantTime, err := time.Parse(time.RFC3339, "2019-08-15T14:15:00+02:00") - if err != nil { - t.Fatal(err) - } - So(status.ServiceETC, ShouldEqual, wantTime) - }) + // Convey("Should get service data", t, func() { + // status, err := vehicle.ServiceData() + // So(err, ShouldBeNil) + // So(status.ServiceStatus, ShouldEqual, "in_service") + // wantTime, err := time.Parse(time.RFC3339, "2019-08-15T14:15:00+02:00") + // if err != nil { + // t.Fatal(err) + // } + // So(status.ServiceETC, ShouldEqual, wantTime) + // }) } func TestStatesSpecError(t *testing.T) { mux := new(http.ServeMux) mux.HandleFunc("/oauth/token", serveJSON("{\"access_token\": \"ghi789\"}")) mux.HandleFunc("/api/1/vehicles", serveJSON(VehiclesJSON)) - mux.HandleFunc("/api/1/vehicles/1234/", serveJSON(ErrorJSON)) + mux.HandleFunc("/api/1/vehicles/1234/vehicle_data", serveJSON(ErrorJSON)) ts := httptest.NewServer(mux) defer ts.Close() @@ -99,7 +98,7 @@ func TestStatesSpecError(t *testing.T) { Convey("Should get error", t, func() { vehicles, _ := client.Vehicles() vehicle := vehicles[0] - _, err := vehicle.VehicleState() + _, err := vehicle.Data() So(err, ShouldNotBeNil) }) } From d5388ca6bc204ff05dd376283bfd375245bdc5f7 Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 28 Apr 2023 16:10:24 +0200 Subject: [PATCH 2/5] wip --- cmd/login/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/login/main.go b/cmd/login/main.go index cdc3010..a55ffc7 100644 --- a/cmd/login/main.go +++ b/cmd/login/main.go @@ -7,6 +7,7 @@ import ( "flag" "fmt" "io" + "io/ioutil" "log" "os" "path/filepath" @@ -86,7 +87,7 @@ func getUsernameAndPassword() (string, string, error) { } func solveCaptcha(ctx context.Context, svg io.Reader) (string, error) { - tmpFile, err := io.TempFile(os.TempDir(), "captcha-*.svg") + tmpFile, err := ioutil.TempFile(os.TempDir(), "captcha-*.svg") if err != nil { return "", fmt.Errorf("cannot create temp file: %w", err) } From 8d856dac0eba37fe04edd201222b717c95b88587 Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 28 Apr 2023 16:23:42 +0200 Subject: [PATCH 3/5] wip --- states.go | 122 +++++++++++++++++++++++++++------------------------- vehicles.go | 43 ++++++++++-------- 2 files changed, 88 insertions(+), 77 deletions(-) diff --git a/states.go b/states.go index aa7be0d..3566c83 100644 --- a/states.go +++ b/states.go @@ -9,6 +9,7 @@ import ( // ChargeState contains the current charge states that exist within the vehicle. type ChargeState struct { + Timestamp timeMsec `json:"timestamp"` ChargingState string `json:"charging_state"` ChargeLimitSoc int `json:"charge_limit_soc"` ChargeLimitSocStd int `json:"charge_limit_soc_std"` @@ -65,6 +66,7 @@ type ChargeState struct { // ClimateState contains the current climate states availale from the vehicle. type ClimateState struct { + Timestamp timeMsec `json:"timestamp"` InsideTemp float64 `json:"inside_temp"` OutsideTemp float64 `json:"outside_temp"` DriverTempSetting float64 `json:"driver_temp_setting"` @@ -98,6 +100,7 @@ type ClimateState struct { // DriveState contains the current drive state of the vehicle. type DriveState struct { + Timestamp timeMsec `json:"timestamp"` ShiftState interface{} `json:"shift_state"` Speed float64 `json:"speed"` Latitude float64 `json:"latitude"` @@ -113,61 +116,63 @@ type DriveState struct { // GuiSettings contains the current GUI settings of the vehicle. type GuiSettings struct { - GuiDistanceUnits string `json:"gui_distance_units"` - GuiTemperatureUnits string `json:"gui_temperature_units"` - GuiChargeRateUnits string `json:"gui_charge_rate_units"` - Gui24HourTime bool `json:"gui_24_hour_time"` - GuiRangeDisplay string `json:"gui_range_display"` - ShowRangeUnits bool `json:"show_range_units"` + Timestamp timeMsec `json:"timestamp"` + GuiDistanceUnits string `json:"gui_distance_units"` + GuiTemperatureUnits string `json:"gui_temperature_units"` + GuiChargeRateUnits string `json:"gui_charge_rate_units"` + Gui24HourTime bool `json:"gui_24_hour_time"` + GuiRangeDisplay string `json:"gui_range_display"` + ShowRangeUnits bool `json:"show_range_units"` } // VehicleState contains the current state of the vehicle. type VehicleState struct { - APIVersion int `json:"api_version"` - AutoParkState string `json:"autopark_state"` - AutoParkStateV2 string `json:"autopark_state_v2"` - AutoParkStateV3 string `json:"autopark_state_v3"` - CalendarSupported bool `json:"calendar_supported"` - CarType string `json:"car_type"` - CarVersion string `json:"car_version"` - CenterDisplayState int `json:"center_display_state"` - DarkRims bool `json:"dark_rims"` - DriverFrontDoor int `json:"df"` - DriverRearDoor int `json:"dr"` - ExteriorColor string `json:"exterior_color"` - FrontTrunk int `json:"ft"` - HasSpoiler bool `json:"has_spoiler"` - Locked bool `json:"locked"` - NotificationsSupported bool `json:"notifications_supported"` - Odometer float64 `json:"odometer"` - ParsedCalendarSupported bool `json:"parsed_calendar_supported"` - PerfConfig string `json:"perf_config"` - PassengerFrontDoor int `json:"pf"` - PassengerRearDoor int `json:"pr"` - RearSeatHeaters int `json:"rear_seat_heaters"` - RemoteStart bool `json:"remote_start"` - RemoteStartSupported bool `json:"remote_start_supported"` - RightHandDrive bool `json:"rhd"` - RoofColor string `json:"roof_color"` - RearTrunk int `json:"rt"` - SentryMode bool `json:"sentry_mode"` - SentryModeAvailable bool `json:"sentry_mode_available"` - SeatType int `json:"seat_type"` - SpoilerType string `json:"spoiler_type"` - SunRoofInstalled int `json:"sun_roof_installed"` - SunRoofPercentOpen int `json:"sun_roof_percent_open"` - SunRoofState string `json:"sun_roof_state"` - ThirdRowSeats string `json:"third_row_seats"` - ValetMode bool `json:"valet_mode"` - VehicleName string `json:"vehicle_name"` - WheelType string `json:"wheel_type"` - FrontDriverWindow int `json:"fd_window"` - FrontPassengerWindow int `json:"fp_window"` - RearDriverWindow int `json:"rd_window"` - RearPassengerWindow int `json:"rp_window"` - IsUserPresent bool `json:"is_user_present"` - RemoteStartEnabled bool `json:"remote_start_enabled"` - ValetPinNeeded bool `json:"valet_pin_needed"` + Timestamp timeMsec `json:"timestamp"` + APIVersion int `json:"api_version"` + AutoParkState string `json:"autopark_state"` + AutoParkStateV2 string `json:"autopark_state_v2"` + AutoParkStateV3 string `json:"autopark_state_v3"` + CalendarSupported bool `json:"calendar_supported"` + CarType string `json:"car_type"` + CarVersion string `json:"car_version"` + CenterDisplayState int `json:"center_display_state"` + DarkRims bool `json:"dark_rims"` + DriverFrontDoor int `json:"df"` + DriverRearDoor int `json:"dr"` + ExteriorColor string `json:"exterior_color"` + FrontTrunk int `json:"ft"` + HasSpoiler bool `json:"has_spoiler"` + Locked bool `json:"locked"` + NotificationsSupported bool `json:"notifications_supported"` + Odometer float64 `json:"odometer"` + ParsedCalendarSupported bool `json:"parsed_calendar_supported"` + PerfConfig string `json:"perf_config"` + PassengerFrontDoor int `json:"pf"` + PassengerRearDoor int `json:"pr"` + RearSeatHeaters int `json:"rear_seat_heaters"` + RemoteStart bool `json:"remote_start"` + RemoteStartSupported bool `json:"remote_start_supported"` + RightHandDrive bool `json:"rhd"` + RoofColor string `json:"roof_color"` + RearTrunk int `json:"rt"` + SentryMode bool `json:"sentry_mode"` + SentryModeAvailable bool `json:"sentry_mode_available"` + SeatType int `json:"seat_type"` + SpoilerType string `json:"spoiler_type"` + SunRoofInstalled int `json:"sun_roof_installed"` + SunRoofPercentOpen int `json:"sun_roof_percent_open"` + SunRoofState string `json:"sun_roof_state"` + ThirdRowSeats string `json:"third_row_seats"` + ValetMode bool `json:"valet_mode"` + VehicleName string `json:"vehicle_name"` + WheelType string `json:"wheel_type"` + FrontDriverWindow int `json:"fd_window"` + FrontPassengerWindow int `json:"fp_window"` + RearDriverWindow int `json:"rd_window"` + RearPassengerWindow int `json:"rp_window"` + IsUserPresent bool `json:"is_user_present"` + RemoteStartEnabled bool `json:"remote_start_enabled"` + ValetPinNeeded bool `json:"valet_pin_needed"` MediaState struct { RemoteControlEnabled bool `json:"remote_control_enabled"` } `json:"media_state"` @@ -189,6 +194,7 @@ type VehicleState struct { // ServiceData contains the service data of the vehicle. type ServiceData struct { + Timestamp timeMsec `json:"timestamp"` ServiceETC time.Time `json:"service_etc"` ServiceStatus string `json:"service_status"` } @@ -196,13 +202,13 @@ type ServiceData struct { // VehicleData represents the states of the vehicle. type VehicleData struct { Response struct { - Timestamp timeMsec `json:"timestamp"` - *ChargeState - *ClimateState - *DriveState - *GuiSettings - *VehicleState - *ServiceData + VehiclePartialResponse + ChargeState ChargeState + ClimateState ClimateState + DriveState DriveState + GuiSettings GuiSettings + VehicleState VehicleState + ServiceData ServiceData } `json:"response"` Error string `json:"error"` ErrorDescription string `json:"error_description"` diff --git a/vehicles.go b/vehicles.go index 33f88a0..ed2486a 100644 --- a/vehicles.go +++ b/vehicles.go @@ -5,27 +5,32 @@ import ( "strings" ) +// VehiclePartialResponse represents the vehicle reponse root data as returned from the Tesla API. +type VehiclePartialResponse struct { + Color interface{} `json:"color"` + DisplayName string `json:"display_name"` + ID int64 `json:"id"` + OptionCodes string `json:"option_codes"` + VehicleID uint64 `json:"vehicle_id"` + Vin string `json:"vin"` + Tokens []string `json:"tokens"` + State string `json:"state"` + IDS string `json:"id_s"` + RemoteStartEnabled bool `json:"remote_start_enabled"` + CalendarEnabled bool `json:"calendar_enabled"` + NotificationsEnabled bool `json:"notifications_enabled"` + BackseatToken interface{} `json:"backseat_token"` + BackseatTokenUpdatedAt interface{} `json:"backseat_token_updated_at"` + AccessType string `json:"access_type"` + InService bool `json:"in_service"` + APIVersion int `json:"api_version"` + CommandSigning string `json:"command_signing"` +} + // Vehicle represents the vehicle as returned from the Tesla API. type Vehicle struct { - Color interface{} `json:"color"` - DisplayName string `json:"display_name"` - ID int64 `json:"id"` - OptionCodes string `json:"option_codes"` - VehicleID uint64 `json:"vehicle_id"` - Vin string `json:"vin"` - Tokens []string `json:"tokens"` - State string `json:"state"` - IDS string `json:"id_s"` - RemoteStartEnabled bool `json:"remote_start_enabled"` - CalendarEnabled bool `json:"calendar_enabled"` - NotificationsEnabled bool `json:"notifications_enabled"` - BackseatToken interface{} `json:"backseat_token"` - BackseatTokenUpdatedAt interface{} `json:"backseat_token_updated_at"` - AccessType string `json:"access_type"` - InService bool `json:"in_service"` - APIVersion int `json:"api_version"` - CommandSigning string `json:"command_signing"` - VehicleConfig *VehicleConfig `json:"vehicle_config"` + VehiclePartialResponse + VehicleConfig *VehicleConfig `json:"vehicle_config"` c *Client } From 3aa4087c28585401c033ea024483b68a7694d41b Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 30 Apr 2023 13:23:02 +0200 Subject: [PATCH 4/5] wip --- examples/manage_car.go | 6 +--- states.go | 13 ++++---- states_test.go | 68 +++++++++++++++++++++--------------------- 3 files changed, 42 insertions(+), 45 deletions(-) diff --git a/examples/manage_car.go b/examples/manage_car.go index 01ed804..5e9e2f8 100644 --- a/examples/manage_car.go +++ b/examples/manage_car.go @@ -27,11 +27,7 @@ func main() { } fmt.Println(status) - fmt.Println(vehicle.ChargeState()) - fmt.Println(vehicle.ClimateState()) - fmt.Println(vehicle.DriveState()) - fmt.Println(vehicle.GuiSettings()) - fmt.Println(vehicle.VehicleState()) + fmt.Println(vehicle.Data()) fmt.Println(vehicle.HonkHorn()) fmt.Println(vehicle.FlashLights()) fmt.Println(vehicle.Wakeup()) diff --git a/states.go b/states.go index 3566c83..717a5c6 100644 --- a/states.go +++ b/states.go @@ -203,12 +203,13 @@ type ServiceData struct { type VehicleData struct { Response struct { VehiclePartialResponse - ChargeState ChargeState - ClimateState ClimateState - DriveState DriveState - GuiSettings GuiSettings - VehicleState VehicleState - ServiceData ServiceData + ChargeState ChargeState `json:"charge_state"` + ClimateState ClimateState `json:"climate_state"` + DriveState DriveState `json:"drive_state"` + GuiSettings GuiSettings `json:"guiset_tings"` + VehicleState VehicleState `json:"vehicle_state"` + VehicleConfig VehicleConfig `json:"vehicle_config"` + // ServiceData ServiceData `json:"service_data"` } `json:"response"` Error string `json:"error"` ErrorDescription string `json:"error_description"` diff --git a/states_test.go b/states_test.go index f69eb86..b17fbea 100644 --- a/states_test.go +++ b/states_test.go @@ -36,46 +36,46 @@ func TestStatesSpec(t *testing.T) { So(status, ShouldBeTrue) }) - // Convey("Should get charge state", t, func() { - // status, err := vehicle.ChargeState() - // So(err, ShouldBeNil) - // So(status.BatteryLevel, ShouldEqual, 90) - // So(status.ChargeRate, ShouldEqual, 0) - // So(status.ChargingState, ShouldEqual, "Complete") - // }) + Convey("Should get charge state", t, func() { + status, err := vehicle.Data() + So(err, ShouldBeNil) + So(status.Response.ChargeState.BatteryLevel, ShouldEqual, 90) + So(status.Response.ChargeState.ChargeRate, ShouldEqual, 0) + So(status.Response.ChargeState.ChargingState, ShouldEqual, "Complete") + }) - // Convey("Should get climate state", t, func() { - // status, err := vehicle.ClimateState() - // So(err, ShouldBeNil) - // So(status.DriverTempSetting, ShouldEqual, 22.0) - // So(status.PassengerTempSetting, ShouldEqual, 22.0) - // So(status.IsRearDefrosterOn, ShouldBeFalse) - // }) + Convey("Should get climate state", t, func() { + status, err := vehicle.Data() + So(err, ShouldBeNil) + So(status.Response.ClimateState.DriverTempSetting, ShouldEqual, 22.0) + So(status.Response.ClimateState.PassengerTempSetting, ShouldEqual, 22.0) + So(status.Response.ClimateState.IsRearDefrosterOn, ShouldBeFalse) + }) - // Convey("Should get drive state", t, func() { - // status, err := vehicle.DriveState() - // So(err, ShouldBeNil) - // So(status.Latitude, ShouldEqual, 35.1) - // So(status.Longitude, ShouldEqual, 20.2) - // }) + Convey("Should get drive state", t, func() { + status, err := vehicle.Data() + So(err, ShouldBeNil) + So(status.Response.DriveState.Latitude, ShouldEqual, 35.1) + So(status.Response.DriveState.Longitude, ShouldEqual, 20.2) + }) - // Convey("Should get GUI settings", t, func() { - // status, err := vehicle.GuiSettings() - // So(err, ShouldBeNil) - // So(status.GuiDistanceUnits, ShouldEqual, "mi/hr") - // So(status.GuiTemperatureUnits, ShouldEqual, "F") - // }) + Convey("Should get GUI settings", t, func() { + status, err := vehicle.Data() + So(err, ShouldBeNil) + So(status.Response.GuiSettings.GuiDistanceUnits, ShouldEqual, "mi/hr") + So(status.Response.GuiSettings.GuiTemperatureUnits, ShouldEqual, "F") + }) - // Convey("Should get Vehicle state", t, func() { - // status, err := vehicle.VehicleState() - // So(err, ShouldBeNil) - // So(status.APIVersion, ShouldEqual, 3) - // So(status.CalendarSupported, ShouldBeTrue) - // So(status.RearTrunk, ShouldEqual, 0) - // }) + Convey("Should get Vehicle state", t, func() { + status, err := vehicle.Data() + So(err, ShouldBeNil) + So(status.Response.VehicleState.APIVersion, ShouldEqual, 3) + So(status.Response.VehicleState.CalendarSupported, ShouldBeTrue) + So(status.Response.VehicleState.RearTrunk, ShouldEqual, 0) + }) // Convey("Should get service data", t, func() { - // status, err := vehicle.ServiceData() + // status, err := vehicle.Data() // So(err, ShouldBeNil) // So(status.ServiceStatus, ShouldEqual, "in_service") // wantTime, err := time.Parse(time.RFC3339, "2019-08-15T14:15:00+02:00") From bb32755b6f40721f6b13dd8041f25823b5243cda Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 30 Apr 2023 13:36:50 +0200 Subject: [PATCH 5/5] wip --- client_test.go | 7 +------ states.go | 3 +-- states_test.go | 18 ++++++++++-------- vehicles.go | 22 +++++++++++++++++++--- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/client_test.go b/client_test.go index f416df8..4588ef0 100644 --- a/client_test.go +++ b/client_test.go @@ -115,12 +115,7 @@ func init() { testMux.HandleFunc("/api/1/vehicles/1234/command/flash_lights", serveJSON(CommandResponseJSON)) testMux.HandleFunc("/api/1/vehicles/1234/command/honk_horn", serveJSON(CommandResponseJSON)) testMux.HandleFunc("/api/1/vehicles/1234/command/reset_valet_pin", serveJSON(CommandResponseJSON)) - testMux.HandleFunc("/api/1/vehicles/1234/data_request/charge_state", serveJSON(ChargeStateJSON)) - testMux.HandleFunc("/api/1/vehicles/1234/data_request/climate_state", serveJSON(ClimateStateJSON)) - testMux.HandleFunc("/api/1/vehicles/1234/data_request/drive_state", serveJSON(DriveStateJSON)) - testMux.HandleFunc("/api/1/vehicles/1234/data_request/gui_settings", serveJSON(GuiSettingsJSON)) - testMux.HandleFunc("/api/1/vehicles/1234/data_request/service_data", serveJSON(ServiceDataJSON)) - testMux.HandleFunc("/api/1/vehicles/1234/data_request/vehicle_state", serveJSON(VehicleStateJSON)) + testMux.HandleFunc("/api/1/vehicles/1234/vehicle_data", serveJSON(DataJSON)) testMux.HandleFunc("/api/1/vehicles/1234/mobile_enabled", serveJSON(TrueJSON)) testMux.HandleFunc("/api/1/vehicles/1234/wake_up", serveJSON(WakeupResponseJSON)) diff --git a/states.go b/states.go index 717a5c6..242965a 100644 --- a/states.go +++ b/states.go @@ -202,12 +202,11 @@ type ServiceData struct { // VehicleData represents the states of the vehicle. type VehicleData struct { Response struct { - VehiclePartialResponse ChargeState ChargeState `json:"charge_state"` ClimateState ClimateState `json:"climate_state"` DriveState DriveState `json:"drive_state"` - GuiSettings GuiSettings `json:"guiset_tings"` VehicleState VehicleState `json:"vehicle_state"` + GuiSettings GuiSettings `json:"gui_settings"` VehicleConfig VehicleConfig `json:"vehicle_config"` // ServiceData ServiceData `json:"service_data"` } `json:"response"` diff --git a/states_test.go b/states_test.go index b17fbea..5eb15c3 100644 --- a/states_test.go +++ b/states_test.go @@ -9,14 +9,16 @@ import ( ) var ( - TrueJSON = `{"response":true}` - ChargeStateJSON = `{"response":{"charging_state":"Complete","charge_limit_soc":90,"charge_limit_soc_std":90,"charge_limit_soc_min":50,"charge_limit_soc_max":100,"charge_to_max_range":false,"battery_heater_on":null,"not_enough_power_to_heat":null,"max_range_charge_counter":0,"fast_charger_present":null,"fast_charger_type":"\u003Cinvalid\u003E","battery_range":235.92,"est_battery_range":200.46,"ideal_battery_range":304.73,"battery_level":90,"usable_battery_level":90,"battery_current":null,"charge_energy_added":19.94,"charge_miles_added_rated":64.5,"charge_miles_added_ideal":83.0,"charger_voltage":null,"charger_pilot_current":null,"charger_actual_current":null,"charger_power":null,"time_to_full_charge":0.0,"trip_charging":null,"charge_rate":0.0,"charge_port_door_open":null,"motorized_charge_port":true,"scheduled_charging_start_time":null,"scheduled_charging_pending":false,"user_charge_enable_request":null,"charge_enable_request":true,"eu_vehicle":false,"charger_phases":null,"charge_port_latch":"\u003Cinvalid\u003E","charge_current_request":40,"charge_current_request_max":40,"managed_charging_active":false,"managed_charging_user_canceled":false,"managed_charging_start_time":null}}` - ClimateStateJSON = `{"response":{"inside_temp":null,"outside_temp":null,"driver_temp_setting":22.0,"passenger_temp_setting":22.0,"left_temp_direction":17,"right_temp_direction":17,"is_auto_conditioning_on":null,"is_front_defroster_on":null,"is_rear_defroster_on":false,"fan_status":null,"is_climate_on":false,"min_avail_temp":15,"max_avail_temp":28,"seat_heater_left":0,"seat_heater_right":0,"seat_heater_rear_left":0,"seat_heater_rear_right":0,"seat_heater_rear_center":0,"seat_heater_rear_right_back":0,"seat_heater_rear_left_back":0,"smart_preconditioning":false}}` - DriveStateJSON = `{"response":{"shift_state":null,"speed":null,"latitude":35.1,"longitude":20.2,"heading":57,"gps_as_of":1452491619}}` - GuiSettingsJSON = `{"response":{"gui_distance_units":"mi/hr","gui_temperature_units":"F","gui_charge_rate_units":"mi/hr","gui_24_hour_time":true,"gui_range_display":"Rated"}}` - VehicleStateJSON = `{"response":{"api_version":3,"calendar_supported":true,"car_type":"s","car_version":"2.9.12","center_display_state":0,"dark_rims":false,"df":0,"dr":0,"exterior_color":"Black","ft":0,"has_spoiler":true,"locked":true,"notifications_supported":true,"odometer":3738.84633,"parsed_calendar_supported":true,"perf_config":"P2","pf":0,"pr":0,"rear_seat_heaters":1,"remote_start":false,"remote_start_supported":true,"rhd":false,"roof_color":"None","rt":0,"seat_type":1,"sun_roof_installed":2,"sun_roof_percent_open":0,"sun_roof_state":"unknown","third_row_seats":"None","valet_mode":false,"vehicle_name":"Macak","wheel_type":"Super21Gray"}}` - ServiceDataJSON = `{"response":{"service_etc": "2019-08-15T14:15:00+02:00", "service_status": "in_service"}}` - ErrorJSON = `{"response":nil,"error":"error message"}` + TrueJSON = `{"response":true}` + ErrorJSON = `{"response":nil,"error":"error message"}` + DataJSON = `{"response":{ + "charge_state": {"charging_state":"Complete","charge_limit_soc":90,"charge_limit_soc_std":90,"charge_limit_soc_min":50,"charge_limit_soc_max":100,"charge_to_max_range":false,"battery_heater_on":null,"not_enough_power_to_heat":null,"max_range_charge_counter":0,"fast_charger_present":null,"fast_charger_type":"\u003Cinvalid\u003E","battery_range":235.92,"est_battery_range":200.46,"ideal_battery_range":304.73,"battery_level":90,"usable_battery_level":90,"battery_current":null,"charge_energy_added":19.94,"charge_miles_added_rated":64.5,"charge_miles_added_ideal":83.0,"charger_voltage":null,"charger_pilot_current":null,"charger_actual_current":null,"charger_power":null,"time_to_full_charge":0.0,"trip_charging":null,"charge_rate":0.0,"charge_port_door_open":null,"motorized_charge_port":true,"scheduled_charging_start_time":null,"scheduled_charging_pending":false,"user_charge_enable_request":null,"charge_enable_request":true,"eu_vehicle":false,"charger_phases":null,"charge_port_latch":"\u003Cinvalid\u003E","charge_current_request":40,"charge_current_request_max":40,"managed_charging_active":false,"managed_charging_user_canceled":false,"managed_charging_start_time":null}, + "climate_state": {"inside_temp":null,"outside_temp":null,"driver_temp_setting":22.0,"passenger_temp_setting":22.0,"left_temp_direction":17,"right_temp_direction":17,"is_auto_conditioning_on":null,"is_front_defroster_on":null,"is_rear_defroster_on":false,"fan_status":null,"is_climate_on":false,"min_avail_temp":15,"max_avail_temp":28,"seat_heater_left":0,"seat_heater_right":0,"seat_heater_rear_left":0,"seat_heater_rear_right":0,"seat_heater_rear_center":0,"seat_heater_rear_right_back":0,"seat_heater_rear_left_back":0,"smart_preconditioning":false}, + "drive_state": {"shift_state":null,"speed":null,"latitude":35.1,"longitude":20.2,"heading":57,"gps_as_of":1452491619}, + "gui_settings": {"gui_distance_units":"mi/hr","gui_temperature_units":"F","gui_charge_rate_units":"mi/hr","gui_24_hour_time":true,"gui_range_display":"Rated"}, + "vehicle_state": {"api_version":3,"calendar_supported":true,"car_type":"s","car_version":"2.9.12","center_display_state":0,"dark_rims":false,"df":0,"dr":0,"exterior_color":"Black","ft":0,"has_spoiler":true,"locked":true,"notifications_supported":true,"odometer":3738.84633,"parsed_calendar_supported":true,"perf_config":"P2","pf":0,"pr":0,"rear_seat_heaters":1,"remote_start":false,"remote_start_supported":true,"rhd":false,"roof_color":"None","rt":0,"seat_type":1,"sun_roof_installed":2,"sun_roof_percent_open":0,"sun_roof_state":"unknown","third_row_seats":"None","valet_mode":false,"vehicle_name":"Macak","wheel_type":"Super21Gray"} + }}` + // "service_data": {"service_etc": "2019-08-15T14:15:00+02:00", "service_status": "in_service"}, ) func TestStatesSpec(t *testing.T) { diff --git a/vehicles.go b/vehicles.go index ed2486a..d0b31dd 100644 --- a/vehicles.go +++ b/vehicles.go @@ -5,7 +5,7 @@ import ( "strings" ) -// VehiclePartialResponse represents the vehicle reponse root data as returned from the Tesla API. +// VehiclePartialResponse represents the vehicle response root data as returned from the Tesla API. type VehiclePartialResponse struct { Color interface{} `json:"color"` DisplayName string `json:"display_name"` @@ -29,8 +29,24 @@ type VehiclePartialResponse struct { // Vehicle represents the vehicle as returned from the Tesla API. type Vehicle struct { - VehiclePartialResponse - VehicleConfig *VehicleConfig `json:"vehicle_config"` + Color interface{} `json:"color"` + DisplayName string `json:"display_name"` + ID int64 `json:"id"` + OptionCodes string `json:"option_codes"` + VehicleID uint64 `json:"vehicle_id"` + Vin string `json:"vin"` + Tokens []string `json:"tokens"` + State string `json:"state"` + IDS string `json:"id_s"` + RemoteStartEnabled bool `json:"remote_start_enabled"` + CalendarEnabled bool `json:"calendar_enabled"` + NotificationsEnabled bool `json:"notifications_enabled"` + BackseatToken interface{} `json:"backseat_token"` + BackseatTokenUpdatedAt interface{} `json:"backseat_token_updated_at"` + AccessType string `json:"access_type"` + InService bool `json:"in_service"` + APIVersion int `json:"api_version"` + CommandSigning string `json:"command_signing"` c *Client }