BMW: upgrade api (#1876)

This commit is contained in:
andig 2021-11-14 17:25:50 +01:00 • committed by GitHub
parent 881ce68636
commit a25875d6ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 35 deletions

View file

@ -3,6 +3,7 @@ package bmw
import (
"fmt"
"net/http"
"time"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
@ -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 {
@ -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 {
@ -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
}

View file

@ -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
@ -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
}
}
@ -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
@ -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

32
vehicle/bmw/types.go Normal file
View file

@ -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
}
}
}