Loadpoint: fix coarse power-limited chargers never enable on fractional current (#31685)
This commit is contained in:
parent
8f570f84c1
commit
999bed78c5
2 changed files with 42 additions and 1 deletions
|
|
@ -1,6 +1,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"math"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
|
|
@ -166,6 +167,11 @@ func (lp *Loadpoint) effectiveMinCurrent() float64 {
|
|||
if c, ok := api.Cap[api.PowerLimiter](lp.charger); ok {
|
||||
if res, _, err := c.GetMinMaxPower(); err == nil && res > 0 {
|
||||
chargerMin = res / (Voltage * float64(lp.minActivePhases()))
|
||||
// coarse chargers truncate to full amps in setLimit, so round the
|
||||
// demand up to keep the enable gate reachable (#31549)
|
||||
if lp.coarseCurrent() {
|
||||
chargerMin = math.Ceil(chargerMin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +203,13 @@ func (lp *Loadpoint) effectiveMaxCurrent() float64 {
|
|||
|
||||
if c, ok := api.Cap[api.PowerLimiter](lp.charger); ok {
|
||||
if _, res, err := c.GetMinMaxPower(); err == nil && res > 0 {
|
||||
maxCurrent = min(maxCurrent, res/(Voltage*float64(lp.maxActivePhases())))
|
||||
powerMax := res / (Voltage * float64(lp.maxActivePhases()))
|
||||
// match effectiveMinCurrent's rounding so a fixed power request
|
||||
// (min == max) doesn't yield min > max on coarse chargers (#31549)
|
||||
if lp.coarseCurrent() {
|
||||
powerMax = math.Ceil(powerMax)
|
||||
}
|
||||
maxCurrent = min(maxCurrent, powerMax)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,35 @@ func TestEffectivePowerLimiter(t *testing.T) {
|
|||
assert.Equal(t, 12.0, lp.effectiveMaxCurrent(), "max")
|
||||
}
|
||||
|
||||
// coarse power-limited charger with fixed request must not yield min > max (#31549)
|
||||
func TestEffectivePowerLimiterCoarse(t *testing.T) {
|
||||
Voltage = 230
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
lp := NewLoadpoint(util.NewLogger("foo"), nil)
|
||||
phases := float64(lp.minActivePhases())
|
||||
|
||||
powerLimiter := api.NewMockPowerLimiter(ctrl)
|
||||
// fixed 5.5 A/phase request -> fractional, coarse charger truncates to 5 A
|
||||
power := 230 * phases * 5.5
|
||||
powerLimiter.EXPECT().GetMinMaxPower().Return(power, power, nil).AnyTimes()
|
||||
|
||||
// MockCharger does not implement api.ChargerEx -> coarseCurrent() == true
|
||||
lp.charger = struct {
|
||||
api.Charger
|
||||
api.PowerLimiter
|
||||
}{
|
||||
Charger: api.NewMockCharger(ctrl),
|
||||
PowerLimiter: powerLimiter,
|
||||
}
|
||||
|
||||
minCurrent := lp.effectiveMinCurrent()
|
||||
maxCurrent := lp.effectiveMaxCurrent()
|
||||
assert.Equal(t, 6.0, minCurrent, "min rounded up to full amps")
|
||||
assert.Equal(t, 6.0, maxCurrent, "max rounded up to full amps")
|
||||
assert.LessOrEqual(t, minCurrent, maxCurrent, "min must not exceed max")
|
||||
}
|
||||
|
||||
func TestNextPlan(t *testing.T) {
|
||||
clock := clock.NewMock()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue