Add PV tooltip (#6226)

This commit is contained in:
andig 2023-02-17 07:46:44 +01:00 • committed by GitHub
parent 93c7c6a1fd
commit 8d18248185
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 109 additions and 65 deletions

View file

@ -14,6 +14,7 @@ import Energyflow from "./Energyflow.vue";
:loadpointsPower="4200"
:activeLoadpointsCount="3"
siteTitle="Home"
:pv="[{ power: 5000 }, { power: 2300 }]"
/>
</Variant>
<Variant title="battery and grid">

View file

@ -16,7 +16,7 @@
:pvProduction="pvProduction"
:homePower="homePower"
:batterySoc="batterySoc"
:valuesInKw="valuesInKw"
:powerInKw="powerInKw"
:vehicleIcons="vehicleIcons"
/>
</div>
@ -56,26 +56,28 @@
:name="$t('main.energyflow.pvProduction')"
icon="sun"
:power="pvProduction"
:valuesInKw="valuesInKw"
:powerTooltip="pvTooltip"
:powerInKw="powerInKw"
/>
<EnergyflowEntry
v-if="batteryConfigured"
:name="$t('main.energyflow.batteryDischarge')"
icon="battery"
:soc="batterySoc"
:power="batteryDischarge"
:valuesInKw="valuesInKw"
:tooltip="batteryTooltip"
:powerInKw="powerInKw"
:soc="batterySoc"
:details="batterySoc"
:detailsFmt="batteryFmt"
:detailsTooltip="batteryTooltip"
/>
<EnergyflowEntry
:name="$t('main.energyflow.gridImport')"
icon="powersupply"
:power="gridImport"
:valuesInKw="valuesInKw"
:price="tariffGrid"
:currency="currency"
:co2="tariffCo2"
:tooltip="detailsTooltip(tariffGrid, tariffCo2)"
:powerInKw="powerInKw"
:details="detailsValue(tariffGrid, tariffCo2)"
:detailsFmt="detailsFmt"
:detailsTooltip="detailsTooltip(tariffGrid, tariffCo2)"
/>
</div>
</div>
@ -93,11 +95,12 @@
:name="$t('main.energyflow.homePower')"
icon="home"
:power="homePower"
:valuesInKw="valuesInKw"
:price="tariffEffectivePrice"
:currency="currency"
:co2="tariffEffectiveCo2"
:tooltip="detailsTooltip(tariffEffectivePrice, tariffEffectiveCo2)"
:powerInKw="powerInKw"
:details="detailsValue(tariffEffectivePrice, tariffEffectiveCo2)"
:detailsFmt="detailsFmt"
:detailsTooltip="
detailsTooltip(tariffEffectivePrice, tariffEffectiveCo2)
"
/>
<EnergyflowEntry
:name="
@ -108,29 +111,32 @@
icon="vehicle"
:vehicleIcons="vehicleIcons"
:power="loadpointsPower"
:valuesInKw="valuesInKw"
:price="tariffEffectivePrice"
:currency="currency"
:co2="tariffEffectiveCo2"
:tooltip="detailsTooltip(tariffEffectivePrice, tariffEffectiveCo2)"
:powerInKw="powerInKw"
:details="detailsValue(tariffEffectivePrice, tariffEffectiveCo2)"
:detailsFmt="detailsFmt"
:detailsTooltip="
detailsTooltip(tariffEffectivePrice, tariffEffectiveCo2)
"
/>
<EnergyflowEntry
v-if="batteryConfigured"
:name="$t('main.energyflow.batteryCharge')"
icon="battery"
:soc="batterySoc"
:power="batteryCharge"
:valuesInKw="valuesInKw"
:tooltip="batteryTooltip"
:powerInKw="powerInKw"
:soc="batterySoc"
:details="batterySoc"
:detailsFmt="batteryFmt"
:detailsTooltip="batteryTooltip"
/>
<EnergyflowEntry
:name="$t('main.energyflow.pvExport')"
icon="powersupply"
:power="pvExport"
:valuesInKw="valuesInKw"
:price="-tariffFeedIn"
:currency="currency"
:tooltip="detailsTooltip(-tariffFeedIn)"
:powerInKw="powerInKw"
:details="detailsValue(-tariffFeedIn)"
:detailsFmt="detailsFmt"
:detailsTooltip="detailsTooltip(-tariffFeedIn)"
/>
</div>
</div>
@ -146,6 +152,7 @@ import EnergyflowEntry from "./EnergyflowEntry.vue";
import formatter from "../../mixins/formatter";
import AnimatedNumber from "../AnimatedNumber.vue";
import settings from "../../settings";
import { showGridPrice, showGridCo2 } from "../../gridDetails";
export default {
name: "Energyflow",
@ -156,6 +163,7 @@ export default {
gridPower: { type: Number, default: 0 },
homePower: { type: Number, default: 0 },
pvConfigured: Boolean,
pv: { type: Array },
pvPower: { type: Number, default: 0 },
loadpointsPower: { type: Number, default: 0 },
activeLoadpointsCount: { type: Number, default: 0 },
@ -199,7 +207,7 @@ export default {
pvExport: function () {
return Math.max(0, this.gridPower * -1);
},
valuesInKw: function () {
powerInKw: function () {
return this.gridImport + this.selfConsumption + this.pvExport > 1000;
},
inPower: function () {
@ -211,6 +219,12 @@ export default {
detailsHeight: function () {
return this.detailsOpen ? this.detailsCompleteHeight + "px" : 0;
},
pvTooltip() {
if (!Array.isArray(this.pv) || this.pv.length <= 1) {
return;
}
return this.pv.map(({ power }) => this.fmtKw(power, this.powerInKw));
},
batteryTooltip() {
if (!Array.isArray(this.battery)) {
return;
@ -221,6 +235,9 @@ export default {
return this.$t("main.energyflow.batteryTooltip", { energy, total, soc });
});
},
batteryFmt() {
return (soc) => `${Math.round(soc)}%`;
},
},
mounted() {
window.addEventListener("resize", this.updateHeight);
@ -243,8 +260,22 @@ export default {
}
return result;
},
detailsValue(price, co2) {
if (showGridPrice() && !isNaN(price)) {
return price;
}
if (showGridCo2() && !isNaN(co2)) {
return co2;
}
},
detailsFmt(value) {
if (showGridPrice()) {
return this.fmtPricePerKWh(value, this.currency, true);
}
return this.fmtCo2Short(value);
},
kw: function (watt) {
return this.fmtKw(watt, this.valuesInKw);
return this.fmtKw(watt, this.powerInKw);
},
toggleDetails: function () {
this.updateHeight();

View file

@ -10,11 +10,11 @@
</span>
<span class="text-end text-nowrap ps-1 fw-bold d-flex">
<div ref="details" class="fw-normal" data-bs-toggle="tooltip" title=" " @click.stop="">
<span v-if="showPrice()"><AnimatedNumber :to="price" :format="fmtPrice" /></span>
<span v-if="showCo2()"><AnimatedNumber :to="co2" :format="fmtCo2Short" /></span>
<span v-if="hasSoc">{{ soc }}%</span>
<AnimatedNumber v-if="details !== undefined" :to="details" :format="detailsFmt" />
</div>
<div ref="power" class="power" data-bs-toggle="tooltip" title=" " @click.stop="">
<AnimatedNumber :to="power" :format="kw" />
</div>
<AnimatedNumber :to="power" :format="kw" class="power" />
</span>
</div>
</template>
@ -28,7 +28,6 @@ import BatteryIcon from "./BatteryIcon.vue";
import formatter from "../../mixins/formatter";
import AnimatedNumber from "../AnimatedNumber.vue";
import VehicleIcon from "../VehicleIcon";
import { showGridPrice, showGridCo2 } from "../../gridDetails";
export default {
name: "EnergyflowEntry",
@ -37,17 +36,17 @@ export default {
props: {
name: { type: String },
icon: { type: String },
power: { type: Number },
soc: { type: Number },
price: { type: Number },
co2: { type: Number },
valuesInKw: { type: Boolean },
vehicleIcons: { type: Array },
currency: { type: String },
tooltip: { type: Array },
power: { type: Number },
powerTooltip: { type: Array },
powerInKw: { type: Boolean },
soc: { type: Number },
details: { type: Number },
detailsFmt: { type: Function },
detailsTooltip: { type: Array },
},
data() {
return { tooltipInstance: null };
return { powerTooltipInstance: null, detailsTooltipInstance: null };
},
computed: {
active: function () {
@ -59,42 +58,54 @@ export default {
isVehicle: function () {
return this.icon === "vehicle";
},
hasSoc: function () {
return this.isBattery && !isNaN(this.soc);
},
},
watch: {
tooltip(newVal, oldVal) {
powerTooltip(newVal, oldVal) {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
this.updateTooltip();
this.updatePowerTooltip();
}
},
detailsTooltip(newVal, oldVal) {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
this.updateDetailsTooltip();
}
},
},
mounted: function () {
this.updateTooltip();
this.updatePowerTooltip();
this.updateDetailsTooltip();
},
methods: {
showPrice() {
return showGridPrice() && !isNaN(this.price);
},
showCo2() {
return showGridCo2() && !isNaN(this.co2);
},
kw: function (watt) {
return this.fmtKw(watt, this.valuesInKw);
return this.fmtKw(watt, this.powerInKw);
},
fmtPrice: function (price) {
return this.fmtPricePerKWh(price, this.currency, true);
updatePowerTooltip() {
this.powerTooltipInstance = this.updateTooltip(
this.powerTooltipInstance,
this.powerTooltip,
this.$refs.power
);
},
updateTooltip: function () {
if (!Array.isArray(this.tooltip) || !this.tooltip.length) {
updateDetailsTooltip() {
this.detailsTooltipInstance = this.updateTooltip(
this.detailsTooltipInstance,
this.detailsTooltip,
this.$refs.details
);
},
updateTooltip: function (instance, content, ref) {
if (!Array.isArray(content) || !content.length) {
if (instance) {
instance.dispose();
}
return;
}
if (!this.tooltipInstance) {
this.tooltipInstance = new Tooltip(this.$refs.details, { html: true });
if (!instance) {
instance = new Tooltip(ref, { html: true });
}
const html = `<div class="text-end">${this.tooltip.join("<br/>")}</div>`;
this.tooltipInstance.setContent({ ".tooltip-inner": html });
const html = `<div class="text-end">${content.join("<br/>")}</div>`;
instance.setContent({ ".tooltip-inner": html });
return instance;
},
},
};

View file

@ -98,7 +98,7 @@ export default {
pvProduction: { type: Number, default: 0 },
homePower: { type: Number, default: 0 },
batterySoc: { type: Number, default: 0 },
valuesInKw: { type: Boolean, default: false },
powerInKw: { type: Boolean, default: false },
vehicleIcons: { type: Array },
},
data: function () {
@ -148,7 +148,7 @@ export default {
},
fmtBarValue: function (watt) {
const valueInKw = this.powerLabelEnoughSpace(watt);
return this.fmtKw(watt, this.valuesInKw, valueInKw);
return this.fmtKw(watt, this.powerInKw, valueInKw);
},
powerLabelAvailableSpace(power) {
if (this.totalAdjusted === 0) return 0;

View file

@ -58,6 +58,7 @@ export default {
homePower: Number,
pvConfigured: Boolean,
pvPower: Number,
pv: Array,
batteryConfigured: Boolean,
batteryPower: Number,
batterySoc: Number,