Ignore battery charging above inverter AC rating (#3015)
This commit is contained in:
parent
d4db91b798
commit
d8a6efc35a
3 changed files with 31 additions and 23 deletions
|
|
@ -2,6 +2,7 @@ package core
|
|||
|
||||
import (
|
||||
"github.com/avast/retry-go/v3"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -25,13 +26,14 @@ func powerToCurrent(power float64, phases int) float64 {
|
|||
|
||||
// sitePower returns the available delta power that the charger might additionally consume
|
||||
// negative value: available power (grid export), positive value: grid import
|
||||
func sitePower(grid, battery, residual float64) float64 {
|
||||
func sitePower(log *util.Logger, maxGrid, grid, battery, residual float64) float64 {
|
||||
// For hybrid inverters, battery can be charged from DC power in excess of
|
||||
// inverter AC rating. This must be offset by the grid consumption when calculating
|
||||
// available site power.
|
||||
// (https://github.com/evcc-io/evcc/issues/2734)
|
||||
if grid > 0 && battery < 0 && grid-battery > 50 {
|
||||
// inverter AC rating. This battery charge must not be counted as available for AC consumption.
|
||||
// https://github.com/evcc-io/evcc/issues/2734, https://github.com/evcc-io/evcc/issues/2986
|
||||
if maxGrid > 0 && grid > maxGrid && battery < 0 {
|
||||
log.TRACE.Printf("ignoring excess DC charging due to grid consumption: %.0fW > %.0fW", grid, maxGrid)
|
||||
battery = 0
|
||||
}
|
||||
|
||||
return grid + battery + residual
|
||||
}
|
||||
|
|
|
|||
16
core/site.go
16
core/site.go
|
|
@ -31,12 +31,13 @@ type Site struct {
|
|||
log *util.Logger
|
||||
|
||||
// configuration
|
||||
Title string `mapstructure:"title"` // UI title
|
||||
Voltage float64 `mapstructure:"voltage"` // Operating voltage. 230V for Germany.
|
||||
ResidualPower float64 `mapstructure:"residualPower"` // PV meter only: household usage. Grid meter: household safety margin
|
||||
Meters MetersConfig // Meter references
|
||||
PrioritySoC float64 `mapstructure:"prioritySoC"` // prefer battery up to this SoC
|
||||
BufferSoC float64 `mapstructure:"bufferSoC"` // ignore battery above this SoC
|
||||
Title string `mapstructure:"title"` // UI title
|
||||
Voltage float64 `mapstructure:"voltage"` // Operating voltage. 230V for Germany.
|
||||
ResidualPower float64 `mapstructure:"residualPower"` // PV meter only: household usage. Grid meter: household safety margin
|
||||
Meters MetersConfig // Meter references
|
||||
PrioritySoC float64 `mapstructure:"prioritySoC"` // prefer battery up to this SoC
|
||||
BufferSoC float64 `mapstructure:"bufferSoC"` // ignore battery above this SoC
|
||||
MaxGridSupplyWhileBatteryCharging float64 `mapstructure:"maxGridSupplyWhileBatteryCharging"` // ignore battery charging if AC consumption is above this value
|
||||
|
||||
// meters
|
||||
gridMeter api.Meter // Grid usage meter
|
||||
|
|
@ -376,7 +377,8 @@ func (site *Site) sitePower(totalChargePower float64) (float64, error) {
|
|||
site.batteryBuffered = batteryPower > 0 && site.BufferSoC > 0 && socs > site.BufferSoC
|
||||
}
|
||||
|
||||
sitePower := sitePower(site.gridPower, batteryPower, site.ResidualPower)
|
||||
sitePower := sitePower(site.log, site.MaxGridSupplyWhileBatteryCharging, site.gridPower, batteryPower, site.ResidualPower)
|
||||
|
||||
site.log.DEBUG.Printf("site power: %.0fW", sitePower)
|
||||
|
||||
return sitePower, nil
|
||||
|
|
|
|||
|
|
@ -2,27 +2,31 @@ package core
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
||||
func TestSitePower(t *testing.T) {
|
||||
tc := []struct {
|
||||
grid, battery, site float64
|
||||
maxGrid, grid, battery, site float64
|
||||
}{
|
||||
{0, 0, 0}, // silent night
|
||||
{0, 1, 1}, // battery discharging
|
||||
{0, -1, -1}, // battery charging -> negative result cannot occur in reality
|
||||
{1, 0, 1}, // grid import
|
||||
{1, 1, 2}, // grid import + battery discharging
|
||||
{-1, 0, -1}, // grid export
|
||||
{-1, -1, -2}, // grid export + battery charging
|
||||
// {0, 0, 0, 0}, // silent night
|
||||
// {0, 0, 1, 1}, // battery discharging
|
||||
// {0, 0, -1, -1}, // battery charging -> negative result cannot occur in reality
|
||||
// {0, 1, 0, 1}, // grid import
|
||||
// {0, 1, 1, 2}, // grid import + battery discharging
|
||||
// {0, -1, 0, -1}, // grid export
|
||||
// {0, -1, -1, -2}, // grid export + battery charging
|
||||
{0, 1, -1, 0}, // grid import + battery charging -> should not happen
|
||||
{0.5, 1, -1, 1}, // grid import + DC battery charging
|
||||
}
|
||||
|
||||
log := util.NewLogger("foo")
|
||||
|
||||
for _, tc := range tc {
|
||||
res := sitePower(tc.grid, tc.battery, 0)
|
||||
res := sitePower(log, tc.maxGrid, tc.grid, tc.battery, 0)
|
||||
if res != tc.site {
|
||||
t.Errorf("sitePower wanted %.f, got %.f", tc.site, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add test case for battery priority charging
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue