Repository: evcc-io/evcc
Pull request #4551 (2022-09-22 17:04:51)

Fix resetOnDisconnect overriding default vehicle properties
/cc @thierolm 


Patch:
diff --git a/api/api.go b/api/api.go
index ee40099a..aa299e34 100644
--- a/api/api.go
+++ b/api/api.go
@@ -57,6 +57,27 @@ type ActionConfig struct {
 	TargetSoC  *int        `mapstructure:"targetSoC,omitempty"`  // Target SoC
 }
 
+// Merge merges all non-nil properties of the additional config into the base config.
+// The receiver's config remains immutable.
+func (a ActionConfig) Merge(m ActionConfig) ActionConfig {
+	if m.Mode != nil {
+		a.Mode = m.Mode
+	}
+	if m.MinCurrent != nil {
+		a.MinCurrent = m.MinCurrent
+	}
+	if m.MaxCurrent != nil {
+		a.MaxCurrent = m.MaxCurrent
+	}
+	if m.MinSoC != nil {
+		a.MinSoC = m.MinSoC
+	}
+	if m.TargetSoC != nil {
+		a.TargetSoC = m.TargetSoC
+	}
+	return a
+}
+
 // String implements Stringer and returns the ActionConfig as comma-separated key:value string
 func (a ActionConfig) String() string {
 	var s []string
diff --git a/core/loadpoint.go b/core/loadpoint.go
index 04e014bf..66ad17c8 100644
--- a/core/loadpoint.go
+++ b/core/loadpoint.go
@@ -449,8 +449,11 @@ func (lp *LoadPoint) evVehicleDisconnectHandler() {
 
 	// set default mode on disconnect
 	if lp.ResetOnDisconnect {
-		// TODO respect defaultVehicle
-		lp.applyAction(lp.onDisconnect)
+		actionCfg := lp.onDisconnect
+		if v := lp.defaultVehicle; v != nil {
+			actionCfg = actionCfg.Merge(v.OnIdentified())
+		}
+		lp.applyAction(actionCfg)
 	}
 
 	// soc update reset


Test patch:
diff --git a/core/loadpoint_vehicle_test.go b/core/loadpoint_vehicle_test.go
index ff257acc..116f68da 100644
--- a/core/loadpoint_vehicle_test.go
+++ b/core/loadpoint_vehicle_test.go
@@ -80,11 +80,19 @@ func TestVehicleDetectByID(t *testing.T) {
 func TestDefaultVehicle(t *testing.T) {
 	ctrl := gomock.NewController(t)
 
+	mode := api.ModePV
+	minsoc := 20
+	targetsoc := 80
+
 	dflt := mock.NewMockVehicle(ctrl)
 	dflt.EXPECT().Title().Return("default").AnyTimes()
 	dflt.EXPECT().Capacity().AnyTimes()
 	dflt.EXPECT().Phases().AnyTimes()
-	dflt.EXPECT().OnIdentified().AnyTimes()
+	dflt.EXPECT().OnIdentified().Return(api.ActionConfig{
+		Mode:      &mode,
+		MinSoC:    &minsoc,
+		TargetSoC: &targetsoc,
+	}).AnyTimes()
 
 	vehicle := mock.NewMockVehicle(ctrl)
 	vehicle.EXPECT().Title().Return("target").AnyTimes()
@@ -94,6 +102,7 @@ func TestDefaultVehicle(t *testing.T) {
 
 	lp := NewLoadPoint(util.NewLogger("foo"))
 	lp.defaultVehicle = dflt
+	lp.collectDefaults()
 
 	// populate channels
 	x, y, z := createChannels(t)
@@ -119,9 +128,19 @@ func TestDefaultVehicle(t *testing.T) {
 	}
 
 	// default vehicle disconnected
+	lp.ResetOnDisconnect = true
 	lp.evVehicleDisconnectHandler()
-	if lp.vehicle != dflt {
-		t.Errorf("expected %v, got %v", title(dflt), title(lp.vehicle))
+	if m := lp.GetMode(); m != mode {
+		t.Errorf("expected mode %v, got %v", mode, m)
+	}
+	if s := lp.GetMinSoC(); s != minsoc {
+		t.Errorf("expected minsoc %v, got %v", minsoc, s)
+	}
+	if s := lp.GetTargetSoC(); s != targetsoc {
+		t.Errorf("expected targetsoc %v, got %v", targetsoc, s)
+	}
+	if m := lp.onDisconnect.Mode; *m != api.ModeOff {
+		t.Errorf("expected ondisconnect mode %v, got %v", api.ModeOff, m)
 	}
 
 	// set non-default vehicle during disconnect - should be default on connect