diff --git a/assets/js/components/Battery/BatterySuggestionIcon.stories.ts b/assets/js/components/Battery/BatterySuggestionIcon.stories.ts
index bc5a4c105..a0eeeaa43 100644
--- a/assets/js/components/Battery/BatterySuggestionIcon.stories.ts
+++ b/assets/js/components/Battery/BatterySuggestionIcon.stories.ts
@@ -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",
diff --git a/assets/js/components/Battery/BatterySuggestionIcon.vue b/assets/js/components/Battery/BatterySuggestionIcon.vue
index df313a213..de285d0e5 100644
--- a/assets/js/components/Battery/BatterySuggestionIcon.vue
+++ b/assets/js/components/Battery/BatterySuggestionIcon.vue
@@ -8,6 +8,11 @@
>
+
+
diff --git a/assets/js/types/evcc.ts b/assets/js/types/evcc.ts
index b5a541e59..f80151321 100644
--- a/assets/js/types/evcc.ts
+++ b/assets/js/types/evcc.ts
@@ -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. */
diff --git a/core/site_optimizer.go b/core/site_optimizer.go
index 0fc3fff5e..ab1283a51 100644
--- a/core/site_optimizer.go
+++ b/core/site_optimizer.go
@@ -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()
}
diff --git a/core/site_optimizer_test.go b/core/site_optimizer_test.go
index 595593c3f..d5ed31b1f 100644
--- a/core/site_optimizer_test.go
+++ b/core/site_optimizer_test.go
@@ -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"},
diff --git a/i18n/en.json b/i18n/en.json
index ac2eb6526..2266e6117 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -49,6 +49,7 @@
"optimizer": {
"action": {
"charge": "Charge from grid",
+ "discharge": "Discharge to grid",
"hold": "Prevent discharging",
"holdcharge": "Prevent charging",
"normal": "Normal operation"
diff --git a/server/mcp/openapi.json b/server/mcp/openapi.json
index 177d919e9..1903503b7 100644
--- a/server/mcp/openapi.json
+++ b/server/mcp/openapi.json
@@ -3530,7 +3530,8 @@
"normal",
"hold",
"charge",
- "holdcharge"
+ "holdcharge",
+ "discharge"
]
},
"charge": {
diff --git a/server/openapi.state.yaml b/server/openapi.state.yaml
index 7dd1746a0..c9c522b20 100644
--- a/server/openapi.state.yaml
+++ b/server/openapi.state.yaml
@@ -408,6 +408,7 @@ components:
- hold
- charge
- holdcharge
+ - discharge
charge:
description: Recommended charge power in W.
type: number