Compare commits

...

3 Commits

Author SHA1 Message Date
1d8d175be0 Refactor vehicle command functions to improve readability and maintainability
All checks were successful
Golan Testing / testing (1.24.x, ubuntu-latest) (push) Successful in 25s
2025-07-06 17:33:34 -04:00
ac19db1271 Update mobile API version to v2.31 2025-07-06 17:33:26 -04:00
f850b55b52 Add methods for two-factor authentication and vehicle refresh functionality 2025-07-06 17:33:22 -04:00
3 changed files with 85 additions and 4 deletions

View File

@ -7,6 +7,7 @@ import (
"log/slog"
"slices"
"sync"
"time"
"git.savin.nyc/alex/mysubaru/config"
"resty.dev/v3"
@ -196,8 +197,81 @@ func (c *Client) GetVehicleByVin(vin string) (*Vehicle, error) {
return nil, errors.New("vin code is not in the list of the available vin codes")
}
// RefreshVehicles refreshes the list of vehicles associated with the client's account.
func (c *Client) RefreshVehicles() error {
params := map[string]string{}
reqURL := MOBILE_API_VERSION + apiURLs["API_REFRESH_VEHICLES"]
resp, err := c.execute(GET, reqURL, params, false)
if err != nil {
c.logger.Error("error while executing RefreshVehicles request", "request", "RefreshVehicles", "error", err.Error())
return errors.New("error while executing RefreshVehicles request: " + err.Error())
}
c.logger.Debug("http request output", "request", "RefreshVehicles", "body", resp)
// var vd VehicleData
// err = json.Unmarshal(resp.Data, &vd)
// if err != nil {
// c.logger.Error("error while parsing json", "request", "SelectVehicle", "error", err.Error())
// return errors.New("error while parsing json while vehicle selection")
// }
// c.logger.Debug("http request output", "request", "SelectVehicle", "body", resp)
return nil
}
// RequestAuthCode requests an authentication code for two-factor authentication (2FA).
func (c *Client) RequestAuthCode() error {
params := map[string]string{
"contactMethod": "0",
"languagePreference": "EN"}
reqUrl := MOBILE_API_VERSION + apiURLs["API_2FA_SEND_VERIFICATION"]
resp, err := c.execute(POST, reqUrl, params, false)
if err != nil {
c.logger.Error("error while executing RequestAuthCode request", "request", "RequestAuthCode", "error", err.Error())
return errors.New("error while executing RequestAuthCode request: " + err.Error())
}
c.logger.Debug("http request output", "request", "RequestAuthCode", "body", resp)
return nil
}
// SubmitAuthCode submits the authentication code received from the RequestAuthCode method.
func (c *Client) SubmitAuthCode(code string, permanent bool) error {
params := map[string]string{
"deviceId": c.credentials.DeviceID,
"deviceName": c.credentials.DeviceName,
"verificationCode": code}
if permanent {
params["rememberDevice"] = "on"
}
reqUrl := MOBILE_API_VERSION + apiURLs["API_2FA_AUTH_VERIFY"]
resp, err := c.execute(POST, reqUrl, params, false)
if err != nil {
c.logger.Error("error while executing SubmitAuthCode request", "request", "SubmitAuthCode", "error", err.Error())
return errors.New("error while executing SubmitAuthCode request: " + err.Error())
}
// Device registration does not always immediately take effect
time.Sleep(time.Second * 3)
c.logger.Debug("http request output", "request", "SubmitAuthCode", "body", resp)
return nil
}
// getContactMethods retrieves the available contact methods for two-factor authentication (2FA).
func (c *Client) GetContactMethods() error {
params := map[string]string{}
reqUrl := MOBILE_API_VERSION + apiURLs["API_2FA_CONTACT"]
resp, err := c.execute(POST, reqUrl, params, false)
if err != nil {
c.logger.Error("error while executing GetContactMethods request", "request", "GetContactMethods", "error", err.Error())
return errors.New("error while executing GetContactMethods request: " + err.Error())
}
c.logger.Debug("http request output", "request", "GetContactMethods", "body", resp)
return nil
}
// func isPINRequired() {}
// func getVehicles() {}
// func getEVStatus() {}
// func getRemoteOptionsStatus() {}
// func getRemoteStartStatus() {}

View File

@ -1,6 +1,6 @@
package mysubaru
var MOBILE_API_VERSION = "/g2v30"
var MOBILE_API_VERSION = "/g2v31"
var MOBILE_API_SERVER = map[string]string{
"USA": "https://mobileapi.prod.subarucs.com",

View File

@ -226,6 +226,7 @@ func (v *Vehicle) Lock() (chan string, error) {
"forceKeyInCar": "false"}
reqUrl := MOBILE_API_VERSION + urlToGen(apiURLs["API_LOCK"], v.getAPIGen())
pollingUrl := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
ch := make(chan string)
go func() {
defer close(ch)
@ -250,6 +251,7 @@ func (v *Vehicle) Unlock() (chan string, error) {
"unlockDoorType": "ALL_DOORS_CMD"} // FRONT_LEFT_DOOR_CMD | ALL_DOORS_CMD
reqUrl := MOBILE_API_VERSION + urlToGen(apiURLs["API_UNLOCK"], v.getAPIGen())
pollingUrl := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
ch := make(chan string)
go func() {
defer close(ch)
@ -287,6 +289,7 @@ func (v *Vehicle) EngineStart() (chan string, error) {
}
reqUrl := MOBILE_API_VERSION + apiURLs["API_G2_REMOTE_ENGINE_START"]
pollingUrl := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
ch := make(chan string)
go func() {
defer close(ch)
@ -337,11 +340,13 @@ func (v *Vehicle) LightsStart() (chan string, error) {
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
pollingUrl = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
}
ch := make(chan string)
go func() {
defer close(ch)
v.executeServiceRequest(params, reqUrl, pollingUrl, ch, 1)
}()
return ch, nil
}
@ -362,6 +367,7 @@ func (v *Vehicle) LightsStop() (chan string, error) {
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
pollingUrl = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
}
ch := make(chan string)
go func() {
defer close(ch)
@ -388,6 +394,7 @@ func (v *Vehicle) HornStart() (chan string, error) {
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
pollingUrl = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
}
ch := make(chan string)
go func() {
defer close(ch)
@ -414,6 +421,7 @@ func (v *Vehicle) HornStop() (chan string, error) {
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
pollingUrl = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
}
ch := make(chan string)
go func() {
defer close(ch)
@ -442,9 +450,8 @@ func (v *Vehicle) ChargeOn() (chan string, error) {
v.executeServiceRequest(params, reqUrl, pollingUrl, ch, 1)
}()
return ch, nil
} else {
return nil, errors.New("not an EV car")
}
return nil, errors.New("not an EV car")
}
// GetLocation