diff --git a/core/chargerhandler.go b/core/chargerhandler.go deleted file mode 100644 index 73aa0e5b9..000000000 --- a/core/chargerhandler.go +++ /dev/null @@ -1,171 +0,0 @@ -package core - -import ( - "fmt" - "time" - - "github.com/andig/evcc/api" - "github.com/andig/evcc/util" - - evbus "github.com/asaskevich/EventBus" - "github.com/benbjohnson/clock" -) - -//go:generate mockgen -package mock -destination ../mock/mock_chargerhandler.go github.com/andig/evcc/core Handler - -// Handler is the charger handler responsible for enabled state, target current and guard durations -type Handler interface { - Prepare() - Sync() - Enabled() bool - Status() (api.ChargeStatus, error) - TargetCurrent() int64 - Ramp(int64, bool) error -} - -// HandlerConfig contains the public configuration for the ChargerHandler -type HandlerConfig struct { - MinCurrent int64 // PV mode: start current Min+PV mode: min current - MaxCurrent int64 // Max allowed current. Physically ensured by the charge controller - GuardDuration time.Duration // charger enable/disable minimum holding time -} - -// ChargerHandler handles steering of the charger state and allowed current -type ChargerHandler struct { - clock clock.Clock // mockable time - bus evbus.Bus // event bus - log *util.Logger - - charger api.Charger // Charger - - HandlerConfig // public configuration - - enabled bool // Charger enabled state - targetCurrent int64 // Charger target current - - // contactor switch guard - guardUpdated time.Time // charger enabled/disabled timestamp -} - -// Status returns charger status -func (lp *ChargerHandler) Status() (api.ChargeStatus, error) { - return lp.charger.Status() -} - -// Enabled returns handler enabled state -func (lp *ChargerHandler) Enabled() bool { - return lp.enabled -} - -// TargetCurrent returns handler target current -func (lp *ChargerHandler) TargetCurrent() int64 { - return lp.targetCurrent -} - -// Prepare synchronizes initial charger enabled state and current -func (lp *ChargerHandler) Prepare() { - // read initial enabled state - enabled, err := lp.charger.Enabled() - if err == nil { - lp.enabled = enabled - lp.log.INFO.Printf("charger %sd", status[lp.enabled]) - - // prevent immediately disabling charger - if lp.enabled { - lp.guardUpdated = lp.clock.Now() - } - } else { - lp.log.ERROR.Printf("charger error: %v", err) - } - - // set current to known value - if err = lp.setTargetCurrent(lp.MinCurrent); err != nil { - lp.log.ERROR.Println(err) - } - lp.bus.Publish(evChargeCurrent, lp.MinCurrent) -} - -// Sync synchronizes charger settings to expected state -func (lp *ChargerHandler) Sync() { - enabled, err := lp.charger.Enabled() - if err == nil && enabled != lp.enabled { - lp.log.WARN.Printf("sync enabled state to %s", status[lp.enabled]) - err = lp.charger.Enable(lp.enabled) - } - - if err != nil { - lp.log.ERROR.Printf("charge controller error: %v", err) - } -} - -// chargerEnable switches charging on or off. Minimum cycle duration is guaranteed. -func (lp *ChargerHandler) chargerEnable(enable bool) error { - if remaining := (lp.GuardDuration - lp.clock.Since(lp.guardUpdated)).Truncate(time.Second); remaining > 0 { - lp.log.DEBUG.Printf("charger %s - contactor delay %v", status[enable], remaining) - return nil - } - - if lp.enabled != enable { - if err := lp.charger.Enable(enable); err != nil { - return fmt.Errorf("charge controller error: %v", err) - } - - lp.enabled = enable // cache - lp.log.INFO.Printf("charger %s", status[enable]) - lp.guardUpdated = lp.clock.Now() - } else { - lp.log.DEBUG.Printf("charger %s", status[enable]) - } - - // if not enabled, current will be reduced to 0 in handler - lp.bus.Publish(evChargeCurrent, lp.MinCurrent) - - return nil -} - -// setTargetCurrent guards setting current against changing to identical value -// and violating MaxCurrent -func (lp *ChargerHandler) setTargetCurrent(targetCurrent int64) error { - target := clamp(targetCurrent, lp.MinCurrent, lp.MaxCurrent) - - if lp.targetCurrent != target { - lp.log.DEBUG.Printf("set charge current: %dA", target) - if err := lp.charger.MaxCurrent(target); err != nil { - return fmt.Errorf("charge controller error: %v", err) - } - - lp.targetCurrent = target // cache - } - - // if not enabled, current will be reduced to 0 in handler - lp.bus.Publish(evChargeCurrent, target) - - return nil -} - -// Ramp performs ramping charger current up and down where targetCurrent=0 -// signals disabled state -func (lp *ChargerHandler) Ramp(targetCurrent int64, force bool) error { - // reset guard updated - if force { - lp.guardUpdated = time.Time{} - } - - // if targetCurrent == 0 disable - if targetCurrent == 0 { - err := lp.chargerEnable(false) - if err == nil && lp.enabled && lp.targetCurrent > lp.MinCurrent { - err = lp.setTargetCurrent(lp.MinCurrent) - } - - return err - } - - // else set targetCurrent and optionally enable - err := lp.setTargetCurrent(targetCurrent) - if err == nil && !lp.enabled { - err = lp.chargerEnable(true) - } - - return err -} diff --git a/core/chargerhandler_test.go b/core/chargerhandler_test.go deleted file mode 100644 index 316707eab..000000000 --- a/core/chargerhandler_test.go +++ /dev/null @@ -1,347 +0,0 @@ -package core - -import ( - "testing" - "time" - - "github.com/andig/evcc/api" - "github.com/andig/evcc/mock" - "github.com/andig/evcc/util" - evbus "github.com/asaskevich/EventBus" - "github.com/benbjohnson/clock" - "github.com/golang/mock/gomock" -) - -const ( - minA int64 = 6 - maxA int64 = 16 - guardDuration = 5 * time.Minute - dt = time.Hour -) - -func newChargerHandler(clock clock.Clock, mc api.Charger) *ChargerHandler { - h := &ChargerHandler{ - log: util.NewLogger("foo"), - clock: clock, - bus: evbus.New(), - charger: mc, - HandlerConfig: HandlerConfig{ - MinCurrent: minA, - MaxCurrent: maxA, - GuardDuration: guardDuration, - }, - } - - // prepare charger and set guardUpdated - mc.(*mock.MockCharger).EXPECT().Enabled().Return(true, nil) - mc.(*mock.MockCharger).EXPECT().MaxCurrent(int64(6)).Return(nil) - h.Prepare() - - return h -} - -// test here to ensure loadpoint defaults are valid -func TestNewChargerHandler(t *testing.T) { - // LoadPoint contains ChargerHandler configuration - r := NewLoadPoint(util.NewLogger("foo")) - - if r.MinCurrent != minA { - t.Errorf("expected %v, got %v", minA, r.MinCurrent) - } - if r.MaxCurrent != maxA { - t.Errorf("expected %v, got %v", maxA, r.MaxCurrent) - } - if r.GuardDuration != guardDuration { - t.Errorf("expected %v, got %v", guardDuration, r.GuardDuration) - } -} - -func TestEnable(t *testing.T) { - tc := []struct { - enabled bool - dt time.Duration - enable bool - targetCurrent int64 - expect func(*mock.MockCharger) - }{ - // any test with current != 0 or min will fail - {false, 0, false, 0, func(mc *mock.MockCharger) { - // nop - }}, - {false, 0, true, 0, func(mc *mock.MockCharger) { - // nop - }}, - {false, dt, true, 0, func(mc *mock.MockCharger) { - mc.EXPECT().Enable(true).Return(nil) - }}, - {false, 0, true, minA, func(mc *mock.MockCharger) { - // nop - }}, - {false, dt, true, minA, func(mc *mock.MockCharger) { - mc.EXPECT().Enable(true).Return(nil) - }}, - {true, 0, false, minA, func(mc *mock.MockCharger) { - // nop - }}, - {true, dt, false, minA, func(mc *mock.MockCharger) { - mc.EXPECT().Enable(false).Return(nil) - }}, - {true, 0, true, minA, func(mc *mock.MockCharger) { - // nop - }}, - {true, dt, true, minA, func(mc *mock.MockCharger) { - // nop - }}, - } - - for _, tc := range tc { - ctrl := gomock.NewController(t) - mc := mock.NewMockCharger(ctrl) - - t.Log(tc) - - clock := clock.NewMock() - r := newChargerHandler(clock, mc) - r.enabled = tc.enabled - r.targetCurrent = tc.targetCurrent - - tc.expect(mc) - clock.Add(tc.dt) - - if err := r.chargerEnable(tc.enable); err != nil { - t.Error(err) - } - - ctrl.Finish() - } -} - -func TestSetCurrent(t *testing.T) { - tc := []struct { - targetCurrentI, targetCurrent, targetCurrentO int64 - expect func(*mock.MockCharger) - }{ - {0, 0, minA, func(mc *mock.MockCharger) { - mc.EXPECT().MaxCurrent(minA).Return(nil) - }}, - {minA, minA, minA, func(mc *mock.MockCharger) { - // we are at min: current call omitted - }}, - {minA, 0, minA, func(mc *mock.MockCharger) { - // we are at min: current call omitted - }}, - {minA, maxA, maxA, func(mc *mock.MockCharger) { - mc.EXPECT().MaxCurrent(maxA).Return(nil) - }}, - {maxA, maxA, maxA, func(mc *mock.MockCharger) { - // we are at min: current call omitted - }}, - {minA, 2 * maxA, maxA, func(mc *mock.MockCharger) { - mc.EXPECT().MaxCurrent(maxA).Return(nil) - }}, - } - - for _, tc := range tc { - ctrl := gomock.NewController(t) - mc := mock.NewMockCharger(ctrl) - - t.Log(tc) - - clock := clock.NewMock() - r := newChargerHandler(clock, mc) - r.targetCurrent = tc.targetCurrentI - - tc.expect(mc) - - if err := r.setTargetCurrent(tc.targetCurrent); err != nil { - t.Error(err) - } - - if r.targetCurrent != tc.targetCurrentO { - t.Errorf("targetCurrent: expected %d, got %d", tc.targetCurrentO, r.targetCurrent) - } - - ctrl.Finish() - } -} - -func TestRampOn(t *testing.T) { - tc := []struct { - enabledI bool - targetCurrentI, targetCurrent int64 - dt time.Duration - expect func(*mock.MockCharger) - }{ - // off at zero: set min - {false, 0, minA, 0, func(mc *mock.MockCharger) { - mc.EXPECT().MaxCurrent(minA).Return(nil) - // guard duration - }}, - {false, 0, minA, dt, func(mc *mock.MockCharger) { - mc.EXPECT().MaxCurrent(minA).Return(nil) - mc.EXPECT().Enable(true).Return(nil) - }}, - // off at max: set min - {false, maxA, minA, 0, func(mc *mock.MockCharger) { - mc.EXPECT().MaxCurrent(minA).Return(nil) - // guard duration - }}, - {false, maxA, minA, dt, func(mc *mock.MockCharger) { - mc.EXPECT().MaxCurrent(minA).Return(nil) - mc.EXPECT().Enable(true).Return(nil) - }}, - // off at min: set on - {false, minA, minA, 0, func(mc *mock.MockCharger) { - // we are at min: current call omitted - // guard duration - }}, - {false, minA, minA, dt, func(mc *mock.MockCharger) { - // we are at min: current call omitted - mc.EXPECT().Enable(true).Return(nil) - }}, - // on at min, set min: set min - {true, minA, minA, 0, func(mc *mock.MockCharger) { - // we are at min: current call omitted - // we are enabled: enable call omitted - }}, - // on at max, set min: set min - {true, maxA, minA, 0, func(mc *mock.MockCharger) { - mc.EXPECT().MaxCurrent(minA).Return(nil) - // we are enabled: enable call omitted - }}, - } - - for _, tc := range tc { - ctrl := gomock.NewController(t) - mc := mock.NewMockCharger(ctrl) - - t.Log(tc) - - clock := clock.NewMock() - r := newChargerHandler(clock, mc) - r.enabled = tc.enabledI - r.targetCurrent = tc.targetCurrentI - - tc.expect(mc) - clock.Add(tc.dt) - - if err := r.Ramp(tc.targetCurrent, false); err != nil { - t.Error(err) - } - - ctrl.Finish() - } -} - -func TestRampOff(t *testing.T) { - tc := []struct { - enabledI bool - targetCurrentI int64 - dt time.Duration - expect func(*mock.MockCharger) - }{ - // off at zero - {false, 0, 0, func(mc *mock.MockCharger) { - // we are off: enable call omitted - }}, - // off at min - {false, minA, 0, func(mc *mock.MockCharger) { - // we are off: enable call omitted - }}, - // off at max - {false, maxA, 0, func(mc *mock.MockCharger) { - // we are off: enable call omitted - }}, - // on at min, disable - {true, minA, 0, func(mc *mock.MockCharger) { - // guard duration - }}, - // on at min, set disable - {true, minA, dt, func(mc *mock.MockCharger) { - // we are at min: current call omitted - mc.EXPECT().Enable(false).Return(nil) - }}, - // on at max, set disable - {true, maxA, 0, func(mc *mock.MockCharger) { - mc.EXPECT().MaxCurrent(minA).Return(nil) - // guard duration - }}, - // on at max, set disable - {true, maxA, dt, func(mc *mock.MockCharger) { - mc.EXPECT().Enable(false).Return(nil) - }}, - } - - for _, tc := range tc { - ctrl := gomock.NewController(t) - mc := mock.NewMockCharger(ctrl) - - t.Log(tc) - - clock := clock.NewMock() - r := newChargerHandler(clock, mc) - r.enabled = tc.enabledI - r.targetCurrent = tc.targetCurrentI - - tc.expect(mc) - clock.Add(tc.dt) - - if err := r.Ramp(0, false); err != nil { - t.Error(err) - } - - ctrl.Finish() - } -} - -func TestRampUpDown(t *testing.T) { - tc := []struct { - targetCurrentI, targetCurrent int64 - expect func(*mock.MockCharger) - }{ - // no change at 0: nop - {0, 0, func(mc *mock.MockCharger) { - // nop - }}, - // no change at min: nop - {minA, minA, func(mc *mock.MockCharger) { - // nop - }}, - // at min: set max - {maxA, maxA + 100, func(mc *mock.MockCharger) { - // nop - }}, - } - - for _, tc := range tc { - ctrl := gomock.NewController(t) - mc := mock.NewMockCharger(ctrl) - - t.Log(tc) - - clock := clock.NewMock() - h := newChargerHandler(clock, mc) - h.enabled = true - h.targetCurrent = tc.targetCurrentI - - tc.expect(mc) - - if err := h.Ramp(tc.targetCurrent, false); err != nil { - t.Error(err) - } - - ctrl.Finish() - } -} diff --git a/core/loadpoint.go b/core/loadpoint.go index 78b99a656..bd825faf9 100644 --- a/core/loadpoint.go +++ b/core/loadpoint.go @@ -73,9 +73,15 @@ type LoadPoint struct { } Enable, Disable ThresholdConfig - handler Handler - HandlerConfig `mapstructure:",squash"` // handle charger state and current + MinCurrent int64 // PV mode: start current Min+PV mode: min current + MaxCurrent int64 // Max allowed current. Physically ensured by the charger + GuardDuration time.Duration // charger enable/disable minimum holding time + enabled bool // Charger enabled state + maxCurrent int64 // Charger current limit + guardUpdated time.Time // Charger enabled/disabled timestamp + + charger api.Charger chargeTimer api.ChargeTimer chargeRater api.ChargeRater @@ -139,21 +145,13 @@ func NewLoadPointFromConfig(log *util.Logger, cp configProvider, other map[strin if lp.ChargerRef == "" { return nil, errors.New("missing charger") } - charger := cp.Charger(lp.ChargerRef) - lp.configureChargerType(charger) + lp.charger = cp.Charger(lp.ChargerRef) + lp.configureChargerType(lp.charger) if lp.Enable.Threshold > lp.Disable.Threshold { log.WARN.Printf("PV mode enable threshold (%.0fW) is larger than disable threshold (%.0fW)", lp.Enable.Threshold, lp.Disable.Threshold) } - lp.handler = &ChargerHandler{ - log: lp.log, - clock: lp.clock, - bus: lp.bus, - charger: charger, - HandlerConfig: lp.HandlerConfig, - } - return lp, nil } @@ -163,17 +161,15 @@ func NewLoadPoint(log *util.Logger) *LoadPoint { bus := evbus.New() lp := &LoadPoint{ - log: log, // logger - clock: clock, // mockable time - bus: bus, // event bus - Mode: api.ModeOff, - Phases: 1, - status: api.StatusNone, - HandlerConfig: HandlerConfig{ - MinCurrent: 6, // A - MaxCurrent: 16, // A - GuardDuration: 5 * time.Minute, - }, + log: log, // logger + clock: clock, // mockable time + bus: bus, // event bus + Mode: api.ModeOff, + Phases: 1, + status: api.StatusNone, + MinCurrent: 6, // A + MaxCurrent: 16, // A + GuardDuration: 5 * time.Minute, } return lp @@ -301,7 +297,7 @@ func (lp *LoadPoint) evChargeCurrentHandler(current int64) { func (lp *LoadPoint) evChargeCurrentWrappedMeterHandler(current int64) { power := float64(current*lp.Phases) * Voltage - if !lp.handler.Enabled() || lp.status != api.StatusC { + if !lp.enabled || lp.status != api.StatusC { // if disabled we cannot be charging power = 0 } @@ -357,8 +353,56 @@ func (lp *LoadPoint) Prepare(uiChan chan<- util.Param, pushChan chan<- push.Even lp.setActiveVehicle(lp.vehicles[0]) } + // read initial charger state to prevent immediately disabling charger + if enabled, err := lp.charger.Enabled(); err == nil { + if lp.enabled = enabled; enabled { + lp.guardUpdated = lp.clock.Now() + } + } else { + lp.log.ERROR.Printf("charger error: %v", err) + } + // prepare charger status - lp.handler.Prepare() + lp.setLimit(lp.MinCurrent, false) +} + +func (lp *LoadPoint) syncCharger() { + enabled, err := lp.charger.Enabled() + if err == nil && enabled != lp.enabled { + lp.log.WARN.Println("charger out of sync") + err = lp.charger.Enable(lp.enabled) + } + + if err != nil { + lp.log.ERROR.Printf("charger error: %v", err) + } +} + +func (lp *LoadPoint) setLimit(maxCurrent int64, force bool) (err error) { + // set current + if maxCurrent != lp.maxCurrent && maxCurrent >= lp.MinCurrent { + if err = lp.charger.MaxCurrent(maxCurrent); err == nil { + lp.maxCurrent = maxCurrent + lp.bus.Publish(evChargeCurrent, maxCurrent) + } + } + + // set enabled + if enabled := maxCurrent != 0; enabled != lp.enabled && err == nil { + if remaining := (lp.GuardDuration - lp.clock.Since(lp.guardUpdated)).Truncate(time.Second); remaining > 0 && !force { + lp.log.DEBUG.Printf("charger %s - contactor delay %v", status[enabled], remaining) + return nil + } + + if err = lp.charger.Enable(enabled); err == nil { + lp.enabled = enabled + lp.guardUpdated = lp.clock.Now() + lp.log.DEBUG.Printf("charger %s", status[enabled]) + lp.bus.Publish(evChargeCurrent, maxCurrent) + } + } + + return err } // connected returns the EVs connection state @@ -475,7 +519,7 @@ func (lp *LoadPoint) findActiveVehicle() { // updateChargerStatus updates charger status and detects car connected/disconnected events func (lp *LoadPoint) updateChargerStatus() error { - status, err := lp.handler.Status() + status, err := lp.charger.Status() if err != nil { return err } @@ -503,7 +547,7 @@ func (lp *LoadPoint) updateChargerStatus() error { } // update whenever there is a state change - lp.bus.Publish(evChargeCurrent, lp.handler.TargetCurrent()) + lp.bus.Publish(evChargeCurrent, lp.maxCurrent) } return nil @@ -551,7 +595,7 @@ func (lp *LoadPoint) pvDisableTimer() { // pvMaxCurrent calculates the maximum target current for PV mode func (lp *LoadPoint) pvMaxCurrent(mode api.ChargeMode, sitePower float64) int64 { // calculate target charge current from delta power and actual current - effectiveCurrent := lp.handler.TargetCurrent() + effectiveCurrent := lp.maxCurrent if lp.status != api.StatusC { effectiveCurrent = 0 } @@ -577,9 +621,7 @@ func (lp *LoadPoint) pvMaxCurrent(mode api.ChargeMode, sitePower float64) int64 } // read only once to simplify testing - enabled := lp.handler.Enabled() - - if mode == api.ModePV && enabled && targetCurrent < lp.MinCurrent { + if mode == api.ModePV && lp.enabled && targetCurrent < lp.MinCurrent { // kick off disable sequence if sitePower >= lp.Disable.Threshold { lp.log.DEBUG.Printf("site power %.0fW >= disable threshold %.0fW", sitePower, lp.Disable.Threshold) @@ -604,7 +646,7 @@ func (lp *LoadPoint) pvMaxCurrent(mode api.ChargeMode, sitePower float64) int64 return lp.MinCurrent } - if mode == api.ModePV && !enabled { + if mode == api.ModePV && !lp.enabled { // kick off enable sequence if targetCurrent >= lp.MinCurrent || (lp.Enable.Threshold != 0 && sitePower <= lp.Enable.Threshold) { @@ -717,7 +759,7 @@ func (lp *LoadPoint) Update(sitePower float64) { lp.updateChargeMeter() // update ChargeRater here to make sure initial meter update is caught - lp.bus.Publish(evChargeCurrent, lp.handler.TargetCurrent()) + lp.bus.Publish(evChargeCurrent, lp.maxCurrent) lp.bus.Publish(evChargePower, lp.chargePower) // update progress and soc before status is updated @@ -725,7 +767,7 @@ func (lp *LoadPoint) Update(sitePower float64) { // read and publish status if err := lp.updateChargerStatus(); err != nil { - lp.log.ERROR.Printf("charge controller error: %v", err) + lp.log.ERROR.Printf("charger error: %v", err) return } @@ -739,9 +781,7 @@ func (lp *LoadPoint) Update(sitePower float64) { lp.publishSoC() // sync settings with charger - if lp.status != api.StatusA { - lp.handler.Sync() - } + lp.syncCharger() // phase detection lp.detectPhases() @@ -757,14 +797,14 @@ func (lp *LoadPoint) Update(sitePower float64) { case !lp.connected(): // always disable charger if not connected // https://github.com/andig/evcc/issues/105 - err = lp.handler.Ramp(0, false) + err = lp.setLimit(0, false) case lp.targetSocReached(): var targetCurrent int64 // zero disables if lp.climateActive() { targetCurrent = lp.MinCurrent } - err = lp.handler.Ramp(targetCurrent, true) + err = lp.setLimit(targetCurrent, true) // OCPP case lp.remoteControlled(RemoteHardDisable): @@ -772,14 +812,14 @@ func (lp *LoadPoint) Update(sitePower float64) { fallthrough case mode == api.ModeOff: - err = lp.handler.Ramp(0, true) + err = lp.setLimit(0, true) case lp.minSocNotReached(): - err = lp.handler.Ramp(lp.MaxCurrent, true) + err = lp.setLimit(lp.MaxCurrent, true) lp.pvDisableTimer() // let PV mode disable immediately afterwards case mode == api.ModeNow: - err = lp.handler.Ramp(lp.MaxCurrent, true) + err = lp.setLimit(lp.MaxCurrent, true) case mode == api.ModeMinPV || mode == api.ModePV: targetCurrent := lp.pvMaxCurrent(mode, sitePower) @@ -798,7 +838,7 @@ func (lp *LoadPoint) Update(sitePower float64) { required = true } - err = lp.handler.Ramp(targetCurrent, required) + err = lp.setLimit(targetCurrent, required) } // effective disabled status diff --git a/core/loadpoint_test.go b/core/loadpoint_test.go index 766306225..004d1c507 100644 --- a/core/loadpoint_test.go +++ b/core/loadpoint_test.go @@ -15,8 +15,8 @@ import ( ) const ( - lpMinCurrent int64 = 6 - lpMaxCurrent int64 = 16 + minA int64 = 6 + maxA int64 = 16 ) type Null struct{} @@ -34,6 +34,8 @@ func (n *Null) ChargingTime() (time.Duration, error) { } func attachListeners(t *testing.T, lp *LoadPoint) { + Voltage = 230 // V + uiChan := make(chan util.Param) pushChan := make(chan push.Event) lpChan := make(chan *LoadPoint) @@ -58,6 +60,11 @@ func attachListeners(t *testing.T, lp *LoadPoint) { } }() + if charger, ok := lp.charger.(*mock.MockCharger); ok && charger != nil { + charger.EXPECT().Enabled().Return(true, nil) + charger.EXPECT().MaxCurrent(lp.MinCurrent).Return(nil) + } + lp.Prepare(uiChan, pushChan, lpChan) } @@ -67,10 +74,10 @@ func TestNew(t *testing.T) { if lp.Phases != 1 { t.Errorf("Phases %v", lp.Phases) } - if lp.MinCurrent != lpMinCurrent { + if lp.MinCurrent != minA { t.Errorf("MinCurrent %v", lp.MinCurrent) } - if lp.MaxCurrent != lpMaxCurrent { + if lp.MaxCurrent != maxA { t.Errorf("MaxCurrent %v", lp.MaxCurrent) } if lp.status != api.StatusNone { @@ -81,60 +88,51 @@ func TestNew(t *testing.T) { } } -func TestUpdate(t *testing.T) { +func TestUpdatePowerZero(t *testing.T) { tc := []struct { status api.ChargeStatus mode api.ChargeMode - expect func(h *mock.MockHandler) + expect func(h *mock.MockCharger) }{ - {api.StatusA, api.ModeOff, func(h *mock.MockHandler) { - h.EXPECT().Ramp(int64(0), false) + {api.StatusA, api.ModeOff, func(h *mock.MockCharger) { + h.EXPECT().Enable(false) }}, - {api.StatusA, api.ModeNow, func(h *mock.MockHandler) { - h.EXPECT().Ramp(int64(0), false) + {api.StatusA, api.ModeNow, func(h *mock.MockCharger) { + h.EXPECT().Enable(false) }}, - {api.StatusA, api.ModeMinPV, func(h *mock.MockHandler) { - h.EXPECT().Ramp(int64(0), false) + {api.StatusA, api.ModeMinPV, func(h *mock.MockCharger) { + h.EXPECT().Enable(false) }}, - {api.StatusA, api.ModePV, func(h *mock.MockHandler) { - h.EXPECT().Ramp(int64(0), false) // zero since update called with 0 - // h.EXPECT().Enabled().Return(false) // short-circuited due to status != C + {api.StatusA, api.ModePV, func(h *mock.MockCharger) { + h.EXPECT().Enable(false) // zero since update called with 0 }}, - {api.StatusB, api.ModeOff, func(h *mock.MockHandler) { - h.EXPECT().Ramp(int64(0), true) + {api.StatusB, api.ModeOff, func(h *mock.MockCharger) { + h.EXPECT().Enable(false) }}, - {api.StatusB, api.ModeNow, func(h *mock.MockHandler) { - h.EXPECT().Ramp(lpMaxCurrent, true) + {api.StatusB, api.ModeNow, func(h *mock.MockCharger) { + h.EXPECT().MaxCurrent(maxA) // true }}, - {api.StatusB, api.ModeMinPV, func(h *mock.MockHandler) { - // min since update called with 0 - // force = false due to pv mode climater check - h.EXPECT().Ramp(lpMinCurrent, false) + {api.StatusB, api.ModeMinPV, func(h *mock.MockCharger) { + // MaxCurrent omitted since identical value }}, - {api.StatusB, api.ModePV, func(h *mock.MockHandler) { + {api.StatusB, api.ModePV, func(h *mock.MockCharger) { // zero since update called with 0 // force = false due to pv mode climater check - h.EXPECT().Ramp(int64(0), false) - // h.EXPECT().Enabled().Return(false) // short-circuited due to status != C + h.EXPECT().Enable(false) }}, - {api.StatusC, api.ModeOff, func(h *mock.MockHandler) { - h.EXPECT().Ramp(int64(0), true) + {api.StatusC, api.ModeOff, func(h *mock.MockCharger) { + h.EXPECT().Enable(false) }}, - {api.StatusC, api.ModeNow, func(h *mock.MockHandler) { - h.EXPECT().Ramp(lpMaxCurrent, true) + {api.StatusC, api.ModeNow, func(h *mock.MockCharger) { + h.EXPECT().MaxCurrent(maxA) // true }}, - {api.StatusC, api.ModeMinPV, func(h *mock.MockHandler) { - // min since update called with 0 - // force = false due to pv mode climater check - h.EXPECT().Ramp(lpMinCurrent, false) + {api.StatusC, api.ModeMinPV, func(h *mock.MockCharger) { + // MaxCurrent omitted since identical value }}, - {api.StatusC, api.ModePV, func(h *mock.MockHandler) { - // zero since update called with 0 - // force = false due to pv mode climater check - h.EXPECT().Ramp(int64(0), false) - h.EXPECT().Enabled().Return(false) + {api.StatusC, api.ModePV, func(h *mock.MockCharger) { + // omitted since PV balanced }}, } @@ -143,43 +141,34 @@ func TestUpdate(t *testing.T) { clck := clock.NewMock() ctrl := gomock.NewController(t) - handler := mock.NewMockHandler(ctrl) + charger := mock.NewMockCharger(ctrl) lp := &LoadPoint{ log: util.NewLogger("foo"), bus: evbus.New(), clock: clck, + charger: charger, chargeMeter: &Null{}, // silence nil panics chargeRater: &Null{}, // silence nil panics chargeTimer: &Null{}, // silence nil panics - HandlerConfig: HandlerConfig{ - MinCurrent: lpMinCurrent, - MaxCurrent: lpMaxCurrent, - }, - handler: handler, - status: tc.status, // no status change + MinCurrent: minA, + MaxCurrent: maxA, + Phases: 1, + status: tc.status, // no status change } - handler.EXPECT().Prepare().Return() attachListeners(t, lp) - handler.EXPECT().Status().Return(tc.status, nil) - handler.EXPECT().TargetCurrent().Return(int64(0)) - - if tc.status != api.StatusA { - handler.EXPECT().Sync() - - if tc.mode == api.ModeMinPV || tc.mode == api.ModePV { - handler.EXPECT().TargetCurrent().Return(int64(0)) - } - } + // initial status + charger.EXPECT().Status().Return(tc.status, nil) + charger.EXPECT().Enabled().Return(true, nil) if tc.expect != nil { - tc.expect(handler) + tc.expect(charger) } lp.Mode = tc.mode - lp.Update(0) + lp.Update(0) // sitePower 0 ctrl.Finish() } @@ -209,7 +198,7 @@ func TestPVHysteresisForStatusC(t *testing.T) { {-6 * 100 * 10, 0, 0}, {-6 * 100 * 10, 1, 0}, {-6 * 100 * 10, dt - 1, 0}, - {-6 * 100 * 10, dt + 1, lpMinCurrent}, + {-6 * 100 * 10, dt + 1, minA}, }}, // keep disabled when threshold not configured {false, 0, 0, []se{ @@ -230,34 +219,34 @@ func TestPVHysteresisForStatusC(t *testing.T) { {-500, 0, 0}, {-500, 1, 0}, {-500, dt - 1, 0}, - {-500, dt + 1, lpMinCurrent}, + {-500, dt + 1, minA}, }}, // keep enabled at max {true, 500, 0, []se{ - {-16 * 100 * 10, 0, lpMaxCurrent}, - {-16 * 100 * 10, 1, lpMaxCurrent}, - {-16 * 100 * 10, dt - 1, lpMaxCurrent}, - {-16 * 100 * 10, dt + 1, lpMaxCurrent}, + {-16 * 100 * 10, 0, maxA}, + {-16 * 100 * 10, 1, maxA}, + {-16 * 100 * 10, dt - 1, maxA}, + {-16 * 100 * 10, dt + 1, maxA}, }}, // keep enabled at min {true, 500, 0, []se{ - {-6 * 100 * 10, 0, lpMinCurrent}, - {-6 * 100 * 10, 1, lpMinCurrent}, - {-6 * 100 * 10, dt - 1, lpMinCurrent}, - {-6 * 100 * 10, dt + 1, lpMinCurrent}, + {-6 * 100 * 10, 0, minA}, + {-6 * 100 * 10, 1, minA}, + {-6 * 100 * 10, dt - 1, minA}, + {-6 * 100 * 10, dt + 1, minA}, }}, // keep enabled at min (negative threshold) {true, 0, 500, []se{ - {-500, 0, lpMinCurrent}, - {-500, 1, lpMinCurrent}, - {-500, dt - 1, lpMinCurrent}, - {-500, dt + 1, lpMinCurrent}, + {-500, 0, minA}, + {-500, 1, minA}, + {-500, dt - 1, minA}, + {-500, dt + 1, minA}, }}, // disable when threshold met {true, 0, 500, []se{ - {500, 0, lpMinCurrent}, - {500, 1, lpMinCurrent}, - {500, dt - 1, lpMinCurrent}, + {500, 0, minA}, + {500, 1, minA}, + {500, dt - 1, minA}, {500, dt + 1, 0}, }}, // reset enable timer when threshold not met while timer active @@ -267,7 +256,7 @@ func TestPVHysteresisForStatusC(t *testing.T) { {-499, dt - 1, 0}, // should reset timer {-500, dt + 1, 0}, // new begin of timer {-500, 2*dt - 2, 0}, - {-500, 2*dt - 1, lpMinCurrent}, + {-500, 2*dt - 1, minA}, }}, // reset enable timer when threshold not met while timer active and threshold not configured {false, 0, 0, []se{ @@ -275,16 +264,16 @@ func TestPVHysteresisForStatusC(t *testing.T) { {-6 * 100 * 10, dt + 1, 0}, {-6 * 100 * 10, dt + 2, 0}, {-6 * 100 * 10, 2 * dt, 0}, - {-6 * 100 * 10, 2*dt + 2, lpMinCurrent}, + {-6 * 100 * 10, 2*dt + 2, minA}, }}, // reset disable timer when threshold not met while timer active {true, 0, 500, []se{ - {500, 0, lpMinCurrent}, - {500, 1, lpMinCurrent}, - {499, dt - 1, lpMinCurrent}, // reset timer - {500, dt + 1, lpMinCurrent}, // within reset timer duration - {500, 2*dt - 2, lpMinCurrent}, // still within reset timer duration - {500, 2*dt - 1, 0}, // reset timer elapsed + {500, 0, minA}, + {500, 1, minA}, + {499, dt - 1, minA}, // reset timer + {500, dt + 1, minA}, // within reset timer duration + {500, 2*dt - 2, minA}, // still within reset timer duration + {500, 2*dt - 1, 0}, // reset timer elapsed }}, } @@ -293,18 +282,16 @@ func TestPVHysteresisForStatusC(t *testing.T) { clck := clock.NewMock() ctrl := gomock.NewController(t) - handler := mock.NewMockHandler(ctrl) + charger := mock.NewMockCharger(ctrl) Voltage = 100 lp := &LoadPoint{ - log: util.NewLogger("foo"), - clock: clck, - HandlerConfig: HandlerConfig{ - MinCurrent: lpMinCurrent, - MaxCurrent: lpMaxCurrent, - }, - handler: handler, - Phases: 10, + log: util.NewLogger("foo"), + clock: clck, + charger: charger, + MinCurrent: minA, + MaxCurrent: maxA, + Phases: 10, Enable: ThresholdConfig{ Threshold: tc.enable, Delay: dt, @@ -324,9 +311,9 @@ func TestPVHysteresisForStatusC(t *testing.T) { clck.Set(start.Add(se.delay)) // maxCurrent will read actual current and enabled state in PV mode - handler.EXPECT().TargetCurrent().Return(int64(0)) - handler.EXPECT().Enabled().Return(tc.enabled) + // charger.EXPECT().Enabled().Return(tc.enabled, nil) + lp.enabled = tc.enabled current := lp.pvMaxCurrent(api.ModePV, se.site) if current != se.current { @@ -341,25 +328,20 @@ func TestPVHysteresisForStatusC(t *testing.T) { func TestPVHysteresisForStatusOtherThanC(t *testing.T) { clck := clock.NewMock() ctrl := gomock.NewController(t) - handler := mock.NewMockHandler(ctrl) Voltage = 100 lp := &LoadPoint{ - log: util.NewLogger("foo"), - clock: clck, - HandlerConfig: HandlerConfig{ - MinCurrent: lpMinCurrent, - MaxCurrent: lpMaxCurrent, - }, - handler: handler, - Phases: 10, + log: util.NewLogger("foo"), + clock: clck, + MinCurrent: minA, + MaxCurrent: maxA, + Phases: 10, } // not connected, test PV mode logic short-circuited lp.status = api.StatusA // maxCurrent will read actual current in PV mode - handler.EXPECT().TargetCurrent().Return(int64(0)) // maxCurrent will read enabled state in PV mode sitePower := -float64(minA*lp.Phases)*Voltage + 1 // 1W below min power @@ -375,7 +357,7 @@ func TestPVHysteresisForStatusOtherThanC(t *testing.T) { func TestDisableAndEnableAtTargetSoC(t *testing.T) { clock := clock.NewMock() ctrl := gomock.NewController(t) - handler := mock.NewMockHandler(ctrl) + charger := mock.NewMockCharger(ctrl) vehicle := mock.NewMockVehicle(ctrl) // wrap vehicle with estimator @@ -383,17 +365,15 @@ func TestDisableAndEnableAtTargetSoC(t *testing.T) { socEstimator := wrapper.NewSocEstimator(util.NewLogger("foo"), vehicle, false) lp := &LoadPoint{ - log: util.NewLogger("foo"), - bus: evbus.New(), - clock: clock, - chargeMeter: &Null{}, // silence nil panics - chargeRater: &Null{}, // silence nil panics - chargeTimer: &Null{}, // silence nil panics - HandlerConfig: HandlerConfig{ - MinCurrent: lpMinCurrent, - MaxCurrent: lpMaxCurrent, - }, - handler: handler, + log: util.NewLogger("foo"), + bus: evbus.New(), + clock: clock, + charger: charger, + chargeMeter: &Null{}, // silence nil panics + chargeRater: &Null{}, // silence nil panics + chargeTimer: &Null{}, // silence nil panics + MinCurrent: minA, + MaxCurrent: maxA, vehicle: vehicle, // needed for targetSoC check socEstimator: socEstimator, // instead of vehicle: vehicle, status: api.StatusC, @@ -403,43 +383,39 @@ func TestDisableAndEnableAtTargetSoC(t *testing.T) { }, } - handler.EXPECT().Prepare().Return() attachListeners(t, lp) - // charging below target - handler.EXPECT().TargetCurrent().Return(int64(6)) - handler.EXPECT().Status().Return(api.StatusC, nil) + lp.enabled = true + lp.maxCurrent = minA + + t.Log("charging below target") vehicle.EXPECT().ChargeState().Return(85.0, nil) - handler.EXPECT().Sync().Return() - handler.EXPECT().Ramp(int64(16), true).Return(nil) + charger.EXPECT().Status().Return(api.StatusC, nil) + charger.EXPECT().Enabled().Return(lp.enabled, nil) + charger.EXPECT().MaxCurrent(maxA).Return(nil) lp.Update(500) - // charging above target deactivates charger + t.Log("charging above target deactivates charger") clock.Add(5 * time.Minute) - handler.EXPECT().TargetCurrent().Return(int64(16)) - handler.EXPECT().Status().Return(api.StatusC, nil) vehicle.EXPECT().ChargeState().Return(90.0, nil) - handler.EXPECT().Sync().Return() - handler.EXPECT().Ramp(int64(0), true).Return(nil) // true due to immediately handling climate requests + charger.EXPECT().Status().Return(api.StatusC, nil) + charger.EXPECT().Enabled().Return(lp.enabled, nil) + charger.EXPECT().Enable(false).Return(nil) lp.Update(500) - // deactivated charger changes status to B + t.Log("deactivated charger changes status to B") clock.Add(5 * time.Minute) - handler.EXPECT().TargetCurrent().Return(int64(0)) - handler.EXPECT().Status().Return(api.StatusB, nil) - handler.EXPECT().TargetCurrent().Return(int64(0)) // once more for status changes vehicle.EXPECT().ChargeState().Return(95.0, nil) - handler.EXPECT().Sync().Return() - handler.EXPECT().Ramp(int64(0), true).Return(nil) // true due to immediately handling climate requests + charger.EXPECT().Status().Return(api.StatusB, nil) + charger.EXPECT().Enabled().Return(lp.enabled, nil) lp.Update(-5000) - // soc has fallen below target + t.Log("soc has fallen below target") clock.Add(5 * time.Minute) - handler.EXPECT().TargetCurrent().Return(int64(0)) - handler.EXPECT().Status().Return(api.StatusB, nil) vehicle.EXPECT().ChargeState().Return(85.0, nil) - handler.EXPECT().Sync().Return() - handler.EXPECT().Ramp(int64(16), true).Return(nil) // TODO don't treat this as forced change + charger.EXPECT().Status().Return(api.StatusB, nil) + charger.EXPECT().Enabled().Return(lp.enabled, nil) + charger.EXPECT().Enable(true).Return(nil) lp.Update(-5000) ctrl.Finish() @@ -448,21 +424,19 @@ func TestDisableAndEnableAtTargetSoC(t *testing.T) { func TestSetModeAndSocAtDisconnect(t *testing.T) { clock := clock.NewMock() ctrl := gomock.NewController(t) - handler := mock.NewMockHandler(ctrl) + charger := mock.NewMockCharger(ctrl) lp := &LoadPoint{ log: util.NewLogger("foo"), bus: evbus.New(), clock: clock, + charger: charger, chargeMeter: &Null{}, // silence nil panics chargeRater: &Null{}, // silence nil panics chargeTimer: &Null{}, // silence nil panics - HandlerConfig: HandlerConfig{ - MinCurrent: lpMinCurrent, - MaxCurrent: lpMaxCurrent, - }, - handler: handler, - status: api.StatusC, + MinCurrent: minA, + MaxCurrent: maxA, + status: api.StatusC, OnDisconnect: struct { Mode api.ChargeMode `mapstructure:"mode"` // Charge mode to apply when car disconnected TargetSoC int `mapstructure:"targetSoC"` // Target SoC to apply when car disconnected @@ -472,21 +446,23 @@ func TestSetModeAndSocAtDisconnect(t *testing.T) { }, } - handler.EXPECT().Prepare().Return() attachListeners(t, lp) + lp.enabled = true + lp.maxCurrent = minA lp.Mode = api.ModeNow - handler.EXPECT().TargetCurrent().Return(int64(6)) - handler.EXPECT().Status().Return(api.StatusC, nil) - handler.EXPECT().Sync().Return() - handler.EXPECT().Ramp(int64(16), true).Return(nil) + + t.Log("charging at min") + charger.EXPECT().Enabled().Return(lp.enabled, nil) + charger.EXPECT().Status().Return(api.StatusC, nil) + charger.EXPECT().MaxCurrent(maxA).Return(nil) lp.Update(500) + t.Log("switch off when disconnected") clock.Add(5 * time.Minute) - handler.EXPECT().TargetCurrent().Return(int64(16)) - handler.EXPECT().Status().Return(api.StatusA, nil) - handler.EXPECT().TargetCurrent().Return(int64(0)) // once more for status changes - handler.EXPECT().Ramp(int64(0), false).Return(nil) + charger.EXPECT().Enabled().Return(lp.enabled, nil) + charger.EXPECT().Status().Return(api.StatusA, nil) + charger.EXPECT().Enable(false).Return(nil) lp.Update(-3000) if lp.Mode != api.ModeOff { @@ -519,91 +495,74 @@ func cacheExpecter(t *testing.T, lp *LoadPoint) (*util.Cache, func(key string, v func TestChargedEnergyAtDisconnect(t *testing.T) { clock := clock.NewMock() ctrl := gomock.NewController(t) - handler := mock.NewMockHandler(ctrl) + charger := mock.NewMockCharger(ctrl) rater := mock.NewMockChargeRater(ctrl) lp := &LoadPoint{ log: util.NewLogger("foo"), bus: evbus.New(), clock: clock, + charger: charger, chargeMeter: &Null{}, // silence nil panics chargeRater: rater, chargeTimer: &Null{}, // silence nil panics - HandlerConfig: HandlerConfig{ - MinCurrent: lpMinCurrent, - MaxCurrent: lpMaxCurrent, - }, - handler: handler, - status: api.StatusC, + MinCurrent: minA, + MaxCurrent: maxA, + status: api.StatusC, } - lp.Mode = api.ModeNow - handler.EXPECT().Prepare().Return() attachListeners(t, lp) + lp.enabled = true + lp.maxCurrent = maxA + lp.Mode = api.ModeNow + // attach cache for verifying values _, expectCache := cacheExpecter(t, lp) - // start charging at 0 kWh - handler.EXPECT().TargetCurrent().Return(int64(6)) + t.Log("start charging at 0 kWh") rater.EXPECT().ChargedEnergy().Return(0.0, nil) - handler.EXPECT().Status().Return(api.StatusC, nil) - handler.EXPECT().Sync().Return() - handler.EXPECT().Ramp(int64(16), true).Return(nil) + charger.EXPECT().Enabled().Return(lp.enabled, nil) + charger.EXPECT().Status().Return(api.StatusC, nil) lp.Update(-1) - // at 1:00h charging at 5 kWh + t.Log("at 1:00h charging at 5 kWh") clock.Add(time.Hour) - handler.EXPECT().TargetCurrent().Return(int64(16)) rater.EXPECT().ChargedEnergy().Return(5.0, nil) - handler.EXPECT().Status().Return(api.StatusC, nil) - handler.EXPECT().Sync().Return() - // handler.EXPECT().TargetCurrent().Return(int64(0)) // once more for status changes - handler.EXPECT().Ramp(int64(16), true).Return(nil) + charger.EXPECT().Enabled().Return(lp.enabled, nil) + charger.EXPECT().Status().Return(api.StatusC, nil) lp.Update(-1) expectCache("chargedEnergy", 5000.0) - // at 1:00h stop charging at 5 kWh + t.Log("at 1:00h stop charging at 5 kWh") clock.Add(time.Second) - handler.EXPECT().TargetCurrent().Return(int64(16)) rater.EXPECT().ChargedEnergy().Return(5.0, nil) - handler.EXPECT().Status().Return(api.StatusB, nil) - handler.EXPECT().Sync().Return() - handler.EXPECT().TargetCurrent().Return(int64(0)) // once more for status changes - handler.EXPECT().Ramp(int64(16), true).Return(nil) + charger.EXPECT().Enabled().Return(lp.enabled, nil) + charger.EXPECT().Status().Return(api.StatusB, nil) lp.Update(-1) expectCache("chargedEnergy", 5000.0) - // at 1:00h restart charging at 5 kWh + t.Log("at 1:00h restart charging at 5 kWh") clock.Add(time.Second) - handler.EXPECT().TargetCurrent().Return(int64(16)) rater.EXPECT().ChargedEnergy().Return(5.0, nil) - handler.EXPECT().Status().Return(api.StatusC, nil) - handler.EXPECT().Sync().Return() - handler.EXPECT().TargetCurrent().Return(int64(0)) // once more for status changes - handler.EXPECT().Ramp(int64(16), true).Return(nil) + charger.EXPECT().Enabled().Return(lp.enabled, nil) + charger.EXPECT().Status().Return(api.StatusC, nil) lp.Update(-1) expectCache("chargedEnergy", 5000.0) - // at 1:30h continue charging at 7.5 kWh + t.Log("at 1:30h continue charging at 7.5 kWh") clock.Add(30 * time.Minute) - handler.EXPECT().TargetCurrent().Return(int64(16)) rater.EXPECT().ChargedEnergy().Return(7.5, nil) - handler.EXPECT().Status().Return(api.StatusC, nil) - handler.EXPECT().Sync().Return() - // handler.EXPECT().TargetCurrent().Return(int64(0)) // once more for status changes - handler.EXPECT().Ramp(int64(16), true).Return(nil) + charger.EXPECT().Enabled().Return(lp.enabled, nil) + charger.EXPECT().Status().Return(api.StatusC, nil) lp.Update(-1) expectCache("chargedEnergy", 7500.0) - // at 2:00h stop charging at 10 kWh + t.Log("at 2:00h stop charging at 10 kWh") clock.Add(30 * time.Minute) - handler.EXPECT().TargetCurrent().Return(int64(16)) rater.EXPECT().ChargedEnergy().Return(10.0, nil) - handler.EXPECT().Status().Return(api.StatusB, nil) - handler.EXPECT().Sync().Return() - handler.EXPECT().TargetCurrent().Return(int64(0)) // once more for status changes - handler.EXPECT().Ramp(int64(16), true).Return(nil) + charger.EXPECT().Enabled().Return(lp.enabled, nil) + charger.EXPECT().Status().Return(api.StatusB, nil) lp.Update(-1) expectCache("chargedEnergy", 10000.0) diff --git a/core/site.go b/core/site.go index 783636225..30e09cce7 100644 --- a/core/site.go +++ b/core/site.go @@ -150,11 +150,10 @@ func (site *Site) DumpConfig() { lp.log.INFO.Printf(" mode: %s", lp.GetMode()) - charger := lp.handler.(*ChargerHandler).charger - _, power := charger.(api.Meter) - _, energy := charger.(api.MeterEnergy) - _, currents := charger.(api.MeterCurrent) - _, timer := charger.(api.ChargeTimer) + _, power := lp.charger.(api.Meter) + _, energy := lp.charger.(api.MeterEnergy) + _, currents := lp.charger.(api.MeterCurrent) + _, timer := lp.charger.(api.ChargeTimer) lp.log.INFO.Printf(" charger: power %s energy %s currents %s timer %s", presence[power], diff --git a/mock/mock_chargerhandler.go b/mock/mock_chargerhandler.go deleted file mode 100644 index ad86552ba..000000000 --- a/mock/mock_chargerhandler.go +++ /dev/null @@ -1,115 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/andig/evcc/core (interfaces: Handler) - -// Package mock is a generated GoMock package. -package mock - -import ( - api "github.com/andig/evcc/api" - gomock "github.com/golang/mock/gomock" - reflect "reflect" -) - -// MockHandler is a mock of Handler interface -type MockHandler struct { - ctrl *gomock.Controller - recorder *MockHandlerMockRecorder -} - -// MockHandlerMockRecorder is the mock recorder for MockHandler -type MockHandlerMockRecorder struct { - mock *MockHandler -} - -// NewMockHandler creates a new mock instance -func NewMockHandler(ctrl *gomock.Controller) *MockHandler { - mock := &MockHandler{ctrl: ctrl} - mock.recorder = &MockHandlerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use -func (m *MockHandler) EXPECT() *MockHandlerMockRecorder { - return m.recorder -} - -// Enabled mocks base method -func (m *MockHandler) Enabled() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Enabled") - ret0, _ := ret[0].(bool) - return ret0 -} - -// Enabled indicates an expected call of Enabled -func (mr *MockHandlerMockRecorder) Enabled() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Enabled", reflect.TypeOf((*MockHandler)(nil).Enabled)) -} - -// Prepare mocks base method -func (m *MockHandler) Prepare() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Prepare") -} - -// Prepare indicates an expected call of Prepare -func (mr *MockHandlerMockRecorder) Prepare() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prepare", reflect.TypeOf((*MockHandler)(nil).Prepare)) -} - -// Ramp mocks base method -func (m *MockHandler) Ramp(arg0 int64, arg1 bool) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Ramp", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// Ramp indicates an expected call of Ramp -func (mr *MockHandlerMockRecorder) Ramp(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ramp", reflect.TypeOf((*MockHandler)(nil).Ramp), arg0, arg1) -} - -// Status mocks base method -func (m *MockHandler) Status() (api.ChargeStatus, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Status") - ret0, _ := ret[0].(api.ChargeStatus) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Status indicates an expected call of Status -func (mr *MockHandlerMockRecorder) Status() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockHandler)(nil).Status)) -} - -// Sync mocks base method -func (m *MockHandler) Sync() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Sync") -} - -// Sync indicates an expected call of Sync -func (mr *MockHandlerMockRecorder) Sync() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sync", reflect.TypeOf((*MockHandler)(nil).Sync)) -} - -// TargetCurrent mocks base method -func (m *MockHandler) TargetCurrent() int64 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TargetCurrent") - ret0, _ := ret[0].(int64) - return ret0 -} - -// TargetCurrent indicates an expected call of TargetCurrent -func (mr *MockHandlerMockRecorder) TargetCurrent() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TargetCurrent", reflect.TypeOf((*MockHandler)(nil).TargetCurrent)) -}