FNN Hems: align power config wording with EEBus (productionNominalMax) (#31948)
This commit is contained in:
parent
4e1b0a8250
commit
bacca990ee
4 changed files with 79 additions and 32 deletions
|
|
@ -23,14 +23,15 @@ func init() {
|
|||
// NewFromConfig creates an FNN HEMS from generic config.
|
||||
func NewFromConfig(ctx context.Context, other map[string]any, site site.API) (*Fnn, error) {
|
||||
cc := struct {
|
||||
MaxPower float64 // TODO deprecated
|
||||
MaxDimPower float64
|
||||
MaxCurtailPower float64
|
||||
W3 *plugin.Config
|
||||
S1 *plugin.Config
|
||||
S2 *plugin.Config
|
||||
W4 *plugin.Config
|
||||
Interval time.Duration
|
||||
MaxPower float64 // TODO deprecated
|
||||
MaxDimPower float64
|
||||
MaxCurtailPower float64 // TODO deprecated
|
||||
ProductionNominalMax float64
|
||||
W3 *plugin.Config
|
||||
S1 *plugin.Config
|
||||
S2 *plugin.Config
|
||||
W4 *plugin.Config
|
||||
Interval time.Duration
|
||||
}{
|
||||
Interval: 10 * time.Second,
|
||||
}
|
||||
|
|
@ -64,30 +65,34 @@ func NewFromConfig(ctx context.Context, other map[string]any, site site.API) (*F
|
|||
return nil, err
|
||||
}
|
||||
|
||||
maxCurtailPower := math.Abs(cc.MaxCurtailPower)
|
||||
productionNominalMax := math.Abs(cc.MaxCurtailPower)
|
||||
if cc.MaxPower > 0 {
|
||||
maxCurtailPower = cc.MaxPower
|
||||
productionNominalMax = cc.MaxPower
|
||||
}
|
||||
// ProductionNominalMax supersedes deprecated MaxCurtailPower/MaxPower
|
||||
if cc.ProductionNominalMax > 0 {
|
||||
productionNominalMax = math.Abs(cc.ProductionNominalMax)
|
||||
}
|
||||
|
||||
return NewFnn(site, math.Abs(cc.MaxDimPower), maxCurtailPower, w3G, s1G, s2G, w4G, cc.Interval)
|
||||
return NewFnn(site, math.Abs(cc.MaxDimPower), productionNominalMax, w3G, s1G, s2G, w4G, cc.Interval)
|
||||
}
|
||||
|
||||
func NewFnn(site site.API, maxDimPower, maxCurtailPower float64, w3G, s1G, s2G, w4G func() (bool, error), interval time.Duration) (*Fnn, error) {
|
||||
func NewFnn(site site.API, maxDimPower, productionNominalMax float64, w3G, s1G, s2G, w4G func() (bool, error), interval time.Duration) (*Fnn, error) {
|
||||
if w4G != nil && maxDimPower == 0 {
|
||||
return nil, errors.New("cannot have w4 without power limit")
|
||||
}
|
||||
|
||||
c := &Fnn{
|
||||
log: util.NewLogger("fnn"),
|
||||
site: site,
|
||||
maxDimPower: maxDimPower,
|
||||
maxCurtailPower: maxCurtailPower,
|
||||
s1: s1G,
|
||||
s2: s2G,
|
||||
w3: w3G,
|
||||
w4: w4G,
|
||||
productionPercent: 100,
|
||||
interval: interval,
|
||||
log: util.NewLogger("fnn"),
|
||||
site: site,
|
||||
maxDimPower: maxDimPower,
|
||||
productionNominalMax: productionNominalMax,
|
||||
s1: s1G,
|
||||
s2: s2G,
|
||||
w3: w3G,
|
||||
w4: w4G,
|
||||
productionPercent: 100,
|
||||
interval: interval,
|
||||
}
|
||||
|
||||
// read the relays once synchronously so limits are valid as soon as NewFnn returns
|
||||
|
|
@ -111,8 +116,8 @@ type Fnn struct {
|
|||
w4 func() (bool, error)
|
||||
publishFunc func()
|
||||
|
||||
maxDimPower float64
|
||||
maxCurtailPower float64
|
||||
maxDimPower float64
|
||||
productionNominalMax float64
|
||||
|
||||
smartgridConsumptionID uint
|
||||
smartgridProductionID uint
|
||||
|
|
@ -211,7 +216,7 @@ func (c *Fnn) setProductionLimit(percent int) error {
|
|||
|
||||
limit := 0.0
|
||||
if active {
|
||||
limit = float64(percent) / 100 * c.maxCurtailPower
|
||||
limit = float64(percent) / 100 * c.productionNominalMax
|
||||
}
|
||||
|
||||
if err := smartgrid.UpdateSession(&c.smartgridProductionID, smartgrid.Curtail, c.site.GetGridPower(), limit, active); err != nil {
|
||||
|
|
@ -279,5 +284,5 @@ func (c *Fnn) MaxProductionPower() *float64 {
|
|||
return new(0.0)
|
||||
}
|
||||
|
||||
return new(float64(c.productionPercent) / 100 * c.maxCurtailPower)
|
||||
return new(float64(c.productionPercent) / 100 * c.productionNominalMax)
|
||||
}
|
||||
|
|
|
|||
40
hems/fnn/fnn_config_test.go
Normal file
40
hems/fnn/fnn_config_test.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package fnn
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"testing"
|
||||
|
||||
"github.com/evcc-io/evcc/server/db"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestPowerParamFallback verifies productionnominalmax supersedes the
|
||||
// deprecated maxcurtailpower/maxpower params while both keep working.
|
||||
func TestPowerParamFallback(t *testing.T) {
|
||||
require.NoError(t, db.NewInstance("sqlite", ":memory:"))
|
||||
|
||||
w3 := map[string]any{"source": "const", "value": "true"}
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
conf map[string]any
|
||||
want float64
|
||||
}{
|
||||
{"new param", map[string]any{"productionnominalmax": 5000.0}, 5000},
|
||||
{"deprecated maxcurtailpower", map[string]any{"maxcurtailpower": 4000.0}, 4000},
|
||||
{"deprecated maxpower", map[string]any{"maxpower": 3000.0}, 3000},
|
||||
{"new supersedes deprecated", map[string]any{
|
||||
"productionnominalmax": 5000.0, "maxcurtailpower": 4000.0, "maxpower": 3000.0,
|
||||
}, 5000},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
conf := map[string]any{"w3": w3}
|
||||
maps.Copy(conf, tc.conf)
|
||||
|
||||
fnn, err := NewFromConfig(t.Context(), conf, &stubSite{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.want, fnn.productionNominalMax)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -22,16 +22,17 @@ params:
|
|||
help:
|
||||
en: Input pin for the W4 signal (Dimmer for controllable loads)
|
||||
de: Eingangspin für das W4-Signal (Dimmen der steuerbaren Verbrauchseinrichtungen)
|
||||
- name: maxproductionpower
|
||||
- name: productionnominalmax
|
||||
type: float
|
||||
unit: W
|
||||
required: true
|
||||
description:
|
||||
en: Installed generator power (Wp)
|
||||
de: Installierte Generatorleistung (Wp)
|
||||
help:
|
||||
en: Rated generator/module power (Wp) of the installation.
|
||||
de: Gesamtnennleistung bzw. Modul- oder Generatorleistung der Anlage (Bezugsgröße nach § 9 EEG).
|
||||
- name: maxproductionpower
|
||||
deprecated: true
|
||||
- name: w3pin
|
||||
type: int
|
||||
required: true
|
||||
|
|
@ -64,7 +65,7 @@ render: |
|
|||
source: gpio
|
||||
pin: {{ .w4pin }}
|
||||
function: read
|
||||
maxcurtailpower: {{ .maxproductionpower }}
|
||||
productionnominalmax: {{ or .productionnominalmax .maxproductionpower }}
|
||||
w3:
|
||||
source: gpio
|
||||
pin: {{ .w3pin }}
|
||||
|
|
|
|||
|
|
@ -14,16 +14,17 @@ params:
|
|||
help:
|
||||
en: Power limit applied to the root circuit while the limit is active.
|
||||
de: Leistungsbegrenzung des Hauptstromkreises während die Limitierung aktiv ist.
|
||||
- name: maxproductionpower
|
||||
- name: productionnominalmax
|
||||
type: float
|
||||
unit: W
|
||||
required: true
|
||||
description:
|
||||
en: Installed generator power (Wp)
|
||||
de: Installierte Generatorleistung (Wp)
|
||||
help:
|
||||
en: Rated generator/module power (Wp) of the installation.
|
||||
de: Gesamtnennleistung bzw. Modul- oder Generatorleistung der Anlage (Bezugsgröße nach § 9 EEG).
|
||||
- name: maxproductionpower
|
||||
deprecated: true
|
||||
render: |
|
||||
type: fnn
|
||||
maxdimpower: {{ .maxconsumptionpower }}
|
||||
|
|
@ -31,7 +32,7 @@ render: |
|
|||
source: gpio
|
||||
pin: 13
|
||||
function: read
|
||||
maxcurtailpower: {{ .maxproductionpower }}
|
||||
productionnominalmax: {{ or .productionnominalmax .maxproductionpower }}
|
||||
w3:
|
||||
source: gpio
|
||||
pin: 5
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue