Skip to content

Commit

Permalink
BMW: upgrade api (evcc-io#1876)
Browse files Browse the repository at this point in the history
  • Loading branch information
andig authored Nov 14, 2021
1 parent 881ce68 commit a25875d
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 35 deletions.
44 changes: 18 additions & 26 deletions vehicle/bmw/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package bmw
import (
"fmt"
"net/http"
"time"

"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
Expand All @@ -12,27 +13,11 @@ import (
// https://github.com/bimmerconnected/bimmer_connected
// https://github.com/TA2k/ioBroker.bmw

const ApiURI = "https://b2vapi.bmwgroup.com/webapi/v1"

type StatusResponse struct {
VehicleStatus struct {
ConnectionStatus string // CONNECTED
ChargingStatus string // CHARGING, ERROR, FINISHED_FULLY_CHARGED, FINISHED_NOT_FULL, INVALID, NOT_CHARGING, WAITING_FOR_CHARGING
ChargingLevelHv int
RemainingRangeElectric int
Mileage int
// UpdateTime time.Time // 2021-08-12T12:00:08+0000
}
}

type VehiclesResponse struct {
Vehicles []Vehicle
}

type Vehicle struct {
VIN string
Model string
}
const (
ApiURI = "https://b2vapi.bmwgroup.com/webapi/v1"
CocoApiURI = "https://cocoapi.bmwgroup.com"
XUserAgent = "android(v1.07_20200330);bmw;1.7.0(11152)"
)

// API is an api.Vehicle implementation for BMW cars
type API struct {
Expand All @@ -58,6 +43,7 @@ func NewAPI(log *util.Logger, identity oauth2.TokenSource) *API {
func (v *API) Vehicles() ([]string, error) {
var resp VehiclesResponse
uri := fmt.Sprintf("%s/user/vehicles", ApiURI)
// uri := fmt.Sprintf("%s/eadrax-vcs/v1/vehicles", CocoApiURI, vin)

req, err := http.NewRequest(http.MethodGet, uri, nil)
if err == nil {
Expand All @@ -73,14 +59,20 @@ func (v *API) Vehicles() ([]string, error) {
}

// Status implements the /user/vehicles/<vin>/status api
func (v *API) Status(vin string) (StatusResponse, error) {
var resp StatusResponse
uri := fmt.Sprintf("%s/user/vehicles/%s/status", ApiURI, vin)
func (v *API) Status(vin string) (VehicleStatus, error) {
var resp VehiclesStatusResponse
uri := fmt.Sprintf("%s/eadrax-vcs/v1/vehicles?apptimezone=60&appDateTime=%d&vin=%s", CocoApiURI, time.Now().Unix(), vin)

req, err := http.NewRequest(http.MethodGet, uri, nil)
req, err := request.New(http.MethodGet, uri, nil, map[string]string{
"X-User-Agent": XUserAgent,
})
if err == nil {
err = v.DoJSON(req, &resp)
}

return resp, err
if l := len(resp); l != 1 {
return VehicleStatus{}, fmt.Errorf("unexpected length: %d", l)
}

return resp[0], err
}
18 changes: 9 additions & 9 deletions vehicle/bmw/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ var _ api.Battery = (*Provider)(nil)
// SoC implements the api.Vehicle interface
func (v *Provider) SoC() (float64, error) {
res, err := v.statusG()
if res, ok := res.(StatusResponse); err == nil && ok {
return float64(res.VehicleStatus.ChargingLevelHv), nil
if res, ok := res.(VehicleStatus); err == nil && ok {
return float64(res.Properties.ChargingState.ChargePercentage), nil
}

return 0, err
Expand All @@ -41,11 +41,11 @@ func (v *Provider) Status() (api.ChargeStatus, error) {
status := api.StatusA // disconnected

res, err := v.statusG()
if res, ok := res.(StatusResponse); err == nil && ok {
if res.VehicleStatus.ConnectionStatus == "CONNECTED" {
if res, ok := res.(VehicleStatus); err == nil && ok {
if res.Properties.ChargingState.IsChargerConnected {
status = api.StatusB
}
if res.VehicleStatus.ChargingStatus == "CHARGING" {
if res.Properties.ChargingState.State == "CHARGING" {
status = api.StatusC
}
}
Expand All @@ -71,8 +71,8 @@ var _ api.VehicleRange = (*Provider)(nil)
// Range implements the api.VehicleRange interface
func (v *Provider) Range() (int64, error) {
res, err := v.statusG()
if res, ok := res.(StatusResponse); err == nil && ok {
return int64(res.VehicleStatus.RemainingRangeElectric), nil
if res, ok := res.(VehicleStatus); err == nil && ok {
return int64(res.Properties.ElectricRange.Distance.Value), nil
}

return 0, err
Expand All @@ -83,8 +83,8 @@ var _ api.VehicleOdometer = (*Provider)(nil)
// Odometer implements the api.VehicleOdometer interface
func (v *Provider) Odometer() (float64, error) {
res, err := v.statusG()
if res, ok := res.(StatusResponse); err == nil && ok {
return float64(res.VehicleStatus.Mileage), nil
if res, ok := res.(VehicleStatus); err == nil && ok {
return float64(res.Status.CurrentMileage.Mileage), nil
}

return 0, err
Expand Down
32 changes: 32 additions & 0 deletions vehicle/bmw/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package bmw

type VehiclesResponse struct {
Vehicles []Vehicle
}

type Vehicle struct {
VIN string
Model string
}

type VehiclesStatusResponse []VehicleStatus

type VehicleStatus struct {
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
}
}
}

0 comments on commit a25875d

Please sign in to comment.