diff --git a/core/loadpoint.go b/core/loadpoint.go index fba363314..ee84555e0 100644 --- a/core/loadpoint.go +++ b/core/loadpoint.go @@ -572,7 +572,11 @@ func (lp *Loadpoint) evVehicleDisconnectHandler() { lp.stopVehicleDetection() // set default mode on disconnect - lp.defaultMode() + // skip for integrated devices: the "disconnect" here is just the socket + // being switched off, not a vehicle being unplugged - keep the user's mode (#30187) + if !lp.chargerHasFeature(api.IntegratedDevice) { + lp.defaultMode() + } // set default vehicle (may be nil) lp.setActiveVehicle(lp.defaultVehicle) diff --git a/core/loadpoint_vehicle_test.go b/core/loadpoint_vehicle_test.go index 2cdcfd10f..2e6cd9e5c 100644 --- a/core/loadpoint_vehicle_test.go +++ b/core/loadpoint_vehicle_test.go @@ -323,6 +323,36 @@ func TestDefaultVehicle(t *testing.T) { assert.Nil(t, lp.vehicle, "expected no vehicle") } +// integratedDeviceCharger is a minimal charger advertising the IntegratedDevice feature. +type integratedDeviceCharger struct{} + +func (c *integratedDeviceCharger) Status() (api.ChargeStatus, error) { return api.StatusA, nil } +func (c *integratedDeviceCharger) Enabled() (bool, error) { return false, nil } +func (c *integratedDeviceCharger) Enable(bool) error { return nil } +func (c *integratedDeviceCharger) MaxCurrent(int64) error { return nil } +func (c *integratedDeviceCharger) Features() []api.Feature { + return []api.Feature{api.IntegratedDevice} +} + +// TestDisconnectIntegratedDeviceKeepsMode is a regression test for #30187: +// switching an integrated-device loadpoint to "off" makes a switch socket report +// StatusA (disconnect). The disconnect handler must NOT reset the mode to the +// configured DefaultMode in that case, otherwise the loadpoint immediately flips +// back to pv and the socket re-enables. +func TestDisconnectIntegratedDeviceKeepsMode(t *testing.T) { + lp := NewLoadpoint(util.NewLogger("foo"), settings.NewDatabaseSettingsAdapter("foo")) + lp.charger = &integratedDeviceCharger{} + lp.DefaultMode = api.ModePV + lp.setMode(api.ModeOff) + + x, y, z := createChannels(t) + attachChannels(lp, x, y, z) + + lp.evVehicleDisconnectHandler() + + assert.Equal(t, api.ModeOff, lp.GetMode(), "integrated device disconnect must not reset mode") +} + func TestReconnectVehicle(t *testing.T) { tc := []struct { name string