From 245721c7013ab1fc613d4ac7b690a74c5329eb2d Mon Sep 17 00:00:00 2001 From: andig Date: Tue, 7 Dec 2021 21:23:37 +0100 Subject: [PATCH] Nissan: fix api access for added Accept: application/json header (#1996) --- vehicle/nissan/api.go | 24 +++++++++++++------ vehicle/nissan/provider.go | 30 +++++++++++++----------- vehicle/nissan/types.go | 48 ++++++++++++++------------------------ 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/vehicle/nissan/api.go b/vehicle/nissan/api.go index d96864d58..3d2416040 100644 --- a/vehicle/nissan/api.go +++ b/vehicle/nissan/api.go @@ -10,8 +10,18 @@ import ( "golang.org/x/oauth2" ) +// api constants const ( - refreshTimeout = 5 * time.Minute + APIVersion = "protocol=1.0,resource=2.1" + ClientID = "a-ncb-prod-android" + ClientSecret = "3LBs0yOx2XO-3m4mMRW27rKeJzskhfWF0A8KUtnim8i/qYQPl8ZItp3IaqJXaYj_" + Scope = "openid profile vehicles" + AuthBaseURL = "https://prod.eu.auth.kamereon.org/kauth" + Realm = "a-ncb-prod" + RedirectURI = "org.kamereon.service.nci:/oauth2redirect" + CarAdapterBaseURL = "https://alliance-platform-caradapter-prod.apps.eu.kamereon.io/car-adapter" + UserAdapterBaseURL = "https://alliance-platform-usersadapter-prod.apps.eu.kamereon.io/user-adapter" + UserBaseURL = "https://nci-bff-web-prod.apps.eu.kamereon.io/bff-web" ) type API struct { @@ -57,18 +67,18 @@ func (v *API) Vehicles() ([]string, error) { } // Battery provides battery api response -func (v *API) BatteryStatus(vin string) (Response, error) { +func (v *API) BatteryStatus(vin string) (StatusResponse, error) { uri := fmt.Sprintf("%s/v1/cars/%s/battery-status", CarAdapterBaseURL, vin) - var res Response + var res StatusResponse err := v.GetJSON(uri, &res) return res, err } // RefreshRequest requests battery status refresh -func (v *API) RefreshRequest(vin string, typ string) (Response, error) { - var res Response +func (v *API) RefreshRequest(vin string, typ string) (ActionResponse, error) { + var res ActionResponse uri := fmt.Sprintf("%s/v1/cars/%s/actions/refresh-battery-status", CarAdapterBaseURL, vin) data := Request{ @@ -96,7 +106,7 @@ const ( ) // ChargingAction provides actions/charging-start api response -func (v *API) ChargingAction(vin string, action Action) (Response, error) { +func (v *API) ChargingAction(vin string, action Action) (ActionResponse, error) { uri := fmt.Sprintf("%s/v1/cars/%s/actions/charging-start", CarAdapterBaseURL, vin) data := Request{ @@ -112,7 +122,7 @@ func (v *API) ChargingAction(vin string, action Action) (Response, error) { "Content-Type": "application/vnd.api+json", }) - var res Response + var res ActionResponse if err == nil { err = v.DoJSON(req, &res) } diff --git a/vehicle/nissan/provider.go b/vehicle/nissan/provider.go index 189722df4..a58a16c94 100644 --- a/vehicle/nissan/provider.go +++ b/vehicle/nissan/provider.go @@ -8,6 +8,8 @@ import ( "github.com/evcc-io/evcc/provider" ) +const refreshTimeout = 2 * time.Minute + // Provider is a kamereon provider type Provider struct { statusG func() (interface{}, error) @@ -28,20 +30,20 @@ func NewProvider(api *API, vin string, expiry, cache time.Duration) *Provider { impl.statusG = provider.NewCached(func() (interface{}, error) { return impl.status( - func() (Response, error) { return api.BatteryStatus(vin) }, - func() (Response, error) { return api.RefreshRequest(vin, "RefreshBatteryStatus") }, + func() (StatusResponse, error) { return api.BatteryStatus(vin) }, + func() (ActionResponse, error) { return api.RefreshRequest(vin, "RefreshBatteryStatus") }, ) }, cache).InterfaceGetter() return impl } -func (v *Provider) status(battery func() (Response, error), refresh func() (Response, error)) (Response, error) { +func (v *Provider) status(battery func() (StatusResponse, error), refresh func() (ActionResponse, error)) (StatusResponse, error) { res, err := battery() if err == nil { // result valid? - if res.Data.Attributes.LastUpdateTime.Add(v.expiry).After(time.Now()) { + if time.Since(res.Attributes.LastUpdateTime.Time) < v.expiry { v.refreshTime = time.Time{} return res, err } @@ -83,8 +85,8 @@ var _ api.Battery = (*Provider)(nil) func (v *Provider) SoC() (float64, error) { res, err := v.statusG() - if res, ok := res.(Response); err == nil && ok { - return float64(res.Data.Attributes.BatteryLevel), nil + if res, ok := res.(StatusResponse); err == nil && ok { + return float64(res.Attributes.BatteryLevel), nil } return 0, err @@ -97,11 +99,11 @@ func (v *Provider) Status() (api.ChargeStatus, error) { status := api.StatusA // disconnected res, err := v.statusG() - if res, ok := res.(Response); err == nil && ok { - if res.Data.Attributes.PlugStatus > 0 { + if res, ok := res.(StatusResponse); err == nil && ok { + if res.Attributes.PlugStatus > 0 { status = api.StatusB } - if res.Data.Attributes.ChargingStatus > 1.0 { + if res.Attributes.ChargeStatus > 1.0 { status = api.StatusC } } @@ -115,8 +117,8 @@ var _ api.VehicleRange = (*Provider)(nil) func (v *Provider) Range() (int64, error) { res, err := v.statusG() - if res, ok := res.(Response); err == nil && ok { - return int64(res.Data.Attributes.RangeHvacOff), nil + if res, ok := res.(StatusResponse); err == nil && ok { + return int64(res.Attributes.RangeHvacOff), nil } return 0, err @@ -128,12 +130,12 @@ var _ api.VehicleFinishTimer = (*Provider)(nil) func (v *Provider) FinishTime() (time.Time, error) { res, err := v.statusG() - if res, ok := res.(Response); err == nil && ok { - if res.Data.Attributes.RemainingTime == nil { + if res, ok := res.(StatusResponse); err == nil && ok { + if res.Attributes.RemainingTime == nil { return time.Time{}, api.ErrNotAvailable } - return res.Data.Attributes.Timestamp.Add(time.Duration(*res.Data.Attributes.RemainingTime) * time.Minute), err + return res.Attributes.LastUpdateTime.Time.Add(time.Duration(*res.Attributes.RemainingTime) * time.Minute), err } return time.Time{}, err diff --git a/vehicle/nissan/types.go b/vehicle/nissan/types.go index af65b3dbd..815a13622 100644 --- a/vehicle/nissan/types.go +++ b/vehicle/nissan/types.go @@ -6,20 +6,6 @@ import ( "time" ) -// api constants -const ( - APIVersion = "protocol=1.0,resource=2.1" - ClientID = "a-ncb-prod-android" - ClientSecret = "3LBs0yOx2XO-3m4mMRW27rKeJzskhfWF0A8KUtnim8i/qYQPl8ZItp3IaqJXaYj_" - Scope = "openid profile vehicles" - AuthBaseURL = "https://prod.eu.auth.kamereon.org/kauth" - Realm = "a-ncb-prod" - RedirectURI = "org.kamereon.service.nci:/oauth2redirect" - CarAdapterBaseURL = "https://alliance-platform-caradapter-prod.apps.eu.kamereon.io/car-adapter" - UserAdapterBaseURL = "https://alliance-platform-usersadapter-prod.apps.eu.kamereon.io/user-adapter" - UserBaseURL = "https://nci-bff-web-prod.apps.eu.kamereon.io/bff-web" -) - type Auth struct { AuthID string `json:"authId"` Template string `json:"template"` @@ -79,27 +65,22 @@ type Payload struct { Attributes map[string]interface{} `json:"attributes,omitempty"` } -// Response structure for kamereon api -type Response struct { - Data struct { - Type, ID string // battery refresh - Attributes attributes `json:"attributes"` - } `json:"data"` - Errors []Error -} - type Error struct { Status, Code, Detail string } -type attributes struct { - Timestamp Timestamp `json:"timestamp"` - ChargingStatus float32 `json:"chargingStatus"` - InstantaneousPower int `json:"instantaneousPower"` - RangeHvacOff int `json:"rangeHvacOff"` // Nissan - BatteryAutonomy int `json:"batteryAutonomy"` // Renault +// StatusResponse structure for kamereon api +type StatusResponse struct { + ID string + Attributes + Errors []Error +} + +type Attributes struct { + ChargeStatus float32 `json:"chargingStatus"` + RangeHvacOff int `json:"rangeHvacOff"` BatteryLevel int `json:"batteryLevel"` - BatteryCapacity int `json:"batteryCapacity"` // Nissan + BatteryCapacity int `json:"batteryCapacity"` BatteryTemperature int `json:"batteryTemperature"` PlugStatus int `json:"plugStatus"` LastUpdateTime Timestamp `json:"lastUpdateTime"` @@ -107,6 +88,13 @@ type attributes struct { RemainingTime *int `json:"chargingRemainingTime"` } +type ActionResponse struct { + Data struct { + Type, ID string // battery refresh + } `json:"data"` + Errors []Error +} + const timeFormat = "2006-01-02T15:04:05Z" // Timestamp implements JSON unmarshal