evcc-io/core/metrics/accumulator.go

115 lines
2.5 KiB
Go

package metrics
import (
"bytes"
"fmt"
"time"
"github.com/benbjohnson/clock"
)
type Accumulator struct {
clock clock.Clock
updated time.Time
energyMeter *float64 // kWh
returnEnergyMeter *float64 // kWh
Energy float64 `json:"energy"` // kWh
ReturnEnergy float64 `json:"returnEnergy"` // kWh
}
func WithClock(clock clock.Clock) func(*Accumulator) {
return func(m *Accumulator) {
m.clock = clock
}
}
func NewAccumulator(opt ...func(*Accumulator)) *Accumulator {
m := &Accumulator{clock: clock.New()}
for _, o := range opt {
o(m)
}
return m
}
func (m *Accumulator) Updated() time.Time {
return m.updated
}
func (m *Accumulator) String() string {
b := new(bytes.Buffer)
fmt.Fprintf(b, "Accumulated: %.3fkWh energy, %.3fkWh return energy, updated: %v", m.Energy, m.ReturnEnergy, m.updated.Truncate(time.Second))
if m.energyMeter != nil || m.returnEnergyMeter != nil {
fmt.Fprintf(b, " energy total:")
if m.energyMeter != nil {
fmt.Fprintf(b, " %.3fkWh", *m.energyMeter)
}
if m.returnEnergyMeter != nil {
fmt.Fprintf(b, " %.3fkWh return energy", *m.returnEnergyMeter)
}
}
return b.String()
}
// SetEnergyMeterTotal adds the difference to the last total meter value in kWh
func (m *Accumulator) SetEnergyMeterTotal(v float64) {
defer func() {
m.updated = m.clock.Now()
m.energyMeter = new(v)
}()
if m.energyMeter == nil {
return
}
if v >= *m.energyMeter {
m.Energy += v - *m.energyMeter
}
}
// SetReturnEnergyMeterTotal adds the difference to the last total meter value in kWh
func (m *Accumulator) SetReturnEnergyMeterTotal(v float64) {
defer func() {
m.updated = m.clock.Now()
m.returnEnergyMeter = new(v)
}()
if m.returnEnergyMeter == nil {
return
}
if v >= *m.returnEnergyMeter {
m.ReturnEnergy += v - *m.returnEnergyMeter
}
}
// AddEnergy adds the given energy in kWh to the energy total
func (m *Accumulator) AddEnergy(v float64) {
defer func() { m.updated = m.clock.Now() }()
if m.updated.IsZero() {
return
}
m.Energy += v
}
// AddReturnEnergy adds the given energy in kWh to the return energy total
func (m *Accumulator) AddReturnEnergy(v float64) {
defer func() { m.updated = m.clock.Now() }()
if m.updated.IsZero() {
return
}
m.ReturnEnergy += v
}
// AddPower adds the given power in W, calculating the energy based on the time since the last update
func (m *Accumulator) AddPower(v float64) {
since := v * m.clock.Since(m.updated).Hours() / 1e3
if v >= 0 {
m.AddEnergy(since)
} else {
m.AddReturnEnergy(-since)
}
}