113 lines
2.9 KiB
Go
113 lines
2.9 KiB
Go
package plugin
|
|
|
|
import (
|
|
"testing"
|
|
|
|
sunspec "github.com/andig/gosunspec"
|
|
"github.com/andig/gosunspec/memory"
|
|
"github.com/andig/gosunspec/models/model704"
|
|
"github.com/evcc-io/evcc/util/modbus"
|
|
"github.com/stretchr/testify/require"
|
|
sunsdev "github.com/volkszaehler/mbmd/meters/sunspec"
|
|
)
|
|
|
|
func TestSunspecBool(t *testing.T) {
|
|
cases := []struct {
|
|
res int64
|
|
mask uint64
|
|
want bool
|
|
}{
|
|
{0, 0, false},
|
|
{1, 0, true},
|
|
{2, 0, true},
|
|
{0b0100, 0b0010, false}, // masked-out bit
|
|
{0b0110, 0b0010, true}, // masked-in bit
|
|
}
|
|
|
|
for _, c := range cases {
|
|
if got := sunspecBool(c.res, c.mask); got != c.want {
|
|
t.Errorf("sunspecBool(%v, %v) = %v, want %v", c.res, c.mask, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// newSunspecTestDevice builds an in-memory SunSpec model 704 (DER AC Controls)
|
|
// device; mbmd never touches the modbus.Client argument, so no connection is needed.
|
|
func newSunspecTestDevice(t *testing.T) (*sunsdev.SunSpec, sunspec.Block) {
|
|
t.Helper()
|
|
|
|
slab, err := memory.NewSlabBuilder().AddModel(model704.ModelID).Build()
|
|
require.NoError(t, err)
|
|
|
|
arr, err := memory.Open(slab)
|
|
require.NoError(t, err)
|
|
|
|
devices := arr.Collect(sunspec.AllDevices)
|
|
require.NotEmpty(t, devices)
|
|
|
|
block := devices[0].MustModel(sunspec.ModelId(model704.ModelID)).MustBlock(0)
|
|
|
|
dev := sunsdev.NewDevice("test")
|
|
require.NoError(t, dev.InitializeWithTree(devices))
|
|
|
|
return dev, block
|
|
}
|
|
|
|
// TestSunspecBoolGetterEnum exercises BoolGetter against a real enum16 point
|
|
// (WMaxLimPctEna, SunSpec 704), the curtailment-enabled flag.
|
|
func TestSunspecBoolGetterEnum(t *testing.T) {
|
|
dev, block := newSunspecTestDevice(t)
|
|
|
|
for _, c := range []struct {
|
|
val sunspec.Enum16
|
|
mask uint64
|
|
want bool
|
|
}{
|
|
{0, 0, false},
|
|
{1, 0, true},
|
|
{0b11, 0b10, true}, // masked-in bit
|
|
{0b11, 0b100, false}, // masked-out bit
|
|
} {
|
|
block.MustPoint(model704.WMaxLimPctEna).SetEnum16(c.val)
|
|
require.NoError(t, block.Write(model704.WMaxLimPctEna))
|
|
|
|
mb := &ModbusSunspec{
|
|
device: dev,
|
|
op: modbus.SunSpecOperation{Model: model704.ModelID, Point: model704.WMaxLimPctEna},
|
|
mask: c.mask,
|
|
}
|
|
|
|
g, err := mb.BoolGetter()
|
|
require.NoError(t, err)
|
|
|
|
got, err := g()
|
|
require.NoError(t, err)
|
|
require.Equal(t, c.want, got, "value %v mask %v", c.val, c.mask)
|
|
}
|
|
}
|
|
|
|
// TestSunspecBoolGetterInt exercises BoolGetter against a real scaled int-like
|
|
// point (WMaxLimPct, a uint16 with a SunSpec scale factor).
|
|
func TestSunspecBoolGetterInt(t *testing.T) {
|
|
dev, block := newSunspecTestDevice(t)
|
|
|
|
mb := &ModbusSunspec{
|
|
device: dev,
|
|
op: modbus.SunSpecOperation{Model: model704.ModelID, Point: model704.WMaxLimPct},
|
|
}
|
|
|
|
g, err := mb.BoolGetter()
|
|
require.NoError(t, err)
|
|
|
|
block.MustPoint(model704.WMaxLimPct).SetUint16(0)
|
|
require.NoError(t, block.Write(model704.WMaxLimPct))
|
|
got, err := g()
|
|
require.NoError(t, err)
|
|
require.False(t, got)
|
|
|
|
block.MustPoint(model704.WMaxLimPct).SetUint16(50)
|
|
require.NoError(t, block.Write(model704.WMaxLimPct))
|
|
got, err = g()
|
|
require.NoError(t, err)
|
|
require.True(t, got)
|
|
}
|