Refactor configuration handling (#12)
This commit is contained in:
parent
9a87f0d059
commit
6bf4b28902
10 changed files with 195 additions and 147 deletions
|
|
@ -13,6 +13,25 @@ type Charger struct {
|
|||
maxCurrentS provider.IntSetter
|
||||
}
|
||||
|
||||
type config struct {
|
||||
Status, Enable, Enabled, MaxCurrent *provider.Config
|
||||
}
|
||||
|
||||
// NewChargerFromConfig creates a new configurable charger
|
||||
func NewChargerFromConfig(log *api.Logger, other map[string]interface{}) api.Charger {
|
||||
var cc config
|
||||
decodeOther(log, other, &cc)
|
||||
|
||||
charger := NewCharger(
|
||||
provider.NewStringGetterFromConfig(cc.Status),
|
||||
provider.NewBoolGetterFromConfig(cc.Enabled),
|
||||
provider.NewBoolSetterFromConfig("enable", cc.Enable),
|
||||
provider.NewIntSetterFromConfig("current", cc.MaxCurrent),
|
||||
)
|
||||
|
||||
return charger
|
||||
}
|
||||
|
||||
// NewCharger creates a new charger
|
||||
func NewCharger(
|
||||
statusG provider.StringGetter,
|
||||
|
|
|
|||
24
charger/decoder.go
Normal file
24
charger/decoder.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package charger
|
||||
|
||||
import (
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func decodeOther(log *api.Logger, other map[string]interface{}, cc interface{}) {
|
||||
decoderConfig := &mapstructure.DecoderConfig{
|
||||
Result: cc,
|
||||
ErrorUnused: true,
|
||||
WeaklyTypedInput: true,
|
||||
DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
|
||||
}
|
||||
|
||||
decoder, err := mapstructure.NewDecoder(decoderConfig)
|
||||
if err != nil {
|
||||
log.FATAL.Fatal(err)
|
||||
}
|
||||
|
||||
if err := decoder.Decode(other); err != nil {
|
||||
log.FATAL.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -39,6 +39,18 @@ type Wallbe struct {
|
|||
handler *modbus.TCPClientHandler
|
||||
}
|
||||
|
||||
type wallbeConfig struct {
|
||||
URI string
|
||||
}
|
||||
|
||||
// NewWallbeFromConfig creates a Wallbe charger from generic config
|
||||
func NewWallbeFromConfig(log *api.Logger, other map[string]interface{}) api.Charger {
|
||||
var cc wallbeConfig
|
||||
decodeOther(log, other, &cc)
|
||||
|
||||
return NewWallbe(cc.URI)
|
||||
}
|
||||
|
||||
// NewWallbe creates a Wallbe charger
|
||||
func NewWallbe(conn string) api.Charger {
|
||||
if conn == "" {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/provider"
|
||||
"github.com/andig/evcc/push"
|
||||
"github.com/andig/evcc/server"
|
||||
)
|
||||
|
|
@ -42,42 +43,25 @@ type influxConfig struct {
|
|||
Interval time.Duration
|
||||
}
|
||||
|
||||
type providerConfig struct {
|
||||
Type string
|
||||
Topic string
|
||||
Cmd string
|
||||
Multiplier float64
|
||||
Timeout time.Duration
|
||||
Cache time.Duration
|
||||
}
|
||||
|
||||
type meterConfig struct {
|
||||
Name string
|
||||
Type string
|
||||
Power *providerConfig
|
||||
Energy *providerConfig
|
||||
Power *provider.Config
|
||||
Energy *provider.Config
|
||||
}
|
||||
|
||||
type chargerConfig struct {
|
||||
Name string
|
||||
Type string
|
||||
|
||||
// wallbe charger
|
||||
URI string
|
||||
|
||||
// composite charger
|
||||
Status *providerConfig // Charger
|
||||
MaxCurrent *providerConfig // ChargeController
|
||||
Enable *providerConfig // Charger
|
||||
Enabled *providerConfig // Charger
|
||||
Name string
|
||||
Type string
|
||||
Other map[string]interface{} `mapstructure:",remain"`
|
||||
}
|
||||
|
||||
type socConfig struct {
|
||||
Name string
|
||||
Title string
|
||||
Type string
|
||||
Title string
|
||||
Capacity int64
|
||||
Charge *providerConfig
|
||||
Charge *provider.Config
|
||||
}
|
||||
|
||||
type loadPointConfig struct {
|
||||
|
|
|
|||
|
|
@ -1,105 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/andig/evcc/provider"
|
||||
)
|
||||
|
||||
const (
|
||||
execTimeout = 5 * time.Second
|
||||
mqttTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
func stringGetter(pc *providerConfig) (res provider.StringGetter) {
|
||||
switch pc.Type {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := provider.NewScriptProvider(pc.Timeout)
|
||||
res = exec.StringGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Printf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = provider.NewCacheGetter(res, pc.Cache).StringGetter
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func boolGetter(pc *providerConfig) (res provider.BoolGetter) {
|
||||
switch pc.Type {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := provider.NewScriptProvider(pc.Timeout)
|
||||
res = exec.BoolGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Printf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = provider.NewCacheGetter(res, pc.Cache).BoolGetter
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func floatGetter(pc *providerConfig) (res provider.FloatGetter) {
|
||||
switch pc.Type {
|
||||
case "mqtt":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = mqttTimeout
|
||||
}
|
||||
if pc.Multiplier == 0 {
|
||||
pc.Multiplier = 1
|
||||
}
|
||||
res = mq.FloatGetter(pc.Topic, pc.Multiplier, pc.Timeout)
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := provider.NewScriptProvider(pc.Timeout)
|
||||
res = exec.FloatGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Printf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = provider.NewCacheGetter(res, pc.Cache).FloatGetter
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func boolSetter(param string, pc *providerConfig) (res provider.BoolSetter) {
|
||||
switch pc.Type {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := provider.NewScriptProvider(pc.Timeout)
|
||||
res = exec.BoolSetter(param, pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Printf("invalid setter type %s", pc.Type)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func intSetter(param string, pc *providerConfig) (res provider.IntSetter) {
|
||||
switch pc.Type {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := provider.NewScriptProvider(pc.Timeout)
|
||||
res = exec.IntSetter(param, pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Printf("invalid setter type %s", pc.Type)
|
||||
}
|
||||
return
|
||||
}
|
||||
22
cmd/setup.go
22
cmd/setup.go
|
|
@ -18,9 +18,6 @@ func init() {
|
|||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// MQTT singleton
|
||||
var mq *provider.MqttClient
|
||||
|
||||
func clientID() string {
|
||||
pid := rand.Int31()
|
||||
return fmt.Sprintf("evcc-%d", pid)
|
||||
|
|
@ -29,13 +26,13 @@ func clientID() string {
|
|||
func configureMeters(conf config) (meters map[string]api.Meter) {
|
||||
meters = make(map[string]api.Meter)
|
||||
for _, mc := range conf.Meters {
|
||||
m := core.NewMeter(floatGetter(mc.Power))
|
||||
m := core.NewMeter(provider.NewFloatGetterFromConfig(mc.Power))
|
||||
|
||||
// decorate Meter with MeterEnergy
|
||||
if mc.Energy != nil {
|
||||
m = &wrapper.CompositeMeter{
|
||||
Meter: m,
|
||||
MeterEnergy: core.NewMeterEnergy(floatGetter(mc.Energy)),
|
||||
MeterEnergy: core.NewMeterEnergy(provider.NewFloatGetterFromConfig(mc.Energy)),
|
||||
}
|
||||
}
|
||||
meters[mc.Name] = m
|
||||
|
|
@ -50,16 +47,9 @@ func configureChargers(conf config) (chargers map[string]api.Charger) {
|
|||
|
||||
switch cc.Type {
|
||||
case "wallbe":
|
||||
c = charger.NewWallbe(cc.URI)
|
||||
|
||||
c = charger.NewWallbeFromConfig(log, cc.Other)
|
||||
case "default", "configurable":
|
||||
c = charger.NewCharger(
|
||||
stringGetter(cc.Status),
|
||||
boolGetter(cc.Enabled),
|
||||
boolSetter("enable", cc.Enable),
|
||||
intSetter("current", cc.MaxCurrent),
|
||||
)
|
||||
|
||||
c = charger.NewChargerFromConfig(log, cc.Other)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid charger type '%s'", cc.Type)
|
||||
}
|
||||
|
|
@ -72,7 +62,7 @@ func configureChargers(conf config) (chargers map[string]api.Charger) {
|
|||
func configureSoCs(conf config) (socs map[string]api.SoC) {
|
||||
socs = make(map[string]api.SoC)
|
||||
for _, sc := range conf.SoCs {
|
||||
soc := core.NewSoC(sc.Capacity, sc.Title, floatGetter(sc.Charge))
|
||||
soc := core.NewSoC(sc.Capacity, sc.Title, provider.NewFloatGetterFromConfig(sc.Charge))
|
||||
socs[sc.Name] = soc
|
||||
}
|
||||
return
|
||||
|
|
@ -113,7 +103,7 @@ func configureLoadPoint(lp *core.LoadPoint, lpc loadPointConfig, subv *viper.Vip
|
|||
|
||||
func loadConfig(conf config, eventsChan chan push.Event) (loadPoints []*core.LoadPoint) {
|
||||
if viper.Get("mqtt") != nil {
|
||||
mq = provider.NewMqttClient(conf.Mqtt.Broker, conf.Mqtt.User, conf.Mqtt.Password, clientID(), 1)
|
||||
provider.MQTT = provider.NewMqttClient(conf.Mqtt.Broker, conf.Mqtt.User, conf.Mqtt.Password, clientID(), 1)
|
||||
}
|
||||
|
||||
meters := configureMeters(conf)
|
||||
|
|
|
|||
1
go.mod
1
go.mod
|
|
@ -19,6 +19,7 @@ require (
|
|||
github.com/hashicorp/go-version v1.2.0 // indirect
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/mitchellh/mapstructure v1.2.2
|
||||
github.com/mjibson/esc v0.2.0
|
||||
github.com/pelletier/go-toml v1.6.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -164,6 +164,8 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
|
|||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
||||
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mjibson/esc v0.2.0 h1:k96hdaR9Z+nMcnDwNrOvhdBqtjyMrbVyxLpsRCdP2mA=
|
||||
github.com/mjibson/esc v0.2.0/go.mod h1:9Hw9gxxfHulMF5OJKCyhYD7PzlSdhzXyaGEBRPH1OPs=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
|
|
|||
121
provider/config.go
Normal file
121
provider/config.go
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
execTimeout = 5 * time.Second
|
||||
mqttTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
// Config contains the getter/setter configuration
|
||||
type Config struct {
|
||||
Type string
|
||||
Topic string
|
||||
Cmd string
|
||||
Multiplier float64
|
||||
Timeout time.Duration
|
||||
Cache time.Duration
|
||||
}
|
||||
|
||||
// MQTT singleton
|
||||
var MQTT *MqttClient
|
||||
|
||||
// NewStringGetterFromConfig creates a StringGetter from config
|
||||
func NewStringGetterFromConfig(pc *Config) (res StringGetter) {
|
||||
switch pc.Type {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := NewScriptProvider(pc.Timeout)
|
||||
res = exec.StringGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = NewCacheGetter(res, pc.Cache).StringGetter
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewBoolGetterFromConfig creates a BoolGetter from config
|
||||
func NewBoolGetterFromConfig(pc *Config) (res BoolGetter) {
|
||||
switch pc.Type {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := NewScriptProvider(pc.Timeout)
|
||||
res = exec.BoolGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = NewCacheGetter(res, pc.Cache).BoolGetter
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewFloatGetterFromConfig creates a FloatGetter from config
|
||||
func NewFloatGetterFromConfig(pc *Config) (res FloatGetter) {
|
||||
switch pc.Type {
|
||||
case "mqtt":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = mqttTimeout
|
||||
}
|
||||
if pc.Multiplier == 0 {
|
||||
pc.Multiplier = 1
|
||||
}
|
||||
res = MQTT.FloatGetter(pc.Topic, pc.Multiplier, pc.Timeout)
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := NewScriptProvider(pc.Timeout)
|
||||
res = exec.FloatGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = NewCacheGetter(res, pc.Cache).FloatGetter
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewBoolSetterFromConfig creates a BoolSetter from config
|
||||
func NewBoolSetterFromConfig(param string, pc *Config) (res BoolSetter) {
|
||||
switch pc.Type {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := NewScriptProvider(pc.Timeout)
|
||||
res = exec.BoolSetter(param, pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid setter type %s", pc.Type)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NewIntSetterFromConfig creates a IntSetter from config
|
||||
func NewIntSetterFromConfig(param string, pc *Config) (res IntSetter) {
|
||||
switch pc.Type {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := NewScriptProvider(pc.Timeout)
|
||||
res = exec.IntSetter(param, pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid setter type %s", pc.Type)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ package push
|
|||
|
||||
// EventTemplate is the push message template for an event
|
||||
type EventTemplate struct {
|
||||
title, msg string
|
||||
Title, Msg string
|
||||
}
|
||||
|
||||
// Hub subscribes to event notifications and sends them to client devices
|
||||
|
|
@ -33,6 +33,6 @@ func (h *Hub) Run(events <-chan Event) {
|
|||
break
|
||||
}
|
||||
|
||||
go h.pushOver.Send(ev, definition.title, definition.msg)
|
||||
go h.pushOver.Send(ev, definition.Title, definition.Msg)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue