Make meters configurable (#55)
This commit is contained in:
parent
fb67ec99cc
commit
a1bb0dc594
9 changed files with 67 additions and 54 deletions
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/charger"
|
||||
"github.com/andig/evcc/core"
|
||||
"github.com/andig/evcc/meter"
|
||||
"github.com/andig/evcc/push"
|
||||
"github.com/andig/evcc/server"
|
||||
"github.com/andig/evcc/vehicle"
|
||||
|
|
@ -19,7 +20,7 @@ type config struct {
|
|||
Influx influxConfig
|
||||
Menu []server.MenuConfig
|
||||
Messaging messagingConfig
|
||||
Meters []namedConfig
|
||||
Meters []qualifiedConfig
|
||||
Chargers []qualifiedConfig
|
||||
Vehicles []qualifiedConfig
|
||||
LoadPoints []core.Config
|
||||
|
|
@ -30,11 +31,6 @@ type qualifiedConfig struct {
|
|||
Other map[string]interface{} `mapstructure:",remain"`
|
||||
}
|
||||
|
||||
type namedConfig struct {
|
||||
Name string
|
||||
Other map[string]interface{} `mapstructure:",remain"`
|
||||
}
|
||||
|
||||
type typedConfig struct {
|
||||
Type string
|
||||
Other map[string]interface{} `mapstructure:",remain"`
|
||||
|
|
@ -102,7 +98,7 @@ func (c *ConfigProvider) configure(conf config) {
|
|||
func (c *ConfigProvider) configureMeters(conf config) {
|
||||
c.meters = make(map[string]api.Meter)
|
||||
for _, cc := range conf.Meters {
|
||||
c.meters[cc.Name] = core.NewMeterFromConfig(log, cc.Other)
|
||||
c.meters[cc.Name] = meter.NewFromConfig(log, cc.Type, cc.Other)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ func (lp *LoadPoint) publishSoC() {
|
|||
if lp.connected() {
|
||||
f, err := lp.vehicle.ChargeState()
|
||||
if err == nil {
|
||||
log.DEBUG.Printf("%s vehicle charge: %.1f%%", lp.Name, f)
|
||||
log.DEBUG.Printf("%s vehicle soc: %.1f%%", lp.Name, f)
|
||||
lp.publish("socCharge", f)
|
||||
lp.publish("chargeEstimate", lp.remainingChargeDuration(f))
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/core/wrapper"
|
||||
"github.com/andig/evcc/provider"
|
||||
)
|
||||
|
||||
// NewMeterFromConfig creates api.Meter from config
|
||||
func NewMeterFromConfig(log *api.Logger, other map[string]interface{}) api.Meter {
|
||||
cc := struct {
|
||||
Power provider.Config
|
||||
Energy *provider.Config // optional
|
||||
}{}
|
||||
api.DecodeOther(log, other, &cc)
|
||||
|
||||
m := NewMeter(provider.NewFloatGetterFromConfig(log, cc.Power))
|
||||
|
||||
// decorate Meter with MeterEnergy
|
||||
if cc.Energy != nil {
|
||||
m = &wrapper.CompositeMeter{
|
||||
Meter: m,
|
||||
MeterEnergy: NewMeterEnergy(provider.NewFloatGetterFromConfig(log, *cc.Energy)),
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/meter"
|
||||
"github.com/andig/evcc/mock"
|
||||
"github.com/andig/evcc/provider"
|
||||
"github.com/andig/evcc/push"
|
||||
|
|
@ -121,13 +122,13 @@ func TestMeterConfigurations(t *testing.T) {
|
|||
|
||||
var gm, pm, cm api.Meter
|
||||
if tc.gm {
|
||||
gm = NewMeter(fg)
|
||||
gm = meter.NewConfigurable(fg)
|
||||
}
|
||||
if tc.cm {
|
||||
cm = NewMeter(fg)
|
||||
cm = meter.NewConfigurable(fg)
|
||||
}
|
||||
if tc.pm {
|
||||
pm = NewMeter(fg)
|
||||
pm = meter.NewConfigurable(fg)
|
||||
}
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
|
|
|
|||
|
|
@ -2,16 +2,8 @@ package wrapper
|
|||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/andig/evcc/api"
|
||||
)
|
||||
|
||||
// CompositeMeter decorates a Meter with MeterEnergy.
|
||||
type CompositeMeter struct {
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
}
|
||||
|
||||
// ChargeMeter is a replacement for a physical charge meter.
|
||||
// It uses the charger's actual or max current to calculate power consumption.
|
||||
type ChargeMeter struct {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/andig/evcc/meter"
|
||||
"github.com/andig/evcc/mock"
|
||||
"github.com/benbjohnson/clock"
|
||||
"github.com/golang/mock/gomock"
|
||||
|
|
@ -43,7 +44,7 @@ func TestWrappedMeter(t *testing.T) {
|
|||
|
||||
mm := mock.NewMockMeter(ctrl)
|
||||
me := mock.NewMockMeterEnergy(ctrl)
|
||||
cm := &CompositeMeter{mm, me}
|
||||
cm := &meter.CompositeMeter{Meter: mm, MeterEnergy: me}
|
||||
|
||||
me.EXPECT().
|
||||
TotalEnergy().
|
||||
|
|
|
|||
|
|
@ -44,16 +44,19 @@ messaging:
|
|||
# meters
|
||||
meters:
|
||||
- name: grid
|
||||
type: default
|
||||
power: # power reading
|
||||
type: mqtt # use mqtt
|
||||
topic: mbmd/sdm1-1/Power # mqtt topic
|
||||
timeout: 10s # don't use older values
|
||||
- name: pv
|
||||
type: default
|
||||
power:
|
||||
type: mqtt
|
||||
topic: mbmd/sdm1-2/Power
|
||||
timeout: 10s # don't use older values
|
||||
- name: charge
|
||||
type: default
|
||||
power:
|
||||
type: script # use script
|
||||
cmd: /bin/sh -c "echo 0" # actual command
|
||||
|
|
|
|||
21
meter/config.go
Normal file
21
meter/config.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package meter
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/andig/evcc/api"
|
||||
)
|
||||
|
||||
// NewFromConfig creates meter from configuration
|
||||
func NewFromConfig(log *api.Logger, typ string, other map[string]interface{}) api.Meter {
|
||||
var c api.Meter
|
||||
|
||||
switch strings.ToLower(typ) {
|
||||
case "default", "configurable":
|
||||
c = NewConfigurableFromConfig(log, other)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid meter type '%s'", typ)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
|
@ -1,22 +1,49 @@
|
|||
package core
|
||||
package meter
|
||||
|
||||
import (
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/provider"
|
||||
)
|
||||
|
||||
// Meter is an api.Meter implementation with configurable getters and setters.
|
||||
type Meter struct {
|
||||
currentPowerG provider.FloatGetter
|
||||
// CompositeMeter decorates a Meter with MeterEnergy.
|
||||
type CompositeMeter struct {
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
}
|
||||
|
||||
// NewMeter creates a new charger
|
||||
func NewMeter(currentPowerG provider.FloatGetter) api.Meter {
|
||||
// NewConfigurableFromConfig creates api.Meter from config
|
||||
func NewConfigurableFromConfig(log *api.Logger, other map[string]interface{}) api.Meter {
|
||||
cc := struct {
|
||||
Power provider.Config
|
||||
Energy *provider.Config // optional
|
||||
}{}
|
||||
api.DecodeOther(log, other, &cc)
|
||||
|
||||
m := NewConfigurable(provider.NewFloatGetterFromConfig(log, cc.Power))
|
||||
|
||||
// decorate Meter with MeterEnergy
|
||||
if cc.Energy != nil {
|
||||
m = &CompositeMeter{
|
||||
Meter: m,
|
||||
MeterEnergy: NewMeterEnergy(provider.NewFloatGetterFromConfig(log, *cc.Energy)),
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// NewConfigurable creates a new charger
|
||||
func NewConfigurable(currentPowerG provider.FloatGetter) api.Meter {
|
||||
return &Meter{
|
||||
currentPowerG: currentPowerG,
|
||||
}
|
||||
}
|
||||
|
||||
// Meter is an api.Meter implementation with configurable getters and setters.
|
||||
type Meter struct {
|
||||
currentPowerG provider.FloatGetter
|
||||
}
|
||||
|
||||
// CurrentPower implements the Meter.CurrentPower interface
|
||||
func (m *Meter) CurrentPower() (float64, error) {
|
||||
return m.currentPowerG()
|
||||
Loading…
Add table
Add a link
Reference in a new issue