Refactor to support Wallbe dip 10 enable/disable
This commit is contained in:
parent
3c503b333d
commit
da74ce17fd
48 changed files with 1274 additions and 1393 deletions
|
|
@ -32,11 +32,12 @@ type mqttConfig struct {
|
|||
}
|
||||
|
||||
type providerConfig struct {
|
||||
Type string
|
||||
Topic string
|
||||
Cmd string
|
||||
Timeout time.Duration
|
||||
Cache time.Duration
|
||||
Type string
|
||||
Topic string
|
||||
Cmd string
|
||||
Multiplier float64
|
||||
Timeout time.Duration
|
||||
Cache time.Duration
|
||||
}
|
||||
|
||||
type meterConfig struct {
|
||||
|
|
@ -54,11 +55,10 @@ type chargerConfig struct {
|
|||
URI string
|
||||
|
||||
// composite charger
|
||||
Status *providerConfig // Charger
|
||||
ActualCurrent *providerConfig // Charger
|
||||
MaxCurrent *providerConfig // ChargeController
|
||||
Enable *providerConfig // Charger
|
||||
Enabled *providerConfig // Charger
|
||||
Status *providerConfig // Charger
|
||||
MaxCurrent *providerConfig // ChargeController
|
||||
Enable *providerConfig // Charger
|
||||
Enabled *providerConfig // Charger
|
||||
}
|
||||
|
||||
type socConfig struct {
|
||||
|
|
@ -80,6 +80,8 @@ type loadPointConfig struct {
|
|||
Phases int64
|
||||
MinCurrent int64
|
||||
MaxCurrent int64
|
||||
Steepness int64
|
||||
GuardDuration time.Duration
|
||||
Voltage float64
|
||||
ResidualPower float64
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,37 +49,16 @@ func boolGetter(pc *providerConfig) (res provider.BoolGetter) {
|
|||
return
|
||||
}
|
||||
|
||||
func intProvider(pc *providerConfig) (res provider.IntGetter) {
|
||||
switch pc.Type {
|
||||
case "mqtt":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = mqttTimeout
|
||||
}
|
||||
res = mq.IntGetter(pc.Topic, pc.Timeout)
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := provider.NewScriptProvider(pc.Timeout)
|
||||
res = exec.IntGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Printf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = provider.NewCacheGetter(res, pc.Cache).IntGetter
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func floatGetter(pc *providerConfig) (res provider.FloatGetter) {
|
||||
switch pc.Type {
|
||||
case "mqtt":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = mqttTimeout
|
||||
}
|
||||
res = mq.FloatGetter(pc.Topic, pc.Timeout)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -21,32 +21,22 @@ meters:
|
|||
if err := viper.ReadConfig(bytes.NewBuffer([]byte(yaml))); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// var conf Config
|
||||
// if err := viper.UnmarshalExact(&conf); err != nil {
|
||||
// t.Error(err)
|
||||
// }
|
||||
|
||||
// _ = configureMeters(conf)
|
||||
}
|
||||
func TestChargerConfig(t *testing.T) {
|
||||
yaml := `
|
||||
chargers:
|
||||
- name: test
|
||||
type: configurable
|
||||
status:
|
||||
status:
|
||||
type: script
|
||||
cmd: script
|
||||
actualCurrent:
|
||||
enable:
|
||||
type: script
|
||||
cmd: script
|
||||
enable:
|
||||
enabled:
|
||||
type: script
|
||||
cmd: script
|
||||
enabled:
|
||||
type: script
|
||||
cmd: script
|
||||
maxCurrent:
|
||||
maxCurrent:
|
||||
type: script
|
||||
cmd: script
|
||||
- name: wallbe
|
||||
|
|
@ -57,11 +47,4 @@ chargers:
|
|||
if err := viper.ReadConfig(bytes.NewBuffer([]byte(yaml))); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// var conf Config
|
||||
// if err := viper.UnmarshalExact(&conf); err != nil {
|
||||
// t.Error(err)
|
||||
// }
|
||||
|
||||
// _ = configureChargers(conf)
|
||||
}
|
||||
|
|
|
|||
63
cmd/root.go
63
cmd/root.go
|
|
@ -1,13 +1,13 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/core"
|
||||
"github.com/andig/evcc/push"
|
||||
"github.com/andig/evcc/server"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
|
@ -115,17 +115,10 @@ func Execute() {
|
|||
}
|
||||
|
||||
func configureLogging(level string) {
|
||||
// f, err := os.OpenFile("evcc.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
// if err != nil {
|
||||
// log.FATAL.Fatal(err)
|
||||
// }
|
||||
|
||||
api.OutThreshold = api.LogLevelToThreshold(level)
|
||||
api.LogThreshold = api.OutThreshold
|
||||
api.Loggers(func(name string, logger *api.Logger) {
|
||||
logger.SetStdoutThreshold(api.OutThreshold)
|
||||
// logger.SetLogThreshold(api.OutThreshold)
|
||||
// logger.SetLogOutput(f)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -143,15 +136,6 @@ func checkVersion() {
|
|||
}
|
||||
}
|
||||
|
||||
// cycle executes loadpoint update and publishes all paramters
|
||||
func cycle(lp *core.LoadPoint, tick time.Duration, updateChan chan core.Param) {
|
||||
lp.Update()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), tick)
|
||||
lp.Publish(ctx, updateChan)
|
||||
cancel()
|
||||
}
|
||||
|
||||
func run(cmd *cobra.Command, args []string) {
|
||||
level, _ := cmd.PersistentFlags().GetString("log")
|
||||
configureLogging(level)
|
||||
|
|
@ -174,35 +158,42 @@ func run(cmd *cobra.Command, args []string) {
|
|||
|
||||
uri := viper.GetString("uri")
|
||||
log.INFO.Println("listening at", uri)
|
||||
loadPoints := loadConfig(conf)
|
||||
|
||||
// setup messaging
|
||||
// if conf.Pushover.App != "" {
|
||||
// po := server.NewMessenger(conf.Pushover.App, conf.Pushover.Recipients)
|
||||
// po.Send("Wallbe", "Charge started", "Charging started in PV mode")
|
||||
// }
|
||||
notificationChan := make(chan push.Event, 1)
|
||||
notificationHub := &push.Hub{}
|
||||
|
||||
if conf.Pushover.App != "" {
|
||||
notificationHub.PushOver = push.NewMessenger(conf.Pushover.App, conf.Pushover.Recipients)
|
||||
}
|
||||
|
||||
loadPoints := loadConfig(conf, notificationChan)
|
||||
go notificationHub.Run(notificationChan)
|
||||
|
||||
// create webserver
|
||||
hub := server.NewSocketHub()
|
||||
httpd := server.NewHttpd(uri, conf.Menu, loadPoints[0], hub)
|
||||
socketHub := server.NewSocketHub()
|
||||
httpd := server.NewHttpd(uri, conf.Menu, loadPoints[0], socketHub)
|
||||
|
||||
// start broadcasting values
|
||||
updateChan := make(chan core.Param)
|
||||
go hub.Run(updateChan)
|
||||
uiChan := make(chan core.Param)
|
||||
triggerChan := make(chan struct{})
|
||||
go socketHub.Run(uiChan, triggerChan)
|
||||
|
||||
// start all loadpoints
|
||||
for _, lp := range loadPoints {
|
||||
lp.Dump()
|
||||
|
||||
// update loop
|
||||
go func(lp *core.LoadPoint) {
|
||||
tick := conf.Interval
|
||||
cycle(lp, tick, updateChan)
|
||||
|
||||
for range time.Tick(tick) {
|
||||
cycle(lp, tick, updateChan)
|
||||
}
|
||||
}(lp)
|
||||
lp.Prepare(uiChan, notificationChan)
|
||||
go lp.Run(conf.Interval)
|
||||
}
|
||||
|
||||
// handle UI update requests whenever browser connects
|
||||
go func() {
|
||||
for range triggerChan {
|
||||
for _, lp := range loadPoints {
|
||||
lp.Update()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
log.FATAL.Println(httpd.ListenAndServe())
|
||||
}
|
||||
|
|
|
|||
100
cmd/setup.go
100
cmd/setup.go
|
|
@ -6,9 +6,11 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/charger"
|
||||
"github.com/andig/evcc/core"
|
||||
"github.com/andig/evcc/core/wrapper"
|
||||
"github.com/andig/evcc/provider"
|
||||
"github.com/andig/evcc/push"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
|
|
@ -27,10 +29,9 @@ 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(floatGetter(mc.Power))
|
||||
|
||||
// decorate Meter with MeterEnergy
|
||||
if mc.Energy != nil {
|
||||
m = &wrapper.CompositeMeter{
|
||||
Meter: m,
|
||||
|
|
@ -49,25 +50,16 @@ func configureChargers(conf config) (chargers map[string]api.Charger) {
|
|||
|
||||
switch cc.Type {
|
||||
case "wallbe":
|
||||
c = core.NewWallbe(cc.URI)
|
||||
c = charger.NewWallbe(cc.URI)
|
||||
|
||||
case "default", "configurable":
|
||||
c = core.NewCharger(
|
||||
c = charger.NewCharger(
|
||||
stringGetter(cc.Status),
|
||||
intProvider(cc.ActualCurrent),
|
||||
boolGetter(cc.Enabled),
|
||||
boolSetter("enable", cc.Enable),
|
||||
intSetter("current", cc.MaxCurrent),
|
||||
)
|
||||
|
||||
// if chargecontroller specified build composite charger
|
||||
if cc.MaxCurrent != nil {
|
||||
c = &wrapper.CompositeCharger{
|
||||
Charger: c,
|
||||
ChargeController: core.NewChargeController(
|
||||
intSetter("current", cc.MaxCurrent),
|
||||
),
|
||||
}
|
||||
}
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid charger type '%s'", cc.Type)
|
||||
}
|
||||
|
|
@ -80,39 +72,46 @@ 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, floatGetter(sc.Charge))
|
||||
socs[sc.Name] = soc
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func configureLoadPoint(lp *core.LoadPoint, lpc loadPointConfig) {
|
||||
// TODO rewrite based on https://github.com/spf13/viper/pull/863
|
||||
func configureLoadPoint(lp *core.LoadPoint, lpc loadPointConfig, subv *viper.Viper) {
|
||||
// for _, key := range []string{"charger", "gridmeter", "pvmeter", "chargemeter", "soc"} {
|
||||
// delete(kv, key)
|
||||
// }
|
||||
|
||||
// config := &mapstructure.DecoderConfig{
|
||||
// WeaklyTypedInput: true,
|
||||
// DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
|
||||
// Result: lp,
|
||||
// }
|
||||
|
||||
// decoder, err := mapstructure.NewDecoder(config)
|
||||
// if err != nil {
|
||||
// log.FATAL.Fatalf("configuring loadpoints failed: %v", err)
|
||||
// }
|
||||
|
||||
// if err := decoder.Decode(kv); err != nil {
|
||||
// log.FATAL.Fatalf("configuring loadpoints failed: %v", err)
|
||||
// }
|
||||
|
||||
// we can ignore the error here as UnmarshalExact has been called before
|
||||
_ = subv.UnmarshalExact(lp)
|
||||
|
||||
if lpc.Mode != "" {
|
||||
lp.Synced().SetMode(api.ChargeMode(lpc.Mode))
|
||||
}
|
||||
if lpc.MinCurrent > 0 {
|
||||
lp.MinCurrent = lpc.MinCurrent
|
||||
}
|
||||
if lpc.MaxCurrent > 0 {
|
||||
lp.MaxCurrent = lpc.MaxCurrent
|
||||
}
|
||||
if lpc.Voltage > 0 {
|
||||
lp.Voltage = lpc.Voltage
|
||||
}
|
||||
if lpc.Phases > 0 {
|
||||
lp.Phases = lpc.Phases
|
||||
}
|
||||
if lpc.ResidualPower != 0 {
|
||||
lp.ResidualPower = lpc.ResidualPower
|
||||
// workaround for golangs yaml off=0 conversion
|
||||
if lpc.Mode == "0" {
|
||||
lpc.Mode = api.ModeOff
|
||||
}
|
||||
lp.Mode = lpc.Mode // don't use SetMode here as that will block on channel send
|
||||
}
|
||||
}
|
||||
|
||||
func loadConfig(conf config) (loadPoints []*core.LoadPoint) {
|
||||
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)
|
||||
}
|
||||
|
|
@ -121,15 +120,18 @@ func loadConfig(conf config) (loadPoints []*core.LoadPoint) {
|
|||
chargers := configureChargers(conf)
|
||||
socs := configureSoCs(conf)
|
||||
|
||||
for _, lpc := range conf.LoadPoints {
|
||||
charger, ok := chargers[lpc.Charger]
|
||||
if !ok {
|
||||
for idx, lpc := range conf.LoadPoints {
|
||||
// configure loadpoint
|
||||
lp := core.NewLoadPoint()
|
||||
subv := viper.SubSlice("loadpoints")[idx]
|
||||
configureLoadPoint(lp, lpc, subv)
|
||||
|
||||
// assign charger
|
||||
if charger, ok := chargers[lpc.Charger]; ok {
|
||||
lp.Charger = charger
|
||||
} else {
|
||||
log.FATAL.Fatalf("invalid charger '%s'", lpc.Charger)
|
||||
}
|
||||
lp := core.NewLoadPoint(
|
||||
lpc.Name,
|
||||
charger,
|
||||
)
|
||||
|
||||
// assign meters
|
||||
for _, m := range []struct {
|
||||
|
|
@ -158,12 +160,6 @@ func loadConfig(conf config) (loadPoints []*core.LoadPoint) {
|
|||
}
|
||||
}
|
||||
|
||||
// assign remaing config
|
||||
configureLoadPoint(lp, lpc)
|
||||
|
||||
// add loadpoint helper objects
|
||||
lp.Prepare()
|
||||
|
||||
loadPoints = append(loadPoints, lp)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue