HEMS: add per-hems tests for nil statements when unconfigured or not connected (#31430)
This commit is contained in:
parent
5e6f1e7356
commit
b6cca9ea1b
4 changed files with 66 additions and 43 deletions
|
|
@ -339,6 +339,11 @@ func (c *EEBus) CurtailedPercent() *int {
|
||||||
c.mux.RLock()
|
c.mux.RLock()
|
||||||
defer c.mux.RUnlock()
|
defer c.mux.RUnlock()
|
||||||
|
|
||||||
|
// no statement until first connected
|
||||||
|
if c.productionLimitActivated == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// without a nominal reference the W limit cannot be expressed as a percent
|
// without a nominal reference the W limit cannot be expressed as a percent
|
||||||
if c.productionNominalMax <= 0 {
|
if c.productionNominalMax <= 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
ucapi "github.com/enbility/eebus-go/usecases/api"
|
ucapi "github.com/enbility/eebus-go/usecases/api"
|
||||||
"github.com/evcc-io/evcc/core/site"
|
"github.com/evcc-io/evcc/core/site"
|
||||||
|
"github.com/evcc-io/evcc/hems/hems"
|
||||||
"github.com/evcc-io/evcc/server/db"
|
"github.com/evcc-io/evcc/server/db"
|
||||||
"github.com/evcc-io/evcc/server/eebus"
|
"github.com/evcc-io/evcc/server/eebus"
|
||||||
"github.com/evcc-io/evcc/util"
|
"github.com/evcc-io/evcc/util"
|
||||||
|
|
@ -168,6 +169,18 @@ func TestRun_ProductionLimitReleasedEarly(t *testing.T) {
|
||||||
assertProductionLimit(t, c, false)
|
assertProductionLimit(t, c, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestNotConnected verifies that all api.HEMS getters make no statement while
|
||||||
|
// no upstream controlbox has connected yet.
|
||||||
|
func TestNotConnected(t *testing.T) {
|
||||||
|
c := newTestEEBus(t) // Connector never connected
|
||||||
|
|
||||||
|
assert.Nil(t, c.MaxConsumptionPower())
|
||||||
|
assert.Nil(t, c.MaxProductionPower())
|
||||||
|
assert.Nil(t, c.CurtailedPercent())
|
||||||
|
assert.Nil(t, hems.Dimmed(c))
|
||||||
|
assert.Nil(t, hems.Curtailed(c))
|
||||||
|
}
|
||||||
|
|
||||||
// TestRun_ProductionLimitWithoutNominalMax verifies an incoming LPP limit
|
// TestRun_ProductionLimitWithoutNominalMax verifies an incoming LPP limit
|
||||||
// errors instead of being silently ignored when productionNominalMax is unset (#31469).
|
// errors instead of being silently ignored when productionNominalMax is unset (#31469).
|
||||||
func TestRun_ProductionLimitWithoutNominalMax(t *testing.T) {
|
func TestRun_ProductionLimitWithoutNominalMax(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/evcc-io/evcc/core/site"
|
"github.com/evcc-io/evcc/core/site"
|
||||||
|
"github.com/evcc-io/evcc/hems/hems"
|
||||||
"github.com/evcc-io/evcc/server/db"
|
"github.com/evcc-io/evcc/server/db"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -15,32 +17,35 @@ type stubSite struct {
|
||||||
|
|
||||||
func (s *stubSite) GetGridPower() float64 { return 0 }
|
func (s *stubSite) GetGridPower() float64 { return 0 }
|
||||||
|
|
||||||
func TestFnn(t *testing.T) {
|
func boolG(v bool) func() (bool, error) {
|
||||||
require.NoError(t, db.NewInstance("sqlite", ":memory:"))
|
return func() (bool, error) { return v, nil }
|
||||||
|
|
||||||
fnn, err := NewFnn(&stubSite{}, 1e3, 1e3, nil, nil, nil, func() (bool, error) {
|
|
||||||
return true, nil
|
|
||||||
}, 0)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Nil(t, fnn.CurtailedPercent())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestFnnNilWhenNotConfigured verifies "nil = limiting undefined": nil unless
|
// TestCurtailmentNotConfigured verifies that without W3 no curtailment
|
||||||
// the relay input is configured, else valid right after NewFnn returns.
|
// statement is made, while dimming via W4 remains available.
|
||||||
func TestFnnNilWhenNotConfigured(t *testing.T) {
|
func TestCurtailmentNotConfigured(t *testing.T) {
|
||||||
require.NoError(t, db.NewInstance("sqlite", ":memory:"))
|
require.NoError(t, db.NewInstance("sqlite", ":memory:"))
|
||||||
|
|
||||||
unconfigured, err := NewFnn(&stubSite{}, 1e3, 1e3, nil, nil, nil, nil, 0)
|
fnn, err := NewFnn(&stubSite{}, 1e3, 1e3, nil, nil, nil, boolG(true), 0)
|
||||||
require.NoError(t, err)
|
|
||||||
require.Nil(t, unconfigured.MaxConsumptionPower())
|
|
||||||
require.Nil(t, unconfigured.MaxProductionPower())
|
|
||||||
|
|
||||||
off := func() (bool, error) { return false, nil }
|
|
||||||
configured, err := NewFnn(&stubSite{}, 1e3, 1e3, off, nil, nil, off, 0)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.NotNil(t, configured.MaxConsumptionPower())
|
assert.Nil(t, fnn.CurtailedPercent())
|
||||||
require.Equal(t, 0.0, *configured.MaxConsumptionPower())
|
assert.Nil(t, fnn.MaxProductionPower())
|
||||||
require.NotNil(t, configured.MaxProductionPower())
|
assert.Nil(t, hems.Curtailed(fnn))
|
||||||
require.Equal(t, 0.0, *configured.MaxProductionPower())
|
|
||||||
|
assert.NotNil(t, fnn.MaxConsumptionPower())
|
||||||
|
assert.NotNil(t, hems.Dimmed(fnn))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestDimmingNotConfigured verifies that without W4 no dimming statement is
|
||||||
|
// made, while curtailment via W3 remains available.
|
||||||
|
func TestDimmingNotConfigured(t *testing.T) {
|
||||||
|
fnn, err := NewFnn(&stubSite{}, 0, 1e3, boolG(false), nil, nil, nil, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Nil(t, fnn.MaxConsumptionPower())
|
||||||
|
assert.Nil(t, hems.Dimmed(fnn))
|
||||||
|
|
||||||
|
assert.NotNil(t, fnn.CurtailedPercent())
|
||||||
|
assert.NotNil(t, hems.Curtailed(fnn))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,28 +3,28 @@ package relay
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/evcc-io/evcc/core/site"
|
"github.com/evcc-io/evcc/hems/hems"
|
||||||
"github.com/evcc-io/evcc/server/db"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// stubSite implements site.API for testing — only GetGridPower is exercised.
|
// TestCurtailmentNotConfigured verifies that relay never makes a curtailment
|
||||||
type stubSite struct {
|
// statement, and that an active relay dims to maxPower.
|
||||||
site.API
|
func TestCurtailmentNotConfigured(t *testing.T) {
|
||||||
}
|
c := new(Relay)
|
||||||
|
|
||||||
func (s *stubSite) GetGridPower() float64 { return 0 }
|
// relay never makes a curtailment statement
|
||||||
|
assert.Nil(t, c.CurtailedPercent())
|
||||||
// TestRelayNoNilState verifies MaxConsumptionPower is always determinable (w1
|
assert.Nil(t, c.MaxProductionPower())
|
||||||
// is mandatory) — NewRelay reads it once so the state is valid immediately.
|
assert.Nil(t, hems.Curtailed(c))
|
||||||
func TestRelayNoNilState(t *testing.T) {
|
|
||||||
require.NoError(t, db.NewInstance("sqlite", ":memory:"))
|
// active relay dims to maxPower
|
||||||
|
c.maxPower = 1e3
|
||||||
off := func() (bool, error) { return false, nil }
|
require.NoError(t, c.setConsumptionLimit(c.maxPower))
|
||||||
c, err := NewRelay(&stubSite{}, off, nil, 1000, 0)
|
assert.Equal(t, new(1e3), c.MaxConsumptionPower())
|
||||||
require.NoError(t, err)
|
assert.Equal(t, new(true), hems.Dimmed(c))
|
||||||
|
|
||||||
require.NotNil(t, c.MaxConsumptionPower())
|
// curtailment statement unaffected by relay activity
|
||||||
require.Equal(t, 0.0, *c.MaxConsumptionPower())
|
assert.Nil(t, c.CurtailedPercent())
|
||||||
require.Nil(t, c.MaxProductionPower()) // scaffolding only, always nil
|
assert.Nil(t, hems.Curtailed(c))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue