Non-solar use cases: make grid meter optional (#14341)
This commit is contained in:
parent
598bf557c5
commit
280976cb7e
20 changed files with 275 additions and 49 deletions
|
|
@ -64,17 +64,19 @@
|
|||
>
|
||||
<div class="d-flex justify-content-between align-items-end mb-4">
|
||||
<h3 class="m-0">In</h3>
|
||||
<span class="fw-bold">
|
||||
<span v-if="pvPossible" class="fw-bold">
|
||||
<AnimatedNumber :to="inPower" :format="kw" />
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<EnergyflowEntry
|
||||
v-if="pvPossible"
|
||||
:name="$t('main.energyflow.pvProduction')"
|
||||
icon="sun"
|
||||
:power="pvProduction"
|
||||
:powerTooltip="pvTooltip"
|
||||
:powerInKw="powerInKw"
|
||||
data-testid="energyflow-entry-production"
|
||||
/>
|
||||
<EnergyflowEntry
|
||||
v-if="batteryConfigured"
|
||||
|
|
@ -106,12 +108,13 @@
|
|||
>
|
||||
<div class="d-flex justify-content-between align-items-end mb-4">
|
||||
<h3 class="m-0">Out</h3>
|
||||
<span class="fw-bold">
|
||||
<span v-if="pvPossible" class="fw-bold">
|
||||
<AnimatedNumber :to="outPower" :format="kw" />
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<EnergyflowEntry
|
||||
v-if="pvPossible"
|
||||
:name="$t('main.energyflow.homePower')"
|
||||
icon="home"
|
||||
:power="homePower"
|
||||
|
|
@ -119,6 +122,7 @@
|
|||
:details="detailsValue(tariffPriceHome, tariffCo2Home)"
|
||||
:detailsFmt="detailsFmt"
|
||||
:detailsTooltip="detailsTooltip(tariffPriceHome, tariffCo2Home)"
|
||||
data-testid="energyflow-entry-home"
|
||||
/>
|
||||
<EnergyflowEntry
|
||||
:name="
|
||||
|
|
@ -139,6 +143,7 @@
|
|||
:detailsTooltip="
|
||||
detailsTooltip(tariffPriceLoadpoints, tariffCo2Loadpoints)
|
||||
"
|
||||
data-testid="energyflow-entry-loadpoints"
|
||||
/>
|
||||
<EnergyflowEntry
|
||||
v-if="batteryConfigured"
|
||||
|
|
@ -153,6 +158,7 @@
|
|||
@details-clicked="openBatterySettingsModal"
|
||||
/>
|
||||
<EnergyflowEntry
|
||||
v-if="pvPossible"
|
||||
:name="$t('main.energyflow.pvExport')"
|
||||
icon="powersupply"
|
||||
:power="pvExport"
|
||||
|
|
@ -160,6 +166,7 @@
|
|||
:details="detailsValue(-tariffFeedIn)"
|
||||
:detailsFmt="detailsFmt"
|
||||
:detailsTooltip="detailsTooltip(-tariffFeedIn)"
|
||||
data-testid="energyflow-entry-gridexport"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -293,6 +300,9 @@ export default {
|
|||
co2Available() {
|
||||
return this.smartCostType === CO2_TYPE;
|
||||
},
|
||||
pvPossible() {
|
||||
return this.pvConfigured || this.gridConfigured;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener("resize", this.updateHeight);
|
||||
|
|
|
|||
|
|
@ -60,11 +60,8 @@
|
|||
:format="fmtBarValue"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="totalAdjusted <= 0"
|
||||
class="site-progress-bar bg-light border no-wrap w-100 text-dark"
|
||||
>
|
||||
<span>{{ $t("main.energyflow.noEnergy") }}</span>
|
||||
<div v-if="totalAdjusted <= 0" class="site-progress-bar w-100 grid-import">
|
||||
<span>{{ fmtKw(0, false, true) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="label-scale d-flex">
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
<LoadpointSettingsButton :id="id" class="d-block d-sm-none" />
|
||||
</div>
|
||||
<div class="mb-3 d-flex align-items-center">
|
||||
<Mode class="flex-grow-1" :mode="mode" @updated="setTargetMode" />
|
||||
<Mode class="flex-grow-1" v-bind="modeProps" @updated="setTargetMode" />
|
||||
<LoadpointSettingsButton :id="id" class="d-none d-sm-block ms-2" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -98,6 +98,7 @@ import LoadpointSettingsButton from "./LoadpointSettingsButton.vue";
|
|||
import LoadpointSettingsModal from "./LoadpointSettingsModal.vue";
|
||||
import VehicleIcon from "./VehicleIcon";
|
||||
import LoadpointSessionInfo from "./LoadpointSessionInfo.vue";
|
||||
import smartCostAvailable from "../utils/smartCostAvailable";
|
||||
|
||||
export default {
|
||||
name: "Loadpoint",
|
||||
|
|
@ -189,6 +190,8 @@ export default {
|
|||
tariffCo2: Number,
|
||||
currency: String,
|
||||
multipleLoadpoints: Boolean,
|
||||
gridConfigured: Boolean,
|
||||
pvConfigured: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -218,6 +221,9 @@ export default {
|
|||
phasesProps: function () {
|
||||
return this.collectProps(Phases);
|
||||
},
|
||||
modeProps: function () {
|
||||
return this.collectProps(Mode);
|
||||
},
|
||||
sessionInfoProps: function () {
|
||||
return this.collectProps(LoadpointSessionInfo);
|
||||
},
|
||||
|
|
@ -251,6 +257,12 @@ export default {
|
|||
socBasedPlanning: function () {
|
||||
return this.socBasedCharging && this.vehicle?.capacity > 0;
|
||||
},
|
||||
pvPossible: function () {
|
||||
return this.pvConfigured || this.gridConfigured;
|
||||
},
|
||||
hasSmartCost: function () {
|
||||
return smartCostAvailable(this.smartCostType);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
phaseRemaining() {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
:tariffCo2="tariffCo2"
|
||||
:currency="currency"
|
||||
:multiple-loadpoints="loadpoints.length > 1"
|
||||
:grid-configured="gridConfigured"
|
||||
:pv-configured="pvConfigured"
|
||||
class="h-100"
|
||||
:class="{ 'loadpoint-unselected': !selected(index) }"
|
||||
@click="scrollTo(index)"
|
||||
|
|
@ -67,6 +69,8 @@ export default {
|
|||
tariffGrid: Number,
|
||||
tariffCo2: Number,
|
||||
currency: String,
|
||||
gridConfigured: Boolean,
|
||||
pvConfigured: Boolean,
|
||||
},
|
||||
data() {
|
||||
return { selectedIndex: 0, snapTimeout: null };
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="mode-group border d-inline-flex" role="group">
|
||||
<div class="mode-group border d-inline-flex" role="group" data-testid="mode">
|
||||
<button
|
||||
v-for="m in modes"
|
||||
:key="m"
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
:class="{ active: isActive(m) }"
|
||||
@click="setTargetMode(m)"
|
||||
>
|
||||
{{ $t(`main.mode.${m}`) }}
|
||||
{{ label(m) }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -18,14 +18,31 @@ export default {
|
|||
name: "Mode",
|
||||
props: {
|
||||
mode: String,
|
||||
pvPossible: Boolean,
|
||||
hasSmartCost: Boolean,
|
||||
},
|
||||
emits: ["updated"],
|
||||
data() {
|
||||
return {
|
||||
modes: ["off", "pv", "minpv", "now"],
|
||||
};
|
||||
|
||||
computed: {
|
||||
modes: function () {
|
||||
if (this.pvPossible) {
|
||||
return ["off", "pv", "minpv", "now"];
|
||||
}
|
||||
if (this.hasSmartCost) {
|
||||
return ["off", "pv", "now"];
|
||||
}
|
||||
return ["off", "now"];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
label: function (mode) {
|
||||
// rename pv mode to smart for non-pv and dynamic tariffs scenarios
|
||||
// TODO: rollout smart name for everyting later
|
||||
if (mode === "pv" && !this.pvPossible && this.hasSmartCost) {
|
||||
return this.$t("main.mode.smart");
|
||||
}
|
||||
return this.$t(`main.mode.${mode}`);
|
||||
},
|
||||
isActive: function (mode) {
|
||||
return this.mode === mode;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
:tariffGrid="tariffGrid"
|
||||
:tariffCo2="tariffCo2"
|
||||
:currency="currency"
|
||||
:gridConfigured="gridConfigured"
|
||||
:pvConfigured="pvConfigured"
|
||||
/>
|
||||
<Footer v-bind="footer"></Footer>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
</p>
|
||||
<p class="mb-1"><strong>Missing features</strong></p>
|
||||
<ul>
|
||||
<li>grid meter</li>
|
||||
<li>aux meters</li>
|
||||
<li>loadpoints and chargers</li>
|
||||
<li>custom/plugin meters and vehicles</li>
|
||||
|
|
@ -41,16 +40,22 @@
|
|||
<ul class="p-0 config-list">
|
||||
<DeviceCard
|
||||
:name="$t('config.grid.title')"
|
||||
:editable="!!gridMeter?.id"
|
||||
:editable="!gridMeter || !!gridMeter.id"
|
||||
:error="deviceError('meter', gridMeter?.name)"
|
||||
data-testid="grid"
|
||||
@edit="editMeter(gridMeter.id, 'grid')"
|
||||
@edit="gridMeter?.id ? editMeter(gridMeter.id, 'pv') : addMeter('grid')"
|
||||
>
|
||||
<template #icon>
|
||||
<shopicon-regular-powersupply></shopicon-regular-powersupply>
|
||||
</template>
|
||||
<template #tags>
|
||||
<DeviceTags :tags="deviceTags('meter', gridMeter?.name)" />
|
||||
<DeviceTags
|
||||
:tags="
|
||||
gridMeter
|
||||
? deviceTags('meter', gridMeter.name)
|
||||
: { configured: { value: false } }
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</DeviceCard>
|
||||
<DeviceCard
|
||||
|
|
@ -547,7 +552,7 @@ export default {
|
|||
removeMeterFromSite(type, name) {
|
||||
if (type === "grid") {
|
||||
this.site.grid = "";
|
||||
} else {
|
||||
} else if (this.site[type]) {
|
||||
this.site[type] = this.site[type].filter((i) => i !== name);
|
||||
}
|
||||
this.saveSite(type);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package core
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
|
@ -215,11 +214,6 @@ func (site *Site) Boot(log *util.Logger, loadpoints []*Loadpoint, tariffs *tarif
|
|||
site.auxMeters = append(site.auxMeters, dev.Instance())
|
||||
}
|
||||
|
||||
// configure meter from references
|
||||
if site.gridMeter == nil && len(site.pvMeters) == 0 {
|
||||
return errors.New("missing either grid or pv meter")
|
||||
}
|
||||
|
||||
// revert battery mode on shutdown
|
||||
shutdown.Register(func() {
|
||||
if mode := site.GetBatteryMode(); batteryModeModified(mode) {
|
||||
|
|
|
|||
|
|
@ -451,6 +451,7 @@ minpv = "Min+PV"
|
|||
now = "Schnell"
|
||||
off = "Aus"
|
||||
pv = "PV"
|
||||
smart = "Smart"
|
||||
|
||||
[main.provider]
|
||||
login = "anmelden"
|
||||
|
|
|
|||
|
|
@ -450,6 +450,7 @@ minpv = "Min+Solar"
|
|||
now = "Fast"
|
||||
off = "Off"
|
||||
pv = "Solar"
|
||||
smart = "Smart"
|
||||
|
||||
[main.provider]
|
||||
login = "log in"
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ import { test, expect } from "@playwright/test";
|
|||
import { start, stop, restart, baseUrl } from "./evcc";
|
||||
import { startSimulator, stopSimulator, simulatorUrl, simulatorHost } from "./simulator";
|
||||
|
||||
const CONFIG_EMPTY = "config-empty.evcc.yaml";
|
||||
const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml";
|
||||
|
||||
test.use({ baseURL: baseUrl() });
|
||||
|
||||
test.beforeAll(async () => {
|
||||
await start(CONFIG_EMPTY, "password.sql");
|
||||
await start(CONFIG_GRID_ONLY, "password.sql");
|
||||
await startSimulator();
|
||||
});
|
||||
test.afterAll(async () => {
|
||||
|
|
@ -29,7 +29,7 @@ async function enableExperimental(page) {
|
|||
await page.getByRole("button", { name: "Close" }).click();
|
||||
}
|
||||
|
||||
test.describe("meters", async () => {
|
||||
test.describe("battery meter", async () => {
|
||||
test("create, edit and remove battery meter", async ({ page }) => {
|
||||
// setup test data for mock openems api
|
||||
await page.goto(simulatorUrl());
|
||||
|
|
@ -71,7 +71,7 @@ test.describe("meters", async () => {
|
|||
await expect(battery.getByTestId("device-tag-capacity")).toContainText("20.0 kWh");
|
||||
|
||||
// restart and check in main ui
|
||||
await restart(CONFIG_EMPTY);
|
||||
await restart(CONFIG_GRID_ONLY);
|
||||
await page.goto("/");
|
||||
await page.getByTestId("visualization").click();
|
||||
await expect(page.getByTestId("energyflow")).toContainText("Battery charging75%2.5 kW");
|
||||
|
|
@ -1,15 +1,5 @@
|
|||
site:
|
||||
title: Hello World
|
||||
meters:
|
||||
grid: grid
|
||||
|
||||
meters:
|
||||
- name: grid
|
||||
type: custom
|
||||
power:
|
||||
source: js
|
||||
script: |
|
||||
1000
|
||||
|
||||
loadpoints:
|
||||
- title: Carport
|
||||
|
|
|
|||
34
tests/config-grid-only.evcc.yaml
Executable file
34
tests/config-grid-only.evcc.yaml
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
site:
|
||||
title: Hello World
|
||||
meters:
|
||||
grid: grid
|
||||
|
||||
meters:
|
||||
- name: grid
|
||||
type: custom
|
||||
power:
|
||||
source: js
|
||||
script: |
|
||||
1000
|
||||
|
||||
loadpoints:
|
||||
- title: Carport
|
||||
charger: charger
|
||||
|
||||
chargers:
|
||||
- name: charger
|
||||
type: custom
|
||||
enable:
|
||||
source: js
|
||||
script:
|
||||
enabled:
|
||||
source: js
|
||||
script: |
|
||||
false
|
||||
status:
|
||||
source: js
|
||||
script: |
|
||||
"B"
|
||||
maxcurrent:
|
||||
source: js
|
||||
script:
|
||||
84
tests/config-grid.spec.js
Normal file
84
tests/config-grid.spec.js
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
import { start, stop, restart, baseUrl } from "./evcc";
|
||||
import { startSimulator, stopSimulator, simulatorUrl, simulatorHost } from "./simulator";
|
||||
|
||||
const CONFIG_EMPTY = "config-empty.evcc.yaml";
|
||||
|
||||
test.use({ baseURL: baseUrl() });
|
||||
|
||||
test.beforeAll(async () => {
|
||||
await start(CONFIG_EMPTY, "password.sql");
|
||||
await startSimulator();
|
||||
});
|
||||
test.afterAll(async () => {
|
||||
await stop();
|
||||
await stopSimulator();
|
||||
});
|
||||
|
||||
async function login(page) {
|
||||
await page.locator("#loginPassword").fill("secret");
|
||||
await page.getByRole("button", { name: "Login" }).click();
|
||||
}
|
||||
|
||||
async function enableExperimental(page) {
|
||||
await page
|
||||
.getByTestId("generalconfig-experimental")
|
||||
.getByRole("button", { name: "edit" })
|
||||
.click();
|
||||
await page.getByLabel("Experimental 🧪").click();
|
||||
await page.getByRole("button", { name: "Close" }).click();
|
||||
}
|
||||
|
||||
test.describe("main screen", async () => {
|
||||
test("modes", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await expect(page.getByRole("button", { name: "Off" })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "Fast" })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("grid meter", async () => {
|
||||
test("create, edit and remove grid meter", async ({ page }) => {
|
||||
// setup test data for mock openems api
|
||||
await page.goto(simulatorUrl());
|
||||
await page.getByLabel("Grid Power").fill("5000");
|
||||
await page.getByRole("button", { name: "Apply changes" }).click();
|
||||
|
||||
await page.goto("/#/config");
|
||||
await login(page);
|
||||
await enableExperimental(page);
|
||||
|
||||
await expect(page.getByTestId("grid")).toHaveCount(1);
|
||||
await expect(page.getByTestId("grid").getByTestId("device-tag-configured")).toContainText("no");
|
||||
|
||||
// create #1
|
||||
await page.getByTestId("grid").getByRole("button", { name: "edit" }).click();
|
||||
|
||||
const meterModal = page.getByTestId("meter-modal");
|
||||
await meterModal.getByLabel("Manufacturer").selectOption("OpenEMS");
|
||||
await meterModal.getByLabel("IP address or hostname").fill(simulatorHost());
|
||||
await expect(meterModal.getByRole("button", { name: "Validate & save" })).toBeVisible();
|
||||
await meterModal.getByRole("link", { name: "validate" }).click();
|
||||
await expect(meterModal.getByTestId("device-tag-power")).toContainText("5.0 kW");
|
||||
await meterModal.getByRole("button", { name: "Save" }).click();
|
||||
await expect(meterModal).not.toBeVisible();
|
||||
|
||||
// restart
|
||||
await restart(CONFIG_EMPTY);
|
||||
await expect(page.getByTestId("grid").getByTestId("device-tag-power")).toContainText("5.0 kW");
|
||||
|
||||
// check in main ui
|
||||
await page.goto("/");
|
||||
await page.getByTestId("visualization").click();
|
||||
await expect(page.getByTestId("energyflow")).toContainText(["Grid use", "5.0 kW"].join(""));
|
||||
|
||||
// delete #1
|
||||
await page.goto("/#/config");
|
||||
await page.getByTestId("grid").getByRole("button", { name: "edit" }).click();
|
||||
await meterModal.getByRole("button", { name: "Delete" }).click();
|
||||
await expect(meterModal).not.toBeVisible();
|
||||
|
||||
await expect(page.getByTestId("grid")).toHaveCount(1);
|
||||
await expect(page.getByTestId("grid").getByTestId("device-tag-configured")).toContainText("no");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
import { start, stop, restart, baseUrl } from "./evcc";
|
||||
|
||||
const CONFIG = "config-empty.evcc.yaml";
|
||||
const CONFIG = "config-grid-only.evcc.yaml";
|
||||
|
||||
test.use({ baseURL: baseUrl() });
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
import { start, stop, restart, baseUrl } from "./evcc";
|
||||
|
||||
const CONFIG_EMPTY = "config-empty.evcc.yaml";
|
||||
const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml";
|
||||
const CONFIG_WITH_TARIFFS = "config-with-tariffs.evcc.yaml";
|
||||
|
||||
test.use({ baseURL: baseUrl() });
|
||||
|
|
@ -34,7 +34,7 @@ async function goToConfig(page) {
|
|||
|
||||
test.describe("tariffs", async () => {
|
||||
test("tariffs not configured", async ({ page }) => {
|
||||
await start(CONFIG_EMPTY, "password.sql");
|
||||
await start(CONFIG_GRID_ONLY, "password.sql");
|
||||
await goToConfig(page);
|
||||
|
||||
await expect(page.getByTestId("tariffs")).toBeVisible();
|
||||
|
|
@ -44,7 +44,7 @@ test.describe("tariffs", async () => {
|
|||
});
|
||||
|
||||
test("tariffs via ui", async ({ page }) => {
|
||||
await start(CONFIG_EMPTY, "password.sql");
|
||||
await start(CONFIG_GRID_ONLY, "password.sql");
|
||||
await goToConfig(page);
|
||||
|
||||
await page.getByTestId("tariffs").getByRole("button", { name: "edit" }).click();
|
||||
|
|
@ -85,7 +85,7 @@ test.describe("tariffs", async () => {
|
|||
.getByRole("button", { name: "Restart" });
|
||||
await expect(restartButton).toBeVisible();
|
||||
|
||||
await restart(CONFIG_EMPTY);
|
||||
await restart(CONFIG_GRID_ONLY);
|
||||
|
||||
// restart done
|
||||
await expect(restartButton).not.toBeVisible();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
import { start, stop, restart, cleanRestart, baseUrl } from "./evcc";
|
||||
|
||||
const CONFIG_EMPTY = "config-empty.evcc.yaml";
|
||||
const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml";
|
||||
const CONFIG_WITH_VEHICLE = "config-with-vehicle.evcc.yaml";
|
||||
|
||||
test.use({ baseURL: baseUrl() });
|
||||
|
||||
test.beforeAll(async () => {
|
||||
await start(CONFIG_EMPTY, "password.sql");
|
||||
await start(CONFIG_GRID_ONLY, "password.sql");
|
||||
});
|
||||
test.afterAll(async () => {
|
||||
await stop();
|
||||
|
|
@ -101,7 +101,7 @@ test.describe("vehicles", async () => {
|
|||
await expect(page.getByTestId("vehicle")).toHaveCount(2);
|
||||
|
||||
// restart evcc
|
||||
await restart(CONFIG_EMPTY);
|
||||
await restart(CONFIG_GRID_ONLY);
|
||||
await page.reload();
|
||||
|
||||
await expect(page.getByTestId("vehicle")).toHaveCount(2);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
import { start, stop, baseUrl } from "./evcc";
|
||||
|
||||
const CONFIG_EMPTY = "config-empty.evcc.yaml";
|
||||
const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml";
|
||||
|
||||
test.use({ baseURL: baseUrl() });
|
||||
|
||||
test.beforeAll(async () => {
|
||||
await start(CONFIG_EMPTY, "password.sql");
|
||||
await start(CONFIG_GRID_ONLY, "password.sql");
|
||||
});
|
||||
test.afterAll(async () => {
|
||||
await stop();
|
||||
|
|
|
|||
44
tests/smart-cost-only.evcc.yaml
Executable file
44
tests/smart-cost-only.evcc.yaml
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
interval: 0.1s
|
||||
|
||||
site:
|
||||
title: Smart Cost, No Grid & PV
|
||||
|
||||
loadpoints:
|
||||
- title: Loadpoint
|
||||
charger: charger
|
||||
meter: meter
|
||||
|
||||
meters:
|
||||
- name: meter
|
||||
type: custom
|
||||
power:
|
||||
source: js
|
||||
script: |
|
||||
11000
|
||||
|
||||
chargers:
|
||||
- name: charger
|
||||
type: custom
|
||||
enable:
|
||||
source: js
|
||||
script:
|
||||
enabled:
|
||||
source: js
|
||||
script: |
|
||||
true
|
||||
status:
|
||||
source: js
|
||||
script: |
|
||||
"C"
|
||||
maxcurrent:
|
||||
source: js
|
||||
script:
|
||||
|
||||
tariffs:
|
||||
currency: EUR
|
||||
grid:
|
||||
type: fixed
|
||||
price: 0.4 # EUR/kWh
|
||||
zones:
|
||||
- hours: 1-6
|
||||
price: 0.2
|
||||
31
tests/smart-cost-only.spec.js
Normal file
31
tests/smart-cost-only.spec.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
import { start, stop, baseUrl } from "./evcc";
|
||||
|
||||
test.use({ baseURL: baseUrl() });
|
||||
|
||||
test.beforeAll(async () => {
|
||||
await start("smart-cost-only.evcc.yaml", "password.sql");
|
||||
});
|
||||
test.afterAll(async () => {
|
||||
await stop();
|
||||
});
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/");
|
||||
});
|
||||
|
||||
test.describe("main screen", async () => {
|
||||
test("smart mode", async ({ page }) => {
|
||||
await expect(page.getByRole("button", { name: "Off" })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "Smart" })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "Fast" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("no production and feedin", async ({ page }) => {
|
||||
await page.getByTestId("energyflow").click();
|
||||
await expect(page.getByTestId("energyflow-entry-gridimport")).toBeVisible();
|
||||
await expect(page.getByTestId("energyflow-entry-home")).not.toBeVisible();
|
||||
await expect(page.getByTestId("energyflow-entry-loadpoints")).toBeVisible();
|
||||
await expect(page.getByTestId("energyflow-entry-gridexport")).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue