Circuit: fix validateCurrent and validatePower (#20183)

This commit is contained in:
mfuchs1984 2025-04-03 10:52:35 +02:00 • committed by GitHub
parent 167124bfa3
commit 455bc3348c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 39 additions and 28 deletions

View file

@ -239,8 +239,8 @@ type Circuit interface {
SetMaxPower(float64)
SetMaxCurrent(float64)
Update([]CircuitLoad) error
ValidateCurrent(old, new float64) float64
ValidatePower(old, new float64) float64
ValidateCurrent(old, new float64, charging bool) float64
ValidatePower(old, new float64, charging bool) float64
}
// Redactor is an interface to redact sensitive data

View file

@ -953,31 +953,31 @@ func (mr *MockCircuitMockRecorder) Update(arg0 any) *gomock.Call {
}
// ValidateCurrent mocks base method.
func (m *MockCircuit) ValidateCurrent(old, new float64) float64 {
func (m *MockCircuit) ValidateCurrent(old, new float64, charging bool) float64 {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ValidateCurrent", old, new)
ret := m.ctrl.Call(m, "ValidateCurrent", old, new, charging)
ret0, _ := ret[0].(float64)
return ret0
}
// ValidateCurrent indicates an expected call of ValidateCurrent.
func (mr *MockCircuitMockRecorder) ValidateCurrent(old, new any) *gomock.Call {
func (mr *MockCircuitMockRecorder) ValidateCurrent(old, new, charging any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateCurrent", reflect.TypeOf((*MockCircuit)(nil).ValidateCurrent), old, new)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateCurrent", reflect.TypeOf((*MockCircuit)(nil).ValidateCurrent), old, new, charging)
}
// ValidatePower mocks base method.
func (m *MockCircuit) ValidatePower(old, new float64) float64 {
func (m *MockCircuit) ValidatePower(old, new float64, charging bool) float64 {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ValidatePower", old, new)
ret := m.ctrl.Call(m, "ValidatePower", old, new, charging)
ret0, _ := ret[0].(float64)
return ret0
}
// ValidatePower indicates an expected call of ValidatePower.
func (mr *MockCircuitMockRecorder) ValidatePower(old, new any) *gomock.Call {
func (mr *MockCircuitMockRecorder) ValidatePower(old, new, charging any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatePower", reflect.TypeOf((*MockCircuit)(nil).ValidatePower), old, new)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatePower", reflect.TypeOf((*MockCircuit)(nil).ValidatePower), old, new, charging)
}
// Wrap mocks base method.

View file

@ -320,17 +320,22 @@ func (c *Circuit) GetMaxPhaseCurrent() float64 {
}
// ValidatePower validates power request
func (c *Circuit) ValidatePower(old, new float64) float64 {
func (c *Circuit) ValidatePower(old, new float64, charging bool) float64 {
if maxPower := c.GetMaxPower(); maxPower != 0 {
delta := max(0, new-old)
potential := maxPower - c.power
if delta > potential {
capped := max(0, old+potential)
c.log.DEBUG.Printf("validate power: %.5gW + (%.5gW -> %.5gW) > %.5gW capped at %.5gW", c.power, old, new, maxPower, capped)
new = capped
if charging {
if delta > potential {
capped := max(0, min(new, min(old+potential, maxPower*1.1))) //allow 10% more than maxPower since some devices may not utilize offered power completely
c.log.DEBUG.Printf("validate power: %.5gW + (%.5gW -> %.5gW) > %.5gW capped at %.5gW", c.power, old, new, maxPower, capped)
new = capped
} else {
c.log.TRACE.Printf("validate power: %.5gW + (%.5gW -> %.5gW) <= %.5gW ok", c.power, old, new, maxPower)
new = min(new, maxPower*1.1)
}
} else {
c.log.TRACE.Printf("validate power: %.5gW + (%.5gW -> %.5gW) <= %.5gW ok", c.power, old, new, maxPower)
new = max(0, min(new, potential))
}
}
@ -338,21 +343,27 @@ func (c *Circuit) ValidatePower(old, new float64) float64 {
return new
}
return c.parent.ValidatePower(old, new)
return c.parent.ValidatePower(old, new, charging)
}
// ValidateCurrent validates current request
func (c *Circuit) ValidateCurrent(old, new float64) float64 {
// ValidateCurrent validates current request
func (c *Circuit) ValidateCurrent(old, new float64, charging bool) float64 {
if maxCurrent := c.GetMaxCurrent(); maxCurrent != 0 {
delta := max(0, new-old)
potential := maxCurrent - c.current
if delta > potential {
capped := max(0, old+potential)
c.log.DEBUG.Printf("validate current: %.3gA + (%.3gA -> %.3gA) > %.3gA capped at %.3gA", c.current, old, new, maxCurrent, capped)
new = capped
if charging {
if delta > potential {
capped := max(0, min(new, min(old+potential, maxCurrent*1.1))) //allow up to 10% more than maxCurrent since some devices may not utilize offered current completely
c.log.DEBUG.Printf("validate current: %.3gA + (%.3gA -> %.3gA) > %.3gA capped at %.3gA", c.current, old, new, maxCurrent, capped)
new = capped
} else {
c.log.TRACE.Printf("validate current: %.3gA + (%.3gA -> %.3gA) <= %.3gA ok", c.current, old, new, maxCurrent)
new = min(new, maxCurrent*1.1)
}
} else {
c.log.TRACE.Printf("validate current: %.3gA + (%.3gA -> %.3gA) <= %.3gA ok", c.current, old, new, maxCurrent)
new = max(0, min(new, potential))
}
}
@ -360,5 +371,5 @@ func (c *Circuit) ValidateCurrent(old, new float64) float64 {
return new
}
return c.parent.ValidateCurrent(old, new)
return c.parent.ValidateCurrent(old, new, charging)
}

View file

@ -82,7 +82,7 @@ func TestCircuitPower(t *testing.T) {
cm2.EXPECT().CurrentPower().Return(tc.c2, nil)
require.NoError(t, pc.Update(nil))
assert.Equal(t, tc.res, c1.ValidatePower(tc.old, tc.new), tc)
assert.Equal(t, tc.res, c1.ValidatePower(tc.old, tc.new, true), tc)
ctrl.Finish()
}
@ -124,7 +124,7 @@ func TestCircuitCurrents(t *testing.T) {
cm2.MockPhaseCurrents.EXPECT().Currents().Return(tc.c2, tc.c2, tc.c2, nil)
require.NoError(t, pc.Update(nil))
assert.Equal(t, tc.res, c1.ValidateCurrent(tc.old, tc.new), tc)
assert.Equal(t, tc.res, c1.ValidateCurrent(tc.old, tc.new, true), tc)
ctrl.Finish()
}

View file

@ -836,10 +836,10 @@ func (lp *Loadpoint) setLimit(chargeCurrent float64) error {
// apply circuit limits
if lp.circuit != nil {
currentLimit := lp.circuit.ValidateCurrent(lp.chargeCurrent, chargeCurrent)
currentLimit := lp.circuit.ValidateCurrent(lp.chargeCurrent, chargeCurrent, lp.charging())
activePhases := lp.ActivePhases()
powerLimit := lp.circuit.ValidatePower(lp.chargePower, currentToPower(chargeCurrent, activePhases))
powerLimit := lp.circuit.ValidatePower(lp.chargePower, currentToPower(chargeCurrent, activePhases), lp.charging())
currentLimitViaPower := powerToCurrent(powerLimit, activePhases)
chargeCurrent = lp.roundedCurrent(min(currentLimit, currentLimitViaPower))