Refactor some functions
This commit is contained in:
269
client.go
269
client.go
@ -2,11 +2,11 @@ package mysubaru
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"slices"
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.savin.nyc/alex/mysubaru/config"
|
"git.savin.nyc/alex/mysubaru/config"
|
||||||
"resty.dev/v3"
|
"resty.dev/v3"
|
||||||
@ -23,6 +23,7 @@ type Client struct {
|
|||||||
listOfVins []string
|
listOfVins []string
|
||||||
isAuthenticated bool
|
isAuthenticated bool
|
||||||
isRegistered bool
|
isRegistered bool
|
||||||
|
isAlive bool
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
@ -52,9 +53,8 @@ func New(config *config.Config) (*Client, error) {
|
|||||||
client.httpClient = httpClient
|
client.httpClient = httpClient
|
||||||
resp := client.auth()
|
resp := client.auth()
|
||||||
|
|
||||||
if r, ok := client.parseResponse(resp); ok {
|
|
||||||
var sd SessionData
|
var sd SessionData
|
||||||
err := json.Unmarshal(r.Data, &sd)
|
err := json.Unmarshal(resp.Data, &sd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
client.logger.Error("error while parsing json", "request", "auth", "error", err.Error())
|
client.logger.Error("error while parsing json", "request", "auth", "error", err.Error())
|
||||||
}
|
}
|
||||||
@ -64,10 +64,12 @@ func New(config *config.Config) (*Client, error) {
|
|||||||
// client.logger.Debug("client authentication successful")
|
// client.logger.Debug("client authentication successful")
|
||||||
client.isAuthenticated = true
|
client.isAuthenticated = true
|
||||||
client.isRegistered = true
|
client.isRegistered = true
|
||||||
} else {
|
|
||||||
// client.logger.Debug("client authentication successful, but devices is not registered")
|
|
||||||
client.registerDevice()
|
|
||||||
}
|
}
|
||||||
|
// TODO: Work on registerDevice()
|
||||||
|
// } else {
|
||||||
|
// // client.logger.Debug("client authentication successful, but devices is not registered")
|
||||||
|
// client.registerDevice()
|
||||||
|
// }
|
||||||
|
|
||||||
// client.logger.Debug("parsing cars assigned to the account", "quantity", len(sd.Vehicles))
|
// client.logger.Debug("parsing cars assigned to the account", "quantity", len(sd.Vehicles))
|
||||||
if len(sd.Vehicles) > 0 {
|
if len(sd.Vehicles) > 0 {
|
||||||
@ -80,28 +82,11 @@ func New(config *config.Config) (*Client, error) {
|
|||||||
client.logger.Error("there no cars assigned to the account")
|
client.logger.Error("there no cars assigned to the account")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// TODO: Work on errors
|
|
||||||
// error, _ := respParsed.Path("errorCode").Data().(string)
|
|
||||||
// switch {
|
|
||||||
// case error == apiErrors["ERROR_INVALID_ACCOUNT"]:
|
|
||||||
// client.logger.Debug("Invalid account")
|
|
||||||
// case error == apiErrors["ERROR_INVALID_CREDENTIALS"]:
|
|
||||||
// client.logger.Debug("Client authentication failed")
|
|
||||||
// case error == apiErrors["ERROR_PASSWORD_WARNING"]:
|
|
||||||
// client.logger.Debug("Multiple Password Failures.")
|
|
||||||
// default:
|
|
||||||
// client.logger.Debug("Uknown error")
|
|
||||||
// }
|
|
||||||
client.logger.Error("request was not successfull", "request", "auth")
|
|
||||||
// TODO: Work on providing error
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectVehicle .
|
// SelectVehicle .
|
||||||
func (c *Client) SelectVehicle(vin string) VehicleData {
|
func (c *Client) SelectVehicle(vin string) (*VehicleData, error) {
|
||||||
if vin == "" {
|
if vin == "" {
|
||||||
vin = c.currentVin
|
vin = c.currentVin
|
||||||
}
|
}
|
||||||
@ -112,46 +97,47 @@ func (c *Client) SelectVehicle(vin string) VehicleData {
|
|||||||
"vin": vin,
|
"vin": vin,
|
||||||
"_": timestamp()}
|
"_": timestamp()}
|
||||||
reqURL := MOBILE_API_VERSION + apiURLs["API_SELECT_VEHICLE"]
|
reqURL := MOBILE_API_VERSION + apiURLs["API_SELECT_VEHICLE"]
|
||||||
resp := c.execute(reqURL, GET, params, "", false)
|
// TODO: Add error handling
|
||||||
|
resp, _ := c.execute(GET, reqURL, params, false)
|
||||||
// c.logger.Debug("http request output", "request", "SelectVehicle", "body", resp)
|
// c.logger.Debug("http request output", "request", "SelectVehicle", "body", resp)
|
||||||
|
|
||||||
if r, ok := c.parseResponse(resp); ok {
|
|
||||||
var vd VehicleData
|
var vd VehicleData
|
||||||
err := json.Unmarshal(r.Data, &vd)
|
err := json.Unmarshal(resp.Data, &vd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("error while parsing json", "request", "SelectVehicle", "error", err.Error())
|
c.logger.Error("error while parsing json", "request", "SelectVehicle", "error", err.Error())
|
||||||
|
return nil, errors.New("error while parsing json while vehicle selection")
|
||||||
}
|
}
|
||||||
// c.logger.Debug("http request output", "request", "SelectVehicle", "body", resp)
|
// c.logger.Debug("http request output", "request", "SelectVehicle", "body", resp)
|
||||||
return vd
|
return &vd, nil
|
||||||
} else {
|
|
||||||
return VehicleData{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVehicles .
|
// GetVehicles .
|
||||||
func (c *Client) GetVehicles() []*Vehicle {
|
func (c *Client) GetVehicles() []*Vehicle {
|
||||||
var vehicles []*Vehicle
|
var vehicles []*Vehicle
|
||||||
for _, vin := range c.listOfVins {
|
for _, vin := range c.listOfVins {
|
||||||
vehicle := c.GetVehicleByVIN(vin)
|
vehicle, err := c.GetVehicleByVIN(vin)
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Error("cannot get vehile data", "request", "SelectVehicle", "error", err.Error())
|
||||||
|
}
|
||||||
vehicles = append(vehicles, vehicle)
|
vehicles = append(vehicles, vehicle)
|
||||||
}
|
}
|
||||||
return vehicles
|
return vehicles
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVehicleByVIN .
|
// GetVehicleByVIN .
|
||||||
func (c *Client) GetVehicleByVIN(vin string) *Vehicle {
|
func (c *Client) GetVehicleByVIN(vin string) (*Vehicle, error) {
|
||||||
var vehicle *Vehicle
|
var vehicle *Vehicle
|
||||||
if slices.Contains(c.listOfVins, vin) {
|
if slices.Contains(c.listOfVins, vin) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"vin": vin,
|
"vin": vin,
|
||||||
"_": timestamp()}
|
"_": timestamp()}
|
||||||
reqURL := MOBILE_API_VERSION + apiURLs["API_SELECT_VEHICLE"]
|
reqURL := MOBILE_API_VERSION + apiURLs["API_SELECT_VEHICLE"]
|
||||||
resp := c.execute(reqURL, GET, params, "", false)
|
// TODO: Add error handling
|
||||||
|
resp, _ := c.execute(GET, reqURL, params, false)
|
||||||
// c.logger.Debug("http request output", "request", "GetVehicleByVIN", "body", resp)
|
// c.logger.Debug("http request output", "request", "GetVehicleByVIN", "body", resp)
|
||||||
|
|
||||||
if r, ok := c.parseResponse(resp); ok {
|
|
||||||
var vd VehicleData
|
var vd VehicleData
|
||||||
err := json.Unmarshal(r.Data, &vd)
|
err := json.Unmarshal(resp.Data, &vd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("error while parsing json", "request", "GetVehicleByVIN", "error", err.Error())
|
c.logger.Error("error while parsing json", "request", "GetVehicleByVIN", "error", err.Error())
|
||||||
}
|
}
|
||||||
@ -194,11 +180,10 @@ func (c *Client) GetVehicleByVIN(vin string) *Vehicle {
|
|||||||
vehicle.GetClimateUserPresets()
|
vehicle.GetClimateUserPresets()
|
||||||
vehicle.GetClimateQuickPresets()
|
vehicle.GetClimateQuickPresets()
|
||||||
|
|
||||||
return vehicle
|
return vehicle, nil
|
||||||
}
|
}
|
||||||
}
|
c.logger.Error("vin code is not in the list of the available vin codes", "request", "GetVehicleByVIN")
|
||||||
c.logger.Error("error while parsing json", "request", "GetVehicleByVIN")
|
return nil, errors.New("vin code is not in the list of the available vin codes")
|
||||||
return &Vehicle{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// func isPINRequired() {}
|
// func isPINRequired() {}
|
||||||
@ -211,8 +196,12 @@ func (c *Client) GetVehicleByVIN(vin string) *Vehicle {
|
|||||||
// func getClimateData() {}
|
// func getClimateData() {}
|
||||||
// func saveClimateSettings() {}
|
// func saveClimateSettings() {}
|
||||||
|
|
||||||
|
func (c *Client) IsAlive() bool {
|
||||||
|
return c.isAlive
|
||||||
|
}
|
||||||
|
|
||||||
// Exec method executes a Client instance with the API URL
|
// 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 {
|
func (c *Client) execute(method string, url string, params map[string]string, j bool) (*Response, error) {
|
||||||
// defer timeTrack("[TIMETRK] Executing HTTP Request")
|
// defer timeTrack("[TIMETRK] Executing HTTP Request")
|
||||||
var resp *resty.Response
|
var resp *resty.Response
|
||||||
|
|
||||||
@ -221,7 +210,7 @@ func (c *Client) execute(requestUrl string, method string, params map[string]str
|
|||||||
resp, _ = c.httpClient.
|
resp, _ = c.httpClient.
|
||||||
R().
|
R().
|
||||||
SetQueryParams(params).
|
SetQueryParams(params).
|
||||||
Get(requestUrl)
|
Get(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST Requests
|
// POST Requests
|
||||||
@ -230,14 +219,16 @@ func (c *Client) execute(requestUrl string, method string, params map[string]str
|
|||||||
resp, _ = c.httpClient.
|
resp, _ = c.httpClient.
|
||||||
R().
|
R().
|
||||||
SetBody(params).
|
SetBody(params).
|
||||||
Post(requestUrl)
|
Post(url)
|
||||||
} else { // POST > Form Data
|
} else { // POST > Form Data
|
||||||
resp, _ = c.httpClient.
|
resp, _ = c.httpClient.
|
||||||
R().
|
R().
|
||||||
SetFormData(params).
|
SetFormData(params).
|
||||||
Post(requestUrl)
|
Post(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.IsSuccess() {
|
||||||
resBytes, err := io.ReadAll(resp.Body)
|
resBytes, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("error while getting body", "error", err.Error())
|
c.logger.Error("error while getting body", "error", err.Error())
|
||||||
@ -245,36 +236,8 @@ func (c *Client) execute(requestUrl string, method string, params map[string]str
|
|||||||
c.logger.Debug("parsed http request output", "data", string(resBytes))
|
c.logger.Debug("parsed http request output", "data", string(resBytes))
|
||||||
|
|
||||||
if r, ok := c.parseResponse(resBytes); ok {
|
if r, ok := c.parseResponse(resBytes); ok {
|
||||||
// c.logger.Debug("parsed http request output", "data", r.Data)
|
c.isAlive = true
|
||||||
|
return &r, nil
|
||||||
// dataName field has the list of the states [ remoteServiceStatus | errorResponse ]
|
|
||||||
if r.DataName == "remoteServiceStatus" {
|
|
||||||
var sr ServiceRequest
|
|
||||||
err := json.Unmarshal(r.Data, &sr)
|
|
||||||
if err != nil {
|
|
||||||
c.logger.Error("error while parsing json", "request", "remoteServiceStatus", "error", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if pollingUrl != "" {
|
|
||||||
switch {
|
|
||||||
case sr.RemoteServiceState == "finished":
|
|
||||||
// Finished RemoteServiceState Service Request does not include Service Request ID
|
|
||||||
c.logger.Debug("Remote service request completed successfully")
|
|
||||||
case sr.RemoteServiceState == "started":
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
c.logger.Debug("Subaru API reports remote service request (started) is in progress", "id", sr.ServiceRequestID)
|
|
||||||
c.execute(pollingUrl, GET, map[string]string{"serviceRequestId": sr.ServiceRequestID}, pollingUrl, false)
|
|
||||||
case sr.RemoteServiceState == "stopping":
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
c.logger.Debug("Subaru API reports remote service request (stopping) is in progress", "id", sr.ServiceRequestID)
|
|
||||||
c.execute(pollingUrl, GET, map[string]string{"serviceRequestId": sr.ServiceRequestID}, pollingUrl, false)
|
|
||||||
default:
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
c.logger.Debug("Subaru API reports remote service request (stopping) is in progress")
|
|
||||||
c.execute(pollingUrl, GET, map[string]string{"serviceRequestId": sr.ServiceRequestID}, pollingUrl, false, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if r.DataName == "errorResponse" {
|
if r.DataName == "errorResponse" {
|
||||||
var er ErrorResponse
|
var er ErrorResponse
|
||||||
@ -283,17 +246,20 @@ func (c *Client) execute(requestUrl string, method string, params map[string]str
|
|||||||
c.logger.Error("error while parsing json", "request", "errorResponse", "error", err.Error())
|
c.logger.Error("error while parsing json", "request", "errorResponse", "error", err.Error())
|
||||||
}
|
}
|
||||||
if _, ok := API_ERRORS[er.ErrorLabel]; ok {
|
if _, ok := API_ERRORS[er.ErrorLabel]; ok {
|
||||||
c.logger.Error("request got an error", "request", "execute", "method", method, "url", requestUrl, "label", er.ErrorLabel, "descrip[tion", er.ErrorDescription)
|
c.logger.Error("request got an error", "request", "execute", "method", method, "url", url, "label", er.ErrorLabel, "descrip[tion", er.ErrorDescription)
|
||||||
}
|
}
|
||||||
c.logger.Error("request got an unknown error", "request", "execute", "method", method, "url", requestUrl, "label", er.ErrorLabel, "descrip[tion", er.ErrorDescription)
|
c.logger.Error("request got an unknown error", "request", "execute", "method", method, "url", url, "label", er.ErrorLabel, "descrip[tion", er.ErrorDescription)
|
||||||
|
return nil, errors.New("request is not successfull, HTTP code: " + resp.Status())
|
||||||
}
|
}
|
||||||
c.logger.Error("request is not successfull", "request", "execute", "method", method, "url", requestUrl, "error", err.Error())
|
c.logger.Error("request is not successfull", "request", "execute", "method", method, "url", url, "error", err.Error())
|
||||||
}
|
}
|
||||||
return resBytes
|
}
|
||||||
|
c.isAlive = false
|
||||||
|
return nil, errors.New("request is not successfull, HTTP code: " + resp.Status())
|
||||||
}
|
}
|
||||||
|
|
||||||
// auth .
|
// auth .
|
||||||
func (c *Client) auth() []byte {
|
func (c *Client) auth() *Response {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"env": "cloudprod",
|
"env": "cloudprod",
|
||||||
"deviceType": "android",
|
"deviceType": "android",
|
||||||
@ -304,7 +270,8 @@ func (c *Client) auth() []byte {
|
|||||||
"selectedVin": "",
|
"selectedVin": "",
|
||||||
"pushToken": ""}
|
"pushToken": ""}
|
||||||
reqURL := MOBILE_API_VERSION + apiURLs["API_LOGIN"]
|
reqURL := MOBILE_API_VERSION + apiURLs["API_LOGIN"]
|
||||||
resp := c.execute(reqURL, POST, params, "", false)
|
// TODO: Add error handling
|
||||||
|
resp, _ := c.execute(POST, reqURL, params, false)
|
||||||
// c.logger.Debug("AUTH HTTP OUTPUT", "body", string([]byte(resp)))
|
// c.logger.Debug("AUTH HTTP OUTPUT", "body", string([]byte(resp)))
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
@ -315,29 +282,23 @@ func (c *Client) parseResponse(b []byte) (Response, bool) {
|
|||||||
err := json.Unmarshal(b, &r)
|
err := json.Unmarshal(b, &r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("error while parsing json", "error", err.Error())
|
c.logger.Error("error while parsing json", "error", err.Error())
|
||||||
|
return r, false
|
||||||
}
|
}
|
||||||
return r, true
|
return r, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateSession .
|
// validateSession .
|
||||||
|
// TODO: add session validation process and add it to the proper functions
|
||||||
// func (c *Client) validateSession() bool {
|
// func (c *Client) validateSession() bool {
|
||||||
// // {
|
|
||||||
// // "success": true,
|
|
||||||
// // "errorCode": null,
|
|
||||||
// // "dataName": null,
|
|
||||||
// // "data": null
|
|
||||||
// // }
|
|
||||||
// reqURL := MOBILE_API_VERSION + apiURLs["API_VALIDATE_SESSION"]
|
// reqURL := MOBILE_API_VERSION + apiURLs["API_VALIDATE_SESSION"]
|
||||||
// resp := c.execute(reqURL, GET, map[string]string{}, "", false)
|
// resp := c.execute(reqURL, GET, map[string]string{}, "", false)
|
||||||
// c.logger.Debug("http request output", "request", "validateSession", "body", resp)
|
// // c.logger.Debug("http request output", "request", "validateSession", "body", resp)
|
||||||
|
|
||||||
// var r Response
|
// if r, ok := c.parseResponse(resp); ok {
|
||||||
// err := json.Unmarshal(resp, &r)
|
|
||||||
// if err != nil {
|
|
||||||
// c.logger.Error("error while parsing json", "request", "validateSession", "error", err.Error())
|
// c.logger.Error("error while parsing json", "request", "validateSession", "error", err.Error())
|
||||||
// }
|
// return true
|
||||||
|
// } else {
|
||||||
// if r.Success {
|
// resp := c.auth()
|
||||||
// return true
|
// return true
|
||||||
// }
|
// }
|
||||||
// return false
|
// return false
|
||||||
@ -358,50 +319,50 @@ func (c *Client) parseResponse(b []byte) (Response, bool) {
|
|||||||
// {"success":true,"dataName":"authorizedDevices","data":[{"telematicsClientDeviceKey":2574212,"deviceType":"android","deviceName":"Alex Google Pixel 4 XL","createdDate":"2019-11-29T20:32:21.000+0000","modifiedDate":"2020-06-08T17:48:22.000+0000"},{"telematicsClientDeviceKey":4847533,"deviceName":"Home Assistant: Added 2021-03-03","createdDate":"2021-03-03T20:53:44.000+0000","modifiedDate":"2021-03-03T20:53:47.000+0000"},{"telematicsClientDeviceKey":7222995,"deviceType":"android","deviceName":"Alex Google Pixel 6 Pro","createdDate":"2021-10-28T15:27:36.000+0000","modifiedDate":"2021-10-28T15:27:58.000+0000"},{"telematicsClientDeviceKey":8207130,"deviceName":"Mac/iOS Chrome","createdDate":"2021-12-21T21:19:40.000+0000","modifiedDate":"2021-12-21T21:19:40.000+0000"}]}
|
// {"success":true,"dataName":"authorizedDevices","data":[{"telematicsClientDeviceKey":2574212,"deviceType":"android","deviceName":"Alex Google Pixel 4 XL","createdDate":"2019-11-29T20:32:21.000+0000","modifiedDate":"2020-06-08T17:48:22.000+0000"},{"telematicsClientDeviceKey":4847533,"deviceName":"Home Assistant: Added 2021-03-03","createdDate":"2021-03-03T20:53:44.000+0000","modifiedDate":"2021-03-03T20:53:47.000+0000"},{"telematicsClientDeviceKey":7222995,"deviceType":"android","deviceName":"Alex Google Pixel 6 Pro","createdDate":"2021-10-28T15:27:36.000+0000","modifiedDate":"2021-10-28T15:27:58.000+0000"},{"telematicsClientDeviceKey":8207130,"deviceName":"Mac/iOS Chrome","createdDate":"2021-12-21T21:19:40.000+0000","modifiedDate":"2021-12-21T21:19:40.000+0000"}]}
|
||||||
// {"success":true,"dataName":"authorizedDevices","data":[{"telematicsClientDeviceKey":2574212,"deviceType":"android","deviceName":"Alex Google Pixel 4 XL","createdDate":"2019-11-29T20:32:21.000+0000","modifiedDate":"2020-06-08T17:48:22.000+0000"},{"telematicsClientDeviceKey":4847533,"deviceName":"Home Assistant: Added 2021-03-03","createdDate":"2021-03-03T20:53:44.000+0000","modifiedDate":"2021-03-03T20:53:47.000+0000"},{"telematicsClientDeviceKey":7222995,"deviceType":"android","deviceName":"Alex Google Pixel 6 Pro","createdDate":"2021-10-28T15:27:36.000+0000","modifiedDate":"2021-10-28T15:27:58.000+0000"},{"telematicsClientDeviceKey":8210723,"deviceName":"Hassio Golang Integration","createdDate":"2021-12-22T01:38:43.000+0000","modifiedDate":"2021-12-22T01:38:43.000+0000"},{"telematicsClientDeviceKey":8207130,"deviceName":"Mac/iOS Chrome","createdDate":"2021-12-21T21:19:40.000+0000","modifiedDate":"2021-12-21T21:19:40.000+0000"}]}
|
// {"success":true,"dataName":"authorizedDevices","data":[{"telematicsClientDeviceKey":2574212,"deviceType":"android","deviceName":"Alex Google Pixel 4 XL","createdDate":"2019-11-29T20:32:21.000+0000","modifiedDate":"2020-06-08T17:48:22.000+0000"},{"telematicsClientDeviceKey":4847533,"deviceName":"Home Assistant: Added 2021-03-03","createdDate":"2021-03-03T20:53:44.000+0000","modifiedDate":"2021-03-03T20:53:47.000+0000"},{"telematicsClientDeviceKey":7222995,"deviceType":"android","deviceName":"Alex Google Pixel 6 Pro","createdDate":"2021-10-28T15:27:36.000+0000","modifiedDate":"2021-10-28T15:27:58.000+0000"},{"telematicsClientDeviceKey":8210723,"deviceName":"Hassio Golang Integration","createdDate":"2021-12-22T01:38:43.000+0000","modifiedDate":"2021-12-22T01:38:43.000+0000"},{"telematicsClientDeviceKey":8207130,"deviceName":"Mac/iOS Chrome","createdDate":"2021-12-21T21:19:40.000+0000","modifiedDate":"2021-12-21T21:19:40.000+0000"}]}
|
||||||
|
|
||||||
// registerDevice .
|
// // registerDevice .
|
||||||
func (c *Client) registerDevice() bool {
|
// func (c *Client) registerDevice() bool {
|
||||||
// c.httpClient.
|
// // c.httpClient.
|
||||||
// SetBaseURL(WEB_API_SERVER[c.country]).
|
// // SetBaseURL(WEB_API_SERVER[c.country]).
|
||||||
// R().
|
// // R().
|
||||||
// SetFormData(map[string]string{
|
// // SetFormData(map[string]string{
|
||||||
// "username": c.credentials.username,
|
// // "username": c.credentials.username,
|
||||||
// "password": c.credentials.password,
|
// // "password": c.credentials.password,
|
||||||
// "deviceId": c.credentials.deviceId,
|
// // "deviceId": c.credentials.deviceId,
|
||||||
// }).
|
// // }).
|
||||||
// Post(apiURLs["WEB_API_LOGIN"])
|
// // Post(apiURLs["WEB_API_LOGIN"])
|
||||||
params := map[string]string{
|
// params := map[string]string{
|
||||||
"username": c.credentials.Username,
|
// "username": c.credentials.Username,
|
||||||
"password": c.credentials.Password,
|
// "password": c.credentials.Password,
|
||||||
"deviceId": c.credentials.DeviceID}
|
// "deviceId": c.credentials.DeviceID}
|
||||||
reqURL := WEB_API_SERVER[c.country] + apiURLs["WEB_API_LOGIN"]
|
// reqURL := WEB_API_SERVER[c.country] + apiURLs["WEB_API_LOGIN"]
|
||||||
c.execute(reqURL, POST, params, "", true)
|
// resp, _ := c.execute(POST, reqURL, params, true)
|
||||||
|
|
||||||
// Authorizing device via web API
|
// // Authorizing device via web API
|
||||||
// c.httpClient.
|
// // c.httpClient.
|
||||||
// SetBaseURL(WEB_API_SERVER[c.country]).
|
// // SetBaseURL(WEB_API_SERVER[c.country]).
|
||||||
// R().
|
// // R().
|
||||||
// SetQueryParams(map[string]string{
|
// // SetQueryParams(map[string]string{
|
||||||
// "deviceId": c.credentials.deviceId,
|
// // "deviceId": c.credentials.deviceId,
|
||||||
// }).
|
// // }).
|
||||||
// Get(apiURLs["WEB_API_AUTHORIZE_DEVICE"])
|
// // Get(apiURLs["WEB_API_AUTHORIZE_DEVICE"])
|
||||||
params = map[string]string{
|
// params = map[string]string{
|
||||||
"deviceId": c.credentials.DeviceID}
|
// "deviceId": c.credentials.DeviceID}
|
||||||
reqURL = WEB_API_SERVER[c.country] + apiURLs["WEB_API_AUTHORIZE_DEVICE"]
|
// reqURL = WEB_API_SERVER[c.country] + apiURLs["WEB_API_AUTHORIZE_DEVICE"]
|
||||||
c.execute(reqURL, GET, params, "", false)
|
// c.execute(reqURL, GET, params, "", false)
|
||||||
|
|
||||||
return c.setDeviceName()
|
// return c.setDeviceName()
|
||||||
}
|
// }
|
||||||
|
|
||||||
// setDeviceName .
|
// // setDeviceName .
|
||||||
func (c *Client) setDeviceName() bool {
|
// func (c *Client) setDeviceName() bool {
|
||||||
params := map[string]string{
|
// params := map[string]string{
|
||||||
"deviceId": c.credentials.DeviceID,
|
// "deviceId": c.credentials.DeviceID,
|
||||||
"deviceName": c.credentials.DeviceName}
|
// "deviceName": c.credentials.DeviceName}
|
||||||
reqURL := WEB_API_SERVER[c.country] + apiURLs["WEB_API_NAME_DEVICE"]
|
// reqURL := WEB_API_SERVER[c.country] + apiURLs["WEB_API_NAME_DEVICE"]
|
||||||
c.execute(reqURL, GET, params, "", false)
|
// c.execute(reqURL, GET, params, "", false)
|
||||||
|
|
||||||
return true
|
// return true
|
||||||
}
|
// }
|
||||||
|
|
||||||
// // listDevices .
|
// // listDevices .
|
||||||
// func (c *Client) listDevices() {
|
// func (c *Client) listDevices() {
|
||||||
@ -457,3 +418,45 @@ func (c *Client) setDeviceName() bool {
|
|||||||
// // logger.Debugf("LIST DEVICES OUTPUT >> %v\n", string(resp))
|
// // logger.Debugf("LIST DEVICES OUTPUT >> %v\n", string(resp))
|
||||||
// // }
|
// // }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// c.logger.Debug("parsed http request output", "data", r.Data)
|
||||||
|
|
||||||
|
// ERROR
|
||||||
|
// {"httpCode":500,"errorCode":"error","errorMessage":"org.springframework.web.HttpMediaTypeNotSupportedException - Content type 'application/x-www-form-urlencoded' not supported"}
|
||||||
|
// {"success":true,"errorCode":null,"dataName":"remoteServiceStatus","data":{"serviceRequestId":"4S4BTGND8L3137058_1640203129607_19_@NGTP","success":false,"cancelled":false,"remoteServiceType":"unlock","remoteServiceState":"started","subState":null,"errorCode":null,"result":null,"updateTime":null,"vin":"4S4BTGND8L3137058"}}
|
||||||
|
// API_REMOTE_SVC_STATUS
|
||||||
|
// {"success":false,"errorCode":"404-soa-unableToParseResponseBody","dataName":"errorResponse","data":{"errorLabel":"404-soa-unableToParseResponseBody","errorDescription":null}}
|
||||||
|
// if js_resp["errorCode"] == sc.ERROR_SOA_403:
|
||||||
|
// raise RemoteServiceFailure("Backend session expired, please try again")
|
||||||
|
// if js_resp["data"]["remoteServiceState"] == "finished":
|
||||||
|
// if js_resp["data"]["success"]:
|
||||||
|
// _LOGGER.info("Remote service request completed successfully: %s", req_id)
|
||||||
|
// return True, js_resp
|
||||||
|
// _LOGGER.error(
|
||||||
|
// "Remote service request completed but failed: %s Error: %s",
|
||||||
|
// req_id,
|
||||||
|
// js_resp["data"]["errorCode"],
|
||||||
|
// )
|
||||||
|
// raise RemoteServiceFailure(
|
||||||
|
// "Remote service request completed but failed: %s" % js_resp["data"]["errorCode"]
|
||||||
|
// )
|
||||||
|
// if js_resp["data"].get("remoteServiceState") == "started":
|
||||||
|
// _LOGGER.info(
|
||||||
|
// "Subaru API reports remote service request is in progress: %s",
|
||||||
|
// req_id,
|
||||||
|
// )
|
||||||
|
// attempts_left -= 1
|
||||||
|
// await asyncio.sleep(2)
|
||||||
|
|
||||||
|
// TODO: Work on errors
|
||||||
|
// error, _ := respParsed.Path("errorCode").Data().(string)
|
||||||
|
// switch {
|
||||||
|
// case error == apiErrors["ERROR_INVALID_ACCOUNT"]:
|
||||||
|
// client.logger.Debug("Invalid account")
|
||||||
|
// case error == apiErrors["ERROR_INVALID_CREDENTIALS"]:
|
||||||
|
// client.logger.Debug("Client authentication failed")
|
||||||
|
// case error == apiErrors["ERROR_PASSWORD_WARNING"]:
|
||||||
|
// client.logger.Debug("Multiple Password Failures.")
|
||||||
|
// default:
|
||||||
|
// client.logger.Debug("Uknown error")
|
||||||
|
// }
|
||||||
|
@ -102,6 +102,8 @@ var API_ERRORS = map[string]string{
|
|||||||
"passwordWarning": "ERROR_PASSWORD_WARNING",
|
"passwordWarning": "ERROR_PASSWORD_WARNING",
|
||||||
"accountLocked": "ERROR_ACCOUNT_LOCKED",
|
"accountLocked": "ERROR_ACCOUNT_LOCKED",
|
||||||
"noVehiclesOnAccount": "ERROR_NO_VEHICLES",
|
"noVehiclesOnAccount": "ERROR_NO_VEHICLES",
|
||||||
|
"noVehiclesAvailable": "ERROR_NO_VEHICLE_AVAILABLE",
|
||||||
|
"VEHICLESETUPERROR": "ERROR_VEHICLE_SETUP_ERROR", // Vehicle Select
|
||||||
"accountNotFound": "ERROR_NO_ACCOUNT",
|
"accountNotFound": "ERROR_NO_ACCOUNT",
|
||||||
"tooManyAttempts": "ERROR_TOO_MANY_ATTEMPTS",
|
"tooManyAttempts": "ERROR_TOO_MANY_ATTEMPTS",
|
||||||
"vehicleNotInAccount": "ERROR_VEHICLE_NOT_IN_ACCOUNT",
|
"vehicleNotInAccount": "ERROR_VEHICLE_NOT_IN_ACCOUNT",
|
||||||
@ -112,6 +114,10 @@ var API_ERRORS = map[string]string{
|
|||||||
"SXM40017": "ERROR_G1_PIN_LOCKED",
|
"SXM40017": "ERROR_G1_PIN_LOCKED",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var APP_ERRORS = map[string]string{
|
||||||
|
"SUBSCRIBTION_REQUIRED": "active STARLINK Security Plus subscription required",
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Get back and add error wrapper
|
// TODO: Get back and add error wrapper
|
||||||
// var apiErrors = map[string]string{
|
// var apiErrors = map[string]string{
|
||||||
// "ERROR_SOA_403": "403-soa-unableToParseResponseBody", // G2 Error Codes
|
// "ERROR_SOA_403": "403-soa-unableToParseResponseBody", // G2 Error Codes
|
||||||
|
1
go.mod
1
go.mod
@ -11,6 +11,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/kr/pretty v0.3.1 // indirect
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
|
github.com/neilotoole/slogt v1.1.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
golang.org/x/net v0.41.0 // indirect
|
golang.org/x/net v0.41.0 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||||
|
43
mysubaru.go
43
mysubaru.go
@ -25,6 +25,27 @@ type Response struct {
|
|||||||
// Unmarshal .
|
// Unmarshal .
|
||||||
// func (r *Response) Unmarshal(b []byte) {}
|
// func (r *Response) Unmarshal(b []byte) {}
|
||||||
|
|
||||||
|
// Request .
|
||||||
|
type Request struct {
|
||||||
|
Vin string `json:"vin"` //
|
||||||
|
Pin string `json:"pin"` //
|
||||||
|
Delay int `json:"delay,string,omitempty"` //
|
||||||
|
ForceKeyInCar *bool `json:"forceKeyInCar,string,omitempty"` //
|
||||||
|
UnlockDoorType *string `json:"unlockDoorType,omitempty"` // [ ALL_DOORS_CMD | FRONT_LEFT_DOOR_CMD | ALL_DOORS_CMD ]
|
||||||
|
Horn *string `json:"horn,omitempty"` //
|
||||||
|
ClimateSettings *string `json:"climateSettings,omitempty"` //
|
||||||
|
ClimateZoneFrontTemp *string `json:"climateZoneFrontTemp,omitempty"` //
|
||||||
|
ClimateZoneFrontAirMode *string `json:"climateZoneFrontAirMode,omitempty"` //
|
||||||
|
ClimateZoneFrontAirVolume *string `json:"climateZoneFrontAirVolume,omitempty"` //
|
||||||
|
HeatedSeatFrontLeft *string `json:"heatedSeatFrontLeft,omitempty"` //
|
||||||
|
HeatedSeatFrontRight *string `json:"heatedSeatFrontRight,omitempty"` //
|
||||||
|
HeatedRearWindowActive *string `json:"heatedRearWindowActive,omitempty"` //
|
||||||
|
OuterAirCirculation *string `json:"outerAirCirculation,omitempty"` //
|
||||||
|
AirConditionOn *string `json:"airConditionOn,omitempty"` //
|
||||||
|
RunTimeMinutes *string `json:"runTimeMinutes,omitempty"` //
|
||||||
|
StartConfiguration *string `json:"startConfiguration,omitempty"` //
|
||||||
|
}
|
||||||
|
|
||||||
// Account .
|
// Account .
|
||||||
type Account struct {
|
type Account struct {
|
||||||
MarketID int `json:"marketId"`
|
MarketID int `json:"marketId"`
|
||||||
@ -277,17 +298,6 @@ type ServiceRequest struct {
|
|||||||
Vin string `json:"vin"` // 4S4BTGND8L3137058
|
Vin string `json:"vin"` // 4S4BTGND8L3137058
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrorResponse .
|
|
||||||
// "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}
|
|
||||||
// {"httpCode":500,"errorCode":"error","errorMessage":"java.lang.NullPointerException - 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// climateSettings: [ climateSettings ]
|
// climateSettings: [ climateSettings ]
|
||||||
// climateZoneFrontTempCelsius: [for _ in range(15, 30 + 1)]
|
// climateZoneFrontTempCelsius: [for _ in range(15, 30 + 1)]
|
||||||
// climateZoneFrontTemp: [for _ in range(60, 85 + 1)]
|
// climateZoneFrontTemp: [for _ in range(60, 85 + 1)]
|
||||||
@ -313,3 +323,14 @@ type VehicleHealthItem struct {
|
|||||||
OnDates []int64 `json:"onDates,omitempty"` // List of the timestamps
|
OnDates []int64 `json:"onDates,omitempty"` // List of the timestamps
|
||||||
WarningCode int `json:"warningCode"`
|
WarningCode int `json:"warningCode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrorResponse .
|
||||||
|
// "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}
|
||||||
|
// {"httpCode":500,"errorCode":"error","errorMessage":"java.lang.NullPointerException - 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
|
||||||
|
}
|
||||||
|
420
vehicle.go
420
vehicle.go
@ -2,6 +2,7 @@ package mysubaru
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -212,9 +213,15 @@ func (v *Vehicle) String() string {
|
|||||||
|
|
||||||
// Lock .
|
// Lock .
|
||||||
// Sends a command to lock doors.
|
// Sends a command to lock doors.
|
||||||
func (v *Vehicle) Lock() {
|
func (v *Vehicle) Lock() (chan string, error) {
|
||||||
if v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return nil, errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"delay": "0",
|
"delay": "0",
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
@ -222,17 +229,26 @@ func (v *Vehicle) Lock() {
|
|||||||
"forceKeyInCar": "false"}
|
"forceKeyInCar": "false"}
|
||||||
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_LOCK"], v.getAPIGen())
|
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_LOCK"], v.getAPIGen())
|
||||||
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
||||||
v.client.execute(reqURL, POST, params, pollingURL, true)
|
ch := make(chan string)
|
||||||
} else {
|
go func() {
|
||||||
v.client.logger.Error("active STARLINK Security Plus subscription required")
|
defer close(ch)
|
||||||
}
|
v.executeServiceRequest(params, reqURL, pollingURL, ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock .
|
// Unlock .
|
||||||
// Send command to unlock doors.
|
// Send command to unlock doors.
|
||||||
func (v *Vehicle) Unlock() {
|
func (v *Vehicle) Unlock() (chan string, error) {
|
||||||
if v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return nil, errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"delay": "0",
|
"delay": "0",
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
@ -240,43 +256,26 @@ func (v *Vehicle) Unlock() {
|
|||||||
"unlockDoorType": "ALL_DOORS_CMD"} // FRONT_LEFT_DOOR_CMD | ALL_DOORS_CMD
|
"unlockDoorType": "ALL_DOORS_CMD"} // FRONT_LEFT_DOOR_CMD | ALL_DOORS_CMD
|
||||||
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_UNLOCK"], v.getAPIGen())
|
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_UNLOCK"], v.getAPIGen())
|
||||||
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
||||||
v.client.execute(reqURL, POST, params, pollingURL, true)
|
ch := make(chan string)
|
||||||
} else {
|
go func() {
|
||||||
v.client.logger.Error("active STARLINK Security Plus subscription required")
|
defer close(ch)
|
||||||
}
|
v.executeServiceRequest(params, reqURL, pollingURL, ch)
|
||||||
// ERROR
|
}()
|
||||||
// {"httpCode":500,"errorCode":"error","errorMessage":"org.springframework.web.HttpMediaTypeNotSupportedException - Content type 'application/x-www-form-urlencoded' not supported"}
|
|
||||||
// {"success":true,"errorCode":null,"dataName":"remoteServiceStatus","data":{"serviceRequestId":"4S4BTGND8L3137058_1640203129607_19_@NGTP","success":false,"cancelled":false,"remoteServiceType":"unlock","remoteServiceState":"started","subState":null,"errorCode":null,"result":null,"updateTime":null,"vin":"4S4BTGND8L3137058"}}
|
return ch, nil
|
||||||
// API_REMOTE_SVC_STATUS
|
|
||||||
// {"success":false,"errorCode":"404-soa-unableToParseResponseBody","dataName":"errorResponse","data":{"errorLabel":"404-soa-unableToParseResponseBody","errorDescription":null}}
|
|
||||||
// if js_resp["errorCode"] == sc.ERROR_SOA_403:
|
|
||||||
// raise RemoteServiceFailure("Backend session expired, please try again")
|
|
||||||
// if js_resp["data"]["remoteServiceState"] == "finished":
|
|
||||||
// if js_resp["data"]["success"]:
|
|
||||||
// _LOGGER.info("Remote service request completed successfully: %s", req_id)
|
|
||||||
// return True, js_resp
|
|
||||||
// _LOGGER.error(
|
|
||||||
// "Remote service request completed but failed: %s Error: %s",
|
|
||||||
// req_id,
|
|
||||||
// js_resp["data"]["errorCode"],
|
|
||||||
// )
|
|
||||||
// raise RemoteServiceFailure(
|
|
||||||
// "Remote service request completed but failed: %s" % js_resp["data"]["errorCode"]
|
|
||||||
// )
|
|
||||||
// if js_resp["data"].get("remoteServiceState") == "started":
|
|
||||||
// _LOGGER.info(
|
|
||||||
// "Subaru API reports remote service request is in progress: %s",
|
|
||||||
// req_id,
|
|
||||||
// )
|
|
||||||
// attempts_left -= 1
|
|
||||||
// await asyncio.sleep(2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EngineStart .
|
// EngineStart .
|
||||||
// Sends a command to start engine and set climate control.
|
// Sends a command to start engine and set climate control.
|
||||||
func (v *Vehicle) EngineStart() {
|
func (v *Vehicle) EngineStart() (chan string, error) {
|
||||||
if v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return nil, errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
// TODO: Get Quick Climate Preset from the Currect Car
|
// TODO: Get Quick Climate Preset from the Currect Car
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"delay": "0",
|
"delay": "0",
|
||||||
@ -297,34 +296,52 @@ func (v *Vehicle) EngineStart() {
|
|||||||
}
|
}
|
||||||
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_REMOTE_ENGINE_START"]
|
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_REMOTE_ENGINE_START"]
|
||||||
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
||||||
v.client.execute(reqURL, POST, params, pollingURL, true)
|
ch := make(chan string)
|
||||||
} else {
|
go func() {
|
||||||
v.client.logger.Error("active STARLINK Security Plus subscription required")
|
defer close(ch)
|
||||||
}
|
v.executeServiceRequest(params, reqURL, pollingURL, ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EngineStop .
|
// EngineStop .
|
||||||
// Sends a command to stop engine.
|
// Sends a command to stop engine.
|
||||||
func (v *Vehicle) EngineStop() {
|
func (v *Vehicle) EngineStop() (chan string, error) {
|
||||||
if v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return nil, errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"delay": "0",
|
"delay": "0",
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
"pin": v.client.credentials.PIN}
|
"pin": v.client.credentials.PIN}
|
||||||
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_REMOTE_ENGINE_STOP"]
|
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_REMOTE_ENGINE_STOP"]
|
||||||
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
||||||
v.client.execute(reqURL, POST, params, pollingURL, true)
|
|
||||||
} else {
|
ch := make(chan string)
|
||||||
v.client.logger.Error("Active STARLINK Security Plus subscription required")
|
go func() {
|
||||||
}
|
defer close(ch)
|
||||||
|
v.executeServiceRequest(params, reqURL, pollingURL, ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LightsStart .
|
// LightsStart .
|
||||||
// Sends a command to flash lights.
|
// Sends a command to flash lights.
|
||||||
func (v *Vehicle) LightsStart() {
|
func (v *Vehicle) LightsStart() (chan string, error) {
|
||||||
if v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return nil, errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"delay": "0",
|
"delay": "0",
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
@ -334,17 +351,25 @@ func (v *Vehicle) LightsStart() {
|
|||||||
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
||||||
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
||||||
}
|
}
|
||||||
v.client.execute(reqURL, POST, params, pollingURL, true)
|
ch := make(chan string)
|
||||||
} else {
|
go func() {
|
||||||
v.client.logger.Error("active STARLINK Security Plus subscription required")
|
defer close(ch)
|
||||||
}
|
v.executeServiceRequest(params, reqURL, pollingURL, ch)
|
||||||
|
}()
|
||||||
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LightsStop .
|
// LightsStop .
|
||||||
// Sends a command to stop flash lights.
|
// Sends a command to stop flash lights.
|
||||||
func (v *Vehicle) LightsStop() {
|
func (v *Vehicle) LightsStop() (chan string, error) {
|
||||||
if v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return nil, errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"delay": "0",
|
"delay": "0",
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
@ -354,17 +379,25 @@ func (v *Vehicle) LightsStop() {
|
|||||||
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
||||||
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
||||||
}
|
}
|
||||||
v.client.execute(reqURL, POST, params, pollingURL, true)
|
ch := make(chan string)
|
||||||
} else {
|
go func() {
|
||||||
v.client.logger.Error("active STARLINK Security Plus subscription required")
|
defer close(ch)
|
||||||
}
|
v.executeServiceRequest(params, reqURL, pollingURL, ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HornStart .
|
// HornStart .
|
||||||
// Send command to sound horn.
|
// Send command to sound horn.
|
||||||
func (v *Vehicle) HornStart() {
|
func (v *Vehicle) HornStart() (chan string, error) {
|
||||||
if v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return nil, errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"delay": "0",
|
"delay": "0",
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
@ -374,17 +407,26 @@ func (v *Vehicle) HornStart() {
|
|||||||
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
||||||
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
||||||
}
|
}
|
||||||
v.client.execute(reqURL, POST, params, pollingURL, true)
|
ch := make(chan string)
|
||||||
} else {
|
go func() {
|
||||||
v.client.logger.Error("active STARLINK Security Plus subscription required")
|
defer close(ch)
|
||||||
}
|
v.executeServiceRequest(params, reqURL, pollingURL, ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HornStop .
|
// HornStop .
|
||||||
// Send command to sound horn.
|
// Send command to sound horn.
|
||||||
func (v *Vehicle) HornStop() {
|
func (v *Vehicle) HornStop() (chan string, error) {
|
||||||
if v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return nil, errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"delay": "0",
|
"delay": "0",
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
@ -394,48 +436,142 @@ func (v *Vehicle) HornStop() {
|
|||||||
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
||||||
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
||||||
}
|
}
|
||||||
v.client.execute(reqURL, POST, params, pollingURL, true)
|
ch := make(chan string)
|
||||||
} else {
|
go func() {
|
||||||
v.client.logger.Error("Active STARLINK Security Plus subscription required")
|
defer close(ch)
|
||||||
}
|
v.executeServiceRequest(params, reqURL, pollingURL, ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChargeStart .
|
// ChargeStart .
|
||||||
func (v *Vehicle) ChargeOn() {
|
func (v *Vehicle) ChargeOn() (chan string, error) {
|
||||||
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return nil, errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
if v.isEV() {
|
if v.isEV() {
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"delay": "0",
|
"delay": "0",
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
"pin": v.client.credentials.PIN}
|
"pin": v.client.credentials.PIN}
|
||||||
reqURL := MOBILE_API_VERSION + apiURLs["API_EV_CHARGE_NOW"]
|
reqURL := MOBILE_API_VERSION + apiURLs["API_EV_CHARGE_NOW"]
|
||||||
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
||||||
v.client.execute(reqURL, POST, params, pollingURL, true)
|
ch := make(chan string)
|
||||||
|
go func() {
|
||||||
|
defer close(ch)
|
||||||
|
v.executeServiceRequest(params, reqURL, pollingURL, ch)
|
||||||
|
}()
|
||||||
|
return ch, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("not an EV car")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLocation .
|
// GetLocation .
|
||||||
func (v *Vehicle) GetLocation(force bool) {
|
func (v *Vehicle) GetLocation(force bool) (chan string, error) {
|
||||||
if force { // Sends a locate command to the vehicle to get real time position
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return nil, errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
|
||||||
|
var reqURL, pollingURL string
|
||||||
|
var params map[string]string
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_LOCATE_UPDATE"]
|
}
|
||||||
pollingURL := MOBILE_API_VERSION + apiURLs["API_G2_LOCATE_STATUS"]
|
if force { // Sends a locate command to the vehicle to get real time position
|
||||||
params := map[string]string{
|
reqURL = MOBILE_API_VERSION + apiURLs["API_G2_LOCATE_UPDATE"]
|
||||||
|
pollingURL = MOBILE_API_VERSION + apiURLs["API_G2_LOCATE_STATUS"]
|
||||||
|
params = map[string]string{
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
"pin": v.client.credentials.PIN}
|
"pin": v.client.credentials.PIN}
|
||||||
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
||||||
reqURL = MOBILE_API_VERSION + apiURLs["API_G1_LOCATE_UPDATE"]
|
reqURL = MOBILE_API_VERSION + apiURLs["API_G1_LOCATE_UPDATE"]
|
||||||
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_LOCATE_STATUS"]
|
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_LOCATE_STATUS"]
|
||||||
}
|
}
|
||||||
v.client.execute(reqURL, POST, params, pollingURL, true)
|
|
||||||
} else { // Reports the last location the vehicle has reported to Subaru
|
} else { // Reports the last location the vehicle has reported to Subaru
|
||||||
v.selectVehicle()
|
params = map[string]string{
|
||||||
params := map[string]string{
|
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
"pin": v.client.credentials.PIN}
|
"pin": v.client.credentials.PIN}
|
||||||
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_LOCATE"], v.getAPIGen())
|
reqURL = MOBILE_API_VERSION + urlToGen(apiURLs["API_LOCATE"], v.getAPIGen())
|
||||||
v.client.execute(reqURL, GET, params, "", false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simulate sending multiple messages to the channel
|
||||||
|
// go func() {
|
||||||
|
// defer close(msgChan) // Close the channel when the goroutine finishes
|
||||||
|
|
||||||
|
// for i := 1; i <= numMessages; i++ {
|
||||||
|
// // Simulate some work or delay before sending the message
|
||||||
|
// time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
|
// msg := Message{
|
||||||
|
// Content: fmt.Sprintf("Message %d", i),
|
||||||
|
// Success: true, // Indicate success for each message
|
||||||
|
// }
|
||||||
|
// msgChan <- msg
|
||||||
|
// fmt.Printf("Sent: %s (Success: %t)\n", msg.Content, msg.Success)
|
||||||
|
// }
|
||||||
|
// }()
|
||||||
|
|
||||||
|
ch := make(chan string)
|
||||||
|
go func() {
|
||||||
|
defer close(ch)
|
||||||
|
v.executeServiceRequest(params, reqURL, pollingURL, ch)
|
||||||
|
}()
|
||||||
|
return ch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeServiceRequest
|
||||||
|
func (v *Vehicle) executeServiceRequest(params map[string]string, reqURL, pollingURL string, ch chan string) error {
|
||||||
|
if v.Vin != v.client.currentVin {
|
||||||
|
v.selectVehicle()
|
||||||
|
}
|
||||||
|
resp, _ := v.client.execute(reqURL, POST, params, true)
|
||||||
|
|
||||||
|
// dataName field has the list of the states [ remoteServiceStatus | errorResponse ]
|
||||||
|
if resp.DataName == "remoteServiceStatus" {
|
||||||
|
if sr, ok := v.parseServiceRequest([]byte(resp.Data)); ok {
|
||||||
|
switch {
|
||||||
|
case sr.RemoteServiceState == "finished":
|
||||||
|
// Finished RemoteServiceState Service Request does not include Service Request ID
|
||||||
|
v.client.logger.Debug("Remote service request completed successfully")
|
||||||
|
ch <- sr.RemoteServiceState
|
||||||
|
case sr.RemoteServiceState == "started":
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
v.client.logger.Debug("Subaru API reports remote service request (started) is in progress", "id", sr.ServiceRequestID)
|
||||||
|
v.executeServiceRequest(map[string]string{"serviceRequestId": sr.ServiceRequestID}, reqURL, pollingURL, ch)
|
||||||
|
ch <- sr.RemoteServiceState
|
||||||
|
case sr.RemoteServiceState == "stopping":
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
v.client.logger.Debug("Subaru API reports remote service request (stopping) is in progress", "id", sr.ServiceRequestID)
|
||||||
|
v.executeServiceRequest(map[string]string{"serviceRequestId": sr.ServiceRequestID}, reqURL, pollingURL, ch)
|
||||||
|
ch <- sr.RemoteServiceState
|
||||||
|
default:
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
v.client.logger.Debug("Subaru API reports remote service request (stopping) is in progress")
|
||||||
|
v.executeServiceRequest(map[string]string{"serviceRequestId": sr.ServiceRequestID}, reqURL, pollingURL, ch)
|
||||||
|
ch <- sr.RemoteServiceState
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors.New("response is not a service request")
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseServiceRequest .
|
||||||
|
func (v *Vehicle) parseServiceRequest(b []byte) (ServiceRequest, bool) {
|
||||||
|
var sr ServiceRequest
|
||||||
|
err := json.Unmarshal(b, &sr)
|
||||||
|
if err != nil {
|
||||||
|
v.client.logger.Error("error while parsing service request json", "error", err.Error())
|
||||||
|
return sr, false
|
||||||
|
}
|
||||||
|
return sr, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClimatePresets connects to the MySubaru API to download available climate presets.
|
// GetClimatePresets connects to the MySubaru API to download available climate presets.
|
||||||
@ -443,16 +579,19 @@ func (v *Vehicle) GetLocation(force bool) {
|
|||||||
// If successful and climate presets are found for the user's vehicle,
|
// If successful and climate presets are found for the user's vehicle,
|
||||||
// it downloads them. If no presets are available, or if the connection fails,
|
// it downloads them. If no presets are available, or if the connection fails,
|
||||||
// appropriate handling should be implemented within the function.
|
// appropriate handling should be implemented within the function.
|
||||||
func (v *Vehicle) GetClimatePresets() {
|
func (v *Vehicle) GetClimatePresets() error {
|
||||||
if v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_RES_SUBARU_PRESETS"]
|
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_RES_SUBARU_PRESETS"]
|
||||||
resp := v.client.execute(reqURL, GET, map[string]string{}, "", false)
|
resp, _ := v.client.execute(GET, reqURL, map[string]string{}, false)
|
||||||
|
|
||||||
if r, ok := v.client.parseResponse(resp); ok {
|
|
||||||
|
|
||||||
re1 := regexp.MustCompile(`\"`)
|
re1 := regexp.MustCompile(`\"`)
|
||||||
result := re1.ReplaceAllString(string(r.Data), "")
|
result := re1.ReplaceAllString(string(resp.Data), "")
|
||||||
re2 := regexp.MustCompile(`\\`)
|
re2 := regexp.MustCompile(`\\`)
|
||||||
result = re2.ReplaceAllString(result, `"`) // \u0022
|
result = re2.ReplaceAllString(result, `"`) // \u0022
|
||||||
|
|
||||||
@ -494,25 +633,25 @@ func (v *Vehicle) GetClimatePresets() {
|
|||||||
v.client.logger.Debug("couldn't find any subaru climate presets")
|
v.client.logger.Debug("couldn't find any subaru climate presets")
|
||||||
}
|
}
|
||||||
v.Updated = time.Now()
|
v.Updated = time.Now()
|
||||||
}
|
return nil
|
||||||
} else {
|
|
||||||
v.client.logger.Error("active STARLINK Security Plus subscription required")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClimateQuickPresets
|
// GetClimateQuickPresets
|
||||||
// Used while user uses "quick start engine" button in the app
|
// Used while user uses "quick start engine" button in the app
|
||||||
func (v *Vehicle) GetClimateQuickPresets() {
|
func (v *Vehicle) GetClimateQuickPresets() error {
|
||||||
if v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_RES_QUICK_START_SETTINGS"]
|
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_RES_QUICK_START_SETTINGS"]
|
||||||
resp := v.client.execute(reqURL, GET, map[string]string{}, "", false)
|
resp, _ := v.client.execute(GET, reqURL, map[string]string{}, false)
|
||||||
// v.client.logger.Debug("http request output", "request", "GetClimateQuickPresets", "body", resp)
|
// v.client.logger.Debug("http request output", "request", "GetClimateQuickPresets", "body", resp)
|
||||||
|
|
||||||
if r, ok := v.client.parseResponse(resp); ok {
|
|
||||||
|
|
||||||
re1 := regexp.MustCompile(`\"`)
|
re1 := regexp.MustCompile(`\"`)
|
||||||
result := re1.ReplaceAllString(string(r.Data), "")
|
result := re1.ReplaceAllString(string(resp.Data), "")
|
||||||
re2 := regexp.MustCompile(`\\`)
|
re2 := regexp.MustCompile(`\\`)
|
||||||
result = re2.ReplaceAllString(result, `"`) // \u0022
|
result = re2.ReplaceAllString(result, `"`) // \u0022
|
||||||
|
|
||||||
@ -531,23 +670,23 @@ func (v *Vehicle) GetClimateQuickPresets() {
|
|||||||
v.ClimateProfiles[cpn] = cp
|
v.ClimateProfiles[cpn] = cp
|
||||||
}
|
}
|
||||||
v.Updated = time.Now()
|
v.Updated = time.Now()
|
||||||
}
|
return nil
|
||||||
} else {
|
|
||||||
v.client.logger.Error("active STARLINK Security Plus subscription required")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClimateUserPresets .
|
// GetClimateUserPresets .
|
||||||
func (v *Vehicle) GetClimateUserPresets() {
|
func (v *Vehicle) GetClimateUserPresets() error {
|
||||||
if v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_RES_USER_PRESETS"]
|
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_RES_USER_PRESETS"]
|
||||||
resp := v.client.execute(reqURL, GET, map[string]string{}, "", false)
|
resp, _ := v.client.execute(GET, reqURL, map[string]string{}, false)
|
||||||
|
|
||||||
if r, ok := v.client.parseResponse(resp); ok {
|
|
||||||
|
|
||||||
re1 := regexp.MustCompile(`\"`)
|
re1 := regexp.MustCompile(`\"`)
|
||||||
result := re1.ReplaceAllString(string(r.Data), "")
|
result := re1.ReplaceAllString(string(resp.Data), "")
|
||||||
re2 := regexp.MustCompile(`\\`)
|
re2 := regexp.MustCompile(`\\`)
|
||||||
result = re2.ReplaceAllString(result, `"`) // \u0022
|
result = re2.ReplaceAllString(result, `"`) // \u0022
|
||||||
|
|
||||||
@ -576,22 +715,24 @@ func (v *Vehicle) GetClimateUserPresets() {
|
|||||||
v.client.logger.Debug("couldn't find any user climate presets")
|
v.client.logger.Debug("couldn't find any user climate presets")
|
||||||
}
|
}
|
||||||
v.Updated = time.Now()
|
v.Updated = time.Now()
|
||||||
}
|
return nil
|
||||||
} else {
|
|
||||||
v.client.logger.Error("active STARLINK Security Plus subscription required")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVehicleStatus .
|
// GetVehicleStatus .
|
||||||
func (v *Vehicle) GetVehicleStatus() {
|
func (v *Vehicle) GetVehicleStatus() error {
|
||||||
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_VEHICLE_STATUS"], v.getAPIGen())
|
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_VEHICLE_STATUS"], v.getAPIGen())
|
||||||
resp := v.client.execute(reqURL, GET, map[string]string{}, "", false)
|
resp, _ := v.client.execute(GET, reqURL, map[string]string{}, false)
|
||||||
// v.client.logger.Info("http request output", "request", "GetVehicleStatus", "body", resp)
|
// v.client.logger.Info("http request output", "request", "GetVehicleStatus", "body", resp)
|
||||||
|
|
||||||
if r, ok := v.client.parseResponse(resp); ok {
|
|
||||||
var vs VehicleStatus
|
var vs VehicleStatus
|
||||||
err := json.Unmarshal(r.Data, &vs)
|
err := json.Unmarshal(resp.Data, &vs)
|
||||||
if err != nil {
|
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", "GetVehicleStatus", "error", err.Error())
|
||||||
}
|
}
|
||||||
@ -631,19 +772,24 @@ func (v *Vehicle) GetVehicleStatus() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
v.Updated = time.Now()
|
v.Updated = time.Now()
|
||||||
}
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVehicleCondition .
|
// GetVehicleCondition .
|
||||||
func (v *Vehicle) GetVehicleCondition() {
|
func (v *Vehicle) GetVehicleCondition() error {
|
||||||
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_CONDITION"], v.getAPIGen())
|
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_CONDITION"], v.getAPIGen())
|
||||||
resp := v.client.execute(reqURL, GET, map[string]string{}, "", false)
|
resp, _ := v.client.execute(GET, reqURL, map[string]string{}, false)
|
||||||
// v.client.logger.Info("http request output", "request", "GetVehicleCondition", "body", resp)
|
// v.client.logger.Info("http request output", "request", "GetVehicleCondition", "body", resp)
|
||||||
|
|
||||||
if r, ok := v.client.parseResponse(resp); ok {
|
|
||||||
var sr ServiceRequest
|
var sr ServiceRequest
|
||||||
err := json.Unmarshal(r.Data, &sr)
|
err := json.Unmarshal(resp.Data, &sr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
v.client.logger.Error("error while parsing json", "request", "GetVehicleCondition", "error", err.Error())
|
v.client.logger.Error("error while parsing json", "request", "GetVehicleCondition", "error", err.Error())
|
||||||
}
|
}
|
||||||
@ -675,22 +821,27 @@ func (v *Vehicle) GetVehicleCondition() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
v.Updated = time.Now()
|
v.Updated = time.Now()
|
||||||
}
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVehicleHealth .
|
// GetVehicleHealth .
|
||||||
func (v *Vehicle) GetVehicleHealth() {
|
func (v *Vehicle) GetVehicleHealth() error {
|
||||||
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
v.selectVehicle()
|
v.selectVehicle()
|
||||||
|
}
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
"_": timestamp()}
|
"_": timestamp()}
|
||||||
reqURL := MOBILE_API_VERSION + apiURLs["API_VEHICLE_HEALTH"]
|
reqURL := MOBILE_API_VERSION + apiURLs["API_VEHICLE_HEALTH"]
|
||||||
resp := v.client.execute(reqURL, GET, params, "", false)
|
resp, _ := v.client.execute(GET, reqURL, params, false)
|
||||||
// v.client.logger.Debug("http request output", "request", "GetVehicleHealth", "body", resp)
|
// v.client.logger.Debug("http request output", "request", "GetVehicleHealth", "body", resp)
|
||||||
|
|
||||||
if r, ok := v.client.parseResponse(resp); ok {
|
|
||||||
var vh VehicleHealth
|
var vh VehicleHealth
|
||||||
err := json.Unmarshal(r.Data, &vh)
|
err := json.Unmarshal(resp.Data, &vh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
v.client.logger.Error("error while parsing json", "request", "GetVehicleHealth", "error", err.Error())
|
v.client.logger.Error("error while parsing json", "request", "GetVehicleHealth", "error", err.Error())
|
||||||
}
|
}
|
||||||
@ -708,9 +859,7 @@ func (v *Vehicle) GetVehicleHealth() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
return nil
|
||||||
v.client.logger.Error("active STARLINK Security Plus subscription required")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFeaturesList .
|
// GetFeaturesList .
|
||||||
@ -727,7 +876,10 @@ func (v *Vehicle) GetFeaturesList() {
|
|||||||
// selectVehicle .
|
// selectVehicle .
|
||||||
func (v *Vehicle) selectVehicle() {
|
func (v *Vehicle) selectVehicle() {
|
||||||
if v.client.currentVin != v.Vin {
|
if v.client.currentVin != v.Vin {
|
||||||
vData := (*v.client).SelectVehicle(v.Vin)
|
vData, err := (v.client).SelectVehicle(v.Vin)
|
||||||
|
if err != nil {
|
||||||
|
v.client.logger.Debug("cannot get vehicle data")
|
||||||
|
}
|
||||||
v.SubscriptionStatus = vData.SubscriptionStatus
|
v.SubscriptionStatus = vData.SubscriptionStatus
|
||||||
v.GeoLocation.Latitude = vData.VehicleGeoPosition.Latitude
|
v.GeoLocation.Latitude = vData.VehicleGeoPosition.Latitude
|
||||||
v.GeoLocation.Longitude = vData.VehicleGeoPosition.Longitude
|
v.GeoLocation.Longitude = vData.VehicleGeoPosition.Longitude
|
||||||
|
Reference in New Issue
Block a user