core: pass grid feed-in cap to optimizer when curtailment active - #31949
Conversation
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.
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- Consider whether
req.Gridshould be initialized explicitly before settingPMaxImp/PMaxExp, to avoid unintentionally overwriting any existing optimizer grid configuration elsewhere and to make the intended merge semantics clear. - It may be worth clarifying in a comment or code guard what should happen when both
site.circuit.GetMaxPower()andsite.hems.MaxProductionPower()are present but conflicting, so future changes don't accidentally assume one cap always dominates the other. - If
site.hems.MaxProductionPower()can change during runtime, consider whether caching or debouncing is needed to avoid frequent small updates toPMaxExpthat could cause unnecessary rescheduling churn.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider whether `req.Grid` should be initialized explicitly before setting `PMaxImp`/`PMaxExp`, to avoid unintentionally overwriting any existing optimizer grid configuration elsewhere and to make the intended merge semantics clear.
- It may be worth clarifying in a comment or code guard what should happen when both `site.circuit.GetMaxPower()` and `site.hems.MaxProductionPower()` are present but conflicting, so future changes don't accidentally assume one cap always dominates the other.
- If `site.hems.MaxProductionPower()` can change during runtime, consider whether caching or debouncing is needed to avoid frequent small updates to `PMaxExp` that could cause unnecessary rescheduling churn.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
Question here: is there a generic way to communicate fixed feed-in curtailment which is implemented on inverter side so that optimizer can use it? This hems piece seems more relevant for steuerbox cases, can't find anything in documentation. |
That's a different topic, lets not hide it here. |
Code reviewBug: missing nil-check on Lines 333 to 341 in 426b3b8 // 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 curtailed := hems.Curtailed(site.hems); curtailed != nil && *curtailed {
if pMaxExp := site.hems.MaxProductionPower(); pMaxExp != nil {
req.Grid.PMaxExp = float32(*pMaxExp)
}
}
func Curtailed(hems api.HEMS) *bool {
percent := hems.CurtailedPercent() // panics on a nil interface
...
}Calling a method on a nil interface value panics. Since The existing sibling code just above ( Suggested fix: if site.hems != nil {
if curtailed := hems.Curtailed(site.hems); curtailed != nil && *curtailed {
if pMaxExp := site.hems.MaxProductionPower(); pMaxExp != nil {
req.Grid.PMaxExp = float32(*pMaxExp)
}
}
} |
part of #23042
Feed the active HEMS production/feed-in limit (e.g. the German 70% rule) into the optimizer as the grid export cap, so it can schedule battery charging into the PV peak and recover energy that would otherwise be curtailed.
optimizerUpdatenow setsreq.Grid.PMaxExpfromsite.hems.MaxProductionPower()when a limit is active (non-nil and > 0).PMaxImpassignment to set the field in place so the import and export caps can coexist.The optimizer already treats
p_max_expas a soft cap: excess PV is curtailed rather than exported, so this never makes the schedule infeasible. The optimizer-side behavior is pinned by a test case in evcc-io/optimizer#93.🤖 Generated with Claude Code