Loadpoint: disable PV mode when idle integrated device lacks surplus (#33073)
This commit is contained in:
parent
469ccb83ab
commit
ebe064ad97
3 changed files with 73 additions and 0 deletions
|
|
@ -1657,6 +1657,11 @@ func (lp *Loadpoint) pvMaxCurrent(mode api.ChargeMode, sitePower, batteryPower f
|
|||
// notes: activePhases can be 1, 2 or 3 and phaseTimer can only be active if lp current is already at minCurrent
|
||||
projectedSitePower -= Voltage * minCurrent * float64(activePhases-1)
|
||||
}
|
||||
// a continuous device that is enabled but not consuming keeps its demand out
|
||||
// of site power, hiding insufficient surplus until it starts (#32282)
|
||||
if lp.chargerHasFeature(api.Continuous) && !lp.charging() {
|
||||
projectedSitePower += currentToPower(minCurrent, lp.minActivePhases())
|
||||
}
|
||||
// kick off disable sequence, unless climater keep-alive is holding
|
||||
// charging at minCurrent — otherwise the "pausing soon" badge would
|
||||
// flash on/off forever while climater is active (issue #29834).
|
||||
|
|
|
|||
|
|
@ -908,3 +908,62 @@ func TestNewLoadpointFromConfigDisabledVehicle(t *testing.T) {
|
|||
// disabled vehicle is filtered from instances
|
||||
require.Empty(t, config.Instances(config.Vehicles().Devices()))
|
||||
}
|
||||
|
||||
// TestPVDisableIdleContinuousDevice is a regression test for #32282: a continuous
|
||||
// device that is enabled but not consuming (heat pump boost signalled, compressor
|
||||
// idle) does not show its demand in site power. Without projecting it, the disable
|
||||
// gate only trips on grid consumption which the idle device never causes.
|
||||
func TestPVDisableIdleContinuousDevice(t *testing.T) {
|
||||
const dt = time.Minute
|
||||
|
||||
tc := []struct {
|
||||
name string
|
||||
status api.ChargeStatus
|
||||
chargePower float64
|
||||
site float64
|
||||
current float64
|
||||
}{
|
||||
// idle device, export below its 600W demand: disable
|
||||
{"idle, insufficient surplus", api.StatusB, 0, -400, 0},
|
||||
// idle device, export covers its demand: keep enabled
|
||||
{"idle, sufficient surplus", api.StatusB, 0, -700, 7},
|
||||
// consuming device: measured power reflects demand, keep lenient hysteresis
|
||||
{"consuming, exporting", api.StatusC, 300, -200, minA},
|
||||
}
|
||||
|
||||
for _, tc := range tc {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
clock := clock.NewMock()
|
||||
|
||||
Voltage = 100
|
||||
lp := &Loadpoint{
|
||||
log: util.NewLogger("foo"),
|
||||
clock: clock,
|
||||
charger: &continuousCharger{},
|
||||
minCurrent: minA,
|
||||
maxCurrent: maxA,
|
||||
phases: 1,
|
||||
phasesConfigured: 1,
|
||||
measuredPhases: 1,
|
||||
status: tc.status,
|
||||
enabled: true,
|
||||
chargePower: tc.chargePower,
|
||||
Disable: loadpoint.ThresholdConfig{Delay: dt},
|
||||
}
|
||||
|
||||
start := clock.Now()
|
||||
for _, delay := range []time.Duration{0, dt + 1} {
|
||||
clock.Set(start.Add(delay))
|
||||
current := lp.pvMaxCurrent(api.ModePV, tc.site, 0, false, false)
|
||||
|
||||
// before the disable delay elapses the device keeps running
|
||||
if delay == 0 {
|
||||
assert.Equal(t, max(tc.current, minA), current, "before disable delay")
|
||||
continue
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.current, current, "after disable delay")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -464,6 +464,15 @@ func (c *integratedDeviceCharger) Features() []api.Feature {
|
|||
return []api.Feature{api.IntegratedDevice}
|
||||
}
|
||||
|
||||
// continuousCharger is a minimal charger advertising the Continuous feature.
|
||||
type continuousCharger struct {
|
||||
integratedDeviceCharger
|
||||
}
|
||||
|
||||
func (c *continuousCharger) Features() []api.Feature {
|
||||
return []api.Feature{api.IntegratedDevice, api.Continuous}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue