From c5b722445f065e0f38de387a79d4c18a99df2994 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:54:55 +0000 Subject: [PATCH] Publish minSocNotReached state (#28218) --- assets/js/components/Loadpoints/Loadpoint.vue | 1 + assets/js/components/Vehicles/Soc.vue | 8 +++--- assets/js/components/Vehicles/Status.test.ts | 18 +++++-------- assets/js/components/Vehicles/Status.vue | 7 ++--- assets/js/components/Vehicles/Vehicle.vue | 1 + assets/js/types/evcc.ts | 1 + core/keys/loadpoint.go | 27 ++++++++++--------- core/loadpoint.go | 6 ++++- 8 files changed, 33 insertions(+), 36 deletions(-) diff --git a/assets/js/components/Loadpoints/Loadpoint.vue b/assets/js/components/Loadpoints/Loadpoint.vue index ab6449966..0c9371ab7 100644 --- a/assets/js/components/Loadpoints/Loadpoint.vue +++ b/assets/js/components/Loadpoints/Loadpoint.vue @@ -181,6 +181,7 @@ export default defineComponent({ vehicleDetectionActive: Boolean, vehicleRange: Number, vehicleSoc: { type: Number, default: 0 }, + minSocNotReached: Boolean, vehicleName: String, vehicleIcon: String, vehicleLimitSoc: Number, diff --git a/assets/js/components/Vehicles/Soc.vue b/assets/js/components/Vehicles/Soc.vue index 57940383f..617828a95 100644 --- a/assets/js/components/Vehicles/Soc.vue +++ b/assets/js/components/Vehicles/Soc.vue @@ -87,6 +87,7 @@ export default defineComponent({ charging: Boolean, heating: Boolean, minSoc: { type: Number, default: 0 }, + minSocNotReached: Boolean, effectivePlanSoc: { type: Number, default: 0 }, effectiveLimitSoc: Number, limitEnergy: { type: Number, default: 0 }, @@ -174,20 +175,17 @@ export default defineComponent({ return isBelowVehicleLimit && isAbovePlanLimit; }, progressColor() { - if (this.minSocActive) { + if (this.minSocNotReached) { return "bg-danger"; } return "bg-primary"; }, - minSocActive() { - return this.minSoc > 0 && this.vehicleSoc < this.minSoc; - }, remainingSocWidth() { if (this.socBasedCharging) { if (this.vehicleSocDisplayWidth === 100) { return null; } - if (this.minSocActive) { + if (this.minSocNotReached) { return this.minSoc - this.vehicleSoc; } const limit = Math.min( diff --git a/assets/js/components/Vehicles/Status.test.ts b/assets/js/components/Vehicles/Status.test.ts index 56ee687bb..d9d50b112 100644 --- a/assets/js/components/Vehicles/Status.test.ts +++ b/assets/js/components/Vehicles/Status.test.ts @@ -60,27 +60,21 @@ describe("basics", () => { }); describe("min charge", () => { - test("active when vehicle soc is below", () => { + test("active when minSocNotReached is true", () => { expectEntries( - { connected: true, minSoc: 20, vehicleSoc: 10 }, + { connected: true, minSoc: 20, minSocNotReached: true }, { charger: "main.vehicleStatus.connected", minsoc: "20 %" } ); }); - test("not active when vehicle soc is above", () => { + test("not active when minSocNotReached is false", () => { expectEntries( - { connected: true, minSoc: 20, vehicleSoc: 21 }, + { connected: true, minSoc: 20, minSocNotReached: false }, { charger: "main.vehicleStatus.connected", minsoc: false } ); }); - test("not active when vehicle soc is equal", () => { + test("not active when minSocNotReached is not set", () => { expectEntries( - { connected: true, minSoc: 20, vehicleSoc: 20 }, - { charger: "main.vehicleStatus.connected", minsoc: false } - ); - }); - test("not active when limit is 0", () => { - expectEntries( - { connected: true, minSoc: 0, vehicleSoc: 10 }, + { connected: true, minSoc: 20 }, { charger: "main.vehicleStatus.connected", minsoc: false } ); }); diff --git a/assets/js/components/Vehicles/Status.vue b/assets/js/components/Vehicles/Status.vue index e220efd3f..c6afc86e2 100644 --- a/assets/js/components/Vehicles/Status.vue +++ b/assets/js/components/Vehicles/Status.vue @@ -105,6 +105,7 @@ export default defineComponent({ enabled: Boolean, heating: Boolean, minSoc: { type: Number, default: 0 }, + minSocNotReached: Boolean, phaseAction: { type: String, default: "" }, phaseRemainingInterpolated: Number, planActive: Boolean, @@ -269,11 +270,7 @@ export default defineComponent({ }, { id: "minSoc", - visible: - !this.heating && - this.connected && - this.minSoc > 0 && - this.vehicleSoc < this.minSoc, + visible: !this.heating && this.connected && this.minSocNotReached, content: this.fmtPercentage(this.minSoc), tooltipContent: t("minCharge", { soc: this.fmtPercentage(this.minSoc), diff --git a/assets/js/components/Vehicles/Vehicle.vue b/assets/js/components/Vehicles/Vehicle.vue index 8064cbec2..c0f86587a 100644 --- a/assets/js/components/Vehicles/Vehicle.vue +++ b/assets/js/components/Vehicles/Vehicle.vue @@ -161,6 +161,7 @@ export default defineComponent({ vehicleSoc: { type: Number, default: 0 }, vehicleLimitSoc: Number, vehicleNotReachable: Boolean, + minSocNotReached: Boolean, }, emits: [ "limit-soc-updated", diff --git a/assets/js/types/evcc.ts b/assets/js/types/evcc.ts index ec462efd2..77392e0a5 100644 --- a/assets/js/types/evcc.ts +++ b/assets/js/types/evcc.ts @@ -263,6 +263,7 @@ export interface Loadpoint { limitSoc: number; maxCurrent: number; minCurrent: number; + minSocNotReached: boolean; mode: CHARGE_MODE; offeredCurrent: number; phaseAction: PHASE_ACTION; diff --git a/core/keys/loadpoint.go b/core/keys/loadpoint.go index fb547f1d1..808ab4878 100644 --- a/core/keys/loadpoint.go +++ b/core/keys/loadpoint.go @@ -2,19 +2,20 @@ package keys const ( // loadpoint settings - Title = "title" // loadpoint title - Mode = "mode" // charge mode - DefaultMode = "defaultMode" // default charge mode - Charger = "charger" // charger ref - Meter = "meter" // meter ref - Circuit = "circuit" // circuit ref - DefaultVehicle = "vehicle" // default vehicle ref - Priority = "priority" // priority - MinCurrent = "minCurrent" // min current - MaxCurrent = "maxCurrent" // max current - MinSoc = "minSoc" // min soc - LimitSoc = "limitSoc" // limit soc - LimitEnergy = "limitEnergy" // limit energy + Title = "title" // loadpoint title + Mode = "mode" // charge mode + DefaultMode = "defaultMode" // default charge mode + Charger = "charger" // charger ref + Meter = "meter" // meter ref + Circuit = "circuit" // circuit ref + DefaultVehicle = "vehicle" // default vehicle ref + Priority = "priority" // priority + MinCurrent = "minCurrent" // min current + MaxCurrent = "maxCurrent" // max current + MinSoc = "minSoc" // min soc + MinSocNotReached = "minSocNotReached" // min soc not reached + LimitSoc = "limitSoc" // limit soc + LimitEnergy = "limitEnergy" // limit energy Soc = "soc" Thresholds = "thresholds" EnableThreshold = "enableThreshold" diff --git a/core/loadpoint.go b/core/loadpoint.go index fe7a271af..0347a7eb1 100644 --- a/core/loadpoint.go +++ b/core/loadpoint.go @@ -1986,6 +1986,10 @@ func (lp *Loadpoint) Update(sitePower, batteryBoostPower float64, consumption, f // update and publish plan without being short-circuited by modes etc. plannerActive := lp.plannerActive() + // update and publish min soc not reached state + minSocNotReached := lp.minSocNotReached() + lp.publish(keys.MinSocNotReached, minSocNotReached) + // execute loading strategy switch { case !lp.connected(): @@ -2004,7 +2008,7 @@ func (lp *Loadpoint) Update(sitePower, batteryBoostPower float64, consumption, f err = lp.setLimit(current) // minimum or target charging - case lp.minSocNotReached() || plannerActive: + case minSocNotReached || plannerActive: err = lp.fastCharging() lp.resetPhaseTimer() lp.elapsePVTimer() // let PV mode disable immediately afterwards