Volvo Connected: require vin (BC) (#24247)

This commit is contained in:
andig 2025-10-09 08:26:04 +02:00 • committed by GitHub
parent 6befca050b
commit e48927af32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 31 additions and 8 deletions

View file

@ -178,6 +178,7 @@ func (o *OAuth) Token() (*oauth2.Token, error) {
if err != nil {
// force logout
if strings.Contains(err.Error(), "invalid_grant") && settings.Exists(o.subject) {
o.token = nil
o.onlineC <- false
settings.Delete(o.subject)
}

View file

@ -49,6 +49,7 @@ params:
example: "https://evcc.example.org/providerauth/callback"
- name: vin
example: WF0FXX...
required: true
- name: accessToken
deprecated: true
- name: refreshToken

View file

@ -2,6 +2,7 @@ package vehicle
import (
"context"
"errors"
"time"
"github.com/evcc-io/evcc/api"
@ -37,21 +38,31 @@ func NewVolvoConnectedFromConfig(ctx context.Context, other map[string]interface
return nil, err
}
log := util.NewLogger("volvo-connected").Redact(cc.VIN, cc.VccApiKey)
if cc.VccApiKey == "" {
return nil, errors.New("missing vccapikey")
}
if cc.VIN == "" {
return nil, errors.New("missing vin")
}
if err := cc.Credentials.Error(); err != nil {
return nil, err
}
log := util.NewLogger("volvo-connected").Redact(cc.VIN, cc.Credentials.ID, cc.Credentials.Secret, cc.VccApiKey)
oc := connected.Oauth2Config(cc.Credentials.ID, cc.Credentials.Secret, cc.RedirectUri)
ts, err := auth.NewOauth(ctx, cc.embed.GetTitle(), oc)
ts, err := auth.NewOauth(ctx, "Volvo", oc)
if err != nil {
return nil, err
}
api := connected.NewAPI(log, cc.VccApiKey, ts)
cc.VIN, err = ensureVehicle(cc.VIN, api.Vehicles)
v := &VolvoConnected{
embed: &cc.embed,
Provider: connected.NewProvider(api, cc.VIN, cc.Cache),
Provider: connected.NewProvider(api, ts, cc.VIN, cc.Cache),
}
return v, err

View file

@ -6,6 +6,7 @@ import (
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
"golang.org/x/oauth2"
)
// Provider implements the vehicle api
@ -14,14 +15,23 @@ type Provider struct {
odoG func() (OdometerState, error)
}
func tokenGuard[T any](fun func(string) (T, error), ts oauth2.TokenSource, vin string) (T, error) {
// don't try as long as there's no token
if _, err := ts.Token(); err != nil {
var zero T
return zero, api.ErrNotAvailable
}
return fun(vin)
}
// NewProvider creates a vehicle api provider
func NewProvider(api *API, vin string, cache time.Duration) *Provider {
func NewProvider(api *API, ts oauth2.TokenSource, vin string, cache time.Duration) *Provider {
impl := &Provider{
statusG: util.Cached(func() (EnergyState, error) {
return api.EnergyState(vin)
return tokenGuard(api.EnergyState, ts, vin)
}, cache),
odoG: util.Cached(func() (OdometerState, error) {
return api.OdometerState(vin)
return tokenGuard(api.OdometerState, ts, vin)
}, cache),
}
return impl