Battery boost: resume from hold when limit is lowered (#32999)
This commit is contained in:
parent
769a6a1aa5
commit
13db309c94
3 changed files with 59 additions and 3 deletions
|
|
@ -2105,8 +2105,9 @@ func (lp *Loadpoint) phaseSwitchCompleted() bool {
|
|||
func (lp *Loadpoint) Update(sitePower, batteryPower float64, consumption, feedin api.Rates, batteryBuffered, batteryStart bool, greenShare float64, effPrice, effCo2 *float64, dim *bool) {
|
||||
// hold battery boost when SOC drops below the limit: stop draining the battery, but
|
||||
// keep the vehicle prioritised over recharging it (via sitePower priorityAdjustment)
|
||||
// until the vehicle disconnects. This holds the battery at the configured level
|
||||
// instead of the naive on/off which lets the battery recharge and oscillate (#30558).
|
||||
// until the vehicle disconnects or the limit is relaxed (see SetBatteryBoostLimit).
|
||||
// This holds the battery at the configured level instead of the naive on/off which
|
||||
// lets the battery recharge and oscillate (#30558).
|
||||
if boost := lp.GetBatteryBoost(); boost != boostDisabled && boost != boostHold {
|
||||
if limit := lp.GetBatteryBoostLimit(); limit < 100 {
|
||||
if batterySoc := lp.site.GetBatterySoc(); batterySoc < float64(limit) {
|
||||
|
|
|
|||
|
|
@ -680,7 +680,8 @@ func (lp *Loadpoint) GetBatteryBoostLimit() int {
|
|||
return lp.batteryBoostLimit
|
||||
}
|
||||
|
||||
// SetBatteryBoostLimit sets the battery boost soc limit
|
||||
// SetBatteryBoostLimit sets the battery boost soc limit. Relaxing the limit
|
||||
// resumes a boost held by it, 100 disables the feature and ends an active boost.
|
||||
func (lp *Loadpoint) SetBatteryBoostLimit(limit int) {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
|
@ -688,9 +689,24 @@ func (lp *Loadpoint) SetBatteryBoostLimit(limit int) {
|
|||
lp.log.DEBUG.Println("set battery boost limit:", limit)
|
||||
|
||||
if lp.batteryBoostLimit != limit {
|
||||
relaxed := limit < lp.batteryBoostLimit && lp.batteryBoostLimit < 100
|
||||
|
||||
lp.batteryBoostLimit = limit
|
||||
lp.settings.SetInt(keys.BatteryBoostLimit, int64(limit))
|
||||
lp.publish(keys.BatteryBoostLimit, limit)
|
||||
|
||||
// lock is held, hence assign instead of setBatteryBoost
|
||||
switch {
|
||||
case limit == 100 && lp.batteryBoost != boostDisabled:
|
||||
lp.log.DEBUG.Println("battery boost disable: limit removed")
|
||||
lp.batteryBoost = boostDisabled
|
||||
lp.publish(keys.BatteryBoost, false)
|
||||
case relaxed && lp.batteryBoost == boostHold:
|
||||
lp.log.DEBUG.Println("battery boost resume: limit relaxed")
|
||||
lp.batteryBoost = boostStart
|
||||
}
|
||||
|
||||
lp.requestUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/core/settings"
|
||||
"github.com/evcc-io/evcc/core/site"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -224,3 +225,41 @@ func TestBoostPowerPhaseSwitchGapBridgingExclusions(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Relaxing the limit resumes a boost it put on hold, tightening it does not.
|
||||
// Setting 100 disables the feature and ends an active boost.
|
||||
func TestSetBatteryBoostLimitResume(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
boost int
|
||||
from, to int
|
||||
want int
|
||||
wantUpdate bool
|
||||
}{
|
||||
{"lowering the limit resumes", boostHold, 50, 30, boostStart, true},
|
||||
{"removing the limit ends held boost", boostHold, 50, 100, boostDisabled, true},
|
||||
{"removing the limit ends active boost", boostContinue, 50, 100, boostDisabled, true},
|
||||
{"raising the limit holds", boostHold, 30, 50, boostHold, true},
|
||||
{"enabling a limit holds", boostHold, 100, 50, boostHold, true},
|
||||
{"unchanged limit holds", boostHold, 50, 50, boostHold, false},
|
||||
{"only a held boost resumes", boostContinue, 50, 30, boostContinue, true},
|
||||
{"disabled boost stays disabled", boostDisabled, 50, 30, boostDisabled, true},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
lp := &Loadpoint{
|
||||
log: util.NewLogger("lp"),
|
||||
settings: settings.NewDatabaseSettingsAdapter("foo"),
|
||||
lpChan: make(chan *Loadpoint, 1),
|
||||
batteryBoost: tc.boost,
|
||||
batteryBoostLimit: tc.from,
|
||||
}
|
||||
|
||||
lp.SetBatteryBoostLimit(tc.to)
|
||||
|
||||
assert.Equal(t, tc.to, lp.batteryBoostLimit)
|
||||
assert.Equal(t, tc.want, lp.batteryBoost)
|
||||
// a changed limit must act now instead of on the next update tick
|
||||
assert.Equal(t, tc.wantUpdate, len(lp.lpChan) == 1)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue