Site: retain last battery soc when all reads fail (#31211)
This commit is contained in:
parent
1b748deaef
commit
518556e6b8
2 changed files with 50 additions and 13 deletions
32
core/site.go
32
core/site.go
|
|
@ -668,21 +668,27 @@ func (site *Site) updateBatteryMeters() {
|
|||
mm[i].Controllable = new(controllable)
|
||||
}
|
||||
|
||||
var batterySocAcc float64
|
||||
var totalCapacity float64
|
||||
|
||||
if lo.SomeBy(mm, func(m types.Measurement) bool { return m.Capacity == nil || *m.Capacity <= 0 }) {
|
||||
// any capacity is missing
|
||||
batterySocAcc = sumOfSocs(mm)
|
||||
totalCapacity = float64(len(site.batteryMeters))
|
||||
// retain the last known soc when every battery read failed this cycle, so a
|
||||
// transient meter error does not report the pack as empty (0%)
|
||||
if lo.EveryBy(mm, func(m types.Measurement) bool { return m.Soc == nil }) {
|
||||
site.log.WARN.Printf("battery soc: read failed, keeping last %.0f%%", site.battery.Soc)
|
||||
} else {
|
||||
// all capacities available - weigh soc by capacity
|
||||
batterySocAcc = weightedSumOfSocs(mm)
|
||||
totalCapacity = lo.SumBy(mm, func(m types.Measurement) float64 { return *m.Capacity })
|
||||
}
|
||||
var batterySocAcc float64
|
||||
var totalCapacity float64
|
||||
|
||||
site.battery.Soc = math.Min(100, batterySocAcc/totalCapacity)
|
||||
site.battery.Capacity = totalCapacity
|
||||
if lo.SomeBy(mm, func(m types.Measurement) bool { return m.Capacity == nil || *m.Capacity <= 0 }) {
|
||||
// any capacity is missing
|
||||
batterySocAcc = sumOfSocs(mm)
|
||||
totalCapacity = float64(len(site.batteryMeters))
|
||||
} else {
|
||||
// all capacities available - weigh soc by capacity
|
||||
batterySocAcc = weightedSumOfSocs(mm)
|
||||
totalCapacity = lo.SumBy(mm, func(m types.Measurement) float64 { return *m.Capacity })
|
||||
}
|
||||
|
||||
site.battery.Soc = math.Min(100, batterySocAcc/totalCapacity)
|
||||
site.battery.Capacity = totalCapacity
|
||||
}
|
||||
|
||||
site.battery.Power = lo.SumBy(mm, func(m types.Measurement) float64 {
|
||||
return m.Power
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -11,6 +12,36 @@ import (
|
|||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// TestBatterySocRetainOnReadError guards that a failed soc read keeps the last
|
||||
// known soc instead of reporting the pack as empty (discussion #26560).
|
||||
func TestBatterySocRetainOnReadError(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
meter := api.NewMockMeter(ctrl)
|
||||
meter.EXPECT().CurrentPower().Return(0.0, nil).AnyTimes()
|
||||
|
||||
battery := api.NewMockBattery(ctrl)
|
||||
battery.EXPECT().Soc().Return(0.0, errors.New("read failed")).AnyTimes()
|
||||
|
||||
var bat api.Meter = &struct {
|
||||
api.Meter
|
||||
api.Battery
|
||||
}{
|
||||
Meter: meter,
|
||||
Battery: battery,
|
||||
}
|
||||
|
||||
site := &Site{
|
||||
log: util.NewLogger("foo"),
|
||||
batteryMeters: []config.Device[api.Meter]{config.NewStaticDevice(config.Named{}, bat)},
|
||||
}
|
||||
site.battery.Soc = 84
|
||||
|
||||
site.updateBatteryMeters()
|
||||
|
||||
assert.Equal(t, 84.0, site.battery.Soc, "soc retained when the read fails")
|
||||
}
|
||||
|
||||
func TestApplyBatteryMode(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
internal, expected api.BatteryMode
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue