Optimizer: derive per-device action suggestions from result#30834
Conversation
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The
suggestionThresholdconstant is a magic number incurrentSlotSuggestion; consider either naming it to convey why 50 W is appropriate (e.g. reference to measurement noise / optimizer resolution) or adding a brief comment explaining how it was chosen so future changes don’t accidentally invalidate the assumption. - For non-battery types,
currentSlotSuggestionalways returns"stop"whencharge <= suggestionThresholdregardless of discharge power or grid direction; if discharge or grid flow should influence EV/loadpoint recommendations, it may be worth revisiting this logic or documenting that this simplification is intentional.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `suggestionThreshold` constant is a magic number in `currentSlotSuggestion`; consider either naming it to convey why 50 W is appropriate (e.g. reference to measurement noise / optimizer resolution) or adding a brief comment explaining how it was chosen so future changes don’t accidentally invalidate the assumption.
- For non-battery types, `currentSlotSuggestion` always returns `"stop"` when `charge <= suggestionThreshold` regardless of discharge power or grid direction; if discharge or grid flow should influence EV/loadpoint recommendations, it may be worth revisiting this logic or documenting that this simplification is intentional.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
@copilot resolve the merge conflicts in this pull request |
Resolved by merging |
Adds an experimental battery HoldCharge mode driven by the optimizer plan. When enabled, the battery's charging is limited to the optimizer's planned per-slot power (read from the per-battery suggestion), so it can withhold charging early and absorb the midday feed-in peak while keeping discharge available. Builds on the optimizer suggestion (evcc-io/evcc evcc-io#30834) and the withhold_charge capability (evcc-io/optimizer#79). - setting batteryAutoHoldCharge: key, field, Get/Set + site.API, HTTP route, persist/publish/restore - optimizer request: set the battery WithholdCharge flag - battery mode: require BatteryHoldCharge while enabled (discharge stays allowed); the meter template applies the planned limit per slot - kostal-plenticore-gen2: holdcharge case reads the suggestion via the state source (jq) and writes it to the charge-power-limit register; new batteryIndex param for multi-battery setups - UI: experimental HoldCharge toggle in battery settings + en/de texts TEMP: go.mod replaces the optimizer with the local fork (evcc-io#79); remove before merge once the optimizer release with withhold_charge is bumped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds an experimental battery HoldCharge mode driven by the optimizer plan. When enabled, the battery's charging is limited to the optimizer's planned per-slot power (read from the per-battery suggestion), so it can withhold charging early and absorb the midday feed-in peak while keeping discharge available. Builds on the optimizer suggestion (evcc-io/evcc evcc-io#30834) and the withhold_charge capability (evcc-io/optimizer#79). - setting batteryAutoHoldCharge: key, field, Get/Set + site.API, HTTP route, persist/publish/restore - optimizer request: set the battery WithholdCharge flag - battery mode: require BatteryHoldCharge while enabled (discharge stays allowed); the meter template applies the planned limit per slot - kostal-plenticore-gen2: holdcharge case reads the suggestion via the state source (jq) and writes it to the charge-power-limit register; new batteryIndex param for multi-battery setups - UI: experimental HoldCharge toggle in battery settings + en/de texts TEMP: go.mod replaces the optimizer with the local fork (evcc-io#79); remove before merge once the optimizer release with withhold_charge is bumped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When the battery is in holdcharge mode (today reachable via external control, REST/MQTT), apply the optimizer's planned per-slot charge power instead of a fixed 0. The kostal-plenticore-gen2 holdcharge case reads the planned charge from the per-battery optimizer suggestion (evcc-io/evcc evcc-io#30834) via the state source (jq) and writes it to the charge-power-limit register. A new batteryIndex param selects the battery in multi-battery setups. Depends on the state plugin (separate PR) and the optimizer suggestion (evcc-io#30834). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When batteryAutoHoldCharge is enabled, follow the optimizer's current-slot plan instead of leaving the battery in normal mode: charge -> holdcharge (the meter template applies the planned per-slot limit), discharge -> normal (discharge allowed), otherwise hold (preserve capacity for a later price peak - important in winter with scarce capacity). The plan is read from the per-battery optimizer suggestion (evcc-io#30834); a stored plan is trusted for 30 min. Builds on the HoldCharge setting (request PR) and the suggestion (evcc-io#30834). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When batteryAutoHoldCharge is enabled, follow the optimizer's current-slot plan instead of leaving the battery in normal mode. The optimizer already classifies each home battery as normal/hold/charge/holdcharge in its per-slot suggestion (evcc-io#30834), accounting for grid flow direction, so map that action directly onto the global battery mode rather than re-deriving it from raw charge power. On conflicting per-battery suggestions the peak-shaving intent wins: holdcharge > hold > charge > normal. A stored plan is trusted for 30 min. Builds on the HoldCharge setting (request PR) and the suggestion (evcc-io#30834). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Created UI for battery and loadpoints. Updated publishing structure. See description and screenshots above,. |
|
Following this with interest. It looks like the direction that would replace a workaround I'm running. I have a Vaillant aroTHERM heat pump modelled as a heating loadpoint (SoC = DHW
Both are exactly what a price+forecast optimizer should decide on its own, so I'd Will the per-slot suggestions (and later the wired-up control) extend to heating/thermal loadpoints, where "SoC" is a tank temperature and the store is thermal rather than a battery/EV? Or is the initial scope battery + EV only? Happy to test on a real thermal + PV + dynamic-tariff system if that's useful. |
|
NICE! |
Replaces reverted #30783, builds on #31383
Converts the optimizer schedule into a per-device advisory action for the current slot, published on the battery device and as a dedicated loadpoint key. Because the optimization is linear, the first slot sits at an operating-range extreme, so it maps cleanly onto the discrete action that control would later apply. Advisory only, control is intentionally not wired up yet.
💡 new optimizer icon (magic suggest bulb)
🔋 Battery page (🧪): each battery card shows its suggestion; with a single battery, suggestion and soc forecast share the optimizer tile
🚗 Vehicle status: optimizer icon (charge/pause variant) with explanatory tooltip, shown only when the suggestion differs from the current charging state
💡 Suggestion actions: home battery
normal|hold|charge|holdcharge, loadpoint/vehiclecharge|stop; idle battery interpreted from grid flow (importing →hold, exporting →holdcharge)🧹 Suggestions are replaced on every optimizer run, cleared (
null) for disconnected loadpoints and on optimizer errors📡 Published state structure. Power values are published but not shown (device support required first)
Wording
chargeholdholdchargenormalScreenshots
battery view: one battery, dedicated optimizer box

batterie view: multiple batteries, suggestions per device, forecast combined

loadpoint charge advice

loadpoint pause advice
