Fix home power and self-consumption calculation (#1788)
This commit is contained in:
parent
9969590bd6
commit
cbd0f23e73
11 changed files with 65 additions and 28 deletions
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
|
|
@ -78,6 +78,9 @@ jobs:
|
|||
- name: Lint
|
||||
run: make lint-ui
|
||||
|
||||
- name: Test
|
||||
run: make test-ui
|
||||
|
||||
- name: Porcelain
|
||||
run: |
|
||||
test -z "$(git status --porcelain)" || (git status; git diff; false)
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -48,7 +48,7 @@ lint-ui:
|
|||
npm run lint
|
||||
|
||||
test-ui:
|
||||
npm run test
|
||||
npm test
|
||||
|
||||
test:
|
||||
@echo "Running testsuite"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ describe("Energyflow.vue", () => {
|
|||
gridPower: 0,
|
||||
pvConfigured: true,
|
||||
pvPower: 0,
|
||||
homePower: 0,
|
||||
batteryConfigured: false,
|
||||
batteryPower: 0,
|
||||
batterySoC: 0,
|
||||
|
|
@ -25,7 +26,13 @@ describe("Energyflow.vue", () => {
|
|||
it("using pv and grid power", async () => {
|
||||
const wrapper = shallowMount(Energyflow, {
|
||||
mocks,
|
||||
propsData: { ...defaultProps, gridPower: 1000, pvPower: 4000, loadpointsPower: 3700 },
|
||||
propsData: {
|
||||
...defaultProps,
|
||||
gridPower: 1000,
|
||||
pvPower: 4000,
|
||||
homePower: 1300,
|
||||
loadpointsPower: 3700,
|
||||
},
|
||||
});
|
||||
await wrapper.find(".energyflow").trigger("click");
|
||||
|
||||
|
|
@ -33,7 +40,7 @@ describe("Energyflow.vue", () => {
|
|||
expect(wrapper.find("[data-test-self-consumption]").text()).toMatch("4.0 kW");
|
||||
expect(wrapper.find("[data-test-pv-export]").text()).toMatch("0.0 kW");
|
||||
|
||||
expect(wrapper.find("[data-test-house-consumption]").text()).toMatch("1.3 kW");
|
||||
expect(wrapper.find("[data-test-home-power]").text()).toMatch("1.3 kW");
|
||||
expect(wrapper.find("[data-test-loadpoints]").text()).toMatch("3.7 kW");
|
||||
expect(wrapper.find("[data-test-pv-production]").text()).toMatch("4.0 kW");
|
||||
expect(wrapper.find("[data-test-battery]").exists()).toBe(false);
|
||||
|
|
@ -42,18 +49,18 @@ describe("Energyflow.vue", () => {
|
|||
it("exporting all pv power, no usage", async () => {
|
||||
const wrapper = shallowMount(Energyflow, {
|
||||
mocks,
|
||||
propsData: { ...defaultProps, gridPower: -4000, pvPower: 4000, loadpointsPower: 1000 },
|
||||
propsData: { ...defaultProps, gridPower: -4000, pvPower: 5000, loadpointsPower: 1000 },
|
||||
});
|
||||
|
||||
await wrapper.find(".energyflow").trigger("click");
|
||||
|
||||
expect(wrapper.find("[data-test-grid-import]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-self-consumption]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-self-consumption]").text()).toMatch("1.0 kW");
|
||||
expect(wrapper.find("[data-test-pv-export]").text()).toMatch("4.0 kW");
|
||||
|
||||
expect(wrapper.find("[data-test-house-consumption]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-home-power]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-loadpoints]").text()).toMatch("1.0 kW");
|
||||
expect(wrapper.find("[data-test-pv-production]").text()).toMatch("4.0 kW");
|
||||
expect(wrapper.find("[data-test-pv-production]").text()).toMatch("5.0 kW");
|
||||
expect(wrapper.find("[data-test-battery]").exists()).toBe(false);
|
||||
});
|
||||
|
||||
|
|
@ -69,7 +76,7 @@ describe("Energyflow.vue", () => {
|
|||
expect(wrapper.find("[data-test-self-consumption]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-pv-export]").text()).toMatch("4.0 kW");
|
||||
|
||||
expect(wrapper.find("[data-test-house-consumption]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-home-power]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-loadpoints]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-pv-production]").text()).toMatch("3.0 kW");
|
||||
expect(wrapper.find("[data-test-battery]").exists()).toBe(false);
|
||||
|
|
@ -87,7 +94,7 @@ describe("Energyflow.vue", () => {
|
|||
expect(wrapper.find("[data-test-self-consumption]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-pv-export]").text()).toMatch("0.0 kW");
|
||||
|
||||
expect(wrapper.find("[data-test-house-consumption]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-home-power]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-loadpoints]").text()).toMatch("7.0 kW");
|
||||
expect(wrapper.find("[data-test-pv-production]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-battery]").exists()).toBe(false);
|
||||
|
|
@ -102,6 +109,7 @@ describe("Energyflow.vue", () => {
|
|||
pvPower: 0,
|
||||
batteryConfigured: true,
|
||||
batteryPower: 0,
|
||||
homePower: 360,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -111,7 +119,7 @@ describe("Energyflow.vue", () => {
|
|||
expect(wrapper.find("[data-test-self-consumption]").text()).toMatch("0 W");
|
||||
expect(wrapper.find("[data-test-pv-export]").text()).toMatch("0 W");
|
||||
|
||||
expect(wrapper.find("[data-test-house-consumption]").text()).toMatch("360 W");
|
||||
expect(wrapper.find("[data-test-home-power]").text()).toMatch("360 W");
|
||||
expect(wrapper.find("[data-test-pv-production]").text()).toMatch("0 W");
|
||||
expect(wrapper.find("[data-test-battery]").text()).toMatch("main.energyflow.battery");
|
||||
});
|
||||
|
|
@ -126,6 +134,7 @@ describe("Energyflow.vue", () => {
|
|||
batteryPower: 234,
|
||||
batterySoC: 77,
|
||||
pvPower: 0,
|
||||
homePower: 534,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -135,7 +144,7 @@ describe("Energyflow.vue", () => {
|
|||
expect(wrapper.find("[data-test-self-consumption]").text()).toMatch("234 W");
|
||||
expect(wrapper.find("[data-test-pv-export]").text()).toMatch("0 W");
|
||||
|
||||
expect(wrapper.find("[data-test-house-consumption]").text()).toMatch("534 W");
|
||||
expect(wrapper.find("[data-test-home-power]").text()).toMatch("534 W");
|
||||
expect(wrapper.find("[data-test-pv-production]").text()).toMatch("0 W");
|
||||
expect(wrapper.find("[data-test-battery]").text()).toMatch("234 W");
|
||||
expect(wrapper.find("[data-test-battery]").text()).toMatch("77%");
|
||||
|
|
@ -151,6 +160,7 @@ describe("Energyflow.vue", () => {
|
|||
batteryConfigured: true,
|
||||
batteryPower: -1700,
|
||||
pvPower: 9000,
|
||||
homePower: 4800,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -160,7 +170,7 @@ describe("Energyflow.vue", () => {
|
|||
expect(wrapper.find("[data-test-self-consumption]").text()).toMatch("6.5 kW");
|
||||
expect(wrapper.find("[data-test-pv-export]").text()).toMatch("2.5 kW");
|
||||
|
||||
expect(wrapper.find("[data-test-house-consumption]").text()).toMatch("4.8 kW");
|
||||
expect(wrapper.find("[data-test-home-power]").text()).toMatch("4.8 kW");
|
||||
expect(wrapper.find("[data-test-pv-production]").text()).toMatch("9.0 kW");
|
||||
expect(wrapper.find("[data-test-battery]").text()).toMatch("1.7 kW");
|
||||
expect(wrapper.find("[data-test-battery]").text()).toMatch("main.energyflow.batteryCharge");
|
||||
|
|
@ -175,6 +185,7 @@ describe("Energyflow.vue", () => {
|
|||
batteryConfigured: true,
|
||||
batteryPower: 1234,
|
||||
pvPower: 378,
|
||||
homePower: 7200,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -184,9 +195,34 @@ describe("Energyflow.vue", () => {
|
|||
expect(wrapper.find("[data-test-self-consumption]").text()).toMatch("1.6 kW");
|
||||
expect(wrapper.find("[data-test-pv-export]").text()).toMatch("0.0 kW");
|
||||
|
||||
expect(wrapper.find("[data-test-house-consumption]").text()).toMatch("7.2 kW");
|
||||
expect(wrapper.find("[data-test-home-power]").text()).toMatch("7.2 kW");
|
||||
expect(wrapper.find("[data-test-pv-production]").text()).toMatch("0.4 kW");
|
||||
expect(wrapper.find("[data-test-battery]").text()).toMatch("1.2 kW");
|
||||
expect(wrapper.find("[data-test-battery]").text()).toMatch("main.energyflow.batteryDischarge");
|
||||
});
|
||||
|
||||
it("battery charge, grid import", async () => {
|
||||
const wrapper = shallowMount(Energyflow, {
|
||||
mocks,
|
||||
propsData: {
|
||||
...defaultProps,
|
||||
gridPower: 1500,
|
||||
batteryConfigured: true,
|
||||
batteryPower: -1000,
|
||||
homePower: 500,
|
||||
pvPower: 0,
|
||||
},
|
||||
});
|
||||
|
||||
await wrapper.find(".energyflow").trigger("click");
|
||||
|
||||
expect(wrapper.find("[data-test-grid-import]").text()).toMatch("1.5 kW");
|
||||
expect(wrapper.find("[data-test-self-consumption]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-pv-export]").text()).toMatch("0.0 kW");
|
||||
|
||||
expect(wrapper.find("[data-test-home-power]").text()).toMatch("0.5 kW");
|
||||
expect(wrapper.find("[data-test-pv-production]").text()).toMatch("0.0 kW");
|
||||
expect(wrapper.find("[data-test-battery]").text()).toMatch("1.0 kW");
|
||||
expect(wrapper.find("[data-test-battery]").text()).toMatch("main.energyflow.batteryCharge");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
}}</span>
|
||||
<span class="text-end text-nowrap ps-1">{{ kw(pvProduction) }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between" data-test-house-consumption>
|
||||
<div class="d-flex justify-content-between" data-test-home-power>
|
||||
<span class="details-icon text-muted"><fa-icon icon="home"></fa-icon></span>
|
||||
<span class="text-nowrap flex-grow-1">{{
|
||||
$t("main.energyflow.homePower")
|
||||
|
|
@ -159,12 +159,6 @@ export default {
|
|||
pvProduction: function () {
|
||||
return this.pvConfigured ? Math.abs(this.pvPower) : this.pvExport;
|
||||
},
|
||||
pvConsumption: function () {
|
||||
return Math.min(
|
||||
this.pvProduction,
|
||||
this.pvProduction + this.gridPower - this.batteryCharge
|
||||
);
|
||||
},
|
||||
batteryPowerAdjusted: function () {
|
||||
const batteryPowerThreshold = 50;
|
||||
return Math.abs(this.batteryPower) < batteryPowerThreshold ? 0 : this.batteryPower;
|
||||
|
|
@ -176,7 +170,9 @@ export default {
|
|||
return Math.min(0, this.batteryPowerAdjusted) * -1;
|
||||
},
|
||||
selfConsumption: function () {
|
||||
return Math.max(0, this.batteryDischarge + this.pvConsumption + this.batteryCharge);
|
||||
const ownPower = this.batteryDischarge + this.pvProduction;
|
||||
const consumption = this.homePower + this.batteryCharge + this.loadpointsPower;
|
||||
return Math.min(ownPower, consumption);
|
||||
},
|
||||
pvExport: function () {
|
||||
return Math.max(0, this.gridPower * -1);
|
||||
|
|
|
|||
|
|
@ -390,7 +390,9 @@ func (site *Site) update(lp Updater) {
|
|||
if sitePower, err := site.sitePower(); err == nil {
|
||||
lp.Update(sitePower, cheap, site.batteryBuffered)
|
||||
|
||||
homePower := site.gridPower + site.pvPower + site.batteryPower
|
||||
gridImport := math.Max(0, site.gridPower)
|
||||
|
||||
homePower := gridImport + site.pvPower + site.batteryPower
|
||||
for _, lp := range site.loadpoints {
|
||||
homePower -= lp.GetChargePower()
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
4
dist/index.html
vendored
4
dist/index.html
vendored
|
|
@ -1,4 +1,4 @@
|
|||
<!DOCTYPE html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="EV Charge Controller"><meta name="author" content="andig"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="apple-touch-icon" sizes="180x180" href="ico/apple-touch-icon.png?[[.Version]]"><link rel="icon" type="image/png" sizes="32x32" href="ico/favicon-32x32.png?[[.Version]]"><link rel="icon" type="image/png" sizes="16x16" href="ico/favicon-16x16.png?[[.Version]]"><link rel="manifest" href="ico/site.webmanifest"><link rel="mask-icon" href="ico/safari-pinned-tab.svg?[[.Version]]" color="#18191a"><link rel="shortcut icon" href="ico/favicon.ico?[[.Version]]"><meta name="apple-mobile-web-app-title" content="evcc"><meta name="application-name" content="evcc"><meta name="msapplication-TileColor" content="#18191a"><meta name="msapplication-config" content="ico/browserconfig.xml"><meta name="theme-color" content="#18191a"><title>evcc</title><link href="css/chunk-vendors.595481b7.css" rel="preload" as="style"><link href="css/index.853953e0.css" rel="preload" as="style"><link href="js/chunk-vendors.d0133034.js" rel="preload" as="script"><link href="js/index.bf5040bb.js" rel="preload" as="script"><link href="css/chunk-vendors.595481b7.css" rel="stylesheet"><link href="css/index.853953e0.css" rel="stylesheet"></head><body><script>window.evcc = {
|
||||
<!DOCTYPE html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="EV Charge Controller"><meta name="author" content="andig"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="apple-touch-icon" sizes="180x180" href="ico/apple-touch-icon.png?[[.Version]]"><link rel="icon" type="image/png" sizes="32x32" href="ico/favicon-32x32.png?[[.Version]]"><link rel="icon" type="image/png" sizes="16x16" href="ico/favicon-16x16.png?[[.Version]]"><link rel="manifest" href="ico/site.webmanifest"><link rel="mask-icon" href="ico/safari-pinned-tab.svg?[[.Version]]" color="#18191a"><link rel="shortcut icon" href="ico/favicon.ico?[[.Version]]"><meta name="apple-mobile-web-app-title" content="evcc"><meta name="application-name" content="evcc"><meta name="msapplication-TileColor" content="#18191a"><meta name="msapplication-config" content="ico/browserconfig.xml"><meta name="theme-color" content="#18191a"><title>evcc</title><link href="css/chunk-vendors.595481b7.css" rel="preload" as="style"><link href="css/index.364185a8.css" rel="preload" as="style"><link href="js/chunk-vendors.d0133034.js" rel="preload" as="script"><link href="js/index.daf0bdf4.js" rel="preload" as="script"><link href="css/chunk-vendors.595481b7.css" rel="stylesheet"><link href="css/index.364185a8.css" rel="stylesheet"></head><body><script>window.evcc = {
|
||||
version: "[[.Version]]",
|
||||
configured: "[[.Configured]]",
|
||||
};</script><div id="app"></div><script src="js/chunk-vendors.d0133034.js"></script><script src="js/index.bf5040bb.js"></script></body></html>
|
||||
};</script><div id="app"></div><script src="js/chunk-vendors.d0133034.js"></script><script src="js/index.daf0bdf4.js"></script></body></html>
|
||||
2
dist/js/index.bf5040bb.js
vendored
2
dist/js/index.bf5040bb.js
vendored
File diff suppressed because one or more lines are too long
1
dist/js/index.bf5040bb.js.map
vendored
1
dist/js/index.bf5040bb.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/js/index.daf0bdf4.js
vendored
Normal file
2
dist/js/index.daf0bdf4.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/js/index.daf0bdf4.js.map
vendored
Normal file
1
dist/js/index.daf0bdf4.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue