Site: make battery discharge limit availability explicit (#32728)
This commit is contained in:
parent
8525e215a9
commit
fc6fe3dce4
6 changed files with 38 additions and 17 deletions
|
|
@ -1605,9 +1605,9 @@ func (lp *Loadpoint) boostPower(batteryPower float64) float64 {
|
|||
}
|
||||
}
|
||||
|
||||
if maxDischargePower := lp.site.GetBatteryMaxDischargePower(); maxDischargePower > 0 {
|
||||
if maxDischargePower := lp.site.GetBatteryMaxDischargePower(); maxDischargePower != nil {
|
||||
// limit delta to what the battery can still provide
|
||||
delta = min(delta, max(0, maxDischargePower-batteryPower))
|
||||
delta = min(delta, max(0, *maxDischargePower-batteryPower))
|
||||
}
|
||||
|
||||
res := max(0, batteryPower) + delta + lp.site.GetResidualPower()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
type mockSite struct {
|
||||
site.API
|
||||
maxDischargePower float64
|
||||
maxDischargePower *float64
|
||||
residualPower float64
|
||||
optimized int
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ func (m *mockSite) Optimize() {
|
|||
m.optimized++
|
||||
}
|
||||
|
||||
func (m *mockSite) GetBatteryMaxDischargePower() float64 {
|
||||
func (m *mockSite) GetBatteryMaxDischargePower() *float64 {
|
||||
return m.maxDischargePower
|
||||
}
|
||||
|
||||
|
|
@ -40,15 +40,22 @@ func TestBoostPower(t *testing.T) {
|
|||
s := &mockSite{}
|
||||
lp.site = s
|
||||
|
||||
// No max discharge power limit
|
||||
s.maxDischargePower = 0
|
||||
// No max discharge power limit (nil)
|
||||
s.maxDischargePower = nil
|
||||
// EffectiveMaxPower will be 230 * 16 * 3 = 11040
|
||||
res := lp.boostPower(0)
|
||||
assert.Equal(t, 11040.0, res)
|
||||
assert.Equal(t, boostContinue, lp.batteryBoost)
|
||||
|
||||
// Discharge power limit is 0W (battery empty)
|
||||
s.maxDischargePower = new(float64)
|
||||
lp.batteryBoost = boostStart
|
||||
res = lp.boostPower(0)
|
||||
assert.Equal(t, 0.0, res)
|
||||
|
||||
// With max discharge power limit
|
||||
s.maxDischargePower = 5000
|
||||
limit5000 := 5000.0
|
||||
s.maxDischargePower = &limit5000
|
||||
lp.batteryBoost = boostStart
|
||||
res = lp.boostPower(0)
|
||||
assert.Equal(t, 5000.0, res)
|
||||
|
|
@ -89,7 +96,8 @@ func TestBoostPower(t *testing.T) {
|
|||
// limit is 50W (less than the standard 790W delta)
|
||||
// without raw negative power, delta would be restricted to 50W
|
||||
// with raw negative power (-2000W), headroom is 2050W, so delta is allowed to be 790W
|
||||
s.maxDischargePower = 50
|
||||
limit50 := 50.0
|
||||
s.maxDischargePower = &limit50
|
||||
s.residualPower = 0 // base delta = 100 + 690 = 790
|
||||
lp.batteryBoost = boostContinue
|
||||
res = lp.boostPower(-2000)
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ type Site struct {
|
|||
excessDCPower float64 // PV excess DC charge power (hybrid only)
|
||||
auxPower float64 // Aux power
|
||||
battery types.BatteryState // Battery cached and published state
|
||||
batteryMaxDischargePower float64 // Max discharge power of all battery meters
|
||||
batteryMaxDischargePower *float64 // Max discharge power of all battery meters
|
||||
batteryMode api.BatteryMode // Battery mode (runtime only, not persisted)
|
||||
batteryModeExternal api.BatteryMode // Battery mode (external, runtime only, not persisted)
|
||||
batteryModeExternalTimer time.Time // Battery mode timer for external control
|
||||
|
|
@ -765,7 +765,11 @@ func (site *Site) updateBatteryMeters() {
|
|||
|
||||
// written from the meter goroutine, read via GetBatteryMaxDischargePower
|
||||
site.Lock()
|
||||
site.batteryMaxDischargePower = max(0, maxDischargePower)
|
||||
if maxDischargePower >= 0 {
|
||||
site.batteryMaxDischargePower = &maxDischargePower
|
||||
} else {
|
||||
site.batteryMaxDischargePower = nil
|
||||
}
|
||||
site.Unlock()
|
||||
|
||||
// retain the last known soc when every battery read failed this cycle, so a
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ type API interface {
|
|||
//
|
||||
|
||||
GetBatterySoc() float64
|
||||
GetBatteryMaxDischargePower() float64
|
||||
GetBatteryMaxDischargePower() *float64
|
||||
GetPrioritySoc() float64
|
||||
SetPrioritySoc(float64) error
|
||||
GetBufferSoc() float64
|
||||
|
|
|
|||
|
|
@ -164,10 +164,13 @@ func (site *Site) GetBatterySoc() float64 {
|
|||
}
|
||||
|
||||
// GetBatteryMaxDischargePower returns the current battery max discharge power
|
||||
func (site *Site) GetBatteryMaxDischargePower() float64 {
|
||||
func (site *Site) GetBatteryMaxDischargePower() *float64 {
|
||||
site.RLock()
|
||||
defer site.RUnlock()
|
||||
return site.batteryMaxDischargePower
|
||||
if site.batteryMaxDischargePower == nil {
|
||||
return nil
|
||||
}
|
||||
return new(*site.batteryMaxDischargePower)
|
||||
}
|
||||
|
||||
// Loadpoints returns the loadpoints as api interfaces.
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ func TestBatteryMaxDischargePowerAggregation(t *testing.T) {
|
|||
}
|
||||
|
||||
site.updateBatteryMeters()
|
||||
assert.Equal(t, 0.0, site.GetBatteryMaxDischargePower())
|
||||
assert.Nil(t, site.GetBatteryMaxDischargePower())
|
||||
|
||||
// both batteries with limit
|
||||
m3 := &mockBatteryPowerLimiter{Meter: &mockMeter{}, discharge: 3000}
|
||||
|
|
@ -59,7 +59,9 @@ func TestBatteryMaxDischargePowerAggregation(t *testing.T) {
|
|||
}
|
||||
|
||||
site.updateBatteryMeters()
|
||||
assert.Equal(t, 5000.0, site.GetBatteryMaxDischargePower())
|
||||
if res := site.GetBatteryMaxDischargePower(); assert.NotNil(t, res) {
|
||||
assert.Equal(t, 5000.0, *res)
|
||||
}
|
||||
}
|
||||
|
||||
type mockBatterySocLimiter struct {
|
||||
|
|
@ -100,7 +102,9 @@ func TestBatteryMaxDischargePowerWithMinSoc(t *testing.T) {
|
|||
|
||||
site.updateBatteryMeters()
|
||||
// Only m2 should contribute
|
||||
assert.Equal(t, 3000.0, site.GetBatteryMaxDischargePower())
|
||||
if res := site.GetBatteryMaxDischargePower(); assert.NotNil(t, res) {
|
||||
assert.Equal(t, 3000.0, *res)
|
||||
}
|
||||
|
||||
// Both empty
|
||||
m3 := &mockLimiter{mockBatterySocLimiter: mockBatterySocLimiter{Meter: &mockMeter{}, soc: 15, min: 20}, discharge: 3000}
|
||||
|
|
@ -110,5 +114,7 @@ func TestBatteryMaxDischargePowerWithMinSoc(t *testing.T) {
|
|||
}
|
||||
|
||||
site.updateBatteryMeters()
|
||||
assert.Equal(t, 0.0, site.GetBatteryMaxDischargePower())
|
||||
if res := site.GetBatteryMaxDischargePower(); assert.NotNil(t, res) {
|
||||
assert.Equal(t, 0.0, *res)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue