Optimizer: surface battery-to-grid discharge as suggestion (#32087)

This commit is contained in:
andig 2026-07-23 15:32:24 +02:00 • committed by GitHub
parent 177ca558c9
commit a1b6a06305
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 20 additions and 4 deletions

View file

@ -2,7 +2,7 @@ import BatterySuggestionIcon from "./BatterySuggestionIcon.vue";
import { ICON_SIZE } from "@/types/evcc";
import type { Meta, StoryFn } from "@storybook/vue3";
const actions = ["normal", "hold", "charge", "holdcharge"] as const;
const actions = ["normal", "hold", "charge", "holdcharge", "discharge"] as const;
export default {
title: "Battery/BatterySuggestionIcon",

View file

@ -8,6 +8,11 @@
></shopicon-regular-powersupply>
<!-- holdcharge: prevent charging -->
<BatteryHoldCharge v-else-if="action === 'holdcharge'" :size="size" />
<!-- discharge: battery-to-grid export -->
<shopicon-regular-powersupply
v-else-if="action === 'discharge'"
:size="size"
></shopicon-regular-powersupply>
<!-- hold: prevent discharging -->
<BatteryHold v-else :size="size" />
</template>

View file

@ -1110,7 +1110,7 @@ export interface Battery {
/** Battery optimizer suggestion for a home battery. */
export interface BatterySuggestion {
/** Suggested operation mode. */
action: "normal" | "hold" | "charge" | "holdcharge";
action: "normal" | "hold" | "charge" | "holdcharge" | "discharge";
/** Recommended charge power in W. */
charge?: number;
/** Recommended discharge power in W. */

View file

@ -120,6 +120,10 @@ const (
actionCharge = "charge"
)
// actionDischarge is the battery-to-grid discharge advisory. It has no matching
// api.BatteryMode, so it always reads as actionable.
const actionDischarge = "discharge"
// evSuggestion notifies when the optimizer's advisory action for a device changes
const evSuggestion = "suggestion"
@ -179,6 +183,9 @@ func currentSlotSuggestion(detail batteryDetail, res optimizer.BatteryResult, gr
case idle && gridExporting:
// idle while exporting: surplus is exported instead of charged
s.Action = api.BatteryHoldCharge.String()
case discharge > suggestionThreshold && gridExporting:
// discharging while exporting means battery-to-grid discharge
s.Action = actionDischarge
default:
s.Action = api.BatteryNormal.String()
}

View file

@ -295,7 +295,8 @@ func TestCurrentSlotSuggestion(t *testing.T) {
{"battery pv charge (no import)", batteryTypeBattery, 3000, 0, false, true, "normal"},
{"battery hold (idle while importing)", batteryTypeBattery, 0, 0, true, false, "hold"},
{"battery holdcharge (idle while exporting)", batteryTypeBattery, 0, 0, false, true, "holdcharge"},
{"battery discharge", batteryTypeBattery, 0, 2000, true, false, "normal"},
{"battery discharge (self-consumption while importing)", batteryTypeBattery, 0, 2000, true, false, "normal"},
{"battery grid discharge (discharge while exporting)", batteryTypeBattery, 0, 2000, false, true, "discharge"},
{"battery idle balanced", batteryTypeBattery, 0, 0, false, false, "normal"},
{"loadpoint charge", batteryTypeLoadpoint, 11000, 0, false, false, "charge"},
{"loadpoint stop", batteryTypeLoadpoint, 0, 0, false, false, "stop"},

View file

@ -49,6 +49,7 @@
"optimizer": {
"action": {
"charge": "Charge from grid",
"discharge": "Discharge to grid",
"hold": "Prevent discharging",
"holdcharge": "Prevent charging",
"normal": "Normal operation"

View file

@ -3530,7 +3530,8 @@
"normal",
"hold",
"charge",
"holdcharge"
"holdcharge",
"discharge"
]
},
"charge": {

View file

@ -408,6 +408,7 @@ components:
- hold
- charge
- holdcharge
- discharge
charge:
description: Recommended charge power in W.
type: number