From d3c2badfcbed455073329fa4943e8f0190187a27 Mon Sep 17 00:00:00 2001 From: Alex Savin Date: Sat, 31 May 2025 19:55:53 -0400 Subject: [PATCH] Some changes --- client.go | 2 + mysubaru.go | 9 +- vehicle.go | 277 ++++++++++++++++++++++++++-------------------------- 3 files changed, 143 insertions(+), 145 deletions(-) diff --git a/client.go b/client.go index 422c73e..c990ff3 100644 --- a/client.go +++ b/client.go @@ -356,6 +356,7 @@ func (c *Client) GetVehicles() []*Vehicle { } vehicle.GetVehicleStatus() vehicle.GetVehicleCondition() + vehicle.GetVehicleHealth() vehicle.GetClimatePresets() vehicle.GetClimateUserPresets() vehicle.GetClimateQuickPresets() @@ -411,6 +412,7 @@ func (c *Client) GetVehicleByVIN(vin string) *Vehicle { vehicle.GetVehicleStatus() vehicle.GetVehicleCondition() + vehicle.GetVehicleHealth() vehicle.GetClimatePresets() vehicle.GetClimateUserPresets() vehicle.GetClimateQuickPresets() diff --git a/mysubaru.go b/mysubaru.go index 79ccdb3..1c6e816 100644 --- a/mysubaru.go +++ b/mysubaru.go @@ -1,6 +1,7 @@ package mysubaru import ( + "encoding/json" "time" "github.com/Jeffail/gabs/v2" @@ -8,10 +9,10 @@ import ( // Response . type Response struct { - Success bool `json:"success"` // true | false - ErrorCode string `json:"errorCode,omitempty"` // string | Error message if Success is false - DataName string `json:"dataName"` // string | Describes the structure which is incleded in Data field - Data any `json:"data"` // Data struct + Success bool `json:"success"` // true | false + ErrorCode string `json:"errorCode,omitempty"` // string | Error message if Success is false + DataName string `json:"dataName"` // string | Describes the structure which is incleded in Data field + Data json.RawMessage `json:"data"` // Data struct } // Account . diff --git a/vehicle.go b/vehicle.go index d34f6a5..b2db235 100644 --- a/vehicle.go +++ b/vehicle.go @@ -3,6 +3,7 @@ package mysubaru import ( "encoding/json" "fmt" + "reflect" "regexp" "strconv" "strings" @@ -440,19 +441,14 @@ func (v *Vehicle) GetClimatePresets() { reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_RES_SUBARU_PRESETS"] resp := v.client.execute(reqURL, GET, map[string]string{}, "", false) - tmp := struct { - Success bool `json:"success"` - ErrorCode string `json:"errorCode"` - DataName string `json:"dataName"` - Data json.RawMessage `json:"data"` - }{} - err := json.Unmarshal(resp, &tmp) + var r Response + err := json.Unmarshal(resp, &r) if err != nil { v.client.logger.Error("error while parsing json", "request", "GetClimatePresets", "error", err.Error()) } re1 := regexp.MustCompile(`\"`) - result := re1.ReplaceAllString(string(tmp.Data), "") + result := re1.ReplaceAllString(string(r.Data), "") re2 := regexp.MustCompile(`\\`) result = re2.ReplaceAllString(result, `"`) // \u0022 @@ -505,23 +501,16 @@ func (v *Vehicle) GetClimateQuickPresets() { resp := v.client.execute(reqURL, GET, map[string]string{}, "", false) v.client.logger.Debug("http request output", "request", "GetClimateQuickPresets", "body", resp) - tmp := struct { - Success bool `json:"success"` - ErrorCode string `json:"errorCode"` - DataName string `json:"dataName"` - Data json.RawMessage `json:"data"` - }{} - err := json.Unmarshal(resp, &tmp) + var r Response + err := json.Unmarshal(resp, &r) if err != nil { v.client.logger.Error("error while parsing json", "request", "GetClimatePresets", "error", err.Error()) } re1 := regexp.MustCompile(`\"`) - result := re1.ReplaceAllString(string(tmp.Data), "") - v.client.logger.Debug("quick climate preset after trimming #1", "request", "GetClimateQuickPresets", "body", result) + result := re1.ReplaceAllString(string(r.Data), "") re2 := regexp.MustCompile(`\\`) result = re2.ReplaceAllString(result, `"`) // \u0022 - v.client.logger.Debug("quick climate preset after trimming #2", "request", "GetClimateQuickPresets", "body", result) var cProfile ClimateProfile err = json.Unmarshal([]byte(result), &cProfile) @@ -547,19 +536,14 @@ func (v *Vehicle) GetClimateUserPresets() { reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_RES_USER_PRESETS"] resp := v.client.execute(reqURL, GET, map[string]string{}, "", false) - tmp := struct { - Success bool `json:"success"` - ErrorCode string `json:"errorCode"` - DataName string `json:"dataName"` - Data json.RawMessage `json:"data"` - }{} - err := json.Unmarshal(resp, &tmp) + var r Response + err := json.Unmarshal(resp, &r) if err != nil { v.client.logger.Error("error while parsing json", "request", "GetClimatePresets", "error", err.Error()) } re1 := regexp.MustCompile(`\"`) - result := re1.ReplaceAllString(string(tmp.Data), "") + result := re1.ReplaceAllString(string(r.Data), "") re2 := regexp.MustCompile(`\\`) result = re2.ReplaceAllString(result, `"`) // \u0022 @@ -603,17 +587,14 @@ func (v *Vehicle) GetVehicleStatus() { v.client.logger.Error("error while parsing json", "request", "GetClimatePresets", "error", err.Error()) } - if v.client.isResponseSuccessfull(resp) { - respParsed, err := gabs.ParseJSON(resp) + if r.Success { + var vSta VehicleStatus + err = json.Unmarshal(r.Data, &vSta) if err != nil { - v.client.logger.Error("error while parsing json", "request", "GetVehicleStatus", "error", err.Error()) + v.client.logger.Error("error while parsing json", "request", "GetClimatePresets", "error", err.Error()) } + v.client.logger.Debug("http request output", "request", "GetVehicleStatus", "body", resp) - vSta := VehicleStatus{} - vsString := respParsed.Path("data").String() - json.Unmarshal([]byte(vsString), &vSta) - - fmt.Printf("CAR STATUS: %+v\n", vSta) v.EngineState = vSta.VehicleStateType v.Odometer.Miles = vSta.OdometerValue v.Odometer.Kilometers = vSta.OdometerValueKm @@ -629,117 +610,129 @@ func (v *Vehicle) GetVehicleStatus() { v.GeoLocation.Longitude = float64(vSta.Longitude) v.GeoLocation.Heading = vSta.Heading - re := regexp.MustCompile(`[A-Z][^A-Z]*`) + // re := regexp.MustCompile(`[A-Z][^A-Z]*`) - for key, child := range respParsed.S("data").ChildrenMap() { - fmt.Printf("key: %v, value: %v\n", key, child.Data()) - if child.Data() == "NOT_EQUIPPED" || child.Data() == "UNKNOWN" || child.Data() == "16383" || child.Data() == "65535" || child.Data() == "None" || child.Data() == "-64.0" || child.Data() == nil { - // fmt.Println("Skipping") - continue - } - if strings.HasPrefix(key, "door") && strings.HasSuffix(key, "Position") { - pos := strings.TrimPrefix(key, "door") - pos = strings.TrimSuffix(pos, "Position") - submatchall := re.FindAllString(pos, -1) - v.client.logger.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall)) + val := reflect.ValueOf(vSta) + typeOfS := val.Type() - if door, ok := v.Doors[pos]; ok { - door.Status = child.Data().(string) - door.Updated = time.Now() - } else { - door.Status = child.Data().(string) - door.Updated = time.Now() - v.Doors[pos] = Door{ - Position: submatchall[0], - Status: child.Data().(string), - Updated: time.Now(), - } - if len(submatchall) >= 2 { - if d, ok := v.Doors[pos]; ok { - d.SubPosition = submatchall[1] - v.Doors[pos] = d - } - } - } - } - if strings.HasPrefix(key, "door") && strings.HasSuffix(key, "LockStatus") { - pos := strings.TrimPrefix(key, "door") - pos = strings.TrimSuffix(pos, "LockStatus") - submatchall := re.FindAllString(pos, -1) - v.client.logger.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall)) - - if door, ok := v.Doors[pos]; ok { - door.Lock = child.Data().(string) - door.Updated = time.Now() - } else { - door.Lock = child.Data().(string) - door.Updated = time.Now() - v.Doors[pos] = Door{ - Position: submatchall[0], - Lock: child.Data().(string), - Updated: time.Now(), - } - if len(submatchall) >= 2 { - if d, ok := v.Doors[pos]; ok { - d.SubPosition = submatchall[1] - v.Doors[pos] = d - } - } - } - } - if strings.HasPrefix(key, "window") && strings.HasSuffix(key, "Status") { - pos := strings.TrimPrefix(key, "window") - pos = strings.TrimSuffix(pos, "Status") - submatchall := re.FindAllString(pos, -1) - v.client.logger.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall)) - - if window, ok := v.Windows[pos]; ok { - window.Status = child.Data().(string) - window.Updated = time.Now() - } else { - window.Status = child.Data().(string) - window.Updated = time.Now() - v.Windows[pos] = Window{ - Position: submatchall[0], - Status: child.Data().(string), - Updated: time.Now(), - } - if len(submatchall) >= 2 { - if w, ok := v.Windows[pos]; ok { - w.SubPosition = submatchall[1] - v.Windows[pos] = w - } - } - } - } - if strings.HasPrefix(key, "tirePressure") && strings.HasSuffix(key, "Psi") { - pos := strings.TrimPrefix(key, "tirePressure") - pos = strings.TrimSuffix(pos, "Psi") - submatchall := re.FindAllString(pos, -1) - v.client.logger.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall)) - - if tire, ok := v.Tires[pos]; ok { - tire.PressurePsi = child.Data().(string) - tire.Updated = time.Now() - } else { - tire.PressurePsi = child.Data().(string) - tire.Updated = time.Now() - v.Tires[pos] = Tire{ - Position: submatchall[0], - PressurePsi: child.Data().(string), - Updated: time.Now(), - } - if len(submatchall) >= 2 { - if t, ok := v.Tires[pos]; ok { - t.SubPosition = submatchall[1] - v.Tires[pos] = t - } - } - } - } + for i := 0; i < val.NumField(); i++ { + fmt.Printf("Field: %s, Value: %v, Type: %v\n", typeOfS.Field(i).Name, val.Field(i).Interface(), val.Field(i).Type()) } + // v := reflect.ValueOf(vSta) + // values := make([]interface{}, v.NumField()) + // for i := 0; i < v.NumField(); i++ { + // values[i] = v.Field(i).Interface() + // } - fmt.Printf("PARTS: %+v\n", parts) + // for key, child := range respParsed.S("data").ChildrenMap() { + // fmt.Printf("key: %v, value: %v\n", key, child.Data()) + // if child.Data() == "NOT_EQUIPPED" || child.Data() == "UNKNOWN" || child.Data() == "16383" || child.Data() == "65535" || child.Data() == "None" || child.Data() == "-64.0" || child.Data() == nil { + // // fmt.Println("Skipping") + // continue + // } + // if strings.HasPrefix(key, "door") && strings.HasSuffix(key, "Position") { + // pos := strings.TrimPrefix(key, "door") + // pos = strings.TrimSuffix(pos, "Position") + // submatchall := re.FindAllString(pos, -1) + // v.client.logger.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall)) + + // if door, ok := v.Doors[pos]; ok { + // door.Status = child.Data().(string) + // door.Updated = time.Now() + // } else { + // door.Status = child.Data().(string) + // door.Updated = time.Now() + // v.Doors[pos] = Door{ + // Position: submatchall[0], + // Status: child.Data().(string), + // Updated: time.Now(), + // } + // if len(submatchall) >= 2 { + // if d, ok := v.Doors[pos]; ok { + // d.SubPosition = submatchall[1] + // v.Doors[pos] = d + // } + // } + // } + // } + // if strings.HasPrefix(key, "door") && strings.HasSuffix(key, "LockStatus") { + // pos := strings.TrimPrefix(key, "door") + // pos = strings.TrimSuffix(pos, "LockStatus") + // submatchall := re.FindAllString(pos, -1) + // v.client.logger.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall)) + + // if door, ok := v.Doors[pos]; ok { + // door.Lock = child.Data().(string) + // door.Updated = time.Now() + // } else { + // door.Lock = child.Data().(string) + // door.Updated = time.Now() + // v.Doors[pos] = Door{ + // Position: submatchall[0], + // Lock: child.Data().(string), + // Updated: time.Now(), + // } + // if len(submatchall) >= 2 { + // if d, ok := v.Doors[pos]; ok { + // d.SubPosition = submatchall[1] + // v.Doors[pos] = d + // } + // } + // } + // } + // if strings.HasPrefix(key, "window") && strings.HasSuffix(key, "Status") { + // pos := strings.TrimPrefix(key, "window") + // pos = strings.TrimSuffix(pos, "Status") + // submatchall := re.FindAllString(pos, -1) + // v.client.logger.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall)) + + // if window, ok := v.Windows[pos]; ok { + // window.Status = child.Data().(string) + // window.Updated = time.Now() + // } else { + // window.Status = child.Data().(string) + // window.Updated = time.Now() + // v.Windows[pos] = Window{ + // Position: submatchall[0], + // Status: child.Data().(string), + // Updated: time.Now(), + // } + // if len(submatchall) >= 2 { + // if w, ok := v.Windows[pos]; ok { + // w.SubPosition = submatchall[1] + // v.Windows[pos] = w + // } + // } + // } + // } + // if strings.HasPrefix(key, "tirePressure") && strings.HasSuffix(key, "Psi") { + // pos := strings.TrimPrefix(key, "tirePressure") + // pos = strings.TrimSuffix(pos, "Psi") + // submatchall := re.FindAllString(pos, -1) + // v.client.logger.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall)) + + // if tire, ok := v.Tires[pos]; ok { + // tire.PressurePsi = child.Data().(string) + // tire.Updated = time.Now() + // } else { + // tire.PressurePsi = child.Data().(string) + // tire.Updated = time.Now() + // v.Tires[pos] = Tire{ + // Position: submatchall[0], + // PressurePsi: child.Data().(string), + // Updated: time.Now(), + // } + // if len(submatchall) >= 2 { + // if t, ok := v.Tires[pos]; ok { + // t.SubPosition = submatchall[1] + // v.Tires[pos] = t + // } + // } + // } + // } + // } + + // fmt.Printf("PARTS: %+v\n", parts) v.Updated = time.Now() } @@ -795,6 +788,7 @@ func (v *Vehicle) GetVehicleCondition() { v.selectVehicle() reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_CONDITION"], v.getAPIGen()) resp := v.client.execute(reqURL, GET, map[string]string{}, "", false) + v.client.logger.Debug("http request output", "request", "GetVehicleCondition", "body", resp) if v.client.isResponseSuccessfull(resp) { respParsed, err := gabs.ParseJSON(resp) @@ -936,6 +930,7 @@ func (v *Vehicle) GetVehicleHealth() { "_": timestamp()} reqURL := MOBILE_API_VERSION + apiURLs["API_VEHICLE_HEALTH"] resp := v.client.execute(reqURL, GET, params, "", false) + v.client.logger.Debug("http request output", "request", "GetVehicleHealth", "body", resp) if v.client.isResponseSuccessfull(resp) { _, err := gabs.ParseJSON(resp)