From c3536512873b69f47a12e0d31e4b4c9523b66232 Mon Sep 17 00:00:00 2001 From: Alex Savin Date: Wed, 4 Jun 2025 12:58:49 -0400 Subject: [PATCH] Beta version --- client.go | 96 ++++++++++++++--------------------------------------- mysubaru.go | 1 + utils.go | 59 ++++++++++++++++---------------- vehicle.go | 16 ++++----- 4 files changed, 63 insertions(+), 109 deletions(-) diff --git a/client.go b/client.go index 2b27c9b..ee40b7d 100644 --- a/client.go +++ b/client.go @@ -4,6 +4,7 @@ import ( "encoding/json" "io" "log/slog" + "slices" "sync" "time" @@ -60,11 +61,11 @@ func New(config *config.Config) (*Client, error) { // client.logger.Debug("unmarshaled json data", "request", "auth", "type", "sessionData", "body", sd) if sd.DeviceRegistered && sd.RegisteredDevicePermanent { - client.logger.Debug("client authentication successful") + // client.logger.Debug("client authentication successful") client.isAuthenticated = true client.isRegistered = true } else { - client.logger.Debug("client authentication successful, but devices is not registered") + // client.logger.Debug("client authentication successful, but devices is not registered") client.registerDevice() } @@ -140,7 +141,7 @@ func (c *Client) GetVehicles() []*Vehicle { // GetVehicleByVIN . func (c *Client) GetVehicleByVIN(vin string) *Vehicle { var vehicle *Vehicle - if contains(c.listOfVins, vin) { + if slices.Contains(c.listOfVins, vin) { params := map[string]string{ "vin": vin, "_": timestamp()} @@ -212,7 +213,7 @@ func (c *Client) GetVehicleByVIN(vin string) *Vehicle { // Exec method executes a Client instance with the API URL func (c *Client) execute(requestUrl string, method string, params map[string]string, pollingUrl string, j bool, attempts ...int) []byte { - defer timeTrack("[TIMETRK] Executing HTTP Request") + // defer timeTrack("[TIMETRK] Executing HTTP Request") var resp *resty.Response // GET Requests @@ -290,35 +291,6 @@ func (c *Client) execute(requestUrl string, method string, params map[string]str return resBytes } -// // isResponseSuccessfull . -// func (c *Client) isResponseSuccessfull(resp []byte) bool { -// respParsed, err := gabs.ParseJSON(resp) -// if err != nil { -// c.logger.Debug("error while parsing json response", "error", err) -// } - -// success, ok := respParsed.Path("success").Data().(bool) -// if !ok { -// c.logger.Debug("response is not successful", "error", resp) -// } - -// // ERRORS FROM CLIENT CREATION AFTER AUTH -// // error, _ := respParsed.Path("errorCode").Data().(string) -// // switch { -// // case error == apiErrors["ERROR_INVALID_ACCOUNT"]: -// // fmt.Println("Invalid account") -// // case error == apiErrors["ERROR_INVALID_CREDENTIALS"]: -// // {"success":false,"errorCode":"InvalidCredentials","dataName":"remoteServiceStatus","data":{"serviceRequestId":null,"success":false,"cancelled":false,"remoteServiceType":null,"remoteServiceState":null,"subState":null,"errorCode":null,"result":null,"updateTime":null,"vin":null,"errorDescription":"The credentials supplied are invalid, tries left 2"}} -// // fmt.Println("Client authentication failed") -// // case error == apiErrors["ERROR_PASSWORD_WARNING"]: -// // fmt.Println("Multiple Password Failures.") -// // default: -// // fmt.Println("Uknown error") -// // } - -// return success -// } - // auth . func (c *Client) auth() []byte { params := map[string]string{ @@ -347,46 +319,28 @@ func (c *Client) parseResponse(b []byte) (Response, bool) { } // validateSession . -func (c *Client) validateSession() bool { - // { - // "success": true, - // "errorCode": null, - // "dataName": null, - // "data": null - // } - reqURL := MOBILE_API_VERSION + apiURLs["API_VALIDATE_SESSION"] - resp := c.execute(reqURL, GET, map[string]string{}, "", false) - c.logger.Debug("http request output", "request", "validateSession", "body", resp) +// func (c *Client) validateSession() bool { +// // { +// // "success": true, +// // "errorCode": null, +// // "dataName": null, +// // "data": null +// // } +// reqURL := MOBILE_API_VERSION + apiURLs["API_VALIDATE_SESSION"] +// resp := c.execute(reqURL, GET, map[string]string{}, "", false) +// c.logger.Debug("http request output", "request", "validateSession", "body", resp) - var r Response - err := json.Unmarshal(resp, &r) - if err != nil { - c.logger.Error("error while parsing json", "request", "validateSession", "error", err.Error()) - } +// var r Response +// err := json.Unmarshal(resp, &r) +// if err != nil { +// c.logger.Error("error while parsing json", "request", "validateSession", "error", err.Error()) +// } - if r.Success { - return true - } - return false - - // result = False - // js_resp = await self.__open(API_VALIDATE_SESSION, GET) - // _LOGGER.debug(pprint.pformat(js_resp)) - // if js_resp["success"]: - // if vin != self._current_vin: - // # API call for VIN that is not the current remote context. - // _LOGGER.debug("Switching Subaru API vehicle context to: %s", vin) - // if await self._select_vehicle(vin): - // result = True - // else: - // result = True - - // if result is False: - // await self._authenticate(vin) - // # New session cookie. Must call selectVehicle.json before any other API call. - // if await self._select_vehicle(vin): - // result = True -} +// if r.Success { +// return true +// } +// return false +// } // GET // https://www.mysubaru.com/profile/verifyDeviceName.json?clientId=2574212&deviceName=Alex%20Google%20Pixel%204%20XL diff --git a/mysubaru.go b/mysubaru.go index 156eae6..8a26eca 100644 --- a/mysubaru.go +++ b/mysubaru.go @@ -281,6 +281,7 @@ type ServiceRequest struct { // "dataName":"errorResponse" // {"success":false,"errorCode":"404-soa-unableToParseResponseBody","dataName":"errorResponse","data":{"errorLabel":"404-soa-unableToParseResponseBody","errorDescription":null}} // {"success":false,"errorCode":"vehicleNotInAccount","dataName":null,"data":null} +// {"success":false,"errorCode":"InvalidCredentials","dataName":"remoteServiceStatus","data":{"serviceRequestId":null,"success":false,"cancelled":false,"remoteServiceType":null,"remoteServiceState":null,"subState":null,"errorCode":null,"result":null,"updateTime":null,"vin":null,"errorDescription":"The credentials supplied are invalid, tries left 2"}} type ErrorResponse struct { ErrorLabel string `json:"errorLabel"` // "404-soa-unableToParseResponseBody" ErrorDescription string `json:"errorDescription,omitempty"` // null diff --git a/utils.go b/utils.go index 1b55f41..62377f8 100644 --- a/utils.go +++ b/utils.go @@ -1,7 +1,6 @@ package mysubaru import ( - "fmt" "math" "regexp" "strconv" @@ -9,6 +8,23 @@ import ( "time" ) +// timestamp is a function +func timestamp() string { + return strconv.FormatInt(time.Now().UnixNano()/1000000, 10) +} + +// urlToGen . +func urlToGen(url string, gen string) string { + var re = regexp.MustCompile(`api_gen`) + // dirty trick for current G3 + if gen == "g3" { + gen = "g2" + } + url = re.ReplaceAllString(url, gen) + + return url +} + // VinCheck - Vehicle Identification Number check digit validation // Parameter: string - 17 digit VIN // Return: @@ -110,34 +126,17 @@ func transcodeDigits(vin string) int { // } // timeTrack . -func timeTrack(name string) { - start := time.Now() - fmt.Printf("%s took %v\n", name, time.Since(start)) -} - -// timestamp is a function -func timestamp() string { - return strconv.FormatInt(time.Now().UnixNano()/1000000, 10) -} +// func timeTrack(name string) { +// start := time.Now() +// fmt.Printf("%s took %v\n", name, time.Since(start)) +// } // contains . -func contains(s []string, str string) bool { - for _, v := range s { - if v == str { - return true - } - } - return false -} - -// urlToGen . -func urlToGen(url string, gen string) string { - var re = regexp.MustCompile(`api_gen`) - // dirty trick for current G3 - if gen == "g3" { - gen = "g2" - } - url = re.ReplaceAllString(url, gen) - - return url -} +// func contains(s []string, str string) bool { +// for _, v := range s { +// if v == str { +// return true +// } +// } +// return false +// } diff --git a/vehicle.go b/vehicle.go index b8a4373..6f32cbe 100644 --- a/vehicle.go +++ b/vehicle.go @@ -759,13 +759,13 @@ func (v *Vehicle) selectVehicle() { // getAPIGen // Get the Subaru telematics API generation of a specified VIN func (v *Vehicle) getAPIGen() string { - if contains(v.Features, FEATURE_G1_TELEMATICS) { + if slices.Contains(v.Features, FEATURE_G1_TELEMATICS) { return "g1" } - if contains(v.Features, FEATURE_G2_TELEMATICS) { + if slices.Contains(v.Features, FEATURE_G2_TELEMATICS) { return "g2" } - if contains(v.Features, FEATURE_G3_TELEMATICS) { + if slices.Contains(v.Features, FEATURE_G3_TELEMATICS) { return "g3" } return "unknown" @@ -780,13 +780,13 @@ func (v *Vehicle) getAPIGen() string { // isEV . // Get whether the specified car is an Electric Vehicle. func (v *Vehicle) isEV() bool { - return contains(v.Features, FEATURE_PHEV) + return slices.Contains(v.Features, FEATURE_PHEV) } // getRemoteOptionsStatus . // Get whether the specified VIN has remote locks/horn/light service available func (v *Vehicle) getRemoteOptionsStatus() bool { - return contains(v.SubscriptionFeatures, FEATURE_REMOTE) + return slices.Contains(v.SubscriptionFeatures, FEATURE_REMOTE) } // parseDoor . @@ -927,19 +927,19 @@ func (v *Vehicle) parseTire(prefix, suffix, name string, value any) { // // getRemoteStartStatus . // // Get whether the specified VIN has remote engine start service available. // func (v *Vehicle) getRemoteStartStatus() bool { -// return contains(v.Features, FEATURE_REMOTE_START) +// return slices.Contains(v.Features, FEATURE_REMOTE_START) // } // // getSafetyStatus . // // Get whether the specified VIN is has an active Starlink Safety Plus service plan. // func (v *Vehicle) getSafetyStatus() bool { -// return contains(v.SubscriptionFeatures, FEATURE_SAFETY) +// return slices.Contains(v.SubscriptionFeatures, FEATURE_SAFETY) // } // // getSubscriptionStatus . // // Get whether the specified VIN has an active service plan. // func (v *Vehicle) getSubscriptionStatus() bool { -// return contains(v.SubscriptionFeatures, FEATURE_ACTIVE) +// return slices.Contains(v.SubscriptionFeatures, FEATURE_ACTIVE) // } // // getVehicleName .