diff --git a/assets/js/components/ChargingPlan.vue b/assets/js/components/ChargingPlan.vue
index 0bf749414..d04601f9e 100644
--- a/assets/js/components/ChargingPlan.vue
+++ b/assets/js/components/ChargingPlan.vue
@@ -132,6 +132,7 @@ export default {
vehicle: Object,
vehicleCapacity: Number,
vehicleSoc: Number,
+ vehicleTargetSoc: Number,
},
data: function () {
return {
diff --git a/assets/js/components/ChargingPlanSettings.vue b/assets/js/components/ChargingPlanSettings.vue
index d8cdb1ead..624223dc1 100644
--- a/assets/js/components/ChargingPlanSettings.vue
+++ b/assets/js/components/ChargingPlanSettings.vue
@@ -69,6 +69,7 @@ export default {
mode: String,
vehicleCapacity: Number,
vehicle: Object,
+ vehicleTargetSoc: Number,
},
emits: ["plan-removed", "plan-updated"],
data: function () {
diff --git a/assets/js/components/ChargingPlanWarnings.vue b/assets/js/components/ChargingPlanWarnings.vue
index 76bed673e..5e7062595 100644
--- a/assets/js/components/ChargingPlanWarnings.vue
+++ b/assets/js/components/ChargingPlanWarnings.vue
@@ -1,28 +1,22 @@
+
+ {{ $t("main.targetCharge.targetIsInThePast") }}
+
+
+ {{ $t("main.targetCharge.targetIsAboveVehicleLimit", { limit: vehicleLimitFmt }) }}
+
{{ $t("main.targetCharge.onlyInPvMode") }}
-
- {{
- $t("main.targetCharge.targetIsAboveLimit", {
- limit: limitFmt,
- goal: goalFmt,
- })
- }}
-
-
- {{ $t("main.targetCharge.targetIsInThePast") }}
+
+ {{ $t("main.targetCharge.targetIsAboveLimit", { limit: limitFmt }) }}
{{ $t("main.targetCharge.targetIsTooFarInTheFuture") }}
- {{
- $t("main.targetCharge.costLimitIgnore", {
- limit: costLimitText,
- })
- }}
+ {{ $t("main.targetCharge.costLimitIgnore", { limit: costLimitText }) }}
@@ -50,6 +44,7 @@ export default {
mode: String,
tariff: Object,
selectedTargetTime: Date,
+ vehicleTargetSoc: Number,
},
computed: {
timeInThePast: function () {
@@ -72,12 +67,21 @@ export default {
}
return this.limitEnergy && this.planEnergy > this.limitEnergy;
},
+ targetIsAboveVehicleLimit: function () {
+ if (this.socBasedPlanning) {
+ return this.effectivePlanSoc > (this.vehicleTargetSoc || 100);
+ }
+ return false;
+ },
limitFmt: function () {
if (this.socBasedPlanning) {
return this.fmtSoc(this.effectiveLimitSoc);
}
return this.fmtKWh(this.limitEnergy * 1e3);
},
+ vehicleLimitFmt: function () {
+ return this.fmtSoc(this.vehicleTargetSoc);
+ },
goalFmt: function () {
if (this.socBasedPlanning) {
return this.fmtSoc(this.effectivePlanSoc);
diff --git a/assets/js/components/VehicleSoc.vue b/assets/js/components/VehicleSoc.vue
index 24beccbf9..fe47990e4 100644
--- a/assets/js/components/VehicleSoc.vue
+++ b/assets/js/components/VehicleSoc.vue
@@ -32,14 +32,17 @@
v-show="energyLimitMarkerPosition"
class="energy-limit-marker"
data-bs-toggle="tooltip"
- :class="{ 'energy-limit-marker--active': energyLimitMarkerPosition < 100 }"
+ :class="{
+ 'energy-limit-marker--active': energyLimitMarkerActive,
+ 'energy-limit-marker--visible': energyLimitMarkerPosition < 100,
+ }"
:style="{ left: `${energyLimitMarkerPosition}%` }"
/>
0;
},
- planMarkerActive: function () {
+ planMarkerUnreachable: function () {
if (this.socBasedPlanning) {
- const sessionLimit = this.selectedLimitSoc || this.effectiveLimitSoc;
const vehicleLimit = this.vehicleTargetSoc || 100;
- const maxLimit = Math.min(sessionLimit, vehicleLimit);
- return this.effectivePlanSoc <= maxLimit;
+ return this.effectivePlanSoc > vehicleLimit;
}
- return this.planEnergy <= this.limitEnergy || !this.limitEnergy;
+ return false;
},
energyLimitMarkerPosition: function () {
if (this.socBasedCharging) {
@@ -159,8 +160,19 @@ export default {
}
return 100;
},
+ energyLimitMarkerActive: function () {
+ if (this.socBasedCharging) {
+ return false;
+ }
+ if (this.planEnergy) {
+ return this.limitEnergy >= this.planEnergy;
+ }
+ return true;
+ },
sliderActive: function () {
- return !this.vehicleTargetSoc || this.visibleLimitSoc <= this.vehicleTargetSoc;
+ const isBelowVehicleLimit = this.visibleLimitSoc <= (this.vehicleTargetSoc || 100);
+ const isAbovePlanLimit = this.visibleLimitSoc >= (this.effectivePlanSoc || 0);
+ return isBelowVehicleLimit && isAbovePlanLimit;
},
progressColor: function () {
if (this.minSocActive) {
@@ -179,14 +191,14 @@ export default {
if (this.minSocActive) {
return this.minSoc - this.vehicleSoc;
}
- let soc = this.sliderActive ? this.visibleLimitSoc : this.vehicleTargetSoc;
- if (soc > this.vehicleSoc) {
- return soc - this.vehicleSoc;
+ const limit = Math.min(
+ this.vehicleTargetSoc || 100,
+ Math.max(this.visibleLimitSoc, this.effectivePlanSoc || 0)
+ );
+ if (limit > this.vehicleSoc) {
+ return limit - this.vehicleSoc;
}
} else {
- if (this.limitEnergy && this.planEnergy > this.limitEnergy) {
- return (100 / this.planEnergy) * this.limitEnergy - this.vehicleSocDisplayWidth;
- }
return 100 - this.vehicleSocDisplayWidth;
}
@@ -383,12 +395,15 @@ export default {
transform: translateX(-50%);
width: 4px;
opacity: 0;
- background-color: var(--evcc-dark-green);
- transition-property: opacity, left;
+ background-color: var(--evcc-gray);
+ transition-property: opacity, left, background-color;
transition-timing-function: linear;
transition-duration: var(--evcc-transition-fast);
}
.energy-limit-marker--active {
+ background-color: var(--evcc-dark-green);
+}
+.energy-limit-marker--visible {
opacity: 1;
}
diff --git a/core/loadpoint.go b/core/loadpoint.go
index 22c86964b..90045e6d3 100644
--- a/core/loadpoint.go
+++ b/core/loadpoint.go
@@ -1560,6 +1560,19 @@ func (lp *Loadpoint) Update(sitePower float64, autoCharge, batteryBuffered, batt
case lp.scalePhasesRequired():
err = lp.scalePhases(lp.ConfiguredPhases)
+ case lp.remoteControlled(loadpoint.RemoteHardDisable):
+ remoteDisabled = loadpoint.RemoteHardDisable
+ fallthrough
+
+ case mode == api.ModeOff:
+ err = lp.setLimit(0, true)
+
+ // minimum or target charging
+ case lp.minSocNotReached() || plannerActive:
+ err = lp.fastCharging()
+ lp.resetPhaseTimer()
+ lp.elapsePVTimer() // let PV mode disable immediately afterwards
+
case lp.limitEnergyReached():
lp.log.DEBUG.Printf("limitEnergy reached: %.0fkWh > %0.1fkWh", lp.getChargedEnergy()/1e3, lp.limitEnergy)
err = lp.disableUnlessClimater()
@@ -1568,23 +1581,10 @@ func (lp *Loadpoint) Update(sitePower float64, autoCharge, batteryBuffered, batt
lp.log.DEBUG.Printf("limitSoc reached: %.1f%% > %d%%", lp.vehicleSoc, lp.effectiveLimitSoc())
err = lp.disableUnlessClimater()
- case lp.remoteControlled(loadpoint.RemoteHardDisable):
- remoteDisabled = loadpoint.RemoteHardDisable
- fallthrough
-
- case mode == api.ModeOff:
- err = lp.setLimit(0, true)
-
- // immediate charging
+ // immediate charging- must be placed after limits are evaluated
case mode == api.ModeNow:
err = lp.fastCharging()
- // minimum or target charging
- case lp.minSocNotReached() || plannerActive:
- err = lp.fastCharging()
- lp.resetPhaseTimer()
- lp.elapsePVTimer() // let PV mode disable immediately afterwards
-
case mode == api.ModeMinPV || mode == api.ModePV:
// cheap tariff
if autoCharge && lp.EffectivePlanTime().IsZero() {
diff --git a/i18n/de.toml b/i18n/de.toml
index 41331f1c3..d12c24a57 100644
--- a/i18n/de.toml
+++ b/i18n/de.toml
@@ -247,7 +247,7 @@ descriptionEnergy = "Bis wann sollen {targetEnergy} ins Fahrzeug geladen sein?"
descriptionSoc = "Wann soll das Fahrzeug auf {targetSoc}% geladen sein?"
inactiveLabel = "Zielzeit"
onlyInPvMode = "Ladeplanung ist nur im PV-Modus aktiv."
-planDescription = "Gib eine Abfahrtszeit an, und evcc lädt dein Fahrzeug so kostengünstig und umweltfreundlich wie möglich."
+planDescription = "Gib eine Abfahrtszeit an, und evcc lädt das Fahrzeug so kostengünstig und umweltfreundlich wie möglich."
planDuration = "Ladedauer"
planPeriodLabel = "Zeitraum"
planPeriodValue = "{start} bis {end}"
@@ -256,7 +256,8 @@ priceLimit = "Preisgrenze von {price}"
remove = "Entfernen"
setPlan = "Ladeplan festlegen"
setTargetTime = "keine"
-targetIsAboveLimit = "Das Ladeziel {goal} liegt über dem konfigurierten Limit {limit}. Erhöhe das Limit, um das Ziel zu erreichen."
+targetIsAboveLimit = "Das eingestellte Ladelimit von {limit} wird in diesem Zeitraum ignoriert."
+targetIsAboveVehicleLimit = "Erhöhe das Fahrzeuglimit ({limit}), um das Ladeziel zu erreichen."
targetIsInThePast = "Wähle einen Zeitpunkt in der Zukunft, Marty."
targetIsTooFarInTheFuture = "Wir passen den Plan an, sobald wir mehr über die Zukunft wissen."
title = "Zielzeit"
diff --git a/i18n/en.toml b/i18n/en.toml
index 05d5b6132..0801e0242 100644
--- a/i18n/en.toml
+++ b/i18n/en.toml
@@ -248,7 +248,7 @@ descriptionEnergy = "Until when should {targetEnergy} be loaded into the vehicle
descriptionSoc = "When should the vehicle be charged to {targetSoc}%?"
inactiveLabel = "Target time"
onlyInPvMode = "Charging plan only works in solar mode."
-planDescription = "Enter your departure time, and evcc will charge your vehicle as cost-effectively or environmentally friendly as possible."
+planDescription = "Enter a departure time, and evcc will charge the vehicle as cost-effectively or environmentally friendly as possible."
planDuration = "Charging time"
planPeriodLabel = "Period"
planPeriodValue = "{start} to {end}"
@@ -257,7 +257,8 @@ priceLimit = "price limit of {price}"
remove = "Remove"
setPlan = "Set a charging plan"
setTargetTime = "none"
-targetIsAboveLimit = "Charging goal {goal} is above the configured limit {limit}. You must increase the limit to reach the goal."
+targetIsAboveLimit = "The configured charging limit of {limit} will be ignored during this period."
+targetIsAboveVehicleLimit = "Increase vehicle limit ({limit}) to reach the charging goal."
targetIsInThePast = "Pick a time in the future, Marty."
targetIsTooFarInTheFuture = "We will adjust the plan as soon as we know more about the future."
title = "Target Time"