From d7d9c7fb77912b5f81baeaacf9dd86e5ced0919c Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 23 Oct 2024 18:26:51 +0200 Subject: [PATCH 1/5] Circuit: make max power and current externally updatable --- core/circuit/circuit.go | 83 +++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/core/circuit/circuit.go b/core/circuit/circuit.go index 93afd3271d..6fb88a599f 100644 --- a/core/circuit/circuit.go +++ b/core/circuit/circuit.go @@ -1,12 +1,14 @@ package circuit import ( + "context" "fmt" "math" "sync" "time" "github.com/evcc-io/evcc/api" + "github.com/evcc-io/evcc/provider" "github.com/evcc-io/evcc/util" "github.com/evcc-io/evcc/util/config" ) @@ -24,8 +26,10 @@ type Circuit struct { meter api.Meter // meter to determine current power timeout time.Duration - maxCurrent float64 // max allowed current - maxPower float64 // max allowed power + maxCurrent float64 // max allowed current + maxPower float64 // max allowed power + getMaxCurrent func() (float64, error) // dynamic max allowed current + getMaxPower func() (float64, error) // dynamic max allowed power current float64 power float64 @@ -37,12 +41,14 @@ type Circuit struct { // NewFromConfig creates a new Circuit func NewFromConfig(log *util.Logger, other map[string]interface{}) (api.Circuit, error) { cc := struct { - Title string `mapstructure:"title"` // title - ParentRef string `mapstructure:"parent"` // parent circuit reference - MeterRef string `mapstructure:"meter"` // meter reference - MaxCurrent float64 `mapstructure:"maxCurrent"` // the max allowed current - MaxPower float64 `mapstructure:"maxPower"` // the max allowed power - Timeout time.Duration `mapstructure:"timeout"` // timeout between meter updates + Title string // title + ParentRef string // parent circuit reference + MeterRef string // meter reference + MaxCurrent float64 // the max allowed current + MaxPower float64 // the max allowed power + GetMaxCurrent *provider.Config // dynamic max allowed current + GetMaxPower *provider.Config // dynamic max allowed power + Timeout time.Duration // timeout between meter updates }{ Timeout: time.Minute, } @@ -65,6 +71,22 @@ func NewFromConfig(log *util.Logger, other map[string]interface{}) (api.Circuit, return nil, err } + if cc.GetMaxPower != nil { + get, err := provider.NewFloatGetterFromConfig(context.TODO(), *cc.GetMaxPower) + if err != nil { + return nil, err + } + circuit.getMaxPower = get + } + + if cc.GetMaxCurrent != nil { + get, err := provider.NewFloatGetterFromConfig(context.TODO(), *cc.GetMaxCurrent) + if err != nil { + return nil, err + } + circuit.getMaxCurrent = get + } + if cc.ParentRef != "" { dev, err := config.Circuits().ByName(cc.ParentRef) if err != nil { @@ -150,6 +172,15 @@ func (c *Circuit) HasMeter() bool { // GetMaxPower returns the max power setting func (c *Circuit) GetMaxPower() float64 { + if c.getMaxPower != nil { + res, err := c.getMaxPower() + if err == nil { + return res + } + + c.log.WARN.Printf("get max power: %v", err) + } + c.mu.RLock() defer c.mu.RUnlock() return c.maxPower @@ -164,6 +195,15 @@ func (c *Circuit) SetMaxPower(power float64) { // GetMaxCurrent returns the max current setting func (c *Circuit) GetMaxCurrent() float64 { + if c.getMaxCurrent != nil { + res, err := c.getMaxCurrent() + if err == nil { + return res + } + + c.log.WARN.Printf("get max current: %v", err) + } + c.mu.RLock() defer c.mu.RUnlock() return c.maxCurrent @@ -232,15 +272,18 @@ func (c *Circuit) updateMeters() error { } func (c *Circuit) Update(loadpoints []api.CircuitLoad) (err error) { + maxPower := c.GetMaxPower() + maxCurrent := c.GetMaxCurrent() + defer func() { - if c.maxPower != 0 && c.power > c.maxPower { - c.log.WARN.Printf("over power detected: %.5gW > %.5gW", c.power, c.maxPower) + if maxPower != 0 && c.power > maxPower { + c.log.WARN.Printf("over power detected: %.5gW > %.5gW", c.power, maxPower) } else { c.log.DEBUG.Printf("power: %.5gW", c.power) } - if c.maxCurrent != 0 && c.current > c.maxCurrent { - c.log.WARN.Printf("over current detected: %.3gA > %.3gA", c.current, c.maxCurrent) + if maxCurrent != 0 && c.current > maxCurrent { + c.log.WARN.Printf("over current detected: %.3gA > %.3gA", c.current, maxCurrent) } else { c.log.DEBUG.Printf("current: %.3gA", c.current) } @@ -282,14 +325,14 @@ func (c *Circuit) GetMaxPhaseCurrent() float64 { func (c *Circuit) ValidatePower(old, new float64) float64 { delta := max(0, new-old) - if c.maxPower != 0 { - potential := c.maxPower - c.power + if maxPower := c.GetMaxPower(); maxPower != 0 { + potential := maxPower - c.power if delta > potential { capped := max(0, old+potential) - c.log.DEBUG.Printf("validate power: %.5gW + (%.5gW -> %.5gW) > %.5gW capped at %.5gW", c.power, old, new, c.maxPower, capped) + c.log.DEBUG.Printf("validate power: %.5gW + (%.5gW -> %.5gW) > %.5gW capped at %.5gW", c.power, old, new, maxPower, capped) new = capped } else { - c.log.TRACE.Printf("validate power: %.5gW + (%.5gW -> %.5gW) <= %.5gW ok", c.power, old, new, c.maxPower) + c.log.TRACE.Printf("validate power: %.5gW + (%.5gW -> %.5gW) <= %.5gW ok", c.power, old, new, maxPower) } } @@ -304,14 +347,14 @@ func (c *Circuit) ValidatePower(old, new float64) float64 { func (c *Circuit) ValidateCurrent(old, new float64) float64 { delta := max(0, new-old) - if c.maxCurrent != 0 { - potential := c.maxCurrent - c.current + if maxCurrent := c.GetMaxCurrent(); maxCurrent != 0 { + potential := maxCurrent - c.current if delta > potential { capped := max(0, old+potential) - c.log.DEBUG.Printf("validate current: %.3gA + (%.3gA -> %.3gA) > %.3gA capped at %.3gA", c.current, old, new, c.maxCurrent, capped) + c.log.DEBUG.Printf("validate current: %.3gA + (%.3gA -> %.3gA) > %.3gA capped at %.3gA", c.current, old, new, maxCurrent, capped) new = capped } else { - c.log.TRACE.Printf("validate current: %.3gA + (%.3gA -> %.3gA) <= %.3gA ok", c.current, old, new, c.maxCurrent) + c.log.TRACE.Printf("validate current: %.3gA + (%.3gA -> %.3gA) <= %.3gA ok", c.current, old, new, maxCurrent) } } From d4a8efc875d994f7b8e523c2ed48830bc11a1afb Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 23 Oct 2024 19:23:32 +0200 Subject: [PATCH 2/5] wip --- core/circuit/circuit.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/circuit/circuit.go b/core/circuit/circuit.go index 6fb88a599f..e59a87df4e 100644 --- a/core/circuit/circuit.go +++ b/core/circuit/circuit.go @@ -42,8 +42,8 @@ type Circuit struct { func NewFromConfig(log *util.Logger, other map[string]interface{}) (api.Circuit, error) { cc := struct { Title string // title - ParentRef string // parent circuit reference - MeterRef string // meter reference + ParentRef string `mapstructure:"parent"` // parent circuit reference + MeterRef string `mapstructure:"meter"` // meter reference MaxCurrent float64 // the max allowed current MaxPower float64 // the max allowed power GetMaxCurrent *provider.Config // dynamic max allowed current From e33f8750ad7c9615d661d59c31b5485dd5e15940 Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 23 Oct 2024 19:34:49 +0200 Subject: [PATCH 3/5] Update core/circuit/circuit.go --- core/circuit/circuit.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/circuit/circuit.go b/core/circuit/circuit.go index e59a87df4e..9a51949130 100644 --- a/core/circuit/circuit.go +++ b/core/circuit/circuit.go @@ -177,7 +177,6 @@ func (c *Circuit) GetMaxPower() float64 { if err == nil { return res } - c.log.WARN.Printf("get max power: %v", err) } From 40e75e97d0d4cf2987f1f9b9a93a1b299234a098 Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 23 Oct 2024 19:34:59 +0200 Subject: [PATCH 4/5] Update core/circuit/circuit.go --- core/circuit/circuit.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/circuit/circuit.go b/core/circuit/circuit.go index 9a51949130..92c70eac51 100644 --- a/core/circuit/circuit.go +++ b/core/circuit/circuit.go @@ -199,7 +199,6 @@ func (c *Circuit) GetMaxCurrent() float64 { if err == nil { return res } - c.log.WARN.Printf("get max current: %v", err) } From 4c976b6ef621e73fdf8c68df435e595b5eb6988d Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 23 Oct 2024 19:36:38 +0200 Subject: [PATCH 5/5] wip --- core/circuit/circuit.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/circuit/circuit.go b/core/circuit/circuit.go index 92c70eac51..d552caa26f 100644 --- a/core/circuit/circuit.go +++ b/core/circuit/circuit.go @@ -72,19 +72,19 @@ func NewFromConfig(log *util.Logger, other map[string]interface{}) (api.Circuit, } if cc.GetMaxPower != nil { - get, err := provider.NewFloatGetterFromConfig(context.TODO(), *cc.GetMaxPower) + res, err := provider.NewFloatGetterFromConfig(context.TODO(), *cc.GetMaxPower) if err != nil { return nil, err } - circuit.getMaxPower = get + circuit.getMaxPower = res } if cc.GetMaxCurrent != nil { - get, err := provider.NewFloatGetterFromConfig(context.TODO(), *cc.GetMaxCurrent) + res, err := provider.NewFloatGetterFromConfig(context.TODO(), *cc.GetMaxCurrent) if err != nil { return nil, err } - circuit.getMaxCurrent = get + circuit.getMaxCurrent = res } if cc.ParentRef != "" {