Use mockable clock (#26)

This commit is contained in:
andig 2020-04-09 13:10:22 +02:00 • committed by GitHub
parent 44388cdc26
commit 2bfeed5451
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 27 additions and 22 deletions

View file

@ -11,6 +11,7 @@ import (
"github.com/andig/evcc/push"
evbus "github.com/asaskevich/EventBus"
"github.com/benbjohnson/clock"
)
var (
@ -34,6 +35,7 @@ func powerToCurrent(power, voltage float64, phases int64) int64 {
// SoC needs and power availability.
type LoadPoint struct {
sync.Mutex // guard status
clock clock.Clock // mockable time
bus evbus.Bus // event bus
triggerChan chan struct{} // API updates
notificationChan chan<- push.Event // notifications
@ -76,6 +78,7 @@ type LoadPoint struct {
// NewLoadPoint creates a LoadPoint with sane defaults
func NewLoadPoint() *LoadPoint {
return &LoadPoint{
clock: clock.New(),
bus: evbus.New(),
triggerChan: make(chan struct{}, 1),
Name: "Main",
@ -85,7 +88,7 @@ func NewLoadPoint() *LoadPoint {
Voltage: 230, // V
MinCurrent: 6, // A
MaxCurrent: 16, // A
Steepness: 1, // A
Steepness: 10, // A
targetCurrent: 0, // A
GuardDuration: 10 * time.Minute,
}
@ -204,16 +207,17 @@ func (lp *LoadPoint) Prepare(uiChan chan<- Param, notificationChan chan<- push.E
_ = lp.bus.Subscribe(evStopCharge, lp.evChargeStopHandler)
// read initial enabled state
var err error
if lp.enabled, err = lp.Charger.Enabled(); err != nil {
log.ERROR.Printf("%s charger error: %v", lp.Name, err)
} else {
enabled, err := lp.Charger.Enabled()
if err == nil {
lp.enabled = enabled
log.INFO.Printf("%s charger %s", lp.Name, status[lp.enabled])
// prevent immediately disabling charger
if lp.enabled {
lp.guardUpdated = time.Now()
lp.guardUpdated = lp.clock.Now()
}
} else {
log.ERROR.Printf("%s charger error: %v", lp.Name, err)
}
// set current to known value
@ -234,7 +238,7 @@ func (lp *LoadPoint) chargerEnable(enable bool) error {
log.FATAL.Fatal("charger enable/disable called without setting min current first")
}
if remaining := lp.GuardDuration - time.Since(lp.guardUpdated).Truncate(time.Second); remaining > 0 {
if remaining := (lp.GuardDuration - time.Since(lp.guardUpdated)).Truncate(time.Second); remaining > 0 {
log.DEBUG.Printf("%s charger %s - contactor delay %v", lp.Name, status[enable], remaining)
return nil
}
@ -243,7 +247,7 @@ func (lp *LoadPoint) chargerEnable(enable bool) error {
if err == nil {
lp.enabled = enable // cache
log.INFO.Printf("%s charger %s", lp.Name, status[enable])
lp.guardUpdated = time.Now()
lp.guardUpdated = lp.clock.Now()
// if not enabled, current will be reduced to 0 in handler
lp.bus.Publish(evChargeCurrent, lp.MinCurrent)
@ -290,7 +294,7 @@ func (lp *LoadPoint) updateChargeStatus() api.ChargeStatus {
log.INFO.Printf("%s car connected (%s)", lp.Name, string(status))
if lp.enabled {
// when car connected don't disable right away
lp.guardUpdated = time.Now()
lp.guardUpdated = lp.clock.Now()
}
}
@ -417,13 +421,14 @@ func (lp *LoadPoint) updateModePV(mode api.ChargeMode) error {
// updateMeter updates and publishes single meter
func (lp *LoadPoint) updateMeter(name string, meter api.Meter, power *float64) {
var err error
*power, err = meter.CurrentPower()
value, err := meter.CurrentPower()
if err != nil {
log.ERROR.Printf("%s %v", lp.Name, err)
return
}
*power = value // update value if no error
log.DEBUG.Printf("%s %s power: %.1fW", lp.Name, name, *power)
lp.publish(name+"Power", *power)
}

View file

@ -8,7 +8,7 @@ import (
// Cached wraps a getter with a cache
type Cached struct {
clck clock.Clock
clock clock.Clock
updated time.Time
cache time.Duration
getter interface{}
@ -18,7 +18,7 @@ type Cached struct {
// NewCached wraps a getter with a cache
func NewCached(getter interface{}, cache time.Duration) *Cached {
return &Cached{
clck: clock.New(),
clock: clock.New(),
getter: getter,
cache: cache,
}
@ -35,13 +35,13 @@ func (c *Cached) FloatGetter() FloatGetter {
}
return FloatGetter(func() (float64, error) {
if c.clck.Since(c.updated) > c.cache {
if c.clock.Since(c.updated) > c.cache {
val, err := g()
if err != nil {
return val, err
}
c.updated = c.clck.Now()
c.updated = c.clock.Now()
c.val = val
}
@ -60,13 +60,13 @@ func (c *Cached) IntGetter() IntGetter {
}
return IntGetter(func() (int64, error) {
if c.clck.Since(c.updated) > c.cache {
if c.clock.Since(c.updated) > c.cache {
val, err := g()
if err != nil {
return val, err
}
c.updated = c.clck.Now()
c.updated = c.clock.Now()
c.val = val
}
@ -85,14 +85,14 @@ func (c *Cached) StringGetter() StringGetter {
}
return StringGetter(func() (string, error) {
if c.clck.Since(c.updated) > c.cache {
if c.clock.Since(c.updated) > c.cache {
val, err := g()
if err != nil {
return val, err
}
c.updated = c.clck.Now()
c.updated = c.clock.Now()
c.val = val
}
@ -111,14 +111,14 @@ func (c *Cached) BoolGetter() BoolGetter {
}
return BoolGetter(func() (bool, error) {
if c.clck.Since(c.updated) > c.cache {
if c.clock.Since(c.updated) > c.cache {
val, err := g()
if err != nil {
return val, err
}
c.updated = c.clck.Now()
c.updated = c.clock.Now()
c.val = val
}

View file

@ -29,7 +29,7 @@ func TestCachedGetter(t *testing.T) {
duration := time.Second
c := NewCached(g, duration)
clck := clock.NewMock()
c.clck = clck
c.clock = clck
getter := c.FloatGetter()
expect := func(s struct {