Add currents to default meter (#267)

This commit is contained in:
andig 2020-08-04 22:31:41 +02:00
parent 21e7356590
commit ec04b22739
2 changed files with 107 additions and 15 deletions

View file

@ -4,7 +4,7 @@ import (
"testing"
"time"
"github.com/andig/evcc/meter"
"github.com/andig/evcc/api"
"github.com/andig/evcc/mock"
"github.com/andig/evcc/util"
"github.com/benbjohnson/clock"
@ -45,7 +45,13 @@ func TestWrappedMeter(t *testing.T) {
mm := mock.NewMockMeter(ctrl)
me := mock.NewMockMeterEnergy(ctrl)
cm := &meter.EnergyDecorator{Meter: mm, MeterEnergy: me}
type EnergyDecorator struct {
api.Meter
api.MeterEnergy
}
cm := &EnergyDecorator{Meter: mm, MeterEnergy: me}
me.EXPECT().
TotalEnergy().

View file

@ -1,6 +1,7 @@
package meter
import (
"errors"
"fmt"
"github.com/andig/evcc/api"
@ -8,17 +9,12 @@ import (
"github.com/andig/evcc/util"
)
// EnergyDecorator decorates an api.Meter with api.MeterEnergy
type EnergyDecorator struct {
api.Meter
api.MeterEnergy
}
// NewConfigurableFromConfig creates api.Meter from config
func NewConfigurableFromConfig(other map[string]interface{}) (api.Meter, error) {
cc := struct {
Power provider.Config
Energy *provider.Config // optional
Power provider.Config
Energy *provider.Config // optional
Currents []provider.Config // optional
}{}
if err := util.DecodeOther(other, &cc); err != nil {
@ -40,14 +36,54 @@ func NewConfigurableFromConfig(other map[string]interface{}) (api.Meter, error)
// decorate Meter with MeterEnergy
if cc.Energy != nil {
energy, err := provider.NewFloatGetterFromConfig(*cc.Energy)
energy, err := NewMeterEnergy(*cc.Energy)
if err != nil {
return nil, err
}
type EnergyDecorator struct {
api.Meter
api.MeterEnergy
}
m = &EnergyDecorator{
Meter: m,
MeterEnergy: NewMeterEnergy(energy),
MeterEnergy: energy,
}
}
// decorate Meter with MeterCurrent
if len(cc.Currents) > 0 {
currents, err := NewCurrents(cc.Currents)
if err != nil {
return nil, err
}
type PowerEnergy interface {
api.Meter
api.MeterEnergy
}
if pe, ok := m.(PowerEnergy); ok {
type CurrentDecorator struct {
PowerEnergy
api.MeterCurrent
}
m = &CurrentDecorator{
PowerEnergy: pe,
MeterCurrent: currents,
}
} else {
type CurrentDecorator struct {
api.Meter
api.MeterCurrent
}
m = &CurrentDecorator{
Meter: m,
MeterCurrent: currents,
}
}
}
@ -77,14 +113,64 @@ type MeterEnergy struct {
totalEnergyG func() (float64, error)
}
// NewMeterEnergy creates a new charger
func NewMeterEnergy(totalEnergyG func() (float64, error)) api.MeterEnergy {
return &MeterEnergy{
// NewMeterEnergy creates a new api.MeterEnergy
func NewMeterEnergy(ccEnergy provider.Config) (api.MeterEnergy, error) {
totalEnergyG, err := provider.NewFloatGetterFromConfig(ccEnergy)
if err != nil {
return nil, err
}
e := &MeterEnergy{
totalEnergyG: totalEnergyG,
}
return e, nil
}
// TotalEnergy implements the Meter.TotalEnergy interface
func (m *MeterEnergy) TotalEnergy() (float64, error) {
return m.totalEnergyG()
}
// Currents is an api.MeterCurrent implementation
type Currents struct {
currentsG []func() (float64, error)
}
// NewCurrents creates a new api.MeterCurrent
func NewCurrents(ccCurrents []provider.Config) (api.MeterCurrent, error) {
if len(ccCurrents) != 3 {
return nil, errors.New("need 3 currents")
}
var currentsG []func() (float64, error)
for _, cc := range ccCurrents {
c, err := provider.NewFloatGetterFromConfig(cc)
if err != nil {
return nil, err
}
currentsG = append(currentsG, c)
}
c := &Currents{
currentsG: currentsG,
}
return c, nil
}
// Currents implements the api.Currents interface
func (c *Currents) Currents() (float64, float64, float64, error) {
var currents []float64
for _, currentG := range c.currentsG {
c, err := currentG()
if err != nil {
return 0, 0, 0, err
}
currents = append(currents, c)
}
return currents[0], currents[1], currents[2], nil
}