Charging plan: show strategy settings without dynamic tariff (#33168)

This commit is contained in:
andig 2026-08-27 15:08:48 +02:00 • committed by GitHub
parent f693454502
commit 0d0815963c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 71 additions and 77 deletions

View file

@ -1,13 +1,7 @@
<template> <template>
<div data-testid="plan-strategy" class="mb-5 mb-lg-4"> <div data-testid="plan-strategy" class="mb-5 mb-lg-4">
<div :class="{ 'mb-2': open }"> <div :class="{ 'mb-2': open }">
<div v-if="disabled">
<span class="fw-bold evcc-gray">{{ $t("main.chargingPlan.strategy.label") }}:</span>
{{ " " }}
<span class="small">{{ summary }}</span>
</div>
<button <button
v-else
type="button" type="button"
class="btn btn-link btn-sm text-gray p-0 border-0 d-flex align-items-center text-start" class="btn btn-link btn-sm text-gray p-0 border-0 d-flex align-items-center text-start"
:class="{ 'text-primary': open }" :class="{ 'text-primary': open }"
@ -22,13 +16,7 @@
</div> </div>
<div class="collapsible-wrapper" :class="{ open }"> <div class="collapsible-wrapper" :class="{ open }">
<div class="collapsible-content ring-space"> <div class="collapsible-content ring-space">
<div v-if="disabled" class="row mb-4"> <div class="row">
<div class="small text-muted">
<strong class="text-primary">{{ $t("general.note") }}</strong>
{{ $t("main.chargingPlan.strategyDisabledDescription") }}
</div>
</div>
<div v-else class="row">
<div class="col-12 col-lg-6 mb-3"> <div class="col-12 col-lg-6 mb-3">
<div class="row"> <div class="row">
<label <label
@ -39,6 +27,15 @@
</label> </label>
<div class="col-7 col-lg-12"> <div class="col-7 col-lg-12">
<select <select
v-if="disabled"
:id="formId('continuous')"
class="form-select"
disabled
>
<option>{{ $t("general.none") }}</option>
</select>
<select
v-else
:id="formId('continuous')" :id="formId('continuous')"
v-model="localContinuous" v-model="localContinuous"
class="form-select" class="form-select"
@ -67,6 +64,17 @@
</label> </label>
<div class="col-7 col-lg-12"> <div class="col-7 col-lg-12">
<select <select
v-if="disabled"
:id="formId('precondition')"
class="form-select"
disabled
>
<option>
{{ $t("main.chargingPlan.precondition.optionAll") }}
</option>
</select>
<select
v-else
:id="formId('precondition')" :id="formId('precondition')"
v-model="localPrecondition" v-model="localPrecondition"
class="form-select" class="form-select"
@ -86,7 +94,11 @@
</div> </div>
</div> </div>
<div class="small text-muted mt-1"> <div class="small text-muted mt-1">
{{ $t("main.chargingPlan.precondition.description") }} {{
$t(
`main.chargingPlan.precondition.${disabled ? "disabledDescription" : "description"}`
)
}}
</div> </div>
</div> </div>
</div> </div>
@ -101,6 +113,13 @@ import formatter from "@/mixins/formatter";
import { SMART_COST_TYPE, type PlanStrategy } from "@/types/evcc"; import { SMART_COST_TYPE, type PlanStrategy } from "@/types/evcc";
import DropdownIcon from "../MaterialIcon/Dropdown.vue"; import DropdownIcon from "../MaterialIcon/Dropdown.vue";
const HOUR = 60 * 60;
const QUARTER_HOUR = 0.25 * HOUR;
const HALF_HOUR = 0.5 * HOUR;
const ONE_HOUR = 1 * HOUR;
const TWO_HOURS = 2 * HOUR;
const EVERYTHING = 7 * 24 * HOUR;
export default defineComponent({ export default defineComponent({
name: "ChargingPlanStrategy", name: "ChargingPlanStrategy",
components: { DropdownIcon }, components: { DropdownIcon },
@ -109,7 +128,6 @@ export default defineComponent({
id: [String, Number], id: [String, Number],
precondition: { type: Number, default: 0 }, precondition: { type: Number, default: 0 },
continuous: { type: Boolean, default: false }, continuous: { type: Boolean, default: false },
disabled: Boolean,
smartCostType: String as PropType<SMART_COST_TYPE>, smartCostType: String as PropType<SMART_COST_TYPE>,
}, },
emits: ["update"], emits: ["update"],
@ -121,6 +139,10 @@ export default defineComponent({
}; };
}, },
computed: { computed: {
disabled(): boolean {
// options only make sense with a dynamic planner tariff
return !this.smartCostType || this.smartCostType === SMART_COST_TYPE.PRICE_STATIC;
},
isCo2(): boolean { isCo2(): boolean {
return this.smartCostType === SMART_COST_TYPE.CO2; return this.smartCostType === SMART_COST_TYPE.CO2;
}, },
@ -129,14 +151,16 @@ export default defineComponent({
}, },
summary(): string { summary(): string {
if (this.disabled) { if (this.disabled) {
return this.$t("main.chargingPlan.strategyDisabledDescription"); return this.$t("main.chargingPlan.precondition.summaryAll");
} }
const parts = [ const parts = [
this.$t( this.$t(
`main.chargingPlan.optimization.${this.continuous ? "continuous" : this.cheapestKey}` `main.chargingPlan.optimization.${this.continuous ? "continuous" : this.cheapestKey}`
), ),
]; ];
if (this.precondition) { if (this.precondition >= EVERYTHING) {
parts.push(this.$t("main.chargingPlan.precondition.summaryAll"));
} else if (this.precondition) {
parts.push( parts.push(
this.$t("main.chargingPlan.precondition.summary", { this.$t("main.chargingPlan.precondition.summary", {
precondition: this.fmtDurationLong(this.precondition), precondition: this.fmtDurationLong(this.precondition),
@ -146,6 +170,9 @@ export default defineComponent({
return parts.join(", "); return parts.join(", ");
}, },
optimizationDescription(): string { optimizationDescription(): string {
if (this.disabled) {
return this.$t("main.chargingPlan.optimization.disabledDescription");
}
const variant = this.localContinuous const variant = this.localContinuous
? this.isCo2 ? this.isCo2
? "continuousCo2" ? "continuousCo2"
@ -154,13 +181,6 @@ export default defineComponent({
return this.$t(`main.chargingPlan.optimization.${variant}Description`); return this.$t(`main.chargingPlan.optimization.${variant}Description`);
}, },
preconditionOptions() { preconditionOptions() {
const HOUR = 60 * 60;
const QUARTER_HOUR = 0.25 * HOUR;
const HALF_HOUR = 0.5 * HOUR;
const ONE_HOUR = 1 * HOUR;
const TWO_HOURS = 2 * HOUR;
const EVERYTHING = 7 * 24 * HOUR;
const options = [QUARTER_HOUR, HALF_HOUR, ONE_HOUR, TWO_HOURS, EVERYTHING]; const options = [QUARTER_HOUR, HALF_HOUR, ONE_HOUR, TWO_HOURS, EVERYTHING];
// support custom values (via API) // support custom values (via API)

View file

@ -36,7 +36,6 @@
:id="id" :id="id"
:precondition="effectivePlanStrategy?.precondition" :precondition="effectivePlanStrategy?.precondition"
:continuous="effectivePlanStrategy?.continuous" :continuous="effectivePlanStrategy?.continuous"
:disabled="strategyDisabled"
:smart-cost-type="smartCostType" :smart-cost-type="smartCostType"
@update="updatePlanStrategy" @update="updatePlanStrategy"
/> />
@ -162,13 +161,6 @@ export default defineComponent({
nextPlanTitle(): string { nextPlanTitle(): string {
return `${this.$t("main.targetCharge.nextPlan")}: #${this.nextPlanId}`; return `${this.$t("main.targetCharge.nextPlan")}: #${this.nextPlanId}`;
}, },
strategyDisabled(): boolean {
// options only make sense if there are variable prices
// TODO: make this logic more robust (api fails, missing data)
const slots = this.forecast?.planner || [];
const values = new Set(slots.map(({ value }) => value));
return values.size <= 1;
},
}, },
watch: { watch: {
effectivePlanTime(newValue: string) { effectivePlanTime(newValue: string) {

View file

@ -1,18 +1,18 @@
<template> <template>
<p class="mb-3 root" data-testid="plan-warnings"> <p class="mb-0 root" data-testid="plan-warnings">
<span v-if="targetIsAboveLimit" class="d-block evcc-gray mb-1"> <span v-if="targetIsAboveLimit" class="d-block evcc-gray mt-1">
{{ $t("main.targetCharge.targetIsAboveLimit", { limit: limitFmt }) }} {{ $t("main.targetCharge.targetIsAboveLimit", { limit: limitFmt }) }}
</span> </span>
<span v-if="mode && ['off', 'now'].includes(mode)" class="d-block text-warning mb-1"> <span v-if="mode && ['off', 'now'].includes(mode)" class="d-block text-warning mt-1">
{{ $t("main.targetCharge.onlyInPvMode") }} {{ $t("main.targetCharge.onlyInPvMode") }}
</span> </span>
<span v-if="timeTooFarInTheFuture" class="d-block evcc-gray mb-1"> <span v-if="timeTooFarInTheFuture" class="d-block evcc-gray mt-1">
{{ $t("main.targetCharge.targetIsTooFarInTheFuture") }} {{ $t("main.targetCharge.targetIsTooFarInTheFuture") }}
</span> </span>
<span v-if="notReachableInTime" class="d-block text-warning mb-1"> <span v-if="notReachableInTime" class="d-block text-warning mt-1">
{{ $t("main.targetCharge.notReachableInTime", { overrun: overrunFmt }) }} {{ $t("main.targetCharge.notReachableInTime", { overrun: overrunFmt }) }}
</span> </span>
<span v-if="targetIsAboveVehicleLimit" class="d-block text-warning mb-1"> <span v-if="targetIsAboveVehicleLimit" class="d-block text-warning mt-1">
{{ $t("main.targetCharge.targetIsAboveVehicleLimit") }} {{ $t("main.targetCharge.targetIsAboveVehicleLimit") }}
</span> </span>
</p> </p>

View file

@ -535,6 +535,7 @@ export enum SMART_COST_TYPE {
CO2 = "co2", CO2 = "co2",
PRICE_DYNAMIC = "pricedynamic", PRICE_DYNAMIC = "pricedynamic",
PRICE_FORECAST = "priceforecast", PRICE_FORECAST = "priceforecast",
PRICE_STATIC = "pricestatic",
} }
export enum LENGTH_UNIT { export enum LENGTH_UNIT {

View file

@ -855,7 +855,6 @@
"repeating": "повтарящ се", "repeating": "повтарящ се",
"repeatingPlans": "Повтарящи се планове", "repeatingPlans": "Повтарящи се планове",
"selectAll": "Изберете всички", "selectAll": "Изберете всички",
"strategyDisabledDescription": "Зареждането започва възможно най-късно, за да приключи точно навреме за тръгване. С динамични цени на електроенергията или тарифа за CO₂, тук са налице повече опции.",
"time": "Време", "time": "Време",
"title": "План", "title": "План",
"unsavedChanges": "Има незаписани промени. Приложи сега?", "unsavedChanges": "Има незаписани промени. Приложи сега?",

View file

@ -1343,7 +1343,6 @@
"strategy": { "strategy": {
"label": "Estratègia" "label": "Estratègia"
}, },
"strategyDisabledDescription": "La càrrega comença tan tard com sigui possible per a acabar just a temps de la sortida. Amb preus dinàmics de xarxa o tarifa de CO₂, hi ha més opcions disponibles.",
"time": "Hora", "time": "Hora",
"title": "Pla", "title": "Pla",
"unsavedChanges": "Hi ha canvis sense aplicar. Voleu aplicar-los ara?", "unsavedChanges": "Hi ha canvis sense aplicar. Voleu aplicar-los ara?",

View file

@ -1343,7 +1343,6 @@
"strategy": { "strategy": {
"label": "Strategie nabíjení" "label": "Strategie nabíjení"
}, },
"strategyDisabledDescription": "Nabíjení začíná co nejpozději, aby bylo dokončeno právě včas před odjezdem. S dynamickými cenami elektřiny nebo tarifem CO₂ je zde k dispozici více možností.",
"time": "Čas", "time": "Čas",
"title": "Plán", "title": "Plán",
"unsavedChanges": "Jsou zde neuložené změny. Použít nyní?", "unsavedChanges": "Jsou zde neuložené změny. Použít nyní?",

View file

@ -1328,7 +1328,6 @@
"strategy": { "strategy": {
"label": "Strategi" "label": "Strategi"
}, },
"strategyDisabledDescription": "Opladningen påbegyndes så sent som muligt og afsluttes præcis ved afgang. Med dynamiske elpriser eller CO₂-tariffer er der flere valgmuligheder.",
"time": "Tid", "time": "Tid",
"title": "Plan", "title": "Plan",
"unsavedChanges": "Der er ændringer som ikke er gemt. Skal de benyttes nu?", "unsavedChanges": "Der er ændringer som ikke er gemt. Skal de benyttes nu?",

View file

@ -1326,15 +1326,18 @@
"continuous": "kontinuierlich", "continuous": "kontinuierlich",
"continuousCo2Description": "Wählt die sauberste unterbrechungsfreie Folge von Zeitfenstern.", "continuousCo2Description": "Wählt die sauberste unterbrechungsfreie Folge von Zeitfenstern.",
"continuousPriceDescription": "Wählt die günstigste unterbrechungsfreie Folge von Zeitfenstern.", "continuousPriceDescription": "Wählt die günstigste unterbrechungsfreie Folge von Zeitfenstern.",
"disabledDescription": "Benötigt einen dynamischen Tarif oder eine CO₂-Prognose.",
"label": "Optimierung" "label": "Optimierung"
}, },
"planNumber": "Plan {number}", "planNumber": "Plan {number}",
"precondition": { "precondition": {
"description": "Verlagert einen Teil des Ladens direkt vor die Abfahrt: warme Batterie, weniger Zeit mit hohem Ladestand.", "description": "Verlagert einen Teil des Ladens direkt vor die Abfahrt: warme Batterie, weniger Zeit mit hohem Ladestand.",
"disabledDescription": "Das gesamte Laden erfolgt direkt vor der Abfahrt.",
"label": "Spätes Laden", "label": "Spätes Laden",
"optionAll": "alles", "optionAll": "alles",
"optionNo": "nein", "optionNo": "nein",
"summary": "{precondition} vorher" "summary": "{precondition} vorher",
"summaryAll": "direkt vor der Abfahrt"
}, },
"remove": "Entfernen", "remove": "Entfernen",
"repeating": "wiederholend", "repeating": "wiederholend",
@ -1343,7 +1346,6 @@
"strategy": { "strategy": {
"label": "Strategie" "label": "Strategie"
}, },
"strategyDisabledDescription": "Das Laden startet so spät wie möglich und wird rechtzeitig zur Abfahrt abgeschlossen. Mit dynamischen Netzpreisen oder einem CO₂-Tarif stehen hier weitere Optionen zur Verfügung.",
"time": "Zeit", "time": "Zeit",
"title": "Plan", "title": "Plan",
"unsavedChanges": "Ungespeicherte Änderungen vorhanden. Jetzt anwenden?", "unsavedChanges": "Ungespeicherte Änderungen vorhanden. Jetzt anwenden?",

View file

@ -855,7 +855,6 @@
"repeating": "επαναλαμβανόμενο", "repeating": "επαναλαμβανόμενο",
"repeatingPlans": "Επαναλαμβανόμενα προγράμματα", "repeatingPlans": "Επαναλαμβανόμενα προγράμματα",
"selectAll": "Επιλογή όλων", "selectAll": "Επιλογή όλων",
"strategyDisabledDescription": "Η φόρτιση ξεκινά όσο το δυνατόν αργότερα, ώστε να ολοκληρωθεί ακριβώς πριν την αναχώρηση. Με τις δυναμικές τιμές δικτύου ή το τιμολόγιο CO₂, υπάρχουν περισσότερες επιλογές διαθέσιμες εδώ.",
"time": "Ώρα", "time": "Ώρα",
"title": "Πρόγραμμα", "title": "Πρόγραμμα",
"unsavedChanges": "Υπάρχουν μη αποθηκευμένες αλλαγές. Υποβολή τώρα;", "unsavedChanges": "Υπάρχουν μη αποθηκευμένες αλλαγές. Υποβολή τώρα;",

View file

@ -1326,15 +1326,18 @@
"continuous": "continuous", "continuous": "continuous",
"continuousCo2Description": "Selects the cleanest uninterrupted series of slots.", "continuousCo2Description": "Selects the cleanest uninterrupted series of slots.",
"continuousPriceDescription": "Selects the cheapest uninterrupted series of slots.", "continuousPriceDescription": "Selects the cheapest uninterrupted series of slots.",
"disabledDescription": "Requires a dynamic tariff or CO₂ forecast.",
"label": "Optimization" "label": "Optimization"
}, },
"planNumber": "Plan {number}", "planNumber": "Plan {number}",
"precondition": { "precondition": {
"description": "Moves part of the charging right before departure: warm battery, less time at high charge level.", "description": "Moves part of the charging right before departure: warm battery, less time at high charge level.",
"disabledDescription": "All charging happens right before departure.",
"label": "Late Charging", "label": "Late Charging",
"optionAll": "everything", "optionAll": "everything",
"optionNo": "no", "optionNo": "no",
"summary": "{precondition} before" "summary": "{precondition} before",
"summaryAll": "right before departure"
}, },
"remove": "Remove", "remove": "Remove",
"repeating": "repeating", "repeating": "repeating",
@ -1343,7 +1346,6 @@
"strategy": { "strategy": {
"label": "Strategy" "label": "Strategy"
}, },
"strategyDisabledDescription": "Charging starts as late as possible to finish just in time for departure. With dynamic grid prices or CO₂ tariff, more options are available here.",
"time": "Time", "time": "Time",
"title": "Plan", "title": "Plan",
"unsavedChanges": "There are unsaved changes. Apply now?", "unsavedChanges": "There are unsaved changes. Apply now?",

View file

@ -986,7 +986,6 @@
"repeating": "repitiendo", "repeating": "repitiendo",
"repeatingPlans": "Planes recurrentes", "repeatingPlans": "Planes recurrentes",
"selectAll": "Seleccionar todo", "selectAll": "Seleccionar todo",
"strategyDisabledDescription": "La recarga comienza lo más tarde posible para terminar justo a tiempo para la salida. Con los precios dinámicos de la red o la tarifa de CO₂, hay más opciones disponibles aquí.",
"time": "Tiempo", "time": "Tiempo",
"title": "Plan", "title": "Plan",
"unsavedChanges": "Hay cambios sin guardar. ¿Aplicar ahora?", "unsavedChanges": "Hay cambios sin guardar. ¿Aplicar ahora?",

View file

@ -1328,7 +1328,6 @@
"strategy": { "strategy": {
"label": "Strategia" "label": "Strategia"
}, },
"strategyDisabledDescription": "Lataus aloitetaan mahdollisimman myöhään, jotta se valmistuu juuri ennen lähtöä. Jos dynaaminen sähköverkkohinnoittelu tai CO₂-tariffit ovat asetetut, on tässä tarjolla enemmän valintoja.",
"time": "Aika", "time": "Aika",
"title": "Suunnitelma", "title": "Suunnitelma",
"unsavedChanges": "Tallentamattomia muutoksia. Asetetaanko nyt?", "unsavedChanges": "Tallentamattomia muutoksia. Asetetaanko nyt?",

View file

@ -1320,7 +1320,6 @@
"strategy": { "strategy": {
"label": "Stratégie" "label": "Stratégie"
}, },
"strategyDisabledDescription": "La charge commence le plus tard possible afin de se terminer juste à temps pour le départ. Avec les prix dynamiques du réseau ou la tarification CO₂, davantage d'options sont disponibles ici.",
"time": "Heure", "time": "Heure",
"title": "Planification", "title": "Planification",
"unsavedChanges": "Il y a des modifications non sauvegardées. Appliquer ?", "unsavedChanges": "Il y a des modifications non sauvegardées. Appliquer ?",

View file

@ -855,7 +855,6 @@
"repeating": "ponavljanje", "repeating": "ponavljanje",
"repeatingPlans": "Ponavljajući planovi", "repeatingPlans": "Ponavljajući planovi",
"selectAll": "Odaberi sve", "selectAll": "Odaberi sve",
"strategyDisabledDescription": "Punjenje počinje što kasnije kako bi se završilo upravo na vrijeme za polazak. Uz dinamične cijene mreže ili CO₂ tarifu ovdje su dostupne dodatne opcije.",
"time": "Vrijeme", "time": "Vrijeme",
"title": "Plan", "title": "Plan",
"unsavedChanges": "Postoje promjene koje nisu spremljene. Spremiti odmah?", "unsavedChanges": "Postoje promjene koje nisu spremljene. Spremiti odmah?",

View file

@ -866,7 +866,6 @@
"repeating": "ismétlődő", "repeating": "ismétlődő",
"repeatingPlans": "Ismétlődő tervek", "repeatingPlans": "Ismétlődő tervek",
"selectAll": "Összes kiválasztása", "selectAll": "Összes kiválasztása",
"strategyDisabledDescription": "A töltés a lehető legkésőbb kezdődik, hogy pontosan az indulás előtt befejeződjön. Dinamikus hálózati árak vagy CO₂-tarifa esetén itt több lehetőség áll rendelkezésre.",
"time": "Idő", "time": "Idő",
"title": "Terv", "title": "Terv",
"unsavedChanges": "Vannak nem mentett módosítások. Alkalmazza most?", "unsavedChanges": "Vannak nem mentett módosítások. Alkalmazza most?",

View file

@ -1222,7 +1222,6 @@
"repeating": "ricorrente", "repeating": "ricorrente",
"repeatingPlans": "Piani ricorrenti", "repeatingPlans": "Piani ricorrenti",
"selectAll": "Seleziona tutti", "selectAll": "Seleziona tutti",
"strategyDisabledDescription": "La ricarica inizia il più tardi possibile per terminare appena in tempo per la partenza. Con i prezzi dinamici della rete elettrica o la tariffa CO₂, sono disponibili ulteriori opzioni.",
"time": "Ora", "time": "Ora",
"title": "Piano", "title": "Piano",
"unsavedChanges": "Ci sono modifiche non salvate. Vuoi salvarle adesso?", "unsavedChanges": "Ci sono modifiche non salvate. Vuoi salvarle adesso?",

View file

@ -1109,7 +1109,6 @@
"repeating": "繰り返し", "repeating": "繰り返し",
"repeatingPlans": "繰り返しプラン", "repeatingPlans": "繰り返しプラン",
"selectAll": "すべて選択", "selectAll": "すべて選択",
"strategyDisabledDescription": "出発時刻に間に合うよう、できるだけ遅い時間帯に充電を開始します。市場連動型の料金プランやCO₂データが設定されている場合、さらに高度なオプションが利用可能になります。",
"time": "時間", "time": "時間",
"title": "プラン", "title": "プラン",
"unsavedChanges": "保存されていない変更があります。今すぐ適用しますか?", "unsavedChanges": "保存されていない変更があります。今すぐ適用しますか?",

View file

@ -1320,7 +1320,6 @@
"strategy": { "strategy": {
"label": "Strategie" "label": "Strategie"
}, },
"strategyDisabledDescription": "D'Laden fänkt sou spéit wéi méiglech un, fir grad rechtzäiteg virum Depart ofzeschléissen. Mat dynamesche Netzpräisser oder engem CO₂-Tarif stinn hei nach méi Optiounen zur Verfügung.",
"time": "Zäit", "time": "Zäit",
"title": "Planifikatioun", "title": "Planifikatioun",
"unsavedChanges": "Net gespäichert Ännerungen leie vir. Elo uwennen?", "unsavedChanges": "Net gespäichert Ännerungen leie vir. Elo uwennen?",

View file

@ -1343,7 +1343,6 @@
"strategy": { "strategy": {
"label": "Strategija" "label": "Strategija"
}, },
"strategyDisabledDescription": "Įkrovimas pradedamas kuo vėliau, kad būtų baigtas prieš pat išvykimą. Jei naudojate 15 minučių biržos planą (arba CO₂ tarifą), čia galite rinktis iš daugiau variantų.",
"time": "Laikas", "time": "Laikas",
"title": "Planas", "title": "Planas",
"unsavedChanges": "Yra neišsaugotų pakeitimų. Išsaugoti dabar?", "unsavedChanges": "Yra neišsaugotų pakeitimų. Išsaugoti dabar?",

View file

@ -1343,7 +1343,6 @@
"strategy": { "strategy": {
"label": "Stratēģija" "label": "Stratēģija"
}, },
"strategyDisabledDescription": "Uzlāde sākas cik vien vēlu iespējams, lai pabeigtu tieši pirms izbraukšanas. Ar dinamiskiem tīkla tarifiem vai CO₂ tarifu šeit ir pieejamas papildus iespējas.",
"time": "Laiks", "time": "Laiks",
"title": "Plāns", "title": "Plāns",
"unsavedChanges": "Ir nesaglabātas izmaiņas. Piemērot tagad?", "unsavedChanges": "Ir nesaglabātas izmaiņas. Piemērot tagad?",

View file

@ -1331,7 +1331,6 @@
"strategy": { "strategy": {
"label": "Strategie" "label": "Strategie"
}, },
"strategyDisabledDescription": "Het opladen begint zo laat mogelijk, zodat het precies op tijd voor vertrek klaar is. Met dynamische netprijzen of een CO₂-tarief zijn er meer mogelijkheden.",
"time": "Tijd", "time": "Tijd",
"title": "Plan", "title": "Plan",
"unsavedChanges": "Wijzigingen nog niet opgeslagen. Nu toepassen?", "unsavedChanges": "Wijzigingen nog niet opgeslagen. Nu toepassen?",

View file

@ -904,7 +904,6 @@
"repeating": "gjentagende", "repeating": "gjentagende",
"repeatingPlans": "Gjentatte planer", "repeatingPlans": "Gjentatte planer",
"selectAll": "Velg alt", "selectAll": "Velg alt",
"strategyDisabledDescription": "Ladingen starter så sent som mulig for å være ferdig akkurat i tide til avreise. Med dynamiske nettpriser eller CO₂-tariff er det flere alternativer tilgjengelig her.",
"time": "Tid", "time": "Tid",
"title": "Plan", "title": "Plan",
"unsavedChanges": "Det er ubehandlede endringer. Vil du bruke dem nå?", "unsavedChanges": "Det er ubehandlede endringer. Vil du bruke dem nå?",

View file

@ -1138,7 +1138,6 @@
"repeating": "powtórzenie", "repeating": "powtórzenie",
"repeatingPlans": "Powtarzające się plany", "repeatingPlans": "Powtarzające się plany",
"selectAll": "Wybierz wszystko", "selectAll": "Wybierz wszystko",
"strategyDisabledDescription": "Ładowanie rozpoczyna się jak najpóźniej, aby zakończyć się tuż przed wyjazdem. Dzięki dynamicznym cenom energii elektrycznej lub taryfie CO₂ dostępnych jest więcej opcji.",
"time": "Czas", "time": "Czas",
"title": "Plan", "title": "Plan",
"unsavedChanges": "Są niezapisane zmiany. Zastosować teraz?", "unsavedChanges": "Są niezapisane zmiany. Zastosować teraz?",

View file

@ -1320,7 +1320,6 @@
"strategy": { "strategy": {
"label": "Estratégia" "label": "Estratégia"
}, },
"strategyDisabledDescription": "O carregamento começa o mais tarde possível para terminar a tempo da partida. Com preços dinâmicos da rede ou tarifa de CO₂, há mais opções disponíveis aqui.",
"time": "Hora", "time": "Hora",
"title": "Plano", "title": "Plano",
"unsavedChanges": "Há alterações não salvas. Aplicar agora?", "unsavedChanges": "Há alterações não salvas. Aplicar agora?",

View file

@ -1019,7 +1019,6 @@
"repeating": "repetând", "repeating": "repetând",
"repeatingPlans": "Planuri repetitive", "repeatingPlans": "Planuri repetitive",
"selectAll": "Selectați tot", "selectAll": "Selectați tot",
"strategyDisabledDescription": "Încărcarea începe cât mai târziu posibil, pentru a se termina chiar înainte de plecare. Cu prețuri dinamice la rețea sau tariful CO₂, aici sunt disponibile mai multe opțiuni.",
"time": "Timp", "time": "Timp",
"title": "Plan", "title": "Plan",
"unsavedChanges": "Există modificări nesalvate. Doriți să le aplicați acum?", "unsavedChanges": "Există modificări nesalvate. Doriți să le aplicați acum?",

View file

@ -1325,7 +1325,6 @@
"strategy": { "strategy": {
"label": "Стратегия" "label": "Стратегия"
}, },
"strategyDisabledDescription": "Зарядка начинается как можно позже, чтобы закончиться как раз к моменту отправления. С динамическими ценами на электроэнергию или тарифом на выбросы CO₂ здесь доступно больше вариантов.",
"time": "Время", "time": "Время",
"title": "План", "title": "План",
"unsavedChanges": "Есть несохраненные изменения. Применить сейчас?", "unsavedChanges": "Есть несохраненные изменения. Применить сейчас?",

View file

@ -1328,7 +1328,6 @@
"strategy": { "strategy": {
"label": "Stratégia" "label": "Stratégia"
}, },
"strategyDisabledDescription": "Nabíjanie začína čo najneskôr, aby sa skončilo presne včas pred odchodom. S dynamickými sieťovými cenami alebo tarifom CO₂ je tu viac možností k dispozícii.",
"time": "Čas", "time": "Čas",
"title": "Plán", "title": "Plán",
"unsavedChanges": "Existujú neuložené zmeny. Uložiť teraz?", "unsavedChanges": "Existujú neuložené zmeny. Uložiť teraz?",

View file

@ -872,7 +872,6 @@
"repeating": "ponavljajoči", "repeating": "ponavljajoči",
"repeatingPlans": "Ponavljajoči načrti", "repeatingPlans": "Ponavljajoči načrti",
"selectAll": "Izberi vse", "selectAll": "Izberi vse",
"strategyDisabledDescription": "Polnjenje se začne čim pozneje, da se konča ravno pravočasno za odhod. Z dinamičnimi cenami omrežja ali tarifo CO₂ je na voljo več možnosti.",
"time": "Čas", "time": "Čas",
"title": "Načrt", "title": "Načrt",
"unsavedChanges": "Obstajajo neshranjene spremembe. Želite uporabiti zdaj?", "unsavedChanges": "Obstajajo neshranjene spremembe. Želite uporabiti zdaj?",

View file

@ -1342,7 +1342,6 @@
"strategy": { "strategy": {
"label": "Strategi" "label": "Strategi"
}, },
"strategyDisabledDescription": "Laddningen startar så sent som möjligt för att avslutas precis i tid före avfärd. Med dynamiska elpriser eller CO₂-avgifter finns fler möjligheter här.",
"time": "Tid", "time": "Tid",
"title": "Plan", "title": "Plan",
"unsavedChanges": "Det finns ej sparade ändringar. Spara nu?", "unsavedChanges": "Det finns ej sparade ändringar. Spara nu?",

View file

@ -1195,7 +1195,6 @@
"repeating": "மறுநிகழ்தல்", "repeating": "மறுநிகழ்தல்",
"repeatingPlans": "மறுநிகழ்வு திட்டங்கள்", "repeatingPlans": "மறுநிகழ்வு திட்டங்கள்",
"selectAll": "அனைத்தையும் தேர்ந்தெடு", "selectAll": "அனைத்தையும் தேர்ந்தெடு",
"strategyDisabledDescription": "புறப்படும் நேரத்தில் முடிவதற்காக சார்சிங் முடிந்தவரை தாமதமாகத் தொடங்குகிறது. மாறும் கிரிட் விலைகள் அல்லது CO₂ கட்டணத்துடன், கூடுதல் விருப்பங்கள் இங்கே கிடைக்கின்றன.",
"time": "நேரம்", "time": "நேரம்",
"title": "திட்டம்", "title": "திட்டம்",
"unsavedChanges": "There அரே unsaved changes. இடு now?", "unsavedChanges": "There அரே unsaved changes. இடு now?",

View file

@ -1162,7 +1162,6 @@
"repeating": "“tekrarlanan”", "repeating": "“tekrarlanan”",
"repeatingPlans": "“Tekrarlanan planlar”", "repeatingPlans": "“Tekrarlanan planlar”",
"selectAll": "“Tümünü seç”", "selectAll": "“Tümünü seç”",
"strategyDisabledDescription": "Şarj işlemi, kalkış saatine tam zamanında bitmek üzere mümkün olduğunca geç başlar. Dinamik şebeke fiyatları veya CO₂ tarifesi ile burada daha fazla seçenek mevcuttur.",
"time": "Zaman", "time": "Zaman",
"title": "Plan", "title": "Plan",
"unsavedChanges": "Kaydedilmemiş değişiklikler var. Şimdi uygulansın mı?", "unsavedChanges": "Kaydedilmemiş değişiklikler var. Şimdi uygulansın mı?",

View file

@ -857,7 +857,6 @@
"repeating": "повторення", "repeating": "повторення",
"repeatingPlans": "Повторювані плани", "repeatingPlans": "Повторювані плани",
"selectAll": "Вибрати все", "selectAll": "Вибрати все",
"strategyDisabledDescription": "Зарядка починається якомога пізніше, щоб завершитися якраз вчасно до відправлення. Завдяки динамічним цінам мережі або тарифу на викиди CO₂ тут доступні додаткові опції.",
"time": "Час", "time": "Час",
"title": "План", "title": "План",
"unsavedChanges": "Є незбережені зміни. Застосувати зараз?", "unsavedChanges": "Є незбережені зміни. Застосувати зараз?",

View file

@ -4517,7 +4517,8 @@
"enum": [ "enum": [
"co2", "co2",
"pricedynamic", "pricedynamic",
"priceforecast" "priceforecast",
"pricestatic"
] ]
}, },
"DeviceColorEntry": { "DeviceColorEntry": {

View file

@ -1636,6 +1636,7 @@ components:
- co2 - co2
- pricedynamic - pricedynamic
- priceforecast - priceforecast
- pricestatic
SolarDetails: SolarDetails:
description: Solar production forecast. description: Solar production forecast.
type: object type: object

View file

@ -687,9 +687,8 @@ test.describe("repeating", async () => {
}); });
}); });
// add test for precondition, start with basic.evcc.yaml and verify that precondition toggle element is not visible. make dedicated describe block
test.describe("plan strategy", async () => { test.describe("plan strategy", async () => {
test("only if dynamic tariff exists", async ({ page }) => { test("no dynamic tariff: options disabled", async ({ page }) => {
await restart(CONFIG_NO_TARIFF); await restart(CONFIG_NO_TARIFF);
await page.goto("/"); await page.goto("/");
const lp1 = await page.getByTestId("loadpoint").first(); const lp1 = await page.getByTestId("loadpoint").first();
@ -697,11 +696,14 @@ test.describe("plan strategy", async () => {
const modal = page.getByTestId("charging-plan-modal"); const modal = page.getByTestId("charging-plan-modal");
await expect(modal.getByTestId("static-plan-active")).toBeVisible(); await expect(modal.getByTestId("static-plan-active")).toBeVisible();
// Strategy line shows informational note only, not clickable const strategy = modal.getByTestId("plan-strategy");
await expect(modal.getByTestId("plan-strategy")).toContainText("just in time for departure"); await expect(strategy).toContainText("right before departure");
await expect(modal.getByTestId("plan-strategy").getByRole("button")).toHaveCount(0); await strategy.getByRole("button").click();
await expect(modal.getByLabel("Optimization")).not.toBeVisible(); await expect(modal.getByLabel("Optimization")).toBeDisabled();
await expect(modal.getByLabel("Late Charging")).not.toBeVisible(); await expect(modal.getByLabel("Optimization")).toHaveText("none");
await expect(modal.getByLabel("Late Charging")).toBeDisabled();
await expect(modal.getByLabel("Late Charging")).toHaveText("everything");
await expect(strategy).toContainText("Requires a dynamic tariff or CO₂ forecast.");
}); });
test("co2 tariff: cleanest instead of cheapest", async ({ page }) => { test("co2 tariff: cleanest instead of cheapest", async ({ page }) => {