Repository: evcc-io/evcc
Pull request #9702 (2023-09-03 13:32:41)

VAG: simplify token refresh handling (replaces #9700)


Patch:
diff --git a/api/actionconfig.go b/api/actionconfig.go
index 0080a7b6..ea13b324 100644
--- a/api/actionconfig.go
+++ b/api/actionconfig.go
@@ -15,7 +15,7 @@ type ActionConfig struct {
 	Mode       *ChargeMode `mapstructure:"mode,omitempty"`       // Charge Mode
 	MinCurrent *float64    `mapstructure:"minCurrent,omitempty"` // Minimum Current
 	MaxCurrent *float64    `mapstructure:"maxCurrent,omitempty"` // Maximum Current
-	MinSoc     *int        `mapstructure:"minSoc,omitempty"`     // Minimum Soc
+	MinSoc_    *int        `mapstructure:"minSoc,omitempty"`     // Minimum Soc (deprecated)
 	TargetSoc  *int        `mapstructure:"targetSoc,omitempty"`  // Target Soc
 	Priority   *int        `mapstructure:"priority,omitempty"`   // Priority
 }
diff --git a/core/loadpoint.go b/core/loadpoint.go
index 178ed9ab..bec4bc3e 100644
--- a/core/loadpoint.go
+++ b/core/loadpoint.go
@@ -317,12 +317,13 @@ func (lp *Loadpoint) collectDefaults() {
 		*actionCfg.Mode = lp.GetMode()
 		*actionCfg.MinCurrent = lp.GetMinCurrent()
 		*actionCfg.MaxCurrent = lp.GetMaxCurrent()
-		*actionCfg.MinSoc = lp.GetMinSoc()
-		*actionCfg.TargetSoc = lp.GetTargetSoc()
 		*actionCfg.Priority = lp.GetPriority()
 	} else {
 		lp.log.ERROR.Printf("error allocating action config: %v", err)
 	}
+	// deprecated: do not reapply deprecated lp config values
+	actionCfg.TargetSoc = nil
+	actionCfg.MinSoc_ = nil
 }
 
 // requestUpdate requests site to update this loadpoint
@@ -552,6 +553,9 @@ func (lp *Loadpoint) applyAction(actionCfg api.ActionConfig) {
 	if min := actionCfg.MinCurrent; min != nil && *min >= *lp.onDisconnect.MinCurrent {
 		lp.SetMinCurrent(*min)
 	}
+	if actionCfg.TargetSoc != nil {
+		lp.SetTargetSoc(*actionCfg.TargetSoc)
+	}
 	if max := actionCfg.MaxCurrent; max != nil && *max <= *lp.onDisconnect.MaxCurrent {
 		lp.SetMaxCurrent(*max)
 	}
diff --git a/vehicle/seat-cupra.go b/vehicle/seat-cupra.go
index c460aa8a..b894e953 100644
--- a/vehicle/seat-cupra.go
+++ b/vehicle/seat-cupra.go
@@ -10,7 +10,7 @@ import (
 	"github.com/evcc-io/evcc/util/request"
 	"github.com/evcc-io/evcc/vehicle/seat"
 	"github.com/evcc-io/evcc/vehicle/seat/cupra"
-	"github.com/evcc-io/evcc/vehicle/vag/tokenrefreshservice"
+	"github.com/evcc-io/evcc/vehicle/vag/service"
 	"github.com/evcc-io/evcc/vehicle/vag/vwidentity"
 	"golang.org/x/oauth2"
 )
@@ -51,20 +51,11 @@ func NewCupraFromConfig(other map[string]interface{}) (api.Vehicle, error) {
 
 	log := util.NewLogger("cupra").Redact(cc.User, cc.Password, cc.VIN)
 
-	// get initial VW identity id_token
-	q, err := vwidentity.Login(log, seat.AuthParams, cc.User, cc.Password)
+	ts, err := service.TokenRefreshServiceTokenSource(log, seat.TRSParams, seat.AuthParams, cc.User, cc.Password)
 	if err != nil {
 		return nil, err
 	}
 
-	trs := tokenrefreshservice.New(log, seat.TRSParams)
-	token, err := trs.Exchange(q)
-	if err != nil {
-		return nil, err
-	}
-
-	ts := trs.TokenSource(token)
-
 	// get OIDC user information
 	ctx := context.WithValue(context.Background(), oauth2.HTTPClient, request.NewClient(log))
 	ui, err := vwidentity.Config.NewProvider(ctx).UserInfo(ctx, ts)
diff --git a/vehicle/seat.go b/vehicle/seat.go
index a905e699..8709ff83 100644
--- a/vehicle/seat.go
+++ b/vehicle/seat.go
@@ -8,7 +8,6 @@ import (
 	"github.com/evcc-io/evcc/util/request"
 	"github.com/evcc-io/evcc/vehicle/seat"
 	"github.com/evcc-io/evcc/vehicle/vag/service"
-	"github.com/evcc-io/evcc/vehicle/vag/tokenrefreshservice"
 	"github.com/evcc-io/evcc/vehicle/vw"
 )
 
@@ -51,12 +50,12 @@ func NewSeatFromConfig(other map[string]interface{}) (api.Vehicle, error) {
 
 	log := util.NewLogger("seat").Redact(cc.User, cc.Password, cc.VIN)
 
-	trs := tokenrefreshservice.New(log, seat.TRSParams)
-	ts, err := service.MbbTokenSource(log, trs, seat.AuthClientID, seat.AuthParams, cc.User, cc.Password)
+	trs, err := service.TokenRefreshServiceTokenSource(log, seat.TRSParams, seat.AuthParams, cc.User, cc.Password)
 	if err != nil {
 		return nil, err
 	}
 
+	ts := service.MbbTokenSource(log, trs, seat.AuthClientID)
 	api := vw.NewAPI(log, ts, seat.Brand, seat.Country)
 	api.Client.Timeout = cc.Timeout
 
diff --git a/vehicle/skoda.go b/vehicle/skoda.go
index ee0caa7a..83c5849f 100644
--- a/vehicle/skoda.go
+++ b/vehicle/skoda.go
@@ -8,7 +8,6 @@ import (
 	"github.com/evcc-io/evcc/util/request"
 	"github.com/evcc-io/evcc/vehicle/skoda"
 	"github.com/evcc-io/evcc/vehicle/vag/service"
-	"github.com/evcc-io/evcc/vehicle/vag/tokenrefreshservice"
 	"github.com/evcc-io/evcc/vehicle/vw"
 )
 
@@ -52,12 +51,12 @@ func NewSkodaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
 	log := util.NewLogger("skoda").Redact(cc.User, cc.Password, cc.VIN)
 
 	// use Skoda api to resolve list of vehicles
-	ts, err := service.TokenRefreshServiceTokenSource(log, skoda.TRSParams, skoda.AuthParams, cc.User, cc.Password)
+	trs, err := service.TokenRefreshServiceTokenSource(log, skoda.TRSParams, skoda.AuthParams, cc.User, cc.Password)
 	if err != nil {
 		return nil, err
 	}
 
-	api := skoda.NewAPI(log, ts)
+	api := skoda.NewAPI(log, trs)
 	api.Client.Timeout = cc.Timeout
 
 	vehicle, err := ensureVehicleEx(
@@ -72,12 +71,7 @@ func NewSkodaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
 	}
 
 	if err == nil {
-		trs := tokenrefreshservice.New(log, skoda.TRSParams)
-		ts, err := service.MbbTokenSource(log, trs, skoda.AuthClientID, skoda.AuthParams, cc.User, cc.Password)
-		if err != nil {
-			return nil, err
-		}
-
+		ts := service.MbbTokenSource(log, trs, skoda.AuthClientID)
 		api := vw.NewAPI(log, ts, skoda.Brand, skoda.Country)
 		api.Client.Timeout = cc.Timeout
 
diff --git a/vehicle/vag/service/mbb.go b/vehicle/vag/service/mbb.go
index 6257bedb..c2767400 100644
--- a/vehicle/vag/service/mbb.go
+++ b/vehicle/vag/service/mbb.go
@@ -6,26 +6,14 @@ import (
 	"github.com/evcc-io/evcc/util"
 	"github.com/evcc-io/evcc/vehicle/vag"
 	"github.com/evcc-io/evcc/vehicle/vag/mbb"
-	"github.com/evcc-io/evcc/vehicle/vag/vwidentity"
 )
 
 // MbbTokenSource creates a refreshing token source for use with the MBB api.
 // Once the MBB token expires, it is recreated from the token exchanger (either TokenRefreshService or IDK)
-func MbbTokenSource(log *util.Logger, tox vag.TokenExchanger, clientID string, q url.Values, user, password string) (vag.TokenSource, error) {
-	q, err := vwidentity.Login(log, q, user, password)
-	if err != nil {
-		return nil, err
-	}
-
-	token, err := tox.Exchange(q)
-	if err != nil {
-		return nil, err
-	}
-
-	trs := tox.TokenSource(token)
+func MbbTokenSource(log *util.Logger, trs vag.TokenSource, clientID string) vag.TokenSource {
 	mbb := mbb.New(log, clientID)
 
-	mts := vag.MetaTokenSource(func() (*vag.Token, error) {
+	return vag.MetaTokenSource(func() (*vag.Token, error) {
 		// get TRS token from refreshing TRS token source
 		itoken, err := trs.TokenEx()
 		if err != nil {
@@ -42,6 +30,4 @@ func MbbTokenSource(log *util.Logger, tox vag.TokenExchanger, clientID string, q
 
 		// produce tokens from refresh MBB token source
 	}, mbb.TokenSource)
-
-	return mts, nil
 }
diff --git a/vehicle/vag/service/tokenrefreshservice.go b/vehicle/vag/service/tokenrefreshservice.go
index 2ac19614..e818b936 100644
--- a/vehicle/vag/service/tokenrefreshservice.go
+++ b/vehicle/vag/service/tokenrefreshservice.go
@@ -4,12 +4,12 @@ import (
 	"net/url"
 
 	"github.com/evcc-io/evcc/util"
+	"github.com/evcc-io/evcc/vehicle/vag"
 	"github.com/evcc-io/evcc/vehicle/vag/tokenrefreshservice"
 	"github.com/evcc-io/evcc/vehicle/vag/vwidentity"
-	"golang.org/x/oauth2"
 )
 
-func TokenRefreshServiceTokenSource(log *util.Logger, data, q url.Values, user, password string) (oauth2.TokenSource, error) {
+func TokenRefreshServiceTokenSource(log *util.Logger, data, q url.Values, user, password string) (vag.TokenSource, error) {
 	q, err := vwidentity.Login(log, q, user, password)
 	if err != nil {
 		return nil, err
diff --git a/vehicle/vw.go b/vehicle/vw.go
index 5108ff6b..f2db0016 100644
--- a/vehicle/vw.go
+++ b/vehicle/vw.go
@@ -7,7 +7,6 @@ import (
 	"github.com/evcc-io/evcc/util"
 	"github.com/evcc-io/evcc/util/request"
 	"github.com/evcc-io/evcc/vehicle/vag/service"
-	"github.com/evcc-io/evcc/vehicle/vag/tokenrefreshservice"
 	"github.com/evcc-io/evcc/vehicle/vw"
 )
 
@@ -50,12 +49,12 @@ func NewVWFromConfig(other map[string]interface{}) (api.Vehicle, error) {
 
 	log := util.NewLogger("vw").Redact(cc.User, cc.Password, cc.VIN)
 
-	trs := tokenrefreshservice.New(log, vw.TRSParams)
-	ts, err := service.MbbTokenSource(log, trs, vw.AuthClientID, vw.AuthParams, cc.User, cc.Password)
+	trs, err := service.TokenRefreshServiceTokenSource(log, vw.TRSParams, vw.AuthParams, cc.User, cc.Password)
 	if err != nil {
 		return nil, err
 	}
 
+	ts := service.MbbTokenSource(log, trs, vw.AuthClientID)
 	api := vw.NewAPI(log, ts, vw.Brand, vw.Country)
 	api.Client.Timeout = cc.Timeout
 


Test patch:
diff --git a/api/actionconfig_test.go b/api/actionconfig_test.go
index 1286b8ef..e2e401d6 100644
--- a/api/actionconfig_test.go
+++ b/api/actionconfig_test.go
@@ -18,10 +18,8 @@ func TestMerge(t *testing.T) {
 
 	now := ModeNow
 	two := 2
-	three := 3
 	new := ActionConfig{
 		Mode:     &now,
-		MinSoc:   &three,
 		Priority: &two,
 	}
 
@@ -38,7 +36,6 @@ func TestMerge(t *testing.T) {
 	assert.Equal(t, dst, ActionConfig{
 		Mode:       &now,
 		MinCurrent: &six,
-		MinSoc:     &three,
 		Priority:   &two,
 	}, "new wrong")
 }
diff --git a/core/loadpoint_vehicle_test.go b/core/loadpoint_vehicle_test.go
index 33b240bf..9e7473d8 100644
--- a/core/loadpoint_vehicle_test.go
+++ b/core/loadpoint_vehicle_test.go
@@ -148,7 +148,6 @@ func TestDefaultVehicle(t *testing.T) {
 	ctrl := gomock.NewController(t)
 
 	mode := api.ModePV
-	minsoc := 20
 	targetsoc := 80
 
 	dflt := mock.NewMockVehicle(ctrl)
@@ -158,7 +157,6 @@ func TestDefaultVehicle(t *testing.T) {
 	dflt.EXPECT().Phases().AnyTimes()
 	dflt.EXPECT().OnIdentified().Return(api.ActionConfig{
 		Mode:      &mode,
-		MinSoc:    &minsoc,
 		TargetSoc: &targetsoc,
 	}).AnyTimes()
 
@@ -175,13 +173,10 @@ func TestDefaultVehicle(t *testing.T) {
 	// ondisconnect
 	off := api.ModeOff
 	zero := 0
-	hundred := 100
 	onDisconnect := api.ActionConfig{
 		Mode:       &off,
 		MinCurrent: &lp.MinCurrent,
 		MaxCurrent: &lp.MaxCurrent,
-		MinSoc:     &zero,
-		TargetSoc:  &hundred,
 		Priority:   &zero,
 	}
 
@@ -227,13 +222,12 @@ func TestDefaultVehicle(t *testing.T) {
 func TestApplyVehicleDefaults(t *testing.T) {
 	ctrl := gomock.NewController(t)
 
-	newConfig := func(mode api.ChargeMode, minCurrent, maxCurrent float64, minSoc, targetSoc int) api.ActionConfig {
+	newConfig := func(mode api.ChargeMode, minCurrent, maxCurrent float64, targetSoc *int) api.ActionConfig {
 		return api.ActionConfig{
 			Mode:       &mode,
 			MinCurrent: &minCurrent,
 			MaxCurrent: &maxCurrent,
-			MinSoc:     &minSoc,
-			TargetSoc:  &targetSoc,
+			TargetSoc:  targetSoc,
 		}
 	}
 
@@ -244,10 +238,11 @@ func TestApplyVehicleDefaults(t *testing.T) {
 	}
 
 	// onIdentified config
-	oi := newConfig(api.ModePV, 7, 15, 1, 99)
+	targetSoc := 99
+	oi := newConfig(api.ModePV, 7, 15, &targetSoc)
 
 	// onDefault config
-	od := newConfig(api.ModeOff, 6, 16, 2, 98)
+	od := newConfig(api.ModeOff, 6, 16, nil)
 
 	vehicle := mock.NewMockVehicle(ctrl)
 	vehicle.EXPECT().Title().Return("it's me").AnyTimes()
@@ -266,7 +261,7 @@ func TestApplyVehicleDefaults(t *testing.T) {
 	lp.ResetOnDisconnect = true
 
 	// check loadpoint default currents can't be violated
-	lp.applyAction(newConfig(*od.Mode, 5, 17, *od.MinSoc, *od.TargetSoc))
+	lp.applyAction(newConfig(*od.Mode, 5, 17, od.TargetSoc))
 	assertConfig(lp, od)
 
 	// vehicle identified