-
-
Notifications
You must be signed in to change notification settings - Fork 663
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add schedule for planner #16091
Draft
Maschga
wants to merge
71
commits into
evcc-io:master
Choose a base branch
from
Maschga:add-schedule-for-planner
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,124
−135
Draft
Add schedule for planner #16091
Changes from 7 commits
Commits
Show all changes
71 commits
Select commit
Hold shift + click to select a range
eb0cb24
wip
Maschga a3a936c
weip
Maschga 6e952d9
wip
Maschga 6c6c591
running lint
Maschga 584b78a
wip
Maschga 618e8ca
remove comment
Maschga 762b84d
running lint
Maschga 3a89e00
replacing `repetitive` with `repeating`
Maschga 01ee9ca
better id-name
Maschga 561eb32
using unique id-name
Maschga 39c70e7
removing unnecessary parameter `socBasedPlanning`
Maschga 88a8ae9
Merge branch 'add-schedule-for-planner' of github.com:Maschga/evcc in…
Maschga 3ab074c
using `Intl` to get weekdays-translations
Maschga d308765
fix bug
Maschga b85c08d
add unit tests for `getShortenedWeekdaysLabel()`-method
Maschga 46b78f9
fix syntax bug
Maschga 1727afc
using `this.$i18n?.locale`
Maschga 685ef0b
rewriting tests for english weekdays
Maschga cf9dc23
Revert "rewriting tests for english weekdays"
Maschga b9f6d7e
fix test
Maschga e56ccbb
add newline at end of file
Maschga 1e12244
giving tags unique data-testids
Maschga a07f746
use hyphen only for more than 2 consecutive weekdays
Maschga 0645cc3
using en-dash and whitespaces
Maschga 6851ffe
add missing `-`
Maschga f079ea6
make data-testid unique
Maschga a0cb4d0
sort toml keys alphabetically
Maschga 0ad95a1
update event names
Maschga a280d31
run lint
Maschga 05e8e17
rename variables
Maschga 1c8172d
wip: implement backend
Maschga 568b2fb
remove unused import
Maschga 77fdab2
make key camelCase
Maschga 77a5fd6
run porcelain
Maschga b585907
Update mock.go
Maschga a3d652f
remove name `entry` + wip: implement backend
Maschga 51c1f87
change key to `repeatingPlans`
Maschga 2eb2417
synchronize data via websocket
Maschga e4411d6
recursion fix
naltatis 22cd019
use key `plans` instead of `repeatingPlans`
Maschga ce592b4
use `splice()` instead of `Object.assign` to avoid a reference
Maschga d0ae604
improve debug message
Maschga fa9d77f
remove comment
Maschga 0672649
remove unnecessary tag
Maschga 171bad6
add tag for space
Maschga 4c1f580
show apply-button on the right side
Maschga 319abef
run lint
Maschga a5aa0f8
lower first character of variable
Maschga d856c8f
WIP: show next plan
Maschga c3cd3aa
avoid circular import
Maschga fac2ab5
disable last remaining field
Maschga 6c22e58
correct name
Maschga fa77c94
handle utc
Maschga b5ef2c6
add onlyActivePlans-parameter
Maschga af83894
fix bugs
Maschga bfd883f
fix test
Maschga 6fabcf2
Merge remote-tracking branch 'upstream/master' into add-schedule-for-…
Maschga 3337d15
run porcelain
Maschga f4d343b
fix tests
Maschga aa4ddcf
run lint
Maschga ff42d34
fix bug
Maschga 77f9c79
rename method `vehiclePlanSoc()` to `nextVehiclePlanSoc()`
Maschga 841d080
rename `AdapterStruct` to `adapter`
Maschga 795f1a4
update the time format on language-change
Maschga e40f0fd
rename functions
Maschga fa76656
get next plan
Maschga fc673c2
refactor code
Maschga 0facffe
begin week with sunday
Maschga 4daa42c
add test for `getWeekdaysList()`
Maschga 27f403f
add `getNextLocalePlan()`
Maschga a147c1b
add preview for repeating plans
Maschga File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
assets/js/components/ChargingPlanRepetitiveSettingsEntries.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
<template> | ||
<div v-for="(plan, index) in plans" :key="index"> | ||
<ChargingPlanRepetitiveSettingsEntry | ||
class="mb-4" | ||
:id="index" | ||
v-bind="plan" | ||
:socBasedPlanning="socBasedPlanning" | ||
:rangePerSoc="rangePerSoc" | ||
@repetitive-plan-updated="updateRepetitivePlan" | ||
@repetitive-plan-removed="removeRepetitivePlan" | ||
/> | ||
</div> | ||
<div class="d-flex align-items-baseline"> | ||
<button | ||
type="button" | ||
class="d-flex btn btn-sm btn-outline-primary border-0 ps-0 align-items-baseline" | ||
data-testid="repetitive-plan-add" | ||
@click="addRepetitivePlan" | ||
> | ||
<shopicon-regular-plus size="s" class="flex-shrink-0 me-2"></shopicon-regular-plus> | ||
<p class="mb-0">{{ $t("main.chargingPlan.addRepetitivePlan") }}</p> | ||
</button> | ||
<button | ||
v-if="hasDataChanged" | ||
type="button" | ||
class="btn btn-sm btn-outline-primary ms-3 border-0 text-decoration-underline" | ||
data-testid="plan-apply" | ||
@click="update" | ||
> | ||
{{ $t("main.chargingPlan.update") }} | ||
</button> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
import api from "../api"; | ||
import ChargingPlanRepetitiveSettingsEntry from "./ChargingPlanRepetitiveSettingsEntry.vue"; | ||
const DEFAULT_WEEKDAYS = [0]; | ||
const DEFAULT_TARGET_TIME = "12:00"; | ||
const DEFAULT_TARGET_SOC = 80; | ||
export default { | ||
name: "ChargingPlanRepetitiveSettingsEntries", | ||
components: { | ||
ChargingPlanRepetitiveSettingsEntry, | ||
}, | ||
props: { | ||
id: Number, | ||
socBasedPlanning: Boolean, | ||
rangePerSoc: Number, | ||
}, | ||
data: function () { | ||
return { | ||
plans: [], | ||
initialPlans: [], | ||
}; | ||
}, | ||
mounted() { | ||
this.fetchRepetitivePlans(); | ||
}, | ||
computed: { | ||
hasDataChanged: function () { | ||
return JSON.stringify(this.initialPlans) !== JSON.stringify(this.plans); | ||
}, | ||
}, | ||
methods: { | ||
fetchRepetitivePlans: async function () { | ||
let response = await api.get(`/loadpoints/${this.id}/plan/repetitive`); | ||
this.plans = response.data.result; | ||
this.initialPlans = [...response.data.result]; // clone array | ||
}, | ||
addRepetitivePlan: function () { | ||
this.plans.push({ | ||
weekdays: DEFAULT_WEEKDAYS, | ||
time: DEFAULT_TARGET_TIME, | ||
soc: DEFAULT_TARGET_SOC, | ||
active: false, | ||
}); | ||
}, | ||
update: async function () { | ||
// TODO: update data | ||
this.initialPlans = [...this.plans]; | ||
}, | ||
updateRepetitivePlan: function (newData) { | ||
this.plans[newData.id] = { | ||
weekdays: newData.weekdays, | ||
time: newData.time, | ||
soc: newData.soc, | ||
active: newData.active, | ||
}; | ||
}, | ||
removeRepetitivePlan: function (index) { | ||
this.plans.splice(index, 1); | ||
}, | ||
}, | ||
}; | ||
</script> |
182 changes: 182 additions & 0 deletions
182
assets/js/components/ChargingPlanRepetitiveSettingsEntry.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
<template> | ||
<div> | ||
<div class="row d-none d-lg-flex mb-2"> | ||
<div class="col-6 col-lg-4"> | ||
<label :for="formId('day')"> | ||
{{ $t("main.chargingPlan.weekdays") }} | ||
</label> | ||
</div> | ||
<div class="col-6 col-lg-2"> | ||
<label :for="formId('time')"> | ||
{{ $t("main.chargingPlan.time") }} | ||
</label> | ||
</div> | ||
<div class="col-6 col-lg-3"> | ||
<label :for="formId('goal')"> | ||
{{ $t("main.chargingPlan.goal") }} | ||
</label> | ||
</div> | ||
<div class="col-6 col-lg-1"> | ||
<label :for="formId('active')"> {{ $t("main.chargingPlan.active") }} </label> | ||
</div> | ||
<div class="col-6 col-lg-1" /> | ||
</div> | ||
<div class="row"> | ||
<div class="col-5 d-lg-none col-form-label"> | ||
<label :for="formId('day')"> | ||
Maschga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{{ $t("main.chargingPlan.weekdays") }} | ||
</label> | ||
</div> | ||
<div class="col-7 col-lg-4 mb-2 mb-lg-0"> | ||
<MultiSelect | ||
id="chargingPlanWeekdaySelect" | ||
Maschga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
:value="selectedWeekdays" | ||
:options="dayOptions()" | ||
:selectAllLabel="$t('main.chargingPlan.selectAll')" | ||
@update:modelValue="changeSelectedWeekdays" | ||
> | ||
{{ weekdaysLabel }} | ||
</MultiSelect> | ||
</div> | ||
<div class="col-5 d-lg-none col-form-label"> | ||
<label :for="formId('day')"> | ||
{{ $t("main.chargingPlan.time") }} | ||
</label> | ||
</div> | ||
<div class="col-7 col-lg-2 mb-2 mb-lg-0"> | ||
<input | ||
:id="formId('time')" | ||
v-model="selectedTime" | ||
type="time" | ||
class="form-control mx-0" | ||
:step="60 * 5" | ||
data-testid="plan-time" | ||
required | ||
@change="update" | ||
/> | ||
</div> | ||
<div class="col-5 d-lg-none col-form-label"> | ||
<label :for="formId('goal')"> | ||
{{ $t("main.chargingPlan.goal") }} | ||
</label> | ||
</div> | ||
<div class="col-7 col-lg-3 mb-2 mb-lg-0"> | ||
<select | ||
:id="formId('goal')" | ||
v-model="selectedSoc" | ||
class="form-select mx-0" | ||
data-testid="plan-soc" | ||
@change="update" | ||
> | ||
<option v-for="opt in socOptions" :key="opt.value" :value="opt.value"> | ||
{{ opt.name }} | ||
</option> | ||
</select> | ||
</div> | ||
<div class="col-5 d-lg-none col-form-label"> | ||
<label :for="formId('active')"> | ||
{{ $t("main.chargingPlan.active") }} | ||
</label> | ||
</div> | ||
<div class="col-1 d-flex align-items-center justify-content-start"> | ||
<div class="form-check form-switch"> | ||
<input | ||
:id="formId('active')" | ||
class="form-check-input" | ||
v-model="selectedActive" | ||
type="checkbox" | ||
role="switch" | ||
data-testid="plan-active" | ||
:checked="selectedActive" | ||
@change="update" | ||
/> | ||
</div> | ||
</div> | ||
<div class="col-1 mx-auto d-flex align-items-center justify-content-start"> | ||
<button | ||
type="button" | ||
class="btn btn-sm btn-outline-secondary border-0" | ||
data-testid="plan-delete" | ||
@click="$emit('repetitive-plan-removed', id)" | ||
> | ||
<shopicon-regular-trash size="s" class="flex-shrink-0"></shopicon-regular-trash> | ||
</button> | ||
</div> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
import "@h2d2/shopicons/es/regular/trash"; | ||
import { distanceUnit } from "../units"; | ||
import MultiSelect from "./MultiSelect.vue"; | ||
|
||
import formatter from "../mixins/formatter"; | ||
|
||
export default { | ||
name: "ChargingPlanRepetitiveSettingsEntry", | ||
components: { | ||
MultiSelect, | ||
}, | ||
mixins: [formatter], | ||
props: { | ||
id: Number, | ||
weekdays: { type: Array, default: () => [] }, | ||
time: String, | ||
soc: Number, | ||
active: Boolean, | ||
socBasedPlanning: Boolean, | ||
Maschga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
rangePerSoc: Number, | ||
}, | ||
emits: ["repetitive-plan-updated", "repetitive-plan-removed"], | ||
data: function () { | ||
return { | ||
selectedWeekdays: this.weekdays, | ||
selectedTime: this.time, | ||
selectedSoc: this.soc, | ||
selectedActive: this.active, | ||
}; | ||
}, | ||
computed: { | ||
weekdaysLabel: function () { | ||
return this.getShortenedWeekdaysLabel(this.selectedWeekdays); | ||
}, | ||
socOptions: function () { | ||
// a list of entries from 5 to 100 with a step of 5 | ||
return Array.from(Array(20).keys()) | ||
.map((i) => 5 + i * 5) | ||
.map(this.socOption); | ||
}, | ||
}, | ||
methods: { | ||
changeSelectedWeekdays: function (weekdays) { | ||
this.selectedWeekdays = weekdays; | ||
this.update(); | ||
}, | ||
formId: function (name) { | ||
return `chargingplan-${this.id}-${name}`; | ||
}, | ||
socOption: function (value) { | ||
const name = this.fmtSocOption(value, this.rangePerSoc, distanceUnit()); | ||
return { value, name }; | ||
}, | ||
dayOptions: function () { | ||
return this.WEEKDAYS.map((weekday, index) => { | ||
return { | ||
name: this.$t(`main.chargingPlan.${weekday}`), | ||
value: index, | ||
}; | ||
}); | ||
}, | ||
update: function () { | ||
this.$emit("repetitive-plan-updated", { | ||
id: this.id, | ||
weekdays: this.selectedWeekdays, | ||
time: this.selectedTime, | ||
soc: this.selectedSoc, | ||
active: this.selectedActive, | ||
}); | ||
}, | ||
}, | ||
}; | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Die Komponente sollte sich nicht selbst die Daten holen. Das Muster was wir standardmäßig verwenden ist, dass wir Schreiboperationen via REST machen die aktualisierten Daten aber über Websockets gepusht werden. Die landen dann im globalen State. Da dieses Feature nur für Fahrzeuge mit SoC verfügbar sein wird sollten wir den Ladeplan auch direkt am Fahrzeug pushen. Siehe hier:
Damit ist er dann auch gleich über MQTT verfügbar und wir lösen das Problem Datensync zwischen Geräten. Also mehrere offene Browserfenster.
Aktuell veröffentlichen wir den "einmaligen Plan" auch noch nicht am Fahrzeug. Das müssen wir aber in diesem Zuge mit machen. Momentan kommen die aktuellen Plandaten die für die Statusanzeige in der UI und für das Ladeplanformular verwendet werden vom Ladepunkt. Mit der Einführung von mehreren Plänen würde ich am Ladepunkt nur noch die Daten des "als nächstes anstehenden Plans" veröffentlichen. Dass kann ein einmaliger sein, aber auch eine Ladung, die aufgrund einer Wiederholungsregel ansteht. Bislang mussten wir das nicht trennen. Jetzt ist das aber erforderlich.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beim Vehicle werden zwei Arrays mitgegeben:
plans
undrepeatingPlans
.Beim Loadpoint werden die
effectivePlanSoc
undeffectivePlanTime
-Felder mitgeschickt.Passt das so?