Added sum values of all inverters to web UI
This commit is contained in:
parent
69b675bc64
commit
438ce36bab
@ -14,6 +14,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
void generateJsonResponse(JsonVariant& root);
|
void generateJsonResponse(JsonVariant& root);
|
||||||
void addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId, String topic = "");
|
void addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId, String topic = "");
|
||||||
|
void addTotalField(JsonObject& root, String name, float value, String unit, uint8_t digits);
|
||||||
void onLivedataStatus(AsyncWebServerRequest* request);
|
void onLivedataStatus(AsyncWebServerRequest* request);
|
||||||
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
|
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
|
||||||
|
|
||||||
|
|||||||
@ -74,9 +74,17 @@ void WebApiWsLiveClass::loop()
|
|||||||
void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
||||||
{
|
{
|
||||||
JsonArray invArray = root.createNestedArray("inverters");
|
JsonArray invArray = root.createNestedArray("inverters");
|
||||||
|
|
||||||
|
float totalPower = 0;
|
||||||
|
float totalYieldDay = 0;
|
||||||
|
float totalYieldTotal = 0;
|
||||||
|
|
||||||
// Loop all inverters
|
// Loop all inverters
|
||||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||||
auto inv = Hoymiles.getInverterByPos(i);
|
auto inv = Hoymiles.getInverterByPos(i);
|
||||||
|
if (inv == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
JsonObject invObject = invArray.createNestedObject();
|
JsonObject invObject = invArray.createNestedObject();
|
||||||
|
|
||||||
@ -123,7 +131,17 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
|||||||
if (inv->Statistics()->getLastUpdate() > _newestInverterTimestamp) {
|
if (inv->Statistics()->getLastUpdate() > _newestInverterTimestamp) {
|
||||||
_newestInverterTimestamp = inv->Statistics()->getLastUpdate();
|
_newestInverterTimestamp = inv->Statistics()->getLastUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalPower += inv->Statistics()->getChannelFieldValue(CH0, FLD_PAC);
|
||||||
|
totalYieldDay += inv->Statistics()->getChannelFieldValue(CH0, FLD_YD);
|
||||||
|
totalYieldTotal += inv->Statistics()->getChannelFieldValue(CH0, FLD_YT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JsonObject totalObj = root.createNestedObject("total");
|
||||||
|
// todo: Fixed hard coded name, unit and digits
|
||||||
|
addTotalField(totalObj, "Power", totalPower, "W", 1);
|
||||||
|
addTotalField(totalObj, "YieldDay", totalYieldDay, "Wh", 0);
|
||||||
|
addTotalField(totalObj, "YieldTotal", totalYieldTotal, "kWh", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebApiWsLiveClass::addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId, String topic)
|
void WebApiWsLiveClass::addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId, String topic)
|
||||||
@ -141,6 +159,13 @@ void WebApiWsLiveClass::addField(JsonObject& root, uint8_t idx, std::shared_ptr<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebApiWsLiveClass::addTotalField(JsonObject& root, String name, float value, String unit, uint8_t digits)
|
||||||
|
{
|
||||||
|
root[name]["v"] = value;
|
||||||
|
root[name]["u"] = unit;
|
||||||
|
root[name]["d"] = digits;
|
||||||
|
}
|
||||||
|
|
||||||
void WebApiWsLiveClass::onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len)
|
void WebApiWsLiveClass::onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len)
|
||||||
{
|
{
|
||||||
if (type == WS_EVT_CONNECT) {
|
if (type == WS_EVT_CONNECT) {
|
||||||
|
|||||||
55
webapp/src/components/InverterTotalInfo.vue
Normal file
55
webapp/src/components/InverterTotalInfo.vue
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<template>
|
||||||
|
<div class="row row-cols-1 row-cols-md-3 g-3">
|
||||||
|
<div class="col">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header text-bg-success">Total Yield Total</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="card-text text-center">
|
||||||
|
<h2>{{ formatNumber(totalData.YieldTotal.v, totalData.YieldTotal.d) }}
|
||||||
|
<small class="text-muted">{{ totalData.YieldTotal.u }}</small>
|
||||||
|
</h2>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header text-bg-success">Total Yield Day</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="card-text text-center">
|
||||||
|
<h2>{{ formatNumber(totalData.YieldDay.v, totalData.YieldDay.d) }}
|
||||||
|
<small class="text-muted">{{ totalData.YieldDay.u }}</small>
|
||||||
|
</h2>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header text-bg-success">Total Power</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="card-text text-center">
|
||||||
|
<h2>{{ formatNumber(totalData.Power.v, totalData.Power.d) }}
|
||||||
|
<small class="text-muted">{{ totalData.Power.u }}</small>
|
||||||
|
</h2>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, type PropType } from 'vue';
|
||||||
|
import type { Total } from '@/types/LiveDataStatus';
|
||||||
|
import { formatNumber } from '@/utils';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
totalData: { type: Object as PropType<Total>, required: true },
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatNumber,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@ -31,6 +31,13 @@ export interface Inverter {
|
|||||||
[key: number]: InverterStatistics,
|
[key: number]: InverterStatistics,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface Total {
|
||||||
|
Power: ValueObject,
|
||||||
|
YieldDay: ValueObject,
|
||||||
|
YieldTotal: ValueObject,
|
||||||
|
};
|
||||||
|
|
||||||
export interface LiveData {
|
export interface LiveData {
|
||||||
inverters: Inverter[],
|
inverters: Inverter[],
|
||||||
|
total: Total,
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<BasePage :title="'Live Data'" :isLoading="dataLoading" :isWideScreen="true">
|
<BasePage :title="'Live Data'" :isLoading="dataLoading" :isWideScreen="true">
|
||||||
|
<InverterTotalInfo :totalData="liveData.total" /><br />
|
||||||
<div class="row gy-3">
|
<div class="row gy-3">
|
||||||
<div class="col-sm-3 col-md-2" :style="[inverterData.length == 1 ? { 'display': 'none' } : {}]">
|
<div class="col-sm-3 col-md-2" :style="[inverterData.length == 1 ? { 'display': 'none' } : {}]">
|
||||||
<div class="nav nav-pills row-cols-sm-1" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
<div class="nav nav-pills row-cols-sm-1" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||||
@ -330,6 +331,7 @@ import EventLog from '@/components/EventLog.vue';
|
|||||||
import DevInfo from '@/components/DevInfo.vue';
|
import DevInfo from '@/components/DevInfo.vue';
|
||||||
import BootstrapAlert from '@/components/BootstrapAlert.vue';
|
import BootstrapAlert from '@/components/BootstrapAlert.vue';
|
||||||
import InverterChannelInfo from "@/components/InverterChannelInfo.vue";
|
import InverterChannelInfo from "@/components/InverterChannelInfo.vue";
|
||||||
|
import InverterTotalInfo from '@/components/InverterTotalInfo.vue';
|
||||||
import type { DevInfoStatus } from '@/types/DevInfoStatus';
|
import type { DevInfoStatus } from '@/types/DevInfoStatus';
|
||||||
import type { EventlogItems } from '@/types/EventlogStatus';
|
import type { EventlogItems } from '@/types/EventlogStatus';
|
||||||
import type { LiveData, Inverter } from '@/types/LiveDataStatus';
|
import type { LiveData, Inverter } from '@/types/LiveDataStatus';
|
||||||
@ -341,6 +343,7 @@ export default defineComponent({
|
|||||||
components: {
|
components: {
|
||||||
BasePage,
|
BasePage,
|
||||||
InverterChannelInfo,
|
InverterChannelInfo,
|
||||||
|
InverterTotalInfo,
|
||||||
EventLog,
|
EventLog,
|
||||||
DevInfo,
|
DevInfo,
|
||||||
BootstrapAlert,
|
BootstrapAlert,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user