From 31201a9d6f1735a619ee2f25c53f5298dc6f09bf Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 17 Mar 2023 15:20:42 +0100 Subject: [PATCH] Mercedes: add odometer --- vehicle/mercedes/api.go | 19 ++++++++++++++++++- vehicle/mercedes/identity.go | 3 ++- vehicle/mercedes/provider.go | 16 +++++++++++++++- vehicle/mercedes/types.go | 4 ++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/vehicle/mercedes/api.go b/vehicle/mercedes/api.go index dab9bd47cb..42172353c7 100644 --- a/vehicle/mercedes/api.go +++ b/vehicle/mercedes/api.go @@ -68,6 +68,19 @@ func (v *API) Range(vin string) (EVResponse, error) { return res, err } +// Odometer implements the /odo response +func (v *API) Odometer(vin string) (EVResponse, error) { + var res EVResponse + + uri := fmt.Sprintf("%s/vehicles/%s/resources/odo", v.BaseURI(), vin) + err := v.GetJSON(uri, &res) + if err != nil { + res, err = v.allinOne(vin) + } + + return res, err +} + // allinOne is a 'fallback' to gather both metrics range and soc. // It is used in case for any reason the single endpoints return an error - which happend in the past. func (v *API) allinOne(vin string) (EVResponse, error) { @@ -76,7 +89,7 @@ func (v *API) allinOne(vin string) (EVResponse, error) { uri := fmt.Sprintf("%s/vehicles/%s/containers/electricvehicle", v.BaseURI(), vin) err := v.GetJSON(uri, &res) - evres := EVResponse{} + var evres EVResponse for _, r := range res { if r.Soc.Timestamp != 0 { @@ -87,6 +100,10 @@ func (v *API) allinOne(vin string) (EVResponse, error) { if r.RangeElectric.Timestamp != 0 { evres.RangeElectric = r.RangeElectric } + + if r.Odometer.Timestamp != 0 { + evres.Odometer = r.Odometer + } } return evres, err diff --git a/vehicle/mercedes/identity.go b/vehicle/mercedes/identity.go index 5bf3cf16ec..0fd986a852 100644 --- a/vehicle/mercedes/identity.go +++ b/vehicle/mercedes/identity.go @@ -50,7 +50,8 @@ func NewIdentity(log *util.Logger, id, secret string, options ...IdentityOption) Scopes: []string{ oidc.ScopeOpenID, oidc.ScopeOfflineAccess, - "mb:vehicle:mbdata:evstatus", + "mb:vehicle:mbdata:evstatus", // soc, range + "mb:vehicle:mbdata:payasyoudrive", // odo }, } diff --git a/vehicle/mercedes/provider.go b/vehicle/mercedes/provider.go index a8f716f355..ad67a17b51 100644 --- a/vehicle/mercedes/provider.go +++ b/vehicle/mercedes/provider.go @@ -10,6 +10,7 @@ import ( type Provider struct { chargerG func() (EVResponse, error) rangeG func() (EVResponse, error) + odoG func() (EVResponse, error) } // NewProvider creates a vehicle api provider @@ -21,6 +22,9 @@ func NewProvider(api *API, vin string, cache time.Duration) *Provider { rangeG: provider.Cached(func() (EVResponse, error) { return api.Range(vin) }, cache), + odoG: provider.Cached(func() (EVResponse, error) { + return api.Odometer(vin) + }, cache), } return impl } @@ -36,7 +40,7 @@ func (v *Provider) Soc() (float64, error) { } // Range implements the api.VehicleRange interface -func (v *Provider) Range() (rng int64, err error) { +func (v *Provider) Range() (int64, error) { res, err := v.rangeG() if err == nil { return int64(res.RangeElectric.Value), nil @@ -44,3 +48,13 @@ func (v *Provider) Range() (rng int64, err error) { return 0, err } + +// Odometer implements the api.VehicleOdometer interface +func (v *Provider) Odometer() (int64, error) { + res, err := v.odoG() + if err == nil { + return int64(res.Odometer.Value), nil + } + + return 0, err +} diff --git a/vehicle/mercedes/types.go b/vehicle/mercedes/types.go index 9c25c0206d..3dd0b21226 100644 --- a/vehicle/mercedes/types.go +++ b/vehicle/mercedes/types.go @@ -9,4 +9,8 @@ type EVResponse struct { Value int64 `json:",string"` Timestamp int64 } + Odometer struct { + Value int64 `json:",string"` + Timestamp int64 + } `json:"odo"` }