Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8a0e113
Config UI: add tariffs
naltatis Jan 14, 2026
2e7de06
fixed templates; working persistance; simplify refs; zones; priceperk…
naltatis Jan 15, 2026
4db8ab5
refactor tariff chart
naltatis Jan 16, 2026
7491955
add translation; add descripotions
naltatis Jan 16, 2026
f61d4f8
zones wip
naltatis Jan 19, 2026
190c7d5
refactor zones
naltatis Jan 19, 2026
0677590
add missing
naltatis Jan 19, 2026
eb04e2e
month/day range refactor
naltatis Jan 21, 2026
653648d
add currency ui
naltatis Jan 22, 2026
94581d5
merge
naltatis Jan 30, 2026
2346c59
fix test
naltatis Jan 30, 2026
844f0c1
simplify api/init
naltatis Jan 31, 2026
5684819
fix test
naltatis Jan 31, 2026
f4a1a78
fix e2e
naltatis Jan 31, 2026
6762ae4
fix tests
naltatis Jan 31, 2026
76961e1
fix modbus test
naltatis Jan 31, 2026
d310c73
fix e2e
naltatis Jan 31, 2026
bb8a33d
Merge remote-tracking branch 'origin/master' into feature/tariff_ui
naltatis Feb 2, 2026
ca360e1
refactor go; simplify ref handling; add yaml source info
naltatis Feb 2, 2026
6f362d3
ui fixes
naltatis Feb 2, 2026
2f3267d
Merge branch 'master' into feature/tariff_ui
naltatis Feb 2, 2026
c29a58e
migration hint; e2e test
naltatis Feb 2, 2026
d9a5766
Merge branch 'master' into feature/tariff_ui
naltatis Feb 2, 2026
70e8673
shadow
naltatis Feb 2, 2026
a13afad
validate time zone
naltatis Feb 2, 2026
7f6e83d
formId
naltatis Feb 2, 2026
4ea91c1
Merge branch 'master' into feature/tariff_ui
naltatis Feb 6, 2026
de5a637
add e2e tests
naltatis Feb 6, 2026
4ad7cf7
add tests; fix lint
naltatis Feb 6, 2026
473d189
Update cmd/setup.go
naltatis Feb 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions api/globalconfig/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,20 @@ import (

// ConfigStatus for publishing config, status and source to UI and external systems
type ConfigStatus struct {
Config any `json:"config,omitempty"`
Status any `json:"status,omitempty"`
FromYaml bool `json:"fromYaml,omitempty"`
Config any `json:"config,omitempty"`
Status any `json:"status,omitempty"`
FromYaml bool `json:"fromYaml,omitempty"`
YamlSource YamlSource `json:"yamlSource,omitempty"`
}

type YamlSource string

const (
YamlSourceFs YamlSource = "fs"
YamlSourceDb YamlSource = "db"
YamlSourceNone YamlSource = ""
)

type All struct {
Network Network
Ocpp ocpp.Config
Expand Down Expand Up @@ -160,6 +169,14 @@ type Tariffs struct {
Solar []config.Typed
}

type TariffRefs struct {
Grid string `json:"grid"`
FeedIn string `json:"feedIn"`
Co2 string `json:"co2"`
Planner string `json:"planner"`
Solar []string `json:"solar"`
}

type Network struct {
Schema_ string `json:"schema,omitempty" mapstructure:"schema"` // TODO deprecated
ExternalUrl string `json:"externalUrl"`
Expand Down
3 changes: 3 additions & 0 deletions assets/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@

--bs-warning: var(--evcc-orange);
--bs-warning-rgb: var(--evcc-orange-rgb);
--bs-warning-bg-subtle: color-mix(in srgb, var(--evcc-orange) 10%, transparent);
--bs-warning-border-subtle: color-mix(in srgb, var(--evcc-orange) 30%, transparent);
--bs-warning-text-emphasis: var(--evcc-orange);
--bs-danger-50: #dc354580;

--bs-danger: var(--evcc-red);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export default defineComponent({
return this.dataChanged && this.selectedActive;
},
weekdaysLabel(): string {
return this.getShortenedWeekdaysLabel(this.selectedWeekdays);
return this.fmtWeekdaysRange(this.selectedWeekdays);
},
socOptions(): SelectOption<number>[] {
// a list of entries from 5 to 100 with a step of 5
Expand Down
120 changes: 120 additions & 0 deletions assets/js/components/Config/CurrencyModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<template>
<GenericModal
id="currencyModal"
ref="modal"
:title="$t('config.currency.title')"
data-testid="currency-modal"
@open="open"
>
<p>{{ $t("config.currency.description") }}</p>
<p v-if="error" class="text-danger">{{ error }}</p>
<form ref="form" class="container mx-0 px-0" @submit.prevent="save">
<FormRow id="currency" :label="$t('config.currency.label')" :example="exampleText">
<select id="currency" v-model="selectedCurrency" class="form-select" required>
<option
v-for="currency in currencies"
:key="currency.code"
:value="currency.code"
>
{{ currency.code }} - {{ currency.name }}
</option>
</select>
</FormRow>

<div class="mt-4 d-flex justify-content-between gap-2 flex-column flex-sm-row">
<button
type="button"
class="btn btn-link text-muted btn-cancel"
data-bs-dismiss="modal"
>
{{ $t("config.general.cancel") }}
</button>

<button
type="submit"
class="btn btn-primary order-1 order-sm-2 flex-grow-1 flex-sm-grow-0 px-4"
:disabled="saving || !changed"
>
<span
v-if="saving"
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
></span>
{{ $t("config.general.save") }}
</button>
</div>
</form>
</GenericModal>
</template>

<script>
import GenericModal from "../Helper/GenericModal.vue";
import FormRow from "./FormRow.vue";
import store from "@/store";
import api from "@/api";
import { CURRENCY } from "@/types/evcc";
import formatter from "@/mixins/formatter";

export default {
name: "CurrencyModal",
components: { FormRow, GenericModal },
mixins: [formatter],
emits: ["changed"],
data() {
return {
saving: false,
error: "",
selectedCurrency: "EUR",
initialCurrency: "EUR",
};
},
computed: {
currencies() {
return Object.values(CURRENCY).map((code) => ({
code,
name: this.fmtCurrencyName(code),
}));
},
changed() {
return this.selectedCurrency !== this.initialCurrency;
},
exampleText() {
const price = this.fmtPricePerKWh(0.122, this.selectedCurrency);
const amount = this.fmtMoney(20.2, this.selectedCurrency, true, true);
return this.$t("config.currency.example", { price, amount });
},
},
methods: {
reset() {
const currency = store?.state?.currency || "EUR";
this.saving = false;
this.error = "";
this.selectedCurrency = currency;
this.initialCurrency = currency;
},
async open() {
this.reset();
},
async save() {
this.saving = true;
this.error = "";
try {
await api.put("/config/currency", JSON.stringify(this.selectedCurrency));
this.$emit("changed");
this.$refs.modal.close();
} catch (e) {
this.error = e.message;
}
this.saving = false;
},
},
};
</script>
<style scoped>
.container {
margin-left: calc(var(--bs-gutter-x) * -0.5);
margin-right: calc(var(--bs-gutter-x) * -0.5);
padding-right: 0;
}
</style>
20 changes: 15 additions & 5 deletions assets/js/components/Config/DeviceCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
:disabled="!editable || noEditButton"
@click="edit"
>
<span
v-if="badge"
class="position-absolute top-0 start-100 translate-middle p-2 rounded-circle bg-warning"
>
<span class="visually-hidden">new</span>
</span>
<shopicon-regular-adjust size="s"></shopicon-regular-adjust>
</button>
</div>
Expand All @@ -56,6 +62,7 @@ export default {
unconfigured: Boolean,
warning: Boolean,
noEditButton: Boolean,
badge: Boolean,
},
emits: ["edit"],
data() {
Expand All @@ -65,14 +72,17 @@ export default {
},
computed: {
tooltipTitle() {
if (!this.name) {
return "";
let result = "";
if (this.name) {
result += `${this.$t("config.main.name")}: <span class='font-monospace'>${this.name}</span>`;
}
let title = `${this.$t("config.main.name")}: <span class='font-monospace'>${this.name}</span>`;
if (!this.editable) {
title += `<div class="mt-1">${this.$t("config.general.fromYamlHint")}</div>`;
result += `<div class="mt-1">${this.$t("config.general.fromYamlHint")}</div>`;
}
if (!result) {
return "";
}
return `<div class="text-start">${title}</div>`;
return `<div class="text-start">${result}</div>`;
},
},
watch: {
Expand Down
3 changes: 3 additions & 0 deletions assets/js/components/Config/DeviceModal/Actions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
v-if="testState"
v-bind="testState"
:sponsor-token-required="sponsorTokenRequired"
:currency="currency"
@test="$emit('test')"
/>

Expand Down Expand Up @@ -51,6 +52,7 @@ import { defineComponent } from "vue";
import type { PropType } from "vue";
import TestResult from "../TestResult.vue";
import { type TestState } from "../utils/test";
import type { CURRENCY } from "@/types/evcc";

export default defineComponent({
name: "DeviceModalActions",
Expand All @@ -67,6 +69,7 @@ export default defineComponent({
isSucceeded: Boolean as PropType<boolean>,
isNew: Boolean as PropType<boolean>,
sponsorTokenRequired: Boolean as PropType<boolean>,
currency: String as PropType<CURRENCY>,
},
emits: ["save", "remove", "test"],
computed: {
Expand Down
9 changes: 6 additions & 3 deletions assets/js/components/Config/DeviceModal/DeviceModalBase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
v-bind="param"
v-model="values[param.Name]"
:service-values="serviceValues[param.Name]"
:currency="currency"
/>

<div v-if="auth.code">
Expand Down Expand Up @@ -126,6 +127,7 @@
v-bind="param"
v-model="values[param.Name]"
:service-values="serviceValues[param.Name]"
:currency="currency"
/>

<PropertyCollapsible>
Expand All @@ -137,6 +139,7 @@
v-bind="param"
v-model="values[param.Name]"
:service-values="serviceValues[param.Name]"
:currency="currency"
/>
</template>
<template v-if="$slots['collapsible-more']" #more>
Expand All @@ -155,6 +158,7 @@
:is-succeeded="succeeded"
:is-new="isNew"
:sponsor-token-required="sponsorTokenRequired"
:currency="currency"
@save="handleSave"
@remove="handleRemove"
@test="testManually"
Expand Down Expand Up @@ -182,6 +186,7 @@ import { initialAuthState, prepareAuthLogin } from "../utils/authProvider";
import sleep from "@/utils/sleep";
import { ConfigType } from "@/types/evcc";
import type { DeviceType, Timeout } from "@/types/evcc";
import { CURRENCY } from "@/types/evcc";
import {
handleError,
type DeviceValues,
Expand Down Expand Up @@ -228,6 +233,7 @@ export default defineComponent({
showMainContent: { type: Boolean, default: true },
// Optional: usage parameter for loadProducts (e.g., meter type: "pv", "battery", "aux", "ext")
usage: String,
currency: { type: String as PropType<CURRENCY>, default: CURRENCY.EUR },
// Optional: custom product name computation
getProductName: Function as PropType<
(values: DeviceValues, templateName: string | null) => string
Expand Down Expand Up @@ -495,7 +501,6 @@ export default defineComponent({
},
values: {
handler() {
this.test = initialTestState();
this.updateServiceValues();
},
deep: true,
Expand Down Expand Up @@ -666,7 +671,6 @@ export default defineComponent({
return this.device.test(this.id, this.apiData);
},
async update(force = false) {
console.log("update called", { force, isUnknown: this.test.isUnknown, id: this.id });
if (this.test.isUnknown && !force) {
const success = await performTest(
this.test,
Expand All @@ -680,7 +684,6 @@ export default defineComponent({
}
this.saving = true;
try {
console.log("calling device.update", this.apiData);
await this.device.update(this.id!, this.apiData, force);
console.log("update succeeded, closing modal");
this.saving = false;
Expand Down
Loading
Loading