From c552fd1be03182c2b598e75eedaacf8d3d0efe84 Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 30 Jun 2023 10:50:49 +0200 Subject: [PATCH] BMW: fix api (#8713) --- vehicle/bmw/api.go | 44 +++++++++++++----------------- vehicle/bmw/provider.go | 59 ++++++++++++++--------------------------- vehicle/bmw/types.go | 37 +++++++++----------------- 3 files changed, 51 insertions(+), 89 deletions(-) diff --git a/vehicle/bmw/api.go b/vehicle/bmw/api.go index df7e037b7..6eec9bc23 100644 --- a/vehicle/bmw/api.go +++ b/vehicle/bmw/api.go @@ -5,7 +5,6 @@ import ( "net/http" "time" - "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/util" "github.com/evcc-io/evcc/util/request" "golang.org/x/oauth2" @@ -15,7 +14,6 @@ import ( // https://github.com/TA2k/ioBroker.bmw const ( - ApiURI = "https://b2vapi.bmwgroup.com/webapi/v1" CocoApiURI = "https://cocoapi.bmwgroup.com" ) @@ -41,30 +39,25 @@ func NewAPI(log *util.Logger, brand string, identity oauth2.TokenSource) *API { return v } -func (v *API) eadrax() (VehiclesStatusResponse, error) { - var res VehiclesStatusResponse - uri := fmt.Sprintf("%s/eadrax-vcs/v1/vehicles?apptimezone=120&appDateTime=%d", CocoApiURI, time.Now().UnixMilli()) +// Vehicles implements returns the /user/vehicles api +func (v *API) Vehicles() ([]string, error) { + var res []Vehicle + uri := fmt.Sprintf("%s/eadrax-vcs/v4/vehicles?apptimezone=120&appDateTime=%d", CocoApiURI, time.Now().UnixMilli()) req, err := request.New(http.MethodGet, uri, nil, map[string]string{ "Content-Type": request.JSONContent, "X-User-Agent": v.xUserAgent, }) - if err == nil { - err = v.DoJSON(req, &res) - } - - return res, err -} - -// Vehicles implements returns the /user/vehicles api -func (v *API) Vehicles() ([]string, error) { - resp, err := v.eadrax() if err != nil { return nil, err } + if err := v.DoJSON(req, &res); err != nil { + return nil, err + } + var vehicles []string - for _, v := range resp { + for _, v := range res { vehicles = append(vehicles, v.VIN) } @@ -73,16 +66,17 @@ func (v *API) Vehicles() ([]string, error) { // Status implements the /user/vehicles//status api func (v *API) Status(vin string) (VehicleStatus, error) { - resp, err := v.eadrax() - if err == nil { - for _, res := range resp { - if res.VIN == vin { - return res, nil - } - } + var res VehicleStatus + uri := fmt.Sprintf("%s/eadrax-vcs/v4/vehicles/state?apptimezone=120&appDateTime=%d", CocoApiURI, time.Now().UnixMilli()) - err = api.ErrNotAvailable + req, err := request.New(http.MethodGet, uri, nil, map[string]string{ + "Content-Type": request.JSONContent, + "X-User-Agent": v.xUserAgent, + "bmw-vin": vin, + }) + if err == nil { + err = v.DoJSON(req, &res) } - return VehicleStatus{}, err + return res, err } diff --git a/vehicle/bmw/provider.go b/vehicle/bmw/provider.go index b5cc330a2..fc838db5a 100644 --- a/vehicle/bmw/provider.go +++ b/vehicle/bmw/provider.go @@ -7,8 +7,6 @@ import ( "github.com/evcc-io/evcc/provider" ) -const kmPerMile = 1.609344 - // Provider implements the vehicle api type Provider struct { statusG func() (VehicleStatus, error) @@ -29,15 +27,11 @@ var _ api.Battery = (*Provider)(nil) // Soc implements the api.Vehicle interface func (v *Provider) Soc() (float64, error) { res, err := v.statusG() - if err == nil { - if cs := res.Properties.ChargingState; cs != nil { - return float64(cs.ChargePercentage), nil - } - - err = api.ErrNotAvailable + if err != nil { + return 0, err } - return 0, err + return float64(res.State.ElectricChargingState.ChargingLevelPercent), nil } var _ api.ChargeState = (*Provider)(nil) @@ -45,24 +39,19 @@ var _ api.ChargeState = (*Provider)(nil) // Status implements the api.ChargeState interface func (v *Provider) Status() (api.ChargeStatus, error) { res, err := v.statusG() - if err == nil { - if cs := res.Properties.ChargingState; cs != nil { - status := api.StatusA // disconnected - - if cs.IsChargerConnected { - status = api.StatusB - } - if cs.State == "CHARGING" { - status = api.StatusC - } - - return status, nil - } - - err = api.ErrNotAvailable + if err != nil { + return api.StatusNone, err } - return api.StatusNone, err + status := api.StatusA // disconnected + if res.State.ElectricChargingState.IsChargerConnected { + status = api.StatusB + } + if res.State.ElectricChargingState.ChargingStatus == "CHARGING" { + status = api.StatusC + } + + return status, nil } // var _ api.VehicleFinishTimer = (*Provider)(nil) @@ -83,15 +72,11 @@ var _ api.VehicleRange = (*Provider)(nil) // Range implements the api.VehicleRange interface func (v *Provider) Range() (int64, error) { res, err := v.statusG() - if err == nil { - if er := res.Properties.ElectricRange; er != nil { - return int64(er.Distance.Value), nil - } - - err = api.ErrNotAvailable + if err != nil { + return 0, err } - return 0, err + return res.State.ElectricChargingState.Range, nil } var _ api.VehicleOdometer = (*Provider)(nil) @@ -99,13 +84,9 @@ var _ api.VehicleOdometer = (*Provider)(nil) // Odometer implements the api.VehicleOdometer interface func (v *Provider) Odometer() (float64, error) { res, err := v.statusG() - if err == nil { - if cm := res.Status.CurrentMileage; cm != nil { - return float64(cm.Mileage) * kmPerMile, nil - } - - err = api.ErrNotAvailable + if err != nil { + return 0, err } - return 0, err + return float64(res.State.CurrentMileage), nil } diff --git a/vehicle/bmw/types.go b/vehicle/bmw/types.go index 12e695093..ddd54fd0c 100644 --- a/vehicle/bmw/types.go +++ b/vehicle/bmw/types.go @@ -1,34 +1,21 @@ package bmw -type VehiclesResponse struct { - Vehicles []Vehicle -} - type Vehicle struct { - VIN string - Model string + VIN string + Model string + AppVehicleType string } -type VehiclesStatusResponse []VehicleStatus - type VehicleStatus struct { - VIN, Model, Brand string - Year int - Properties struct { - ChargingState *struct { - ChargePercentage int - State string // CHARGING, ERROR, FINISHED_FULLY_CHARGED, FINISHED_NOT_FULL, INVALID, NOT_CHARGING, WAITING_FOR_CHARGING, COMPLETED - IsChargerConnected bool - } - ElectricRange *struct { - Distance struct { - Value int - } - } - } - Status struct { - CurrentMileage *struct { - Mileage int + State struct { + CurrentMileage int64 + Range int64 + ElectricChargingState struct { + ChargingLevelPercent int64 + Range int64 + IsChargerConnected bool + ChargingStatus string + ChargingTarget int64 } } }