evcc-io/core/site_test.go

194 lines
4.6 KiB
Go

package core
import (
"testing"
"time"
"github.com/benbjohnson/clock"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/core/metrics"
"github.com/evcc-io/evcc/server/db"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGreenShare(t *testing.T) {
tc := []struct {
title string
grid, pv, battery, home, lp float64
greenShareTotal, greenShareHome, greenShareLoadpoints float64
}{
{
"half grid, half pv, green home",
1000, 1000, 0, 1000, 1000,
0.5, 1, 0,
},
{
"half grid, half pv, no home",
1000, 1000, 0, 0, 2000,
0.5, 1, 0.5,
},
{
"half grid, half pv, no lp",
2500, 2500, 0, 5000, 0,
0.5, 0.5, 0,
},
{
"full pv",
0, 5000, 0, 1000, 4000,
1, 1, 1,
},
{
"full grid",
5000, 0, 0, 1000, 4000,
0, 0, 0,
},
{
"half grid, half battery, green home",
1000, 0, 1000, 1000, 1000,
0.5, 1, 0,
},
{
"half grid, half battery, no home",
1000, 0, 1000, 0, 2000,
0.5, 1, 0.5,
},
{
"half grid, half battery, no lp",
1000, 0, 1000, 2000, 0,
0.5, 0.5, 0,
},
{
"full pv, pv export",
-5000, 10000, 0, 1000, 4000,
1, 1, 1,
},
{
"full pv, pv export, no lp",
-5000, 10000, 0, 5000, 0,
1, 1, 1,
},
{
"full pv, pv export, battery charge",
-2500, 10000, -2500, 1000, 4000,
1, 1, 1,
},
{
"full grid, battery charge",
3000, 0, -1000, 1000, 1000,
0, 0, 0,
},
{
"full grid, battery charge, no lp",
2000, 0, -1000, 1000, 0,
0, 0, 0,
},
{
"half grid, half pv, battery charge, no lp",
1000, 1000, -1000, 1000, 0,
0.5, 1, 0,
},
{
"half grid, half pv, battery charge, home, lp",
1000, 1000, -1000, 500, 500,
0.5, 1, 0,
},
{
"pv ac limited, battery charge & grid import",
1000, 3000, -1000, 1000, 2000,
0.75, 1, 0.5,
},
}
for _, tc := range tc {
t.Log(tc.title)
s := &Site{
gridPower: tc.grid,
pvPower: tc.pv,
batteryPower: tc.battery,
}
totalPower := tc.grid + tc.pv + max(0, tc.battery)
greenShareTotal := s.greenShare(0, totalPower)
if greenShareTotal != tc.greenShareTotal {
t.Errorf("greenShareTotal wanted %.3f, got %.3f", tc.greenShareTotal, greenShareTotal)
}
greenShareHome := s.greenShare(0, tc.home)
if greenShareHome != tc.greenShareHome {
t.Errorf("greenShareHome wanted %.3f, got %.3f", tc.greenShareHome, greenShareHome)
}
greenShareLoadpoints := s.greenShare(tc.home+max(0, -tc.battery), totalPower)
if greenShareLoadpoints != tc.greenShareLoadpoints {
t.Errorf("greenShareLoadpoints wanted %.3f, got %.3f", tc.greenShareLoadpoints, greenShareLoadpoints)
}
}
}
func TestRequiredBatteryMode(t *testing.T) {
tc := []struct {
gridChargeActive bool
mode, res api.BatteryMode
}{
{false, api.BatteryUnknown, api.BatteryUnknown}, // ignore
{false, api.BatteryNormal, api.BatteryUnknown}, // ignore
{false, api.BatteryHold, api.BatteryNormal},
{false, api.BatteryCharge, api.BatteryNormal},
{true, api.BatteryUnknown, api.BatteryCharge},
{true, api.BatteryNormal, api.BatteryCharge},
{true, api.BatteryHold, api.BatteryCharge},
{true, api.BatteryCharge, api.BatteryUnknown}, // ignore
}
{
// no battery
res := new(Site).requiredBatteryMode(true, api.Rate{})
assert.Equal(t, api.BatteryUnknown, res, "expected %s, got %s", api.BatteryUnknown, res)
}
for _, tc := range tc {
t.Logf("%+v", tc)
s := &Site{
batteryMeters: []config.Device[api.Meter]{nil},
batteryMode: tc.mode,
}
res := s.requiredBatteryMode(tc.gridChargeActive, api.Rate{})
assert.Equal(t, tc.res, res, "expected %s, got %s", tc.res, res)
}
}
func TestUpdateHomeConsumption(t *testing.T) {
clock := clock.NewMock()
require.NoError(t, db.NewInstance("sqlite", ":memory:"))
require.NoError(t, metrics.SetupSchema())
s := &Site{
log: util.NewLogger("foo"),
gridPower: 4e3,
householdEnergy: &meterEnergy{clock: clock},
}
require.True(t, s.householdEnergy.updated.IsZero())
clock.Add(5 * time.Minute)
s.updateHomeConsumption(1e3)
require.False(t, s.householdEnergy.updated.IsZero())
clock.Add(5 * time.Minute)
s.updateHomeConsumption(1e3)
require.Equal(t, 1e3*5/60/1e3, s.householdEnergy.AccumulatedEnergy()) // kWh
clock.Add(5 * time.Minute)
s.updateHomeConsumption(1e3)
require.Equal(t, 0.0, s.householdEnergy.AccumulatedEnergy()) // accumulator reset after 15 minutes
clock.Add(15 * time.Minute)
s.updateHomeConsumption(1e3)
require.Equal(t, 0.0, s.householdEnergy.AccumulatedEnergy()) // accumulator reset after 15 minutes
}