Replace current precendence with min/max logic (#11311)

This commit is contained in:
andig 2023-12-30 19:06:08 +01:00 • committed by GitHub
parent 32dc8384b2
commit cf597421d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 13 deletions

View file

@ -9,7 +9,7 @@ import (
"time"
)
//go:generate mockgen -package api -destination mock.go github.com/evcc-io/evcc/api Charger,ChargeState,PhaseSwitcher,Identifier,Meter,MeterEnergy,Vehicle,ChargeRater,Battery,Tariff,BatteryController
//go:generate mockgen -package api -destination mock.go github.com/evcc-io/evcc/api Charger,ChargeState,CurrentLimiter,PhaseSwitcher,Identifier,Meter,MeterEnergy,Vehicle,ChargeRater,Battery,Tariff,BatteryController
// ChargeMode is the charge operation mode. Valid values are off, now, minpv and pv
type ChargeMode string

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/evcc-io/evcc/api (interfaces: Charger,ChargeState,PhaseSwitcher,Identifier,Meter,MeterEnergy,Vehicle,ChargeRater,Battery,Tariff,BatteryController)
// Source: github.com/evcc-io/evcc/api (interfaces: Charger,ChargeState,CurrentLimiter,PhaseSwitcher,Identifier,Meter,MeterEnergy,Vehicle,ChargeRater,Battery,Tariff,BatteryController)
// Package api is a generated GoMock package.
package api
@ -129,6 +129,45 @@ func (mr *MockChargeStateMockRecorder) Status() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockChargeState)(nil).Status))
}
// MockCurrentLimiter is a mock of CurrentLimiter interface.
type MockCurrentLimiter struct {
ctrl *gomock.Controller
recorder *MockCurrentLimiterMockRecorder
}
// MockCurrentLimiterMockRecorder is the mock recorder for MockCurrentLimiter.
type MockCurrentLimiterMockRecorder struct {
mock *MockCurrentLimiter
}
// NewMockCurrentLimiter creates a new mock instance.
func NewMockCurrentLimiter(ctrl *gomock.Controller) *MockCurrentLimiter {
mock := &MockCurrentLimiter{ctrl: ctrl}
mock.recorder = &MockCurrentLimiterMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockCurrentLimiter) EXPECT() *MockCurrentLimiterMockRecorder {
return m.recorder
}
// GetMinMaxCurrent mocks base method.
func (m *MockCurrentLimiter) GetMinMaxCurrent() (float64, float64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetMinMaxCurrent")
ret0, _ := ret[0].(float64)
ret1, _ := ret[1].(float64)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
}
// GetMinMaxCurrent indicates an expected call of GetMinMaxCurrent.
func (mr *MockCurrentLimiterMockRecorder) GetMinMaxCurrent() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMinMaxCurrent", reflect.TypeOf((*MockCurrentLimiter)(nil).GetMinMaxCurrent))
}
// MockPhaseSwitcher is a mock of PhaseSwitcher interface.
type MockPhaseSwitcher struct {
ctrl *gomock.Controller

View file

@ -60,38 +60,46 @@ func (lp *Loadpoint) SocBasedPlanning() bool {
// effectiveMinCurrent returns the effective min current
func (lp *Loadpoint) effectiveMinCurrent() float64 {
minCurrent := lp.GetMinCurrent()
if v := lp.GetVehicle(); v != nil {
if res, ok := v.OnIdentified().GetMinCurrent(); ok {
return res
minCurrent = max(minCurrent, res)
}
}
if c, ok := lp.charger.(api.CurrentLimiter); ok {
if res, _, err := c.GetMinMaxCurrent(); err == nil {
lp.publish(keys.EffectiveMinCurrent, res)
return res
if res > 0 && res < minCurrent {
minCurrent = res
} else {
minCurrent = max(minCurrent, res)
}
lp.publish(keys.EffectiveMinCurrent, minCurrent)
}
}
return lp.GetMinCurrent()
return minCurrent
}
// effectiveMaxCurrent returns the effective max current
func (lp *Loadpoint) effectiveMaxCurrent() float64 {
maxCurrent := lp.GetMaxCurrent()
if v := lp.GetVehicle(); v != nil {
if res, ok := v.OnIdentified().GetMaxCurrent(); ok {
return res
maxCurrent = min(maxCurrent, res)
}
}
if c, ok := lp.charger.(api.CurrentLimiter); ok {
if _, res, err := c.GetMinMaxCurrent(); err == nil {
lp.publish(keys.EffectiveMaxCurrent, res)
return res
maxCurrent = min(maxCurrent, res)
lp.publish(keys.EffectiveMaxCurrent, maxCurrent)
}
}
return lp.GetMaxCurrent()
return maxCurrent
}
// effectiveLimitSoc returns the effective session limit soc

View file

@ -3,7 +3,9 @@ package core
import (
"testing"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
)
@ -11,3 +13,54 @@ func TestEffectiveLimitSoc(t *testing.T) {
lp := NewLoadpoint(util.NewLogger("foo"), nil)
assert.Equal(t, 100, lp.effectiveLimitSoc())
}
func TestEffectiveMinMaxCurrent(t *testing.T) {
tc := []struct {
chargerMin, chargerMax float64
vehicleMin, vehicleMax float64
effectiveMin, effectiveMax float64
}{
{0, 0, 0, 0, 6, 16},
{1, 10, 0, 0, 1, 10}, // charger lower
{10, 20, 0, 0, 10, 16}, // charger higher - max ignored
{0, 0, 1, 10, 6, 10}, // vehicle lower - min ignored
{0, 0, 10, 20, 10, 16}, // vehicle higher - max ignored
{1, 10, 2, 12, 1, 10}, // charger + vehicle lower
{10, 20, 12, 22, 10, 16}, // charger + vehicle higher
}
for _, tc := range tc {
t.Logf("%+v", tc)
ctrl := gomock.NewController(t)
lp := NewLoadpoint(util.NewLogger("foo"), nil)
lp.charger = api.NewMockCharger(ctrl)
if tc.chargerMin+tc.chargerMax > 0 {
currentLimiter := api.NewMockCurrentLimiter(ctrl)
currentLimiter.EXPECT().GetMinMaxCurrent().Return(tc.chargerMin, tc.chargerMax, nil).AnyTimes()
lp.charger = struct {
api.Charger
api.CurrentLimiter
}{
Charger: lp.charger,
CurrentLimiter: currentLimiter,
}
}
if tc.vehicleMin+tc.vehicleMax > 0 {
vehicle := api.NewMockVehicle(ctrl)
ac := api.ActionConfig{
MinCurrent: tc.vehicleMin,
MaxCurrent: tc.vehicleMax,
}
vehicle.EXPECT().OnIdentified().Return(ac).AnyTimes()
lp.vehicle = vehicle
}
assert.Equal(t, tc.effectiveMin, lp.effectiveMinCurrent())
assert.Equal(t, tc.effectiveMax, lp.effectiveMaxCurrent())
}
}

View file

@ -88,9 +88,6 @@ func TestNew(t *testing.T) {
if lp.phases != 0 {
t.Errorf("Phases %v", lp.phases)
}
if lp.MinCurrent != minA {
t.Errorf("MinCurrent %v", lp.MinCurrent)
}
if lp.MaxCurrent != maxA {
t.Errorf("MaxCurrent %v", lp.MaxCurrent)
}