Allow charge rater and timer to sum over multiple measurement intervals (#354)
This commit is contained in:
parent
c78a43b340
commit
96490b49df
5 changed files with 61 additions and 29 deletions
|
|
@ -222,9 +222,7 @@ func (lp *LoadPoint) configureChargerType(charger api.Charger) {
|
|||
} else {
|
||||
mt := &wrapper.ChargeMeter{}
|
||||
_ = lp.bus.Subscribe(evChargeCurrent, lp.evChargeCurrentWrappedMeterHandler)
|
||||
_ = lp.bus.Subscribe(evChargeStop, func() {
|
||||
mt.SetPower(0)
|
||||
})
|
||||
_ = lp.bus.Subscribe(evChargeStop, func() { mt.SetPower(0) })
|
||||
lp.chargeMeter = mt
|
||||
}
|
||||
}
|
||||
|
|
@ -235,7 +233,8 @@ func (lp *LoadPoint) configureChargerType(charger api.Charger) {
|
|||
} else {
|
||||
rt := wrapper.NewChargeRater(lp.log, lp.chargeMeter)
|
||||
_ = lp.bus.Subscribe(evChargePower, rt.SetChargePower)
|
||||
_ = lp.bus.Subscribe(evChargeStart, rt.StartCharge)
|
||||
_ = lp.bus.Subscribe(evVehicleConnect, func() { rt.StartCharge(false) })
|
||||
_ = lp.bus.Subscribe(evChargeStart, func() { rt.StartCharge(true) })
|
||||
_ = lp.bus.Subscribe(evChargeStop, rt.StopCharge)
|
||||
lp.chargeRater = rt
|
||||
}
|
||||
|
|
@ -245,7 +244,8 @@ func (lp *LoadPoint) configureChargerType(charger api.Charger) {
|
|||
lp.chargeTimer = ct
|
||||
} else {
|
||||
ct := wrapper.NewChargeTimer()
|
||||
_ = lp.bus.Subscribe(evChargeStart, ct.StartCharge)
|
||||
_ = lp.bus.Subscribe(evVehicleConnect, func() { ct.StartCharge(false) })
|
||||
_ = lp.bus.Subscribe(evChargeStart, func() { ct.StartCharge(true) })
|
||||
_ = lp.bus.Subscribe(evChargeStop, ct.StopCharge)
|
||||
lp.chargeTimer = ct
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func NewChargeRater(log *util.Logger, meter api.Meter) *ChargeRater {
|
|||
|
||||
// StartCharge records meter start energy. If meter does not supply TotalEnergy,
|
||||
// start time is recorded and charged energy set to zero.
|
||||
func (cr *ChargeRater) StartCharge() {
|
||||
func (cr *ChargeRater) StartCharge(continued bool) {
|
||||
cr.Lock()
|
||||
defer cr.Unlock()
|
||||
|
||||
|
|
@ -51,7 +51,9 @@ func (cr *ChargeRater) StartCharge() {
|
|||
} else {
|
||||
cr.log.ERROR.Printf("charge meter error %v", err)
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
if !continued {
|
||||
cr.chargedEnergy = 0
|
||||
}
|
||||
}
|
||||
|
|
@ -67,7 +69,7 @@ func (cr *ChargeRater) StopCharge() {
|
|||
// get end energy amount
|
||||
if m, ok := cr.meter.(api.MeterEnergy); ok {
|
||||
if f, err := m.TotalEnergy(); err == nil {
|
||||
cr.chargedEnergy = f - cr.startEnergy
|
||||
cr.chargedEnergy += f - cr.startEnergy
|
||||
cr.log.DEBUG.Printf("final charge energy: %.0fkWh", cr.chargedEnergy)
|
||||
} else {
|
||||
cr.log.ERROR.Printf("charge meter error %v", err)
|
||||
|
|
@ -109,7 +111,7 @@ func (cr *ChargeRater) ChargedEnergy() (float64, error) {
|
|||
f, err := m.TotalEnergy()
|
||||
|
||||
if err == nil {
|
||||
return f - cr.startEnergy, nil
|
||||
return cr.chargedEnergy + f - cr.startEnergy, nil
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("charge meter error %v", err)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ func TestNoMeter(t *testing.T) {
|
|||
clck := clock.NewMock()
|
||||
cr.clck = clck
|
||||
|
||||
cr.StartCharge()
|
||||
cr.StartCharge(false)
|
||||
|
||||
// 1kWh
|
||||
clck.Add(time.Hour)
|
||||
|
|
@ -33,12 +33,23 @@ func TestNoMeter(t *testing.T) {
|
|||
clck.Add(time.Hour)
|
||||
cr.SetChargePower(1e3)
|
||||
|
||||
f, err := cr.ChargedEnergy()
|
||||
if f, err := cr.ChargedEnergy(); f != 1 || err != nil {
|
||||
t.Errorf("energy: %.1f %v", f, err)
|
||||
}
|
||||
|
||||
if f != 1 || err != nil {
|
||||
// continue
|
||||
cr.StartCharge(true)
|
||||
|
||||
// 1kWh
|
||||
clck.Add(2 * time.Hour)
|
||||
cr.SetChargePower(1e3)
|
||||
cr.StopCharge()
|
||||
|
||||
if f, err := cr.ChargedEnergy(); f != 3 || err != nil {
|
||||
t.Errorf("energy: %.1f %v", f, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrappedMeter(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
|
@ -53,18 +64,13 @@ func TestWrappedMeter(t *testing.T) {
|
|||
|
||||
cm := &EnergyDecorator{Meter: mm, MeterEnergy: me}
|
||||
|
||||
me.EXPECT().
|
||||
TotalEnergy().
|
||||
Return(2.0, nil)
|
||||
me.EXPECT().
|
||||
TotalEnergy().
|
||||
Return(3.0, nil)
|
||||
|
||||
cr := NewChargeRater(util.NewLogger("foo"), cm)
|
||||
clck := clock.NewMock()
|
||||
cr.clck = clck
|
||||
|
||||
cr.StartCharge()
|
||||
me.EXPECT().TotalEnergy().Return(2.0, nil)
|
||||
|
||||
cr.StartCharge(false)
|
||||
|
||||
// ignored with meter present
|
||||
clck.Add(time.Hour)
|
||||
|
|
@ -72,15 +78,29 @@ func TestWrappedMeter(t *testing.T) {
|
|||
clck.Add(time.Hour)
|
||||
cr.SetChargePower(0)
|
||||
|
||||
me.EXPECT().TotalEnergy().Return(3.0, nil)
|
||||
|
||||
cr.StopCharge()
|
||||
|
||||
if f, err := cr.ChargedEnergy(); f != 1 || err != nil {
|
||||
t.Errorf("energy: %.1f %v", f, err)
|
||||
}
|
||||
|
||||
// ignored with meter present
|
||||
clck.Add(time.Hour)
|
||||
cr.SetChargePower(1e3)
|
||||
|
||||
f, err := cr.ChargedEnergy()
|
||||
// continue
|
||||
me.EXPECT().TotalEnergy().Return(10.0, nil)
|
||||
|
||||
if f != 1 || err != nil {
|
||||
cr.StartCharge(true)
|
||||
clck.Add(time.Hour) // actual timing ignored as energy comes from meter
|
||||
|
||||
me.EXPECT().TotalEnergy().Return(12.0, nil)
|
||||
|
||||
cr.StopCharge()
|
||||
|
||||
if f, err := cr.ChargedEnergy(); f != 3 || err != nil {
|
||||
t.Errorf("energy: %.1f %v", f, err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,13 +26,16 @@ func NewChargeTimer() *ChargeTimer {
|
|||
}
|
||||
|
||||
// StartCharge signals charge timer start
|
||||
func (m *ChargeTimer) StartCharge() {
|
||||
func (m *ChargeTimer) StartCharge(continued bool) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
m.charging = true
|
||||
m.start = m.clck.Now()
|
||||
m.duration = 0
|
||||
|
||||
if !continued {
|
||||
m.duration = 0
|
||||
}
|
||||
}
|
||||
|
||||
// StopCharge signals charge timer stop
|
||||
|
|
@ -41,7 +44,7 @@ func (m *ChargeTimer) StopCharge() {
|
|||
defer m.Unlock()
|
||||
|
||||
m.charging = false
|
||||
m.duration = m.clck.Since(m.start)
|
||||
m.duration += m.clck.Since(m.start)
|
||||
}
|
||||
|
||||
// ChargingTime implements the api.ChargeTimer interface
|
||||
|
|
@ -50,7 +53,7 @@ func (m *ChargeTimer) ChargingTime() (time.Duration, error) {
|
|||
defer m.Unlock()
|
||||
|
||||
if m.charging {
|
||||
return m.clck.Since(m.start), nil
|
||||
return m.duration + m.clck.Since(m.start), nil
|
||||
}
|
||||
return m.duration, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,14 +12,21 @@ func TestTimer(t *testing.T) {
|
|||
clck := clock.NewMock()
|
||||
ct.clck = clck
|
||||
|
||||
ct.StartCharge()
|
||||
ct.StartCharge(false)
|
||||
clck.Add(time.Hour)
|
||||
ct.StopCharge()
|
||||
clck.Add(time.Hour)
|
||||
|
||||
d, err := ct.ChargingTime()
|
||||
if d, err := ct.ChargingTime(); d != 1*time.Hour || err != nil {
|
||||
t.Error(d, err)
|
||||
}
|
||||
|
||||
if d != time.Hour || err != nil {
|
||||
// continue
|
||||
ct.StartCharge(true)
|
||||
clck.Add(2 * time.Hour)
|
||||
ct.StopCharge()
|
||||
|
||||
if d, err := ct.ChargingTime(); d != 3*time.Hour || err != nil {
|
||||
t.Error(d, err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue