1284 lines
44 KiB
Go
1284 lines
44 KiB
Go
package mysubaru
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/Jeffail/gabs/v2"
|
|
)
|
|
|
|
var parts = map[string]map[string][]string{
|
|
"door": map[string][]string{
|
|
"suffix": []string{"position", "status"},
|
|
"position1": []string{"front", "rear", "boot", "enginehood"},
|
|
"position2": []string{"right", "left"},
|
|
},
|
|
"window": map[string][]string{
|
|
"suffix": []string{"status"},
|
|
"position1": []string{"front", "rear", "sunroof"},
|
|
"position2": []string{"right", "left"},
|
|
},
|
|
"tire": map[string][]string{
|
|
"prefix": []string{"status"},
|
|
"position1": []string{"front", "rear"},
|
|
"position2": []string{"right", "left"},
|
|
},
|
|
"tyre": map[string][]string{
|
|
"prefix": []string{"pressure"},
|
|
"suffix": []string{"psi", "unit"},
|
|
"position1": []string{"front", "rear"},
|
|
"position2": []string{"right", "left"},
|
|
},
|
|
}
|
|
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "vehicle",
|
|
// "data": {
|
|
// "customer": {
|
|
// "sessionCustomer": null,
|
|
// "email": null,
|
|
// "firstName": null,
|
|
// "lastName": null,
|
|
// "zip": null,
|
|
// "oemCustId": null,
|
|
// "phone": null
|
|
// },
|
|
// "stolenVehicle": false,
|
|
// "vehicleName": "Subaru Outback LXT",
|
|
// "features": ["ATF_MIL","11.6MMAN","ABS_MIL","CEL_MIL","ACCS","RCC","REARBRK","TEL_MIL","VDC_MIL","TPMS_MIL","WASH_MIL","BSDRCT_MIL","OPL_MIL","EYESIGHT","RAB_MIL","SRS_MIL","ESS_MIL","RESCC","EOL_MIL","BSD","EBD_MIL","EPB_MIL","RES","RHSF","AWD_MIL","NAV_TOMTOM","ISS_MIL","RPOIA","EPAS_MIL","RPOI","AHBL_MIL","SRH_MIL","g2"],
|
|
// "vin": "4S4BTGND8L3137058",
|
|
// "modelYear": "2020",
|
|
// "modelCode": "LDJ",
|
|
// "engineSize": 2.4,
|
|
// "nickname": "Subaru Outback LXT",
|
|
// "vehicleKey": 3832950,
|
|
// "active": true,
|
|
// "licensePlate": "8KV8",
|
|
// "licensePlateState": "NJ",
|
|
// "email": null,
|
|
// "firstName": null,
|
|
// "lastName": null,
|
|
// "subscriptionFeatures": ["REMOTE","SAFETY","Retail"],
|
|
// "accessLevel": -1,
|
|
// "zip": null,
|
|
// "oemCustId": "CRM-631-HQN48K",
|
|
// "vehicleMileage": null,
|
|
// "phone": null,
|
|
// "userOemCustId": "CRM-631-HQN48K",
|
|
// "subscriptionStatus": "ACTIVE",
|
|
// "authorizedVehicle": false,
|
|
// "preferredDealer": null,
|
|
// "cachedStateCode": "NJ",
|
|
// "subscriptionPlans": [],
|
|
// "needMileagePrompt": false,
|
|
// "phev": null,
|
|
// "remoteServicePinExist": true,
|
|
// "needEmergencyContactPrompt": false,
|
|
// "vehicleGeoPosition": {
|
|
// "latitude": 40.70018,
|
|
// "longitude": -74.40139,
|
|
// "speed": null,
|
|
// "heading": null,
|
|
// "timestamp": 1642538410000
|
|
// },
|
|
// "extDescrip": "Abyss Blue Pearl",
|
|
// "intDescrip": "Gray",
|
|
// "modelName": "Outback",
|
|
// "transCode": "CVT",
|
|
// "provisioned": true,
|
|
// "timeZone": "America/New_York"
|
|
// }
|
|
// }
|
|
|
|
// Vehicle .
|
|
type Vehicle struct {
|
|
CarId int64
|
|
Vin string // SELECT CAR REQUEST > "vin": "4S4BTGND8L3137058"
|
|
CarName string // SELECT CAR REQUEST > "vehicleName": "Subaru Outback LXT"
|
|
CarNickname string // SELECT CAR REQUEST > "nickname": "Subaru Outback LXT"
|
|
ExtDescrip string // SELECT CAR REQUEST > "extDescrip": "Abyss Blue Pearl"
|
|
IntDescrip string // SELECT CAR REQUEST > "intDescrip": "Gray"
|
|
ModelName string // SELECT CAR REQUEST > "modelName": "Outback",
|
|
ModelYear string // SELECT CAR REQUEST > "modelYear": "2020"
|
|
ModelCode string // SELECT CAR REQUEST > "modelCode": "LDJ"
|
|
TransCode string // SELECT CAR REQUEST > "transCode": "CVT"
|
|
EngineSize float64 // SELECT CAR REQUEST > "engineSize": 2.4
|
|
VehicleKey int64 // SELECT CAR REQUEST > "vehicleKey": 3832950
|
|
EV bool // SELECT CAR REQUEST >
|
|
LicensePlate string // SELECT CAR REQUEST > "licensePlate": "8KV8"
|
|
LicensePlateState string // SELECT CAR REQUEST > "licensePlateState": "NJ"
|
|
Features []string // SELECT CAR REQUEST > "features": ["ATF_MIL","11.6MMAN","ABS_MIL","CEL_MIL","ACCS","RCC","REARBRK","TEL_MIL","VDC_MIL","TPMS_MIL","WASH_MIL","BSDRCT_MIL","OPL_MIL","EYESIGHT","RAB_MIL","SRS_MIL","ESS_MIL","RESCC","EOL_MIL","BSD","EBD_MIL","EPB_MIL","RES","RHSF","AWD_MIL","NAV_TOMTOM","ISS_MIL","RPOIA","EPAS_MIL","RPOI","AHBL_MIL","SRH_MIL","g2"],
|
|
SubscriptionFeatures []string // SELECT CAR REQUEST > "subscriptionFeatures": ["REMOTE","SAFETY","Retail"]
|
|
SubscriptionStatus string // SELECT CAR REQUEST > "subscriptionStatus": "ACTIVE"
|
|
EngineState string // STATUS REQUEST > "vehicleStateType": "IGNITION_OFF"
|
|
Odometer struct {
|
|
Miles int // STATUS REQUEST > "odometerValue": 24999
|
|
Kilometers int // STATUS REQUEST > "odometerValueKilometers": 40223
|
|
}
|
|
DistanceToEmpty struct {
|
|
Miles int // STATUS REQUEST > "distanceToEmptyFuelMiles": 149.75
|
|
Kilometers int // STATUS REQUEST > "distanceToEmptyFuelKilometers": 241
|
|
Miles10s int // STATUS REQUEST > "distanceToEmptyFuelMiles10s": 150
|
|
Kilometers10s int // STATUS REQUEST > "distanceToEmptyFuelKilometers10s": 240
|
|
}
|
|
FuelConsumptionAvg struct {
|
|
MPG float64 // STATUS REQUEST > "avgFuelConsumptionMpg": 18.5
|
|
LP100Km float64 // STATUS REQUEST > "avgFuelConsumptionLitersPer100Kilometers": 12.7
|
|
}
|
|
ClimateProfiles []*ClimateProfile
|
|
Doors []*Door // CONDITION REQUEST >
|
|
Windows []*Window // CONDITION REQUEST >
|
|
Tires []*Tire // CONDITION AND STATUS REQUEST >
|
|
GeoLocation GeoLocation
|
|
Updated time.Time
|
|
client *Client
|
|
// "evStateOfChargePercent": null,
|
|
// "evDistanceToEmptyMiles": null,
|
|
// "evDistanceToEmptyKilometers": null,
|
|
// "evDistanceToEmptyByStateMiles": null,
|
|
// "evDistanceToEmptyByStateKilometers": null,
|
|
|
|
}
|
|
|
|
// ClimateProfile .
|
|
type ClimateProfile struct {
|
|
Name string `json:"name,omitempty"`
|
|
RunTimeMinutes int `json:"runTimeMinutes,string"` // runTimeMinutes [ 5 | 10 ]
|
|
ClimateZoneFrontTemp int `json:"climateZoneFrontTemp,string"` // climateZoneFrontTemp: [ for _ in range(60, 85 + 1)] // climateZoneFrontTempCelsius: [for _ in range(15, 30 + 1) ]
|
|
ClimateZoneFrontAirMode string `json:"climateZoneFrontAirMode"` // climateZoneFrontAirMode: [ WINDOW | FEET_WINDOW | FACE | FEET | FEET_FACE_BALANCED | AUTO ]
|
|
ClimateZoneFrontAirVolume string `json:"climateZoneFrontAirVolume"` // climateZoneFrontAirVolume: [ AUTO | 2 | 4 | 7 ]
|
|
OuterAirCirculation string `json:"outerAirCirculation"` // outerAirCirculation: [ outsideAir, recirculation ]
|
|
HeatedRearWindowActive bool `json:"heatedRearWindowActive,string"` // heatedRearWindowActive: [ false | true ]
|
|
AirConditionOn bool `json:"airConditionOn,string"` // airConditionOn: [ false | true ]
|
|
HeatedSeatFrontLeft string `json:"heatedSeatFrontLeft"` // heatedSeatFrontLeft: [ OFF | LOW_HEAT | MEDIUM_HEAT | HIGH_HEAT ]
|
|
HeatedSeatFrontRight string `json:"heatedSeatFrontRight"` // heatedSeatFrontRight: [ OFF | LOW_HEAT | MEDIUM_HEAT | HIGH_HEAT ]
|
|
StartConfiguration string `json:"startConfiguration"` // startConfiguration [ START_ENGINE_ALLOW_KEY_IN_IGNITION (gas) | START_CLIMATE_CONTROL_ONLY_ALLOW_KEY_IN_IGNITION (phev) ]
|
|
CanEdit bool `json:"canEdit,string,omitempty"` // canEdit [ false | true ]
|
|
Disabled bool `json:"disabled,string,omitempty"` // disabled [ false | true ]
|
|
VehicleType string `json:"vehicleType,omitempty"` // vehicleType [ gas | phev ]
|
|
PresetType string `json:"presetType,omitempty"` // presetType [ subaruPreset | userPreset ]
|
|
}
|
|
|
|
// func (cp *ClimateProfile) New() {}
|
|
|
|
// GeoLocation .
|
|
type GeoLocation struct {
|
|
Latitude float64 // 40.700184
|
|
Longitude float64 // -74.401375
|
|
Speed float64 // 0.00
|
|
Heading int // 189
|
|
Updated time.Time
|
|
}
|
|
|
|
// Door .
|
|
type Door struct {
|
|
Position string
|
|
SubPosition string
|
|
Status string
|
|
Updated time.Time
|
|
}
|
|
|
|
// Window .
|
|
type Window struct {
|
|
Position string
|
|
SubPosition string
|
|
Status string
|
|
Updated time.Time
|
|
}
|
|
|
|
// Tire .
|
|
type Tire struct {
|
|
Position string
|
|
SubPosition string
|
|
Pressure int
|
|
PressurePsi int
|
|
Status string
|
|
Updated time.Time
|
|
}
|
|
|
|
func (v *Vehicle) String() string {
|
|
|
|
var vString string
|
|
vString += "=== INFORMATION =====================\n"
|
|
vString += "Nickname: " + v.CarNickname + "\n"
|
|
vString += "Car Name: " + v.CarName + "\n"
|
|
vString += "Model: " + v.ModelName + "\n"
|
|
|
|
vString += "=== ODOMETER =====================\n"
|
|
vString += "Miles: " + strconv.Itoa(v.Odometer.Miles) + "\n"
|
|
vString += "Kilometers: " + strconv.Itoa(v.Odometer.Kilometers) + "\n"
|
|
|
|
vString += "=== DISTANCE TO EMPTY =====================\n"
|
|
vString += "Miles: " + strconv.Itoa(v.DistanceToEmpty.Miles) + "\n"
|
|
vString += "Kilometers: " + strconv.Itoa(v.DistanceToEmpty.Kilometers) + "\n"
|
|
|
|
vString += "=== FUEL CONSUMPTION =====================\n"
|
|
vString += "MPG: " + fmt.Sprintf("%v", v.FuelConsumptionAvg.MPG) + "\n"
|
|
vString += "Litres per 100 km: " + fmt.Sprintf("%v", v.FuelConsumptionAvg.LP100Km) + "\n"
|
|
|
|
vString += "=== WINDOWS =====================\n"
|
|
for i, w := range v.Windows {
|
|
vString += fmt.Sprintf("%d >> %+v\n", i+1, w)
|
|
// fmt.Printf("%d >> %+v\n", i+1, w)
|
|
}
|
|
|
|
vString += "=== DOORS =====================\n"
|
|
for i, d := range v.Doors {
|
|
vString += fmt.Sprintf("%d >> %+v\n", i+1, d)
|
|
// fmt.Printf("%d >> %+v\n", i+1, d)
|
|
}
|
|
|
|
vString += "=== FEATURES =====================\n"
|
|
for i, f := range v.Features {
|
|
if !strings.HasSuffix(f, "_MIL") {
|
|
if _, ok := features[f]; ok {
|
|
vString += fmt.Sprintf("%d >> %+v || %s\n", i+1, f, features[f])
|
|
// fmt.Printf("%d >> %s // %s\n", i+1, f, features[f])
|
|
} else {
|
|
vString += fmt.Sprintf("%d >> %+v\n", i+1, f)
|
|
// fmt.Printf("%d >> %s\n", i+1, f)
|
|
}
|
|
}
|
|
}
|
|
return vString
|
|
}
|
|
|
|
// Lock .
|
|
// Send command to lock doors.
|
|
func (v *Vehicle) Lock() {
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640454085449_20_@NGTP",
|
|
// "success": false,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "lock",
|
|
// "remoteServiceState": "started",
|
|
// "subState": null,
|
|
// "errorCode": null,
|
|
// "result": null,
|
|
// "updateTime": 1640454085000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640454085449_20_@NGTP",
|
|
// "success": true,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "lock",
|
|
// "remoteServiceState": "finished",
|
|
// "subState": null,
|
|
// "errorCode": "null:null",
|
|
// "result": null,
|
|
// "updateTime": 1640454091000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
|
|
if v.getRemoteOptionsStatus() {
|
|
v.selectVehicle()
|
|
params := map[string]string{
|
|
"delay": "0",
|
|
"vin": v.Vin,
|
|
"pin": v.client.credentials.pin,
|
|
"forceKeyInCar": "false"}
|
|
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_LOCK"], v.getAPIGen())
|
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
|
v.client.execute(reqURL, POST, params, pollingURL, true)
|
|
} else {
|
|
v.client.log.Error("active STARLINK Security Plus subscription required")
|
|
}
|
|
}
|
|
|
|
// Unlock .
|
|
// Send command to unlock doors.
|
|
func (v *Vehicle) Unlock() {
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640539133289_19_@NGTP",
|
|
// "success": false,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "unlock",
|
|
// "remoteServiceState": "started",
|
|
// "subState": null,
|
|
// "errorCode": null,
|
|
// "result": null,
|
|
// "updateTime": 1640539133000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640539133289_19_@NGTP",
|
|
// "success": true,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "unlock",
|
|
// "remoteServiceState": "finished",
|
|
// "subState": null,
|
|
// "errorCode": "null:null",
|
|
// "result": null,
|
|
// "updateTime": 1640539140000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
|
|
if v.getRemoteOptionsStatus() {
|
|
v.selectVehicle()
|
|
params := map[string]string{
|
|
"delay": "0",
|
|
"vin": v.Vin,
|
|
"pin": v.client.credentials.pin,
|
|
"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"]
|
|
v.client.execute(reqURL, POST, params, pollingURL, true)
|
|
} else {
|
|
v.client.log.Error("active STARLINK Security Plus subscription required")
|
|
}
|
|
// 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)
|
|
}
|
|
|
|
// EngineOn .
|
|
// Send command to start engine and set climate control.
|
|
func (v *Vehicle) EngineStart() {
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640456287656_22_@NGTP",
|
|
// "success": false,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "engineStart",
|
|
// "remoteServiceState": "started",
|
|
// "subState": null,
|
|
// "errorCode": null,
|
|
// "result": null,
|
|
// "updateTime": 1640456287000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640456287656_22_@NGTP",
|
|
// "success": true,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "engineStart",
|
|
// "remoteServiceState": "finished",
|
|
// "subState": null,
|
|
// "errorCode": "null:null",
|
|
// "result": null,
|
|
// "updateTime": 1640456302000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
|
|
if v.getRemoteOptionsStatus() {
|
|
v.selectVehicle()
|
|
params := map[string]string{
|
|
"delay": "0",
|
|
"vin": v.Vin,
|
|
"pin": v.client.credentials.pin,
|
|
"horn": "true",
|
|
"climateSettings": "climateSettings", // climateSettings
|
|
"climateZoneFrontTemp": "65", // 60-86
|
|
"climateZoneFrontAirMode": "WINDOW", // FEET_FACE_BALANCED | FEET_WINDOW | WINDOW | FEET
|
|
"climateZoneFrontAirVolume": "6", // 1-7
|
|
"heatedSeatFrontLeft": "OFF", // OFF | LOW_HEAT | MEDIUM_HEAT | HIGH_HEAT | low_cool | medium_cool | high_cool
|
|
"heatedSeatFrontRight": "OFF", // ---//---
|
|
"heatedRearWindowActive": "true", // boolean
|
|
"outerAirCirculation": "outsideAir", // outsideAir | recirculation
|
|
"airConditionOn": "false", // boolean
|
|
"runTimeMinutes": "10", // 1-10
|
|
"startConfiguration": START_CONFIG_DEFAULT_RES, // 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"]
|
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
|
v.client.execute(reqURL, POST, params, pollingURL, true)
|
|
} else {
|
|
v.client.log.Error("active STARLINK Security Plus subscription required")
|
|
}
|
|
}
|
|
|
|
// EngineOff .
|
|
// Send command to stop engine.
|
|
func (v *Vehicle) EngineStop() {
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640456318773_23_@NGTP",
|
|
// "success": false,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "engineStop",
|
|
// "remoteServiceState": "started",
|
|
// "subState": null,
|
|
// "errorCode": null,
|
|
// "result": null,
|
|
// "updateTime": null,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640456318773_23_@NGTP",
|
|
// "success": true,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "engineStop",
|
|
// "remoteServiceState": "finished",
|
|
// "subState": null,
|
|
// "errorCode": "null:null",
|
|
// "result": null,
|
|
// "updateTime": 1640456321000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
|
|
if v.getRemoteOptionsStatus() {
|
|
v.selectVehicle()
|
|
params := map[string]string{
|
|
"delay": "0",
|
|
"vin": v.Vin,
|
|
"pin": v.client.credentials.pin}
|
|
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_REMOTE_ENGINE_STOP"]
|
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
|
v.client.execute(reqURL, POST, params, pollingURL, true)
|
|
} else {
|
|
v.client.log.Error("Active STARLINK Security Plus subscription required")
|
|
}
|
|
}
|
|
|
|
// LightsStart .
|
|
// Send command to flash lights.
|
|
func (v *Vehicle) LightsStart() {
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640457256003_21_@NGTP",
|
|
// "success": false,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "lightsOnly",
|
|
// "remoteServiceState": "started",
|
|
// "subState": null,
|
|
// "errorCode": null,
|
|
// "result": null,
|
|
// "updateTime": 1640457256000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640457256003_21_@NGTP",
|
|
// "success": true,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "lightsOnly",
|
|
// "remoteServiceState": "finished",
|
|
// "subState": null,
|
|
// "errorCode": "null:null",
|
|
// "result": null,
|
|
// "updateTime": 1640457262000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
|
|
if v.getRemoteOptionsStatus() {
|
|
v.selectVehicle()
|
|
params := map[string]string{
|
|
"delay": "0",
|
|
"vin": v.Vin,
|
|
"pin": v.client.credentials.pin}
|
|
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_LIGHTS"], v.getAPIGen())
|
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
|
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
|
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
|
}
|
|
v.client.execute(reqURL, POST, params, pollingURL, true)
|
|
} else {
|
|
v.client.log.Error("active STARLINK Security Plus subscription required")
|
|
}
|
|
}
|
|
|
|
// LightsStop .
|
|
// Send command to stop flash lights.
|
|
func (v *Vehicle) LightsStop() {
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640457280857_47_@NGTP",
|
|
// "success": false,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "lightsOnly",
|
|
// "remoteServiceState": "stopping",
|
|
// "subState": null,
|
|
// "errorCode": "null:null",
|
|
// "result": null,
|
|
// "updateTime": 1640457262000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640457280857_47_@NGTP",
|
|
// "success": true,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "lightsOnly",
|
|
// "remoteServiceState": "finished",
|
|
// "subState": null,
|
|
// "errorCode": "null:null",
|
|
// "result": null,
|
|
// "updateTime": 1640457280000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
|
|
if v.getRemoteOptionsStatus() {
|
|
v.selectVehicle()
|
|
params := map[string]string{
|
|
"delay": "0",
|
|
"vin": v.Vin,
|
|
"pin": v.client.credentials.pin}
|
|
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_LIGHTS_STOP"], v.getAPIGen())
|
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
|
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
|
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
|
}
|
|
v.client.execute(reqURL, POST, params, pollingURL, true)
|
|
} else {
|
|
v.client.log.Error("active STARLINK Security Plus subscription required")
|
|
}
|
|
}
|
|
|
|
// HornStart .
|
|
// Send command to sound horn.
|
|
func (v *Vehicle) HornStart() {
|
|
if v.getRemoteOptionsStatus() {
|
|
v.selectVehicle()
|
|
params := map[string]string{
|
|
"delay": "0",
|
|
"vin": v.Vin,
|
|
"pin": v.client.credentials.pin}
|
|
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_HORN_LIGHTS"], v.getAPIGen())
|
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
|
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
|
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
|
}
|
|
v.client.execute(reqURL, POST, params, pollingURL, true)
|
|
} else {
|
|
v.client.log.Error("active STARLINK Security Plus subscription required")
|
|
}
|
|
}
|
|
|
|
// HornStop .
|
|
// Send command to sound horn.
|
|
func (v *Vehicle) HornStop() {
|
|
if v.getRemoteOptionsStatus() {
|
|
v.selectVehicle()
|
|
params := map[string]string{
|
|
"delay": "0",
|
|
"vin": v.Vin,
|
|
"pin": v.client.credentials.pin}
|
|
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_HORN_LIGHTS_STOP"], v.getAPIGen())
|
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
|
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
|
pollingURL = MOBILE_API_VERSION + apiURLs["API_G1_HORN_LIGHTS_STATUS"]
|
|
}
|
|
v.client.execute(reqURL, POST, params, pollingURL, true)
|
|
} else {
|
|
v.client.log.Error("Active STARLINK Security Plus subscription required")
|
|
}
|
|
}
|
|
|
|
// ChargeStart .
|
|
func (v *Vehicle) ChargeOn() {
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640542818241_31_@NGTP",
|
|
// "success": false,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "phevChargeNow",
|
|
// "remoteServiceState": "started",
|
|
// "subState": null,
|
|
// "errorCode": null,
|
|
// "result": null,
|
|
// "updateTime": null,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640542818241_31_@NGTP",
|
|
// "success": false,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "phevChargeNow",
|
|
// "remoteServiceState": "finished",
|
|
// "subState": null,
|
|
// "errorCode": "NegativeAcknowledge:unknown",
|
|
// "result": null,
|
|
// "updateTime": 1640542824000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
|
|
if v.isEV() {
|
|
v.selectVehicle()
|
|
params := map[string]string{
|
|
"delay": "0",
|
|
"vin": v.Vin,
|
|
"pin": v.client.credentials.pin}
|
|
reqURL := MOBILE_API_VERSION + apiURLs["API_EV_CHARGE_NOW"]
|
|
pollingURL := MOBILE_API_VERSION + apiURLs["API_REMOTE_SVC_STATUS"]
|
|
v.client.execute(reqURL, POST, params, pollingURL, true)
|
|
}
|
|
}
|
|
|
|
// GetLocation .
|
|
func (v *Vehicle) GetLocation(force bool) {
|
|
if force { // Sends a locate command to the vehicle to get real time position
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": "4S4BTGND8L3137058_1640454589498_11_@NGTP",
|
|
// "success": false,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "vehicleStatus",
|
|
// "remoteServiceState": "started",
|
|
// "subState": null,
|
|
// "errorCode": null,
|
|
// "result": null,
|
|
// "updateTime": 1640454589000,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": null,
|
|
// "success": true,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "locate",
|
|
// "remoteServiceState": "finished",
|
|
// "subState": null,
|
|
// "errorCode": null,
|
|
// "result": {
|
|
// "latitude": 40.700294,
|
|
// "longitude": -74.401344,
|
|
// "speed": 0,
|
|
// "heading": 189,
|
|
// "timestamp": 1640454600000
|
|
// },
|
|
// "updateTime": null,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
v.selectVehicle()
|
|
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,
|
|
"pin": v.client.credentials.pin}
|
|
if v.getAPIGen() == FEATURE_G1_TELEMATICS {
|
|
reqURL = MOBILE_API_VERSION + apiURLs["API_G1_LOCATE_UPDATE"]
|
|
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
|
|
// {
|
|
// "success": true,
|
|
// "errorCode": null,
|
|
// "dataName": "remoteServiceStatus",
|
|
// "data": {
|
|
// "serviceRequestId": null,
|
|
// "success": true,
|
|
// "cancelled": false,
|
|
// "remoteServiceType": "locate",
|
|
// "remoteServiceState": "finished",
|
|
// "subState": null,
|
|
// "errorCode": null,
|
|
// "result": {
|
|
// "latitude": 40.700203,
|
|
// "longitude": -74.40142,
|
|
// "speed": 0,
|
|
// "heading": 156,
|
|
// "timestamp": 1642526388000
|
|
// },
|
|
// "updateTime": null,
|
|
// "vin": "4S4BTGND8L3137058"
|
|
// }
|
|
// }
|
|
v.selectVehicle()
|
|
params := map[string]string{
|
|
"vin": v.Vin,
|
|
"pin": v.client.credentials.pin}
|
|
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_LOCATE"], v.getAPIGen())
|
|
v.client.execute(reqURL, GET, params, "", false)
|
|
}
|
|
}
|
|
|
|
// GetClimateQuickPresets .
|
|
func (v *Vehicle) GetClimateQuickPresets() {
|
|
if v.getRemoteOptionsStatus() {
|
|
// params := map[string]string{
|
|
// "vin": v.Vin,
|
|
// "pin": v.Client.credentials.pin}
|
|
v.selectVehicle()
|
|
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_RES_QUICK_START_SETTINGS"]
|
|
resp := v.client.execute(reqURL, GET, map[string]string{}, "", false)
|
|
|
|
respParsed, err := gabs.ParseJSON(resp)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
v.client.log.Debug("CLIMATE SETTINGS OUTPUT", "body", respParsed)
|
|
|
|
// ONLY FOR THAT REQUEST BECAUSE OF API SENDS BACK ESCAPING DATA IN DATA FIELD
|
|
data, ok := respParsed.Path("data").Data().(string)
|
|
// rawIn := json.RawMessage(in)
|
|
// bytes, err := rawIn.MarshalJSON()
|
|
// if err != nil {
|
|
// panic(err)
|
|
// }
|
|
|
|
// value == string, ok == false
|
|
if !ok {
|
|
// TODO: Work with errorCode
|
|
panic(data)
|
|
}
|
|
v.client.log.Debug("PRESETS", "output", data)
|
|
} else {
|
|
v.client.log.Error("active STARLINK Security Plus subscription required")
|
|
}
|
|
}
|
|
|
|
// GetClimatePresets .
|
|
func (v *Vehicle) GetClimatePresets() {
|
|
if v.getRemoteOptionsStatus() {
|
|
v.selectVehicle()
|
|
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_RES_SUBARU_PRESETS"]
|
|
resp := v.client.execute(reqURL, GET, map[string]string{}, "", false)
|
|
respParsed, err := gabs.ParseJSON(resp)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// ONLY FOR THAT REQUEST BECAUSE OF API SENDS BACK ESCAPED DATA IN DATA FIELD
|
|
for _, child := range respParsed.S("data").Children() {
|
|
// log.Debugf("key: %v, value: %v\n", key, child.Data().(string))
|
|
var climateProfile ClimateProfile
|
|
json.Unmarshal([]byte(child.Data().(string)), &climateProfile)
|
|
|
|
if v.isEV() && climateProfile.VehicleType == "phev" {
|
|
v.ClimateProfiles = append(v.ClimateProfiles, &climateProfile)
|
|
}
|
|
if !v.isEV() && climateProfile.VehicleType == "gas" {
|
|
v.ClimateProfiles = append(v.ClimateProfiles, &climateProfile)
|
|
}
|
|
v.Updated = time.Now()
|
|
}
|
|
} else {
|
|
v.client.log.Error("active STARLINK Security Plus subscription required")
|
|
}
|
|
}
|
|
|
|
// GetClimateUserPresets .
|
|
func (v *Vehicle) GetClimateUserPresets() {
|
|
if v.getRemoteOptionsStatus() {
|
|
v.selectVehicle()
|
|
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_RES_USER_PRESETS"]
|
|
resp := v.client.execute(reqURL, GET, map[string]string{}, "", false)
|
|
respParsed, err := gabs.ParseJSON(resp)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
v.client.log.Debug("CLIMATE USER SETTINGS OUTPUT", "body", respParsed)
|
|
|
|
// ONLY FOR THAT REQUEST BECAUSE OF API SENDS BACK ESCAPED DATA IN DATA FIELD
|
|
for _, child := range respParsed.S("data").Children() {
|
|
// log.Debugf("key: %v, value: %v\n", key, child.Data().(string))
|
|
var climateProfile ClimateProfile
|
|
json.Unmarshal([]byte(child.Data().(string)), &climateProfile)
|
|
|
|
if v.isEV() && climateProfile.VehicleType == "phev" {
|
|
v.ClimateProfiles = append(v.ClimateProfiles, &climateProfile)
|
|
}
|
|
if !v.isEV() && climateProfile.VehicleType == "gas" {
|
|
v.ClimateProfiles = append(v.ClimateProfiles, &climateProfile)
|
|
}
|
|
}
|
|
v.Updated = time.Now()
|
|
// // ONLY FOR THAT REQUEST BECAUSE OF API SENDS BACK ESCAPING DATA IN DATA FIELD
|
|
// data, ok := respParsed.Path("data").Data().(string)
|
|
// // rawIn := json.RawMessage(in)
|
|
// // bytes, err := rawIn.MarshalJSON()
|
|
// // if err != nil {
|
|
// // panic(err)
|
|
// // }
|
|
|
|
// // value == string, ok == false
|
|
// if !ok {
|
|
// // TODO: Work with errorCode
|
|
// panic(data)
|
|
// }
|
|
// log.Debugf("PRESETS: %+v\n", data)
|
|
} else {
|
|
v.client.log.Error("active STARLINK Security Plus subscription required")
|
|
}
|
|
}
|
|
|
|
// GetVehicleStatus .
|
|
func (v *Vehicle) GetVehicleStatus() {
|
|
v.selectVehicle()
|
|
reqURL := MOBILE_API_VERSION + urlToGen(apiURLs["API_VEHICLE_STATUS"], v.getAPIGen())
|
|
resp := v.client.execute(reqURL, GET, map[string]string{}, "", false)
|
|
|
|
if v.client.isResponseSuccessfull(resp) {
|
|
respParsed, err := gabs.ParseJSON(resp)
|
|
if err != nil {
|
|
v.client.log.Error("error", err)
|
|
}
|
|
|
|
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
|
|
v.DistanceToEmpty.Miles = int(vSta.DistanceToEmptyFuelMiles)
|
|
v.DistanceToEmpty.Kilometers = vSta.DistanceToEmptyFuelKilometers
|
|
v.DistanceToEmpty.Miles10s = vSta.DistanceToEmptyFuelMiles10s
|
|
v.DistanceToEmpty.Kilometers10s = vSta.DistanceToEmptyFuelKilometers10s
|
|
v.FuelConsumptionAvg.MPG = float64(vSta.AvgFuelConsumptionMpg)
|
|
v.FuelConsumptionAvg.LP100Km = float64(vSta.AvgFuelConsumptionLitersPer100Kilometers)
|
|
|
|
v.GeoLocation.Latitude = float64(vSta.Latitude)
|
|
v.GeoLocation.Longitude = float64(vSta.Longitude)
|
|
|
|
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") {
|
|
submatchall := re.FindAllString(key, -1)
|
|
v.client.log.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall))
|
|
for _, element := range submatchall {
|
|
fmt.Println(element)
|
|
}
|
|
door := Door{}
|
|
door.Position = submatchall[0]
|
|
if len(submatchall) >= 3 {
|
|
door.SubPosition = submatchall[1]
|
|
}
|
|
door.Status = child.Data().(string)
|
|
door.Updated = time.Now()
|
|
v.Doors = append(v.Doors, &door)
|
|
}
|
|
if strings.HasPrefix(key, "door") && strings.HasSuffix(key, "Status") {
|
|
submatchall := re.FindAllString(key, -1)
|
|
v.client.log.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall))
|
|
for _, element := range submatchall {
|
|
fmt.Println(element)
|
|
}
|
|
door := Door{}
|
|
door.Position = submatchall[0]
|
|
if len(submatchall) >= 3 {
|
|
door.SubPosition = submatchall[1]
|
|
}
|
|
door.Status = child.Data().(string)
|
|
door.Updated = time.Now()
|
|
v.Doors = append(v.Doors, &door)
|
|
}
|
|
if strings.HasPrefix(key, "window") && strings.HasSuffix(key, "Status") {
|
|
submatchall := re.FindAllString(key, -1)
|
|
v.client.log.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall))
|
|
for _, element := range submatchall {
|
|
fmt.Println(element)
|
|
}
|
|
window := Window{}
|
|
window.Position = submatchall[0]
|
|
if len(submatchall) >= 3 {
|
|
window.SubPosition = submatchall[1]
|
|
}
|
|
window.Status = child.Data().(string)
|
|
window.Updated = time.Now()
|
|
v.Windows = append(v.Windows, &window)
|
|
}
|
|
if strings.HasPrefix(key, "tire") && !strings.HasSuffix(key, "Psi") {
|
|
v.client.log.Debug("VEHICLE COND", "key", key, "data", child.Data())
|
|
submatchall := re.FindAllString(key, -1)
|
|
for _, element := range submatchall {
|
|
fmt.Println(element)
|
|
}
|
|
}
|
|
}
|
|
|
|
fmt.Printf("PARTS: %+v\n", parts)
|
|
v.Updated = time.Now()
|
|
}
|
|
|
|
// vData := VehicleData{}
|
|
// vdString := respParsed.Path("data").String()
|
|
// json.Unmarshal([]byte(vdString), &vData)
|
|
|
|
// { "data": {
|
|
// "vhsId": 1038682433,
|
|
|
|
// "odometerValue": 24999,
|
|
// "odometerValueKilometers": 40223,
|
|
|
|
// "eventDate": 1642538410000,
|
|
// "eventDateStr": "2022-01-18T20:40+0000",
|
|
|
|
// "latitude": 40.70018,
|
|
// "longitude": -74.40139,
|
|
// "positionHeadingDegree": "155",
|
|
|
|
// "tirePressureFrontLeft": "2275",
|
|
// "tirePressureFrontRight": "2206",
|
|
// "tirePressureRearLeft": "2344",
|
|
// "tirePressureRearRight": "2275",
|
|
|
|
// "tirePressureFrontLeftPsi": "33",
|
|
// "tirePressureFrontRightPsi": "32",
|
|
// "tirePressureRearLeftPsi": "34",
|
|
// "tirePressureRearRightPsi": "33",
|
|
|
|
// "distanceToEmptyFuelMiles": 149.75,
|
|
// "distanceToEmptyFuelKilometers": 241,
|
|
|
|
// "avgFuelConsumptionMpg": 18.5,
|
|
// "avgFuelConsumptionLitersPer100Kilometers": 12.7,
|
|
|
|
// "evStateOfChargePercent": null,
|
|
// "evDistanceToEmptyMiles": null,
|
|
// "evDistanceToEmptyKilometers": null,
|
|
// "evDistanceToEmptyByStateMiles": null,
|
|
// "evDistanceToEmptyByStateKilometers": null,
|
|
|
|
// "vehicleStateType": "IGNITION_OFF",
|
|
|
|
// "distanceToEmptyFuelMiles10s": 150,
|
|
// "distanceToEmptyFuelKilometers10s": 240
|
|
// }
|
|
// }
|
|
}
|
|
|
|
// GetVehicleStatus .
|
|
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)
|
|
|
|
if v.client.isResponseSuccessfull(resp) {
|
|
respParsed, err := gabs.ParseJSON(resp)
|
|
if err != nil {
|
|
v.client.log.Error("error", err)
|
|
}
|
|
|
|
re := regexp.MustCompile(`[A-Z][^A-Z]*`)
|
|
|
|
for key, child := range respParsed.S("data").S("result").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") {
|
|
submatchall := re.FindAllString(key, -1)
|
|
v.client.log.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall))
|
|
for _, element := range submatchall {
|
|
fmt.Println(element)
|
|
}
|
|
door := Door{}
|
|
door.Position = submatchall[0]
|
|
if len(submatchall) >= 3 {
|
|
door.SubPosition = submatchall[1]
|
|
}
|
|
door.Status = child.Data().(string)
|
|
door.Updated = time.Now()
|
|
v.Doors = append(v.Doors, &door)
|
|
|
|
}
|
|
if strings.HasPrefix(key, "window") && strings.HasSuffix(key, "Status") {
|
|
submatchall := re.FindAllString(key, -1)
|
|
v.client.log.Debug("VEHICLE COND", "key", key, "data", child.Data(), "number", len(submatchall))
|
|
for _, element := range submatchall {
|
|
fmt.Println(element)
|
|
}
|
|
window := Window{}
|
|
window.Position = submatchall[0]
|
|
if len(submatchall) >= 3 {
|
|
window.SubPosition = submatchall[1]
|
|
}
|
|
window.Status = child.Data().(string)
|
|
window.Updated = time.Now()
|
|
v.Windows = append(v.Windows, &window)
|
|
}
|
|
if strings.HasPrefix(key, "tire") && !strings.HasSuffix(key, "Unit") {
|
|
v.client.log.Debug("VEHICLE COND", "key", key, "data", child.Data())
|
|
submatchall := re.FindAllString(key, -1)
|
|
for _, element := range submatchall {
|
|
fmt.Println(element)
|
|
}
|
|
}
|
|
v.Updated = time.Now()
|
|
}
|
|
|
|
// vCon := VehicleCondition{}
|
|
// vcString := respParsed.Path("data.result").String()
|
|
// json.Unmarshal([]byte(vcString), &vCon)
|
|
|
|
// for _, elem := range vCon.VehicleStatus {
|
|
// if elem.Value == "NOT_EQUIPPED" || elem.Value == "UNKNOWN" || elem.Value == "16383" || elem.Value == "65535" || elem.Value == "None" || elem.Value == "-64.0" {
|
|
// continue
|
|
// }
|
|
// if strings.HasPrefix(elem.Key, "door") {
|
|
// log.Debugf("VEHICLE COND: %v > %v\n", elem.Key, elem.Value)
|
|
// }
|
|
// }
|
|
// for _, elem := range vCon.VehicleStatus {
|
|
// if elem.Value == "NOT_EQUIPPED" || elem.Value == "UNKNOWN" || elem.Value == "16383" || elem.Value == "65535" || elem.Value == "None" || elem.Value == "-64.0" {
|
|
// continue
|
|
// }
|
|
// if strings.HasPrefix(elem.Key, "window") {
|
|
// log.Debugf("VEHICLE COND: %v > %v\n", elem.Key, elem.Value)
|
|
// }
|
|
// }
|
|
// for _, elem := range vCon.VehicleStatus {
|
|
// if elem.Value == "NOT_EQUIPPED" || elem.Value == "UNKNOWN" || elem.Value == "16383" || elem.Value == "65535" || elem.Value == "None" || elem.Value == "-64.0" {
|
|
// continue
|
|
// }
|
|
// if strings.HasPrefix(elem.Key, "tire") {
|
|
// log.Debugf("VEHICLE COND: %v > %v\n", elem.Key, elem.Value)
|
|
// }
|
|
// }
|
|
// log.Debugf("VEHICLE COND REQUEST: %+v", vCon)
|
|
}
|
|
|
|
// VEHICLE_STATE_TYPE >> IGNITION_OFF
|
|
// DISTANCE_TO_EMPTY_FUEL >> 241
|
|
// AVG_FUEL_CONSUMPTION >> 127
|
|
// POSITION_SPEED_KMPH >> 0
|
|
// POSITION_HEADING_DEGREE >> 155
|
|
// POSITION_TIMESTAMP >> 2022-01-18T20:40:10Z
|
|
// ODOMETER >> 40223712 (meters)
|
|
// TYRE_( STATUS | PRESSURE )_( REAR | FRONT )_( LEFT | RIGHT ) >> 2275 | UNKNOWN
|
|
// SEAT_BELT_STATUS_( ( FRONT | SECOND | THIRD )_( LEFT | MIDDLE | RIGHT ) ) >> NOT_EQUIPPED | UNKNOWN | NOT_BELTED | BELTED
|
|
// SEAT_OCCUPATION_STATUS_( ( FRONT | SECOND | THIRD )_( LEFT | MIDDLE | RIGHT ) ) >>
|
|
// DOOR_( ( FRONT | REAR )_( LEFT | RIGHT ) | ENGINE_HOOD | BOOT )_LOCK_STATUS >> UNKNOWN
|
|
// DOOR_( ( FRONT | REAR )_( LEFT | RIGHT ) | ENGINE_HOOD | BOOT )_POSITION >> CLOSED
|
|
// WINDOW_( BACK | SUNROOF | ( FRONT | REAR )_( LEFT | RIGHT ) )_STATUS >> UNKNOWN | CLOSE
|
|
}
|
|
|
|
// GetVehicleHealth .
|
|
func (v *Vehicle) GetVehicleHealth() {
|
|
v.selectVehicle()
|
|
params := map[string]string{
|
|
"vin": v.Vin,
|
|
"_": timestamp()}
|
|
reqURL := MOBILE_API_VERSION + apiURLs["API_VEHICLE_HEALTH"]
|
|
resp := v.client.execute(reqURL, GET, params, "", false)
|
|
|
|
if v.client.isResponseSuccessfull(resp) {
|
|
_, err := gabs.ParseJSON(resp)
|
|
if err != nil {
|
|
v.client.log.Error("error", err)
|
|
}
|
|
// TODO:
|
|
}
|
|
}
|
|
|
|
// GetClimateSettings .
|
|
func (v *Vehicle) GetClimateSettings() {
|
|
v.selectVehicle()
|
|
reqURL := MOBILE_API_VERSION + apiURLs["API_G2_FETCH_CLIMATE_SETTINGS"]
|
|
v.client.execute(reqURL, GET, map[string]string{}, "", false)
|
|
// TODO
|
|
}
|
|
|
|
// GetFeaturesList .
|
|
func (v *Vehicle) GetFeaturesList() {
|
|
for i, f := range v.Features {
|
|
if _, ok := features[f]; ok {
|
|
fmt.Printf("%d >> %s // %s\n", i+1, f, features[f])
|
|
} else {
|
|
fmt.Printf("%d >> %s\n", i+1, f)
|
|
}
|
|
}
|
|
}
|
|
|
|
// selectVehicle .
|
|
func (v *Vehicle) selectVehicle() {
|
|
if v.client.currentVin != v.Vin {
|
|
vData := (*v.client).SelectVehicle(v.Vin)
|
|
v.SubscriptionStatus = vData.SubscriptionStatus
|
|
v.GeoLocation.Latitude = vData.VehicleGeoPosition.Latitude
|
|
v.GeoLocation.Longitude = vData.VehicleGeoPosition.Longitude
|
|
v.GeoLocation.Heading = vData.VehicleGeoPosition.Heading
|
|
v.GeoLocation.Speed = vData.VehicleGeoPosition.Speed
|
|
v.GeoLocation.Updated = time.Now()
|
|
v.Updated = time.Now()
|
|
}
|
|
}
|
|
|
|
// getAPIGen
|
|
// Get the Subaru telematics API generation of a specified VIN
|
|
func (v *Vehicle) getAPIGen() string {
|
|
if contains(v.Features, FEATURE_G1_TELEMATICS) {
|
|
return "g1"
|
|
}
|
|
if contains(v.Features, FEATURE_G2_TELEMATICS) {
|
|
return "g2"
|
|
}
|
|
if contains(v.Features, FEATURE_G3_TELEMATICS) {
|
|
return "g3"
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
// isPINRequired .
|
|
// Return if a vehicle with an active remote service subscription exists.
|
|
func (v *Vehicle) isPINRequired() bool {
|
|
return v.getRemoteOptionsStatus()
|
|
}
|
|
|
|
// isEV .
|
|
// Get whether the specified VIN is an Electric Vehicle.
|
|
func (v *Vehicle) isEV() bool {
|
|
return contains(v.Features, FEATURE_PHEV)
|
|
}
|
|
|
|
// getRemoteOptionsStatus .
|
|
// Get whether the specified VIN has remote locks/horn/light service available
|
|
func (v *Vehicle) getRemoteOptionsStatus() bool {
|
|
return contains(v.SubscriptionFeatures, FEATURE_REMOTE)
|
|
}
|
|
|
|
// getRemoteStartStatus .
|
|
// Get whether the specified VIN has remote engine start service available.
|
|
func (v *Vehicle) getRemoteStartStatus() bool {
|
|
return contains(v.Features, FEATURE_REMOTE_START)
|
|
}
|
|
|
|
// getSafetyStatus .
|
|
// Get whether the specified VIN is has an active Starlink Safety Plus service plan.
|
|
func (v *Vehicle) getSafetyStatus() bool {
|
|
return contains(v.SubscriptionFeatures, FEATURE_SAFETY)
|
|
}
|
|
|
|
// getSubscriptionStatus .
|
|
// Get whether the specified VIN has an active service plan.
|
|
func (v *Vehicle) getSubscriptionStatus() bool {
|
|
return contains(v.SubscriptionFeatures, FEATURE_ACTIVE)
|
|
}
|
|
|
|
// getVehicleName .
|
|
// Get the nickname of a specified VIN.
|
|
func (v *Vehicle) getVehicleName() string {
|
|
return v.CarName
|
|
}
|
|
|
|
// func getClimateData() {}
|
|
// func saveClimateSettings() {}
|
|
// func fetch() {}
|
|
|
|
// "vhsId": 914631252,
|
|
|
|
// "odometerValue": 23865,
|
|
// "odometerValueKilometers": 38399,
|
|
|
|
// "tirePressureFrontLeft": "2344",
|
|
// "tirePressureFrontRight": "2344",
|
|
// "tirePressureRearLeft": "2413",
|
|
// "tirePressureRearRight": "2344",
|
|
|
|
// "tirePressureFrontLeftPsi": "34",
|
|
// "tirePressureFrontRightPsi": "34",
|
|
// "tirePressureRearLeftPsi": "35",
|
|
// "tirePressureRearRightPsi": "34",
|
|
|
|
// TireStatusFrontLeft string `json:"tyreStatusFrontLeft"` // "UNKNOWN"
|
|
// TireStatusFrontRight string `json:"tyreStatusFrontRight"` // "UNKNOWN"
|
|
// TireStatusRearLeft string `json:"tyreStatusRearLeft"` // "UNKNOWN"
|
|
// TireStatusRearRight string `json:"tyreStatusRearRight"` // "UNKNOWN"
|
|
|
|
// WindowFrontLeftStatus string `json:"windowFrontLeftStatus"` // "CLOSE"
|
|
// WindowFrontRightStatus string `json:"windowFrontRightStatus"` // "CLOSE"
|
|
// WindowRearLeftStatus string `json:"windowRearLeftStatus"` // "CLOSE"
|
|
// WindowRearRightStatus string `json:"windowRearRightStatus"` // "CLOSE"
|
|
// WindowSunroofStatus string `json:"windowSunroofStatus"` // "UNKNOWN"
|