BMW: upgrade api (#1876)
This commit is contained in:
parent
881ce68636
commit
a25875d6ae
3 changed files with 59 additions and 35 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
32
vehicle/bmw/types.go
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue