Refactor vehicle climate control methods to improve parameter handling and add new climate preset updates
Some checks failed
Golan Testing / testing (1.24.x, ubuntu-latest) (push) Failing after 24s
Some checks failed
Golan Testing / testing (1.24.x, ubuntu-latest) (push) Failing after 24s
This commit is contained in:
33
consts.go
33
consts.go
@ -70,8 +70,6 @@ var apiURLs = map[string]string{
|
|||||||
"API_EV_FETCH_CHARGE_SETTINGS": "/service/g2/phevGetTimerSettings/execute.json",
|
"API_EV_FETCH_CHARGE_SETTINGS": "/service/g2/phevGetTimerSettings/execute.json",
|
||||||
"API_EV_SAVE_CHARGE_SETTINGS": "/service/g2/phevSendTimerSetting/execute.json",
|
"API_EV_SAVE_CHARGE_SETTINGS": "/service/g2/phevSendTimerSetting/execute.json",
|
||||||
"API_EV_DELETE_CHARGE_SCHEDULE": "/service/g2/phevDeleteTimerSetting/execute.json",
|
"API_EV_DELETE_CHARGE_SCHEDULE": "/service/g2/phevDeleteTimerSetting/execute.json",
|
||||||
// "API_G2_FETCH_CLIMATE_SETTINGS": "/service/g2/remoteEngineStart/fetch.json",
|
|
||||||
// "API_G2_SAVE_CLIMATE_SETTINGS": "/service/g2/remoteEngineStart/save.json",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Get back and add wrapper to support Feature List
|
// TODO: Get back and add wrapper to support Feature List
|
||||||
@ -267,7 +265,7 @@ const (
|
|||||||
REAR_AC_ON = "true"
|
REAR_AC_ON = "true"
|
||||||
REAR_AC_OFF = "false"
|
REAR_AC_OFF = "false"
|
||||||
START_CONFIG = "startConfiguration"
|
START_CONFIG = "startConfiguration"
|
||||||
START_CONFIG_DEFAULT_EV = "start_Climate_Control_only_allow_key_in_ignition"
|
START_CONFIG_DEFAULT_EV = "START_CLIMATE_CONTROL_ONLY_ALLOW_KEY_IN_IGNITION"
|
||||||
START_CONFIG_DEFAULT_RES = "START_ENGINE_ALLOW_KEY_IN_IGNITION"
|
START_CONFIG_DEFAULT_RES = "START_ENGINE_ALLOW_KEY_IN_IGNITION"
|
||||||
WHICH_DOOR = "unlockDoorType" // Unlock doors constants
|
WHICH_DOOR = "unlockDoorType" // Unlock doors constants
|
||||||
ALL_DOORS = "ALL_DOORS_CMD"
|
ALL_DOORS = "ALL_DOORS_CMD"
|
||||||
@ -411,3 +409,32 @@ const (
|
|||||||
// ]
|
// ]
|
||||||
// BAD_BINARY_SENSOR_VALUES = [UNKNOWN, VENTED, NOT_EQUIPPED]
|
// BAD_BINARY_SENSOR_VALUES = [UNKNOWN, VENTED, NOT_EQUIPPED]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RAW_API_FIELDS_TO_REDACT = [
|
||||||
|
// "cachedStateCode",
|
||||||
|
// "customer",
|
||||||
|
// "email",
|
||||||
|
// "firstName",
|
||||||
|
// "lastName",
|
||||||
|
// "latitude",
|
||||||
|
// "licensePlate",
|
||||||
|
// "licensePlateState",
|
||||||
|
// "longitude",
|
||||||
|
// "nickname",
|
||||||
|
// "odometer",
|
||||||
|
// "odometerValue",
|
||||||
|
// "odometerValueKilometers",
|
||||||
|
// "oemCustId",
|
||||||
|
// "phone",
|
||||||
|
// "preferredDealer",
|
||||||
|
// "sessionCustomer",
|
||||||
|
// "timeZone",
|
||||||
|
// "userOemCustId",
|
||||||
|
// "vehicleGeoPosition",
|
||||||
|
// "vehicleKey",
|
||||||
|
// "vehicleMileage",
|
||||||
|
// "vehicleName",
|
||||||
|
// "vhsId",
|
||||||
|
// "vin",
|
||||||
|
// "zip",
|
||||||
|
// ]
|
||||||
|
49
mysubaru.go
49
mysubaru.go
@ -349,38 +349,23 @@ type VehicleCondition struct {
|
|||||||
LastUpdatedTime string `json:"lastUpdatedTime"` // "2023-04-10T17:50:54+0000",
|
LastUpdatedTime string `json:"lastUpdatedTime"` // "2023-04-10T17:50:54+0000",
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClimateSettings .
|
|
||||||
// "dataName":null
|
|
||||||
// type ClimateSettings struct {
|
|
||||||
// RunTimeMinutes string `json:"runTimeMinutes"`
|
|
||||||
// StartConfiguration string `json:"startConfiguration"`
|
|
||||||
// AirConditionOn string `json:"airConditionOn"`
|
|
||||||
// OuterAirCirculation string `json:"outerAirCirculation"`
|
|
||||||
// ClimateZoneFrontAirMode string `json:"climateZoneFrontAirMode"`
|
|
||||||
// ClimateZoneFrontTemp string `json:"climateZoneFrontTemp"`
|
|
||||||
// ClimateZoneFrontAirVolume string `json:"climateZoneFrontAirVolume"`
|
|
||||||
// HeatedSeatFrontLeft string `json:"heatedSeatFrontLeft"`
|
|
||||||
// HeatedSeatFrontRight string `json:"heatedSeatFrontRight"`
|
|
||||||
// HeatedRearWindowActive string `json:"heatedRearWindowActive"`
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ClimateProfile represents a climate control profile for a Subaru vehicle.
|
// ClimateProfile represents a climate control profile for a Subaru vehicle.
|
||||||
type ClimateProfile struct {
|
type ClimateProfile struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name"`
|
||||||
VehicleType string `json:"vehicleType,omitempty"` // vehicleType [ gas | phev ]
|
VehicleType string `json:"vehicleType,omitempty"` // vehicleType [ gas | phev ]
|
||||||
PresetType string `json:"presetType,omitempty"` // presetType [ subaruPreset | userPreset ]
|
PresetType string `json:"presetType"` // presetType [ subaruPreset | userPreset ]
|
||||||
CanEdit bool `json:"canEdit,string,omitempty"` // canEdit [ false | true ]
|
StartConfiguration string `json:"startConfiguration"` // startConfiguration [ START_ENGINE_ALLOW_KEY_IN_IGNITION (gas) | START_CLIMATE_CONTROL_ONLY_ALLOW_KEY_IN_IGNITION (phev) ]
|
||||||
Disabled bool `json:"disabled,string,omitempty"` // disabled [ false | true ]
|
RunTimeMinutes int `json:"runTimeMinutes,string"` // runTimeMinutes [ 5 | 10 ]
|
||||||
RunTimeMinutes int `json:"runTimeMinutes,string"` // runTimeMinutes [ 5 | 10 ]
|
HeatedRearWindowActive string `json:"heatedRearWindowActive"` // heatedRearWindowActive: [ false | true ]
|
||||||
ClimateZoneFrontTemp int `json:"climateZoneFrontTemp,string"` // climateZoneFrontTemp: [ for _ in range(60, 85 + 1)] // climateZoneFrontTempCelsius: [for _ in range(15, 30 + 1) ]
|
HeatedSeatFrontRight string `json:"heatedSeatFrontRight"` // heatedSeatFrontRight: [ OFF | LOW_HEAT | MEDIUM_HEAT | HIGH_HEAT ]
|
||||||
ClimateZoneFrontAirMode string `json:"climateZoneFrontAirMode"` // climateZoneFrontAirMode: [ WINDOW | FEET_WINDOW | FACE | FEET | FEET_FACE_BALANCED | AUTO ]
|
HeatedSeatFrontLeft string `json:"heatedSeatFrontLeft"` // heatedSeatFrontLeft: [ OFF | LOW_HEAT | MEDIUM_HEAT | HIGH_HEAT ]
|
||||||
ClimateZoneFrontAirVolume string `json:"climateZoneFrontAirVolume"` // climateZoneFrontAirVolume: [ AUTO | 2 | 4 | 7 ]
|
ClimateZoneFrontTemp int `json:"climateZoneFrontTemp,string"` // climateZoneFrontTemp: [ for _ in range(60, 85 + 1)] // climateZoneFrontTempCelsius: [for _ in range(15, 30 + 1) ]
|
||||||
OuterAirCirculation string `json:"outerAirCirculation"` // outerAirCirculation: [ outsideAir, recirculation ]
|
ClimateZoneFrontAirMode string `json:"climateZoneFrontAirMode"` // climateZoneFrontAirMode: [ WINDOW | FEET_WINDOW | FACE | FEET | FEET_FACE_BALANCED | AUTO ]
|
||||||
HeatedRearWindowActive bool `json:"heatedRearWindowActive,string"` // heatedRearWindowActive: [ false | true ]
|
ClimateZoneFrontAirVolume int `json:"climateZoneFrontAirVolume,string"` // climateZoneFrontAirVolume: [ AUTO | 2 | 4 | 7 ]
|
||||||
AirConditionOn bool `json:"airConditionOn,string"` // airConditionOn: [ false | true ]
|
OuterAirCirculation string `json:"outerAirCirculation"` // airConditionOn: [ false | true ]
|
||||||
HeatedSeatFrontLeft string `json:"heatedSeatFrontLeft"` // heatedSeatFrontLeft: [ OFF | LOW_HEAT | MEDIUM_HEAT | HIGH_HEAT ]
|
AirConditionOn bool `json:"airConditionOn"` // airConditionOn: [ false | true ]
|
||||||
HeatedSeatFrontRight string `json:"heatedSeatFrontRight"` // heatedSeatFrontRight: [ OFF | LOW_HEAT | MEDIUM_HEAT | HIGH_HEAT ]
|
CanEdit bool `json:"canEdit"` // canEdit [ false | true ]
|
||||||
StartConfiguration string `json:"startConfiguration"` // startConfiguration [ START_ENGINE_ALLOW_KEY_IN_IGNITION (gas) | START_CLIMATE_CONTROL_ONLY_ALLOW_KEY_IN_IGNITION (phev) ]
|
Disabled bool `json:"disabled"` // disabled [ false | true ]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeoLocation represents the geographical location of a Subaru vehicle.
|
// GeoLocation represents the geographical location of a Subaru vehicle.
|
||||||
@ -497,7 +482,7 @@ type CustomTime1 struct {
|
|||||||
func (ct *CustomTime1) UnmarshalJSON(b []byte) (err error) {
|
func (ct *CustomTime1) UnmarshalJSON(b []byte) (err error) {
|
||||||
// Use the correct layout string for the desired format
|
// Use the correct layout string for the desired format
|
||||||
const layout = "2006-01-02T15:04:05"
|
const layout = "2006-01-02T15:04:05"
|
||||||
s := strings.Trim(string(b), "\\\"") // Remove surrounding quotes
|
s := strings.Trim(string(b), "\\\"") // Remove surrounding escapes and quotes (parsing time \"\\\"2025-07-09T00:23:19\\\"\" as \"2006-01-02T15:04:05\")
|
||||||
if string(b) == "null" {
|
if string(b) == "null" {
|
||||||
ct.Time = time.Time{}
|
ct.Time = time.Time{}
|
||||||
return nil
|
return nil
|
||||||
@ -515,7 +500,7 @@ type CustomTime2 struct {
|
|||||||
func (ct *CustomTime2) UnmarshalJSON(b []byte) (err error) {
|
func (ct *CustomTime2) UnmarshalJSON(b []byte) (err error) {
|
||||||
// Use the correct layout string for the desired format
|
// Use the correct layout string for the desired format
|
||||||
const layout = "2006-01-02T15:04:05-0700"
|
const layout = "2006-01-02T15:04:05-0700"
|
||||||
s := strings.Trim(string(b), "\\\"") // Remove surrounding quotes
|
s := strings.Trim(string(b), "\\\"") // Remove surrounding escapes and quotes ((parsing time \"\\\"2025-07-09T00:23:19\\\"\" as \"2006-01-02T15:04:05\"))
|
||||||
if string(b) == "null" {
|
if string(b) == "null" {
|
||||||
ct.Time = time.Time{}
|
ct.Time = time.Time{}
|
||||||
return nil
|
return nil
|
||||||
|
121
vehicle.go
121
vehicle.go
@ -201,24 +201,34 @@ func (v *Vehicle) Unlock() (chan string, error) {
|
|||||||
|
|
||||||
// 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() (chan string, error) {
|
func (v *Vehicle) EngineStart(run, delay int, horn bool) (chan string, error) {
|
||||||
// TODO: Get Quick Climate Preset from the Currect Car
|
if run < 1 || run > 10 {
|
||||||
|
return nil, errors.New("run time must be between 1 and 10 minutes")
|
||||||
|
}
|
||||||
|
|
||||||
|
var startConfig string
|
||||||
|
if v.EV {
|
||||||
|
startConfig = START_CONFIG_DEFAULT_EV
|
||||||
|
} else {
|
||||||
|
startConfig = START_CONFIG_DEFAULT_RES
|
||||||
|
}
|
||||||
|
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"delay": "0",
|
"delay": strconv.Itoa(delay),
|
||||||
"vin": v.Vin,
|
"vin": v.Vin,
|
||||||
"pin": v.client.credentials.PIN,
|
"pin": v.client.credentials.PIN,
|
||||||
"horn": "true",
|
"horn": strconv.FormatBool(horn),
|
||||||
"climateSettings": "climateSettings", // climateSettings
|
"climateSettings": "climateSettings", // climateSettings
|
||||||
"climateZoneFrontTemp": "65", // 60-86
|
"climateZoneFrontTemp": "65", // 60-86
|
||||||
"climateZoneFrontAirMode": "WINDOW", // FEET_FACE_BALANCED | FEET_WINDOW | WINDOW | FEET
|
"climateZoneFrontAirMode": "WINDOW", // FEET_FACE_BALANCED | FEET_WINDOW | WINDOW | FEET
|
||||||
"climateZoneFrontAirVolume": "6", // 1-7
|
"climateZoneFrontAirVolume": "6", // 1-7
|
||||||
"heatedSeatFrontLeft": "OFF", // OFF | LOW_HEAT | MEDIUM_HEAT | HIGH_HEAT | low_cool | medium_cool | high_cool
|
"heatedSeatFrontLeft": "OFF", // OFF | LOW_HEAT | MEDIUM_HEAT | HIGH_HEAT | LOW_COOL | MEDIUM_COOL | HIGH_COOL
|
||||||
"heatedSeatFrontRight": "OFF", // ---//---
|
"heatedSeatFrontRight": "OFF", // ---//---
|
||||||
"heatedRearWindowActive": "true", // boolean
|
"heatedRearWindowActive": "true", // boolean
|
||||||
"outerAirCirculation": "outsideAir", // outsideAir | recirculation
|
"outerAirCirculation": "outsideAir", // outsideAir | recirculation
|
||||||
"airConditionOn": "false", // boolean
|
"airConditionOn": "false", // boolean
|
||||||
"runTimeMinutes": "10", // 1-10
|
"runTimeMinutes": strconv.Itoa(run), // 1-10
|
||||||
"startConfiguration": START_CONFIG_DEFAULT_RES, // START_ENGINE_ALLOW_KEY_IN_IGNITION | ONLY FOR PHEV > START_CLIMATE_CONTROL_ONLY_ALLOW_KEY_IN_IGNITION
|
"startConfiguration": startConfig, // START_ENGINE_ALLOW_KEY_IN_IGNITION | ONLY FOR PHEV > START_CLIMATE_CONTROL_ONLY_ALLOW_KEY_IN_IGNITION
|
||||||
}
|
}
|
||||||
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"]
|
||||||
@ -500,6 +510,47 @@ func (v *Vehicle) GetClimateQuickPresets() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateClimateQuickPresets
|
||||||
|
// Updates the quick climate presets by fetching them from the MySubaru API.
|
||||||
|
func (v *Vehicle) UpdateClimateQuickPresets() error {
|
||||||
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate session before executing the request
|
||||||
|
if !v.client.validateSession() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SESSION_EXPIRED"])
|
||||||
|
return errors.New(APP_ERRORS["SESSION_EXPIRED"])
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
|
v.selectVehicle()
|
||||||
|
}
|
||||||
|
|
||||||
|
params := map[string]string{
|
||||||
|
"presetType": "userPreset",
|
||||||
|
"name": "Cooling",
|
||||||
|
"runTimeMinutes": "10",
|
||||||
|
"climateZoneFrontTemp": "65",
|
||||||
|
"climateZoneFrontAirMode": "FEET_FACE_BALANCED",
|
||||||
|
"climateZoneFrontAirVolume": "7",
|
||||||
|
"outerAirCirculation": "outsideAir",
|
||||||
|
"heatedRearWindowActive": "false",
|
||||||
|
"heatedSeatFrontLeft": "HIGH_COOL",
|
||||||
|
"airConditionOn": "false",
|
||||||
|
"startConfiguration": "START_ENGINE_ALLOW_KEY_IN_IGNITION",
|
||||||
|
// "canEdit": "true",
|
||||||
|
// "disabled": "false",
|
||||||
|
}
|
||||||
|
reqUrl := MOBILE_API_VERSION + apiURLs["API_G2_SAVE_RES_QUICK_START_SETTINGS"]
|
||||||
|
resp, _ := v.client.execute(POST, reqUrl, params, false)
|
||||||
|
|
||||||
|
v.client.logger.Debug("http request output", "request", "UpdateClimateUserPresets", "body", resp)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetClimateUserPresets
|
// GetClimateUserPresets
|
||||||
func (v *Vehicle) GetClimateUserPresets() error {
|
func (v *Vehicle) GetClimateUserPresets() error {
|
||||||
if !v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
@ -552,6 +603,46 @@ func (v *Vehicle) GetClimateUserPresets() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateClimateUserPresets
|
||||||
|
// Updates the user's climate presets by fetching them from the MySubaru API.
|
||||||
|
func (v *Vehicle) UpdateClimateUserPresets() error {
|
||||||
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
return errors.New(APP_ERRORS["SUBSCRIBTION_REQUIRED"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate session before executing the request
|
||||||
|
if !v.client.validateSession() {
|
||||||
|
v.client.logger.Error(APP_ERRORS["SESSION_EXPIRED"])
|
||||||
|
return errors.New(APP_ERRORS["SESSION_EXPIRED"])
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Vin != (v.client).currentVin {
|
||||||
|
v.selectVehicle()
|
||||||
|
}
|
||||||
|
params := map[string]string{
|
||||||
|
"presetType": "userPreset",
|
||||||
|
"name": "Cooling",
|
||||||
|
"runTimeMinutes": "10",
|
||||||
|
"climateZoneFrontTemp": "65",
|
||||||
|
"climateZoneFrontAirMode": "FEET_FACE_BALANCED",
|
||||||
|
"climateZoneFrontAirVolume": "7",
|
||||||
|
"outerAirCirculation": "outsideAir",
|
||||||
|
"heatedRearWindowActive": "false",
|
||||||
|
"heatedSeatFrontLeft": "HIGH_COOL",
|
||||||
|
"airConditionOn": "false",
|
||||||
|
"startConfiguration": "START_ENGINE_ALLOW_KEY_IN_IGNITION",
|
||||||
|
// "canEdit": "true",
|
||||||
|
// "disabled": "false",
|
||||||
|
}
|
||||||
|
reqUrl := MOBILE_API_VERSION + apiURLs["API_G2_SAVE_RES_SETTINGS"]
|
||||||
|
resp, _ := v.client.execute(POST, reqUrl, params, false)
|
||||||
|
|
||||||
|
v.client.logger.Debug("http request output", "request", "UpdateClimateUserPresets", "body", resp)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetVehicleStatus .
|
// GetVehicleStatus .
|
||||||
func (v *Vehicle) GetVehicleStatus() error {
|
func (v *Vehicle) GetVehicleStatus() error {
|
||||||
if !v.getRemoteOptionsStatus() {
|
if !v.getRemoteOptionsStatus() {
|
||||||
|
Reference in New Issue
Block a user