diff --git a/core/loadpoint.go b/core/loadpoint.go index 8e86fbe69..5eed52e4b 100644 --- a/core/loadpoint.go +++ b/core/loadpoint.go @@ -103,6 +103,7 @@ type Loadpoint struct { Mode api.ChargeMode `mapstructure:"mode"` // Charge mode, guarded by mutex Title_ string `mapstructure:"title"` // UI title + Priority_ int `mapstructure:"priority"` // Priority ConfiguredPhases int `mapstructure:"phases"` // Charger configured phase mode 0/1/3 ChargerRef string `mapstructure:"charger"` // Charger reference VehicleRef string `mapstructure:"vehicle"` // Vehicle reference diff --git a/core/loadpoint/api.go b/core/loadpoint/api.go index 295189392..20fea55c5 100644 --- a/core/loadpoint/api.go +++ b/core/loadpoint/api.go @@ -6,6 +6,8 @@ import ( "github.com/evcc-io/evcc/api" ) +//go:generate mockgen -package loadpoint -destination mock.go -mock_names API=MockAPI github.com/evcc-io/evcc/core/loadpoint API + // Controller gives access to loadpoint type Controller interface { LoadpointControl(API) @@ -15,6 +17,7 @@ type Controller interface { type API interface { // Title returns the defined loadpoint title Title() string + Priority() int // // status @@ -76,6 +79,8 @@ type API interface { HasChargeMeter() bool // GetChargePower returns the current charging power GetChargePower() float64 + // GetChargePowerFlexibility returns the flexible amount of current charging power + GetChargePowerFlexibility() float64 // GetMinCurrent returns the min charging current GetMinCurrent() float64 // SetMinCurrent sets the min charging current diff --git a/core/loadpoint/mock.go b/core/loadpoint/mock.go new file mode 100644 index 000000000..991780e13 --- /dev/null +++ b/core/loadpoint/mock.go @@ -0,0 +1,520 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/evcc-io/evcc/core/loadpoint (interfaces: API) + +// Package loadpoint is a generated GoMock package. +package loadpoint + +import ( + reflect "reflect" + time "time" + + api "github.com/evcc-io/evcc/api" + gomock "github.com/golang/mock/gomock" +) + +// MockAPI is a mock of API interface. +type MockAPI struct { + ctrl *gomock.Controller + recorder *MockAPIMockRecorder +} + +// MockAPIMockRecorder is the mock recorder for MockAPI. +type MockAPIMockRecorder struct { + mock *MockAPI +} + +// NewMockAPI creates a new mock instance. +func NewMockAPI(ctrl *gomock.Controller) *MockAPI { + mock := &MockAPI{ctrl: ctrl} + mock.recorder = &MockAPIMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAPI) EXPECT() *MockAPIMockRecorder { + return m.recorder +} + +// GetChargePower mocks base method. +func (m *MockAPI) GetChargePower() float64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChargePower") + ret0, _ := ret[0].(float64) + return ret0 +} + +// GetChargePower indicates an expected call of GetChargePower. +func (mr *MockAPIMockRecorder) GetChargePower() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChargePower", reflect.TypeOf((*MockAPI)(nil).GetChargePower)) +} + +// GetChargePowerFlexibility mocks base method. +func (m *MockAPI) GetChargePowerFlexibility() float64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChargePowerFlexibility") + ret0, _ := ret[0].(float64) + return ret0 +} + +// GetChargePowerFlexibility indicates an expected call of GetChargePowerFlexibility. +func (mr *MockAPIMockRecorder) GetChargePowerFlexibility() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChargePowerFlexibility", reflect.TypeOf((*MockAPI)(nil).GetChargePowerFlexibility)) +} + +// GetDisableThreshold mocks base method. +func (m *MockAPI) GetDisableThreshold() float64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDisableThreshold") + ret0, _ := ret[0].(float64) + return ret0 +} + +// GetDisableThreshold indicates an expected call of GetDisableThreshold. +func (mr *MockAPIMockRecorder) GetDisableThreshold() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDisableThreshold", reflect.TypeOf((*MockAPI)(nil).GetDisableThreshold)) +} + +// GetEnableThreshold mocks base method. +func (m *MockAPI) GetEnableThreshold() float64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEnableThreshold") + ret0, _ := ret[0].(float64) + return ret0 +} + +// GetEnableThreshold indicates an expected call of GetEnableThreshold. +func (mr *MockAPIMockRecorder) GetEnableThreshold() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnableThreshold", reflect.TypeOf((*MockAPI)(nil).GetEnableThreshold)) +} + +// GetMaxCurrent mocks base method. +func (m *MockAPI) GetMaxCurrent() float64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMaxCurrent") + ret0, _ := ret[0].(float64) + return ret0 +} + +// GetMaxCurrent indicates an expected call of GetMaxCurrent. +func (mr *MockAPIMockRecorder) GetMaxCurrent() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMaxCurrent", reflect.TypeOf((*MockAPI)(nil).GetMaxCurrent)) +} + +// GetMaxPower mocks base method. +func (m *MockAPI) GetMaxPower() float64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMaxPower") + ret0, _ := ret[0].(float64) + return ret0 +} + +// GetMaxPower indicates an expected call of GetMaxPower. +func (mr *MockAPIMockRecorder) GetMaxPower() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMaxPower", reflect.TypeOf((*MockAPI)(nil).GetMaxPower)) +} + +// GetMinCurrent mocks base method. +func (m *MockAPI) GetMinCurrent() float64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMinCurrent") + ret0, _ := ret[0].(float64) + return ret0 +} + +// GetMinCurrent indicates an expected call of GetMinCurrent. +func (mr *MockAPIMockRecorder) GetMinCurrent() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMinCurrent", reflect.TypeOf((*MockAPI)(nil).GetMinCurrent)) +} + +// GetMinPower mocks base method. +func (m *MockAPI) GetMinPower() float64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMinPower") + ret0, _ := ret[0].(float64) + return ret0 +} + +// GetMinPower indicates an expected call of GetMinPower. +func (mr *MockAPIMockRecorder) GetMinPower() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMinPower", reflect.TypeOf((*MockAPI)(nil).GetMinPower)) +} + +// GetMinSoc mocks base method. +func (m *MockAPI) GetMinSoc() int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMinSoc") + ret0, _ := ret[0].(int) + return ret0 +} + +// GetMinSoc indicates an expected call of GetMinSoc. +func (mr *MockAPIMockRecorder) GetMinSoc() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMinSoc", reflect.TypeOf((*MockAPI)(nil).GetMinSoc)) +} + +// GetMode mocks base method. +func (m *MockAPI) GetMode() api.ChargeMode { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMode") + ret0, _ := ret[0].(api.ChargeMode) + return ret0 +} + +// GetMode indicates an expected call of GetMode. +func (mr *MockAPIMockRecorder) GetMode() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMode", reflect.TypeOf((*MockAPI)(nil).GetMode)) +} + +// GetPhases mocks base method. +func (m *MockAPI) GetPhases() int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPhases") + ret0, _ := ret[0].(int) + return ret0 +} + +// GetPhases indicates an expected call of GetPhases. +func (mr *MockAPIMockRecorder) GetPhases() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPhases", reflect.TypeOf((*MockAPI)(nil).GetPhases)) +} + +// GetPlan mocks base method. +func (m *MockAPI) GetPlan(arg0 time.Time, arg1 float64) (time.Duration, api.Rates, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPlan", arg0, arg1) + ret0, _ := ret[0].(time.Duration) + ret1, _ := ret[1].(api.Rates) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GetPlan indicates an expected call of GetPlan. +func (mr *MockAPIMockRecorder) GetPlan(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPlan", reflect.TypeOf((*MockAPI)(nil).GetPlan), arg0, arg1) +} + +// GetPlannerUnit mocks base method. +func (m *MockAPI) GetPlannerUnit() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPlannerUnit") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetPlannerUnit indicates an expected call of GetPlannerUnit. +func (mr *MockAPIMockRecorder) GetPlannerUnit() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPlannerUnit", reflect.TypeOf((*MockAPI)(nil).GetPlannerUnit)) +} + +// GetRemainingDuration mocks base method. +func (m *MockAPI) GetRemainingDuration() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRemainingDuration") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// GetRemainingDuration indicates an expected call of GetRemainingDuration. +func (mr *MockAPIMockRecorder) GetRemainingDuration() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRemainingDuration", reflect.TypeOf((*MockAPI)(nil).GetRemainingDuration)) +} + +// GetRemainingEnergy mocks base method. +func (m *MockAPI) GetRemainingEnergy() float64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRemainingEnergy") + ret0, _ := ret[0].(float64) + return ret0 +} + +// GetRemainingEnergy indicates an expected call of GetRemainingEnergy. +func (mr *MockAPIMockRecorder) GetRemainingEnergy() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRemainingEnergy", reflect.TypeOf((*MockAPI)(nil).GetRemainingEnergy)) +} + +// GetStatus mocks base method. +func (m *MockAPI) GetStatus() api.ChargeStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetStatus") + ret0, _ := ret[0].(api.ChargeStatus) + return ret0 +} + +// GetStatus indicates an expected call of GetStatus. +func (mr *MockAPIMockRecorder) GetStatus() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStatus", reflect.TypeOf((*MockAPI)(nil).GetStatus)) +} + +// GetTargetEnergy mocks base method. +func (m *MockAPI) GetTargetEnergy() float64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTargetEnergy") + ret0, _ := ret[0].(float64) + return ret0 +} + +// GetTargetEnergy indicates an expected call of GetTargetEnergy. +func (mr *MockAPIMockRecorder) GetTargetEnergy() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTargetEnergy", reflect.TypeOf((*MockAPI)(nil).GetTargetEnergy)) +} + +// GetTargetSoc mocks base method. +func (m *MockAPI) GetTargetSoc() int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTargetSoc") + ret0, _ := ret[0].(int) + return ret0 +} + +// GetTargetSoc indicates an expected call of GetTargetSoc. +func (mr *MockAPIMockRecorder) GetTargetSoc() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTargetSoc", reflect.TypeOf((*MockAPI)(nil).GetTargetSoc)) +} + +// GetTargetTime mocks base method. +func (m *MockAPI) GetTargetTime() time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTargetTime") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// GetTargetTime indicates an expected call of GetTargetTime. +func (mr *MockAPIMockRecorder) GetTargetTime() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTargetTime", reflect.TypeOf((*MockAPI)(nil).GetTargetTime)) +} + +// GetVehicle mocks base method. +func (m *MockAPI) GetVehicle() api.Vehicle { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetVehicle") + ret0, _ := ret[0].(api.Vehicle) + return ret0 +} + +// GetVehicle indicates an expected call of GetVehicle. +func (mr *MockAPIMockRecorder) GetVehicle() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVehicle", reflect.TypeOf((*MockAPI)(nil).GetVehicle)) +} + +// HasChargeMeter mocks base method. +func (m *MockAPI) HasChargeMeter() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasChargeMeter") + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasChargeMeter indicates an expected call of HasChargeMeter. +func (mr *MockAPIMockRecorder) HasChargeMeter() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasChargeMeter", reflect.TypeOf((*MockAPI)(nil).HasChargeMeter)) +} + +// Priority mocks base method. +func (m *MockAPI) Priority() int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Priority") + ret0, _ := ret[0].(int) + return ret0 +} + +// Priority indicates an expected call of Priority. +func (mr *MockAPIMockRecorder) Priority() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Priority", reflect.TypeOf((*MockAPI)(nil).Priority)) +} + +// RemoteControl mocks base method. +func (m *MockAPI) RemoteControl(arg0 string, arg1 RemoteDemand) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RemoteControl", arg0, arg1) +} + +// RemoteControl indicates an expected call of RemoteControl. +func (mr *MockAPIMockRecorder) RemoteControl(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoteControl", reflect.TypeOf((*MockAPI)(nil).RemoteControl), arg0, arg1) +} + +// SetDisableThreshold mocks base method. +func (m *MockAPI) SetDisableThreshold(arg0 float64) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetDisableThreshold", arg0) +} + +// SetDisableThreshold indicates an expected call of SetDisableThreshold. +func (mr *MockAPIMockRecorder) SetDisableThreshold(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDisableThreshold", reflect.TypeOf((*MockAPI)(nil).SetDisableThreshold), arg0) +} + +// SetEnableThreshold mocks base method. +func (m *MockAPI) SetEnableThreshold(arg0 float64) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetEnableThreshold", arg0) +} + +// SetEnableThreshold indicates an expected call of SetEnableThreshold. +func (mr *MockAPIMockRecorder) SetEnableThreshold(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetEnableThreshold", reflect.TypeOf((*MockAPI)(nil).SetEnableThreshold), arg0) +} + +// SetMaxCurrent mocks base method. +func (m *MockAPI) SetMaxCurrent(arg0 float64) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetMaxCurrent", arg0) +} + +// SetMaxCurrent indicates an expected call of SetMaxCurrent. +func (mr *MockAPIMockRecorder) SetMaxCurrent(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMaxCurrent", reflect.TypeOf((*MockAPI)(nil).SetMaxCurrent), arg0) +} + +// SetMinCurrent mocks base method. +func (m *MockAPI) SetMinCurrent(arg0 float64) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetMinCurrent", arg0) +} + +// SetMinCurrent indicates an expected call of SetMinCurrent. +func (mr *MockAPIMockRecorder) SetMinCurrent(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMinCurrent", reflect.TypeOf((*MockAPI)(nil).SetMinCurrent), arg0) +} + +// SetMinSoc mocks base method. +func (m *MockAPI) SetMinSoc(arg0 int) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetMinSoc", arg0) +} + +// SetMinSoc indicates an expected call of SetMinSoc. +func (mr *MockAPIMockRecorder) SetMinSoc(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMinSoc", reflect.TypeOf((*MockAPI)(nil).SetMinSoc), arg0) +} + +// SetMode mocks base method. +func (m *MockAPI) SetMode(arg0 api.ChargeMode) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetMode", arg0) +} + +// SetMode indicates an expected call of SetMode. +func (mr *MockAPIMockRecorder) SetMode(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMode", reflect.TypeOf((*MockAPI)(nil).SetMode), arg0) +} + +// SetPhases mocks base method. +func (m *MockAPI) SetPhases(arg0 int) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetPhases", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetPhases indicates an expected call of SetPhases. +func (mr *MockAPIMockRecorder) SetPhases(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPhases", reflect.TypeOf((*MockAPI)(nil).SetPhases), arg0) +} + +// SetTargetEnergy mocks base method. +func (m *MockAPI) SetTargetEnergy(arg0 float64) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetTargetEnergy", arg0) +} + +// SetTargetEnergy indicates an expected call of SetTargetEnergy. +func (mr *MockAPIMockRecorder) SetTargetEnergy(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTargetEnergy", reflect.TypeOf((*MockAPI)(nil).SetTargetEnergy), arg0) +} + +// SetTargetSoc mocks base method. +func (m *MockAPI) SetTargetSoc(arg0 int) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetTargetSoc", arg0) +} + +// SetTargetSoc indicates an expected call of SetTargetSoc. +func (mr *MockAPIMockRecorder) SetTargetSoc(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTargetSoc", reflect.TypeOf((*MockAPI)(nil).SetTargetSoc), arg0) +} + +// SetTargetTime mocks base method. +func (m *MockAPI) SetTargetTime(arg0 time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetTargetTime", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetTargetTime indicates an expected call of SetTargetTime. +func (mr *MockAPIMockRecorder) SetTargetTime(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTargetTime", reflect.TypeOf((*MockAPI)(nil).SetTargetTime), arg0) +} + +// SetVehicle mocks base method. +func (m *MockAPI) SetVehicle(arg0 api.Vehicle) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetVehicle", arg0) +} + +// SetVehicle indicates an expected call of SetVehicle. +func (mr *MockAPIMockRecorder) SetVehicle(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetVehicle", reflect.TypeOf((*MockAPI)(nil).SetVehicle), arg0) +} + +// StartVehicleDetection mocks base method. +func (m *MockAPI) StartVehicleDetection() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "StartVehicleDetection") +} + +// StartVehicleDetection indicates an expected call of StartVehicleDetection. +func (mr *MockAPIMockRecorder) StartVehicleDetection() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartVehicleDetection", reflect.TypeOf((*MockAPI)(nil).StartVehicleDetection)) +} + +// Title mocks base method. +func (m *MockAPI) Title() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Title") + ret0, _ := ret[0].(string) + return ret0 +} + +// Title indicates an expected call of Title. +func (mr *MockAPIMockRecorder) Title() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Title", reflect.TypeOf((*MockAPI)(nil).Title)) +} diff --git a/core/loadpoint_api.go b/core/loadpoint_api.go index 04a15c534..2a32e5c1d 100644 --- a/core/loadpoint_api.go +++ b/core/loadpoint_api.go @@ -3,6 +3,7 @@ package core import ( "errors" "fmt" + "math" "time" "github.com/evcc-io/evcc/api" @@ -17,6 +18,11 @@ func (lp *Loadpoint) Title() string { return lp.Title_ } +// Priority returns the loadpoint priority +func (lp *Loadpoint) Priority() int { + return lp.Priority_ +} + // GetStatus returns the charging status func (lp *Loadpoint) GetStatus() api.ChargeStatus { lp.Lock() @@ -285,6 +291,22 @@ func (lp *Loadpoint) GetChargePower() float64 { return lp.chargePower } +// GetChargePowerFlexibility returns the flexible amount of current charging power +func (lp *Loadpoint) GetChargePowerFlexibility() float64 { + // no locking + mode := lp.GetMode() + if mode == api.ModeNow || !lp.charging() || lp.minSocNotReached() { + return 0 + } + + if mode == api.ModePV { + return lp.GetChargePower() + } + + // MinPV mode + return math.Max(0, lp.GetChargePower()-lp.GetMinPower()) +} + // GetMinCurrent returns the min loadpoint current func (lp *Loadpoint) GetMinCurrent() float64 { lp.Lock() diff --git a/core/prioritizer/prioritizer.go b/core/prioritizer/prioritizer.go new file mode 100644 index 000000000..334dac202 --- /dev/null +++ b/core/prioritizer/prioritizer.go @@ -0,0 +1,34 @@ +package prioritizer + +import ( + "github.com/evcc-io/evcc/core/loadpoint" +) + +type Prioritizer struct { + demand map[loadpoint.API]float64 +} + +func New() *Prioritizer { + return &Prioritizer{ + demand: make(map[loadpoint.API]float64), + } +} + +func (p *Prioritizer) UpdateChargePowerFlexibility(lp loadpoint.API) { + if power := lp.GetChargePowerFlexibility(); power >= 0 { + p.demand[lp] = power + } +} + +func (p *Prioritizer) GetChargePowerFlexibility(lp loadpoint.API) float64 { + prio := lp.Priority() + + var reduceBy float64 + for lp, power := range p.demand { + if lp.Priority() < prio { + reduceBy += power + } + } + + return reduceBy +} diff --git a/core/prioritizer/prioritizer_test.go b/core/prioritizer/prioritizer_test.go new file mode 100644 index 000000000..f3d322c6a --- /dev/null +++ b/core/prioritizer/prioritizer_test.go @@ -0,0 +1,36 @@ +package prioritizer + +import ( + "testing" + + "github.com/evcc-io/evcc/core/loadpoint" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +func TestPrioritzer(t *testing.T) { + ctrl := gomock.NewController(t) + + p := New() + + lo := loadpoint.NewMockAPI(ctrl) + lo.EXPECT().Priority().Return(0).AnyTimes() + + hi := loadpoint.NewMockAPI(ctrl) + hi.EXPECT().Priority().Return(1).AnyTimes() + + // no additional power available + lo.EXPECT().GetChargePowerFlexibility().Return(300.0) + p.UpdateChargePowerFlexibility(lo) + assert.Equal(t, 0.0, p.GetChargePowerFlexibility(lo)) + + // additional power available + hi.EXPECT().GetChargePowerFlexibility().Return(1e3) + p.UpdateChargePowerFlexibility(hi) + assert.Equal(t, 300.0, p.GetChargePowerFlexibility(hi)) + + // additional power removed + lo.EXPECT().GetChargePowerFlexibility().Return(0.0) + p.UpdateChargePowerFlexibility(lo) + assert.Equal(t, 0.0, p.GetChargePowerFlexibility(hi)) +} diff --git a/core/site.go b/core/site.go index 95ba444ad..dac066e33 100644 --- a/core/site.go +++ b/core/site.go @@ -14,6 +14,7 @@ import ( "github.com/evcc-io/evcc/core/db" "github.com/evcc-io/evcc/core/loadpoint" "github.com/evcc-io/evcc/core/planner" + "github.com/evcc-io/evcc/core/prioritizer" "github.com/evcc-io/evcc/push" serverdb "github.com/evcc-io/evcc/server/db" "github.com/evcc-io/evcc/tariff" @@ -25,6 +26,7 @@ const standbyPower = 10 // consider less than 10W as charger in standby // Updater abstracts the Loadpoint implementation for testing type Updater interface { + loadpoint.API Update(availablePower float64, batteryBuffered bool) } @@ -68,6 +70,7 @@ type Site struct { tariffs tariff.Tariffs // Tariff loadpoints []*Loadpoint // Loadpoints coordinator *coordinator.Coordinator // Vehicles + prioritizer *prioritizer.Prioritizer // Power budgets savings *Savings // Savings // cached state @@ -108,6 +111,7 @@ func NewSiteFromConfig( site.loadpoints = loadpoints site.tariffs = tariffs site.coordinator = coordinator.New(log, vehicles) + site.prioritizer = prioritizer.New() site.savings = NewSavings(tariffs) // upload telemetry on shutdown @@ -485,7 +489,7 @@ func (site *Site) updateMeters() error { // sitePower returns the net power exported by the site minus a residual margin. // negative values mean grid: export, battery: charging -func (site *Site) sitePower(totalChargePower float64) (float64, error) { +func (site *Site) sitePower(totalChargePower, flexiblePower float64) (float64, error) { if err := site.updateMeters(); err != nil { return 0, err } @@ -537,6 +541,12 @@ func (site *Site) sitePower(totalChargePower float64) (float64, error) { site.publish("auxPower", auxPower) sitePower -= auxPower + // handle priority + if flexiblePower > 0 { + site.log.DEBUG.Printf("giving loadpoint priority for additional: %.0fW", flexiblePower) + sitePower -= flexiblePower + } + site.log.DEBUG.Printf("site power: %.0fW", sitePower) return sitePower, nil @@ -609,9 +619,17 @@ func (site *Site) update(lp Updater) { for _, lp := range site.loadpoints { lp.UpdateChargePower() totalChargePower += lp.GetChargePower() + + site.prioritizer.UpdateChargePowerFlexibility(lp) } - if sitePower, err := site.sitePower(totalChargePower); err == nil { + // prioritize if possible + var flexiblePower float64 + if lp.GetMode() == api.ModePV { + flexiblePower = site.prioritizer.GetChargePowerFlexibility(lp) + } + + if sitePower, err := site.sitePower(totalChargePower, flexiblePower); err == nil { lp.Update(sitePower, site.batteryBuffered) // ignore negative pvPower values as that means it is not an energy source but consumption