From e05135af58b8d524cc38997e5165beb2d4728bfd Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 19 Jul 2026 17:08:44 +0200 Subject: [PATCH 1/2] core: pass grid feed-in cap to optimizer when curtailment active When a HEMS reports an active production/feed-in limit (e.g. German 70% rule), send it as the optimizer grid export cap so battery charging is scheduled into the PV peak to recover otherwise-curtailed energy. --- core/site_optimizer.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/site_optimizer.go b/core/site_optimizer.go index 4abdc7eb02c..ed590c00852 100644 --- a/core/site_optimizer.go +++ b/core/site_optimizer.go @@ -325,10 +325,16 @@ func (site *Site) optimizerUpdate(battery []types.Measurement) error { if site.circuit != nil { if pMaxImp := site.circuit.GetMaxPower(); pMaxImp > 0 { - req.Grid = optimizer.GridConfig{ - // hard grid import limit if no price penalty is set by PrcPExcImp - PMaxImp: float32(pMaxImp), - } + // hard grid import limit if no price penalty is set by PrcPExcImp + req.Grid.PMaxImp = float32(pMaxImp) + } + } + + // soft grid feed-in cap from active HEMS curtailment (e.g. German 70% rule): + // export is capped at this power, excess PV is curtailed instead of exported + if site.hems != nil { + if p := site.hems.MaxProductionPower(); p != nil && *p > 0 { + req.Grid.PMaxExp = float32(*p) } } From 426b3b8876a3f91c22b6d59a0179ddaa2fab7faf Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 19 Jul 2026 18:34:27 +0200 Subject: [PATCH 2/2] wip --- core/site_optimizer.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/site_optimizer.go b/core/site_optimizer.go index ed590c00852..8ae55ae48fb 100644 --- a/core/site_optimizer.go +++ b/core/site_optimizer.go @@ -18,6 +18,7 @@ import ( "github.com/evcc-io/evcc/core/loadpoint" "github.com/evcc-io/evcc/core/metrics" "github.com/evcc-io/evcc/core/types" + "github.com/evcc-io/evcc/hems/hems" "github.com/evcc-io/evcc/tariff" "github.com/evcc-io/evcc/util/config" "github.com/evcc-io/evcc/util/request" @@ -332,9 +333,9 @@ func (site *Site) optimizerUpdate(battery []types.Measurement) error { // soft grid feed-in cap from active HEMS curtailment (e.g. German 70% rule): // export is capped at this power, excess PV is curtailed instead of exported - if site.hems != nil { - if p := site.hems.MaxProductionPower(); p != nil && *p > 0 { - req.Grid.PMaxExp = float32(*p) + if curtailed := hems.Curtailed(site.hems); curtailed != nil && *curtailed { + if pMaxExp := site.hems.MaxProductionPower(); pMaxExp != nil { + req.Grid.PMaxExp = float32(*pMaxExp) } }