Skip to content

Commit

Permalink
Ignore battery charging above inverter AC rating
Browse files Browse the repository at this point in the history
  • Loading branch information
andig committed Mar 27, 2022
1 parent b49d366 commit 8f5e08e
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 23 deletions.
12 changes: 7 additions & 5 deletions core/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package core

import (
"github.com/avast/retry-go/v3"
"github.com/evcc-io/evcc/util"
)

var (
Expand All @@ -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 changes: 9 additions & 7 deletions core/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
26 changes: 15 additions & 11 deletions core/site_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 8f5e08e

Please sign in to comment.