From 69c923a74978bf36498b3ec066025390affd10dc Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 12 Dec 2021 18:16:46 +0100 Subject: [PATCH] Audi/Seat/Skoda/VW: add position api (#2032) --- vehicle/vw/api.go | 22 ++++++++++++++++++++++ vehicle/vw/provider.go | 27 ++++++++++++++++++++++----- vehicle/vw/types.go | 19 +++++++++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/vehicle/vw/api.go b/vehicle/vw/api.go index 2ff61c31d..93c33fad6 100644 --- a/vehicle/vw/api.go +++ b/vehicle/vw/api.go @@ -158,6 +158,28 @@ func (v *API) Climater(vin string) (ClimaterResponse, error) { return res, err } +// Position implements the /position response +func (v *API) Position(vin string) (PositionResponse, error) { + var res PositionResponse + uri := fmt.Sprintf("%s/bs/cf/v1/%s/%s/vehicles/%s/position", v.baseURI, v.brand, v.country, vin) + + req, err := request.New(http.MethodGet, uri, nil, map[string]string{ + "Accept": request.JSONContent, + "Content-type": "application/vnd.vwg.mbb.carfinderservice_v1_0_0+json", + "X-App-Version": "TODO", + "X-App-Name": "TODO", + }) + if err == nil { + err = v.DoJSON(req, &res) + } + + if err != nil && res.Error != nil { + err = res.Error.Error() + } + + return res, err +} + const ( ActionCharge = "batterycharge" ActionChargeStart = "start" diff --git a/vehicle/vw/provider.go b/vehicle/vw/provider.go index 7029c468f..2ab998868 100644 --- a/vehicle/vw/provider.go +++ b/vehicle/vw/provider.go @@ -17,11 +17,12 @@ import ( // Provider implements the evcc vehicle api type Provider struct { - chargerG func() (interface{}, error) - statusG func() (interface{}, error) - climateG func() (interface{}, error) - action func(action, value string) error - rr func() (RolesRights, error) + chargerG func() (interface{}, error) + statusG func() (interface{}, error) + climateG func() (interface{}, error) + positionG func() (interface{}, error) + action func(action, value string) error + rr func() (RolesRights, error) } // NewProvider provides the evcc vehicle api provider @@ -36,6 +37,9 @@ func NewProvider(api *API, vin string, cache time.Duration) *Provider { climateG: provider.NewCached(func() (interface{}, error) { return api.Climater(vin) }, cache).InterfaceGetter(), + positionG: provider.NewCached(func() (interface{}, error) { + return api.Position(vin) + }, cache).InterfaceGetter(), action: func(action, value string) error { return api.Action(vin, action, value) }, @@ -154,6 +158,19 @@ func (v *Provider) Climater() (active bool, outsideTemp float64, targetTemp floa return active, outsideTemp, targetTemp, err } +var _ api.VehiclePosition = (*Provider)(nil) + +// Position implements the api.VehiclePosition interface +func (v *Provider) Position() (float64, float64, error) { + res, err := v.positionG() + if res, ok := res.(PositionResponse); err == nil && ok { + coord := res.FindCarResponse.Position.CarCoordinate + return float64(coord.Latitude) / 1e6, float64(coord.Longitude) / 1e6, nil + } + + return 0, 0, err +} + var _ api.VehicleStartCharge = (*Provider)(nil) // StartCharge implements the api.VehicleStartCharge interface diff --git a/vehicle/vw/types.go b/vehicle/vw/types.go index 9660881ed..a141cf94f 100644 --- a/vehicle/vw/types.go +++ b/vehicle/vw/types.go @@ -5,6 +5,7 @@ import ( "fmt" "math" "strconv" + "time" ) type Error struct { @@ -69,6 +70,24 @@ type ClimaterResponse struct { Error *Error // optional error } +// PositionResponse is the /bs/cf/v1/%s/%s/vehicles/%s/position api +type PositionResponse struct { + FindCarResponse struct { + Position struct { + TimestampCarSent string // "2021-12-12T16:42:44" + TimestampTssReceived time.Time + CarCoordinate struct { + Latitude int64 + Longitude int64 + } + TimestampCarSentUTC time.Time + TimestampCarCaptured string // "2021-12-12T16:42:44" + } + ParkingTimeUTC time.Time + } + Error *Error // optional error +} + // VehiclesResponse is the /usermanagement/users/v1/%s/%s/vehicles api type VehiclesResponse struct { UserVehicles struct {