diff --git a/include/WebApi_ws_live.h b/include/WebApi_ws_live.h index d21f376..f06faa6 100644 --- a/include/WebApi_ws_live.h +++ b/include/WebApi_ws_live.h @@ -13,7 +13,7 @@ public: private: void generateJsonResponse(JsonVariant& root); - void addField(JsonVariant& root, uint8_t idx, std::shared_ptr inv, uint8_t channel, uint8_t fieldId, String topic = ""); + void addField(JsonObject& root, uint8_t idx, std::shared_ptr inv, uint8_t channel, uint8_t fieldId, String topic = ""); void onLivedataStatus(AsyncWebServerRequest* request); void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len); diff --git a/src/WebApi_ws_live.cpp b/src/WebApi_ws_live.cpp index 1d6442a..a5c5832 100644 --- a/src/WebApi_ws_live.cpp +++ b/src/WebApi_ws_live.cpp @@ -73,48 +73,51 @@ void WebApiWsLiveClass::loop() void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root) { + JsonArray invArray = root.createNestedArray("inverters"); // Loop all inverters for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) { auto inv = Hoymiles.getInverterByPos(i); - root[i][F("serial")] = inv->serialString(); - root[i][F("name")] = inv->name(); - root[i][F("data_age")] = (millis() - inv->Statistics()->getLastUpdate()) / 1000; - root[i][F("reachable")] = inv->isReachable(); - root[i][F("producing")] = inv->isProducing(); - root[i][F("limit_relative")] = inv->SystemConfigPara()->getLimitPercent(); + JsonObject invObject = invArray.createNestedObject(); + + invObject[F("serial")] = inv->serialString(); + invObject[F("name")] = inv->name(); + invObject[F("data_age")] = (millis() - inv->Statistics()->getLastUpdate()) / 1000; + invObject[F("reachable")] = inv->isReachable(); + invObject[F("producing")] = inv->isProducing(); + invObject[F("limit_relative")] = inv->SystemConfigPara()->getLimitPercent(); if (inv->DevInfo()->getMaxPower() > 0) { - root[i][F("limit_absolute")] = inv->SystemConfigPara()->getLimitPercent() * inv->DevInfo()->getMaxPower() / 100.0; + invObject[F("limit_absolute")] = inv->SystemConfigPara()->getLimitPercent() * inv->DevInfo()->getMaxPower() / 100.0; } else { - root[i][F("limit_absolute")] = -1; + invObject[F("limit_absolute")] = -1; } // Loop all channels for (uint8_t c = 0; c <= inv->Statistics()->getChannelCount(); c++) { - addField(root, i, inv, c, FLD_PAC); - addField(root, i, inv, c, FLD_UAC); - addField(root, i, inv, c, FLD_IAC); + addField(invObject, i, inv, c, FLD_PAC); + addField(invObject, i, inv, c, FLD_UAC); + addField(invObject, i, inv, c, FLD_IAC); if (c == 0) { - addField(root, i, inv, c, FLD_PDC, F("Power DC")); + addField(invObject, i, inv, c, FLD_PDC, F("Power DC")); } else { - addField(root, i, inv, c, FLD_PDC); + addField(invObject, i, inv, c, FLD_PDC); } - addField(root, i, inv, c, FLD_UDC); - addField(root, i, inv, c, FLD_IDC); - addField(root, i, inv, c, FLD_YD); - addField(root, i, inv, c, FLD_YT); - addField(root, i, inv, c, FLD_F); - addField(root, i, inv, c, FLD_T); - addField(root, i, inv, c, FLD_PF); - addField(root, i, inv, c, FLD_PRA); - addField(root, i, inv, c, FLD_EFF); - addField(root, i, inv, c, FLD_IRR); + addField(invObject, i, inv, c, FLD_UDC); + addField(invObject, i, inv, c, FLD_IDC); + addField(invObject, i, inv, c, FLD_YD); + addField(invObject, i, inv, c, FLD_YT); + addField(invObject, i, inv, c, FLD_F); + addField(invObject, i, inv, c, FLD_T); + addField(invObject, i, inv, c, FLD_PF); + addField(invObject, i, inv, c, FLD_PRA); + addField(invObject, i, inv, c, FLD_EFF); + addField(invObject, i, inv, c, FLD_IRR); } if (inv->Statistics()->hasChannelFieldValue(CH0, FLD_EVT_LOG)) { - root[i][F("events")] = inv->EventLog()->getEntryCount(); + invObject[F("events")] = inv->EventLog()->getEntryCount(); } else { - root[i][F("events")] = -1; + invObject[F("events")] = -1; } if (inv->Statistics()->getLastUpdate() > _newestInverterTimestamp) { @@ -123,7 +126,7 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root) } } -void WebApiWsLiveClass::addField(JsonVariant& root, uint8_t idx, std::shared_ptr inv, uint8_t channel, uint8_t fieldId, String topic) +void WebApiWsLiveClass::addField(JsonObject& root, uint8_t idx, std::shared_ptr inv, uint8_t channel, uint8_t fieldId, String topic) { if (inv->Statistics()->hasChannelFieldValue(channel, fieldId)) { String chanName; @@ -132,9 +135,9 @@ void WebApiWsLiveClass::addField(JsonVariant& root, uint8_t idx, std::shared_ptr } else { chanName = topic; } - root[idx][String(channel)][chanName]["v"] = inv->Statistics()->getChannelFieldValue(channel, fieldId); - root[idx][String(channel)][chanName]["u"] = inv->Statistics()->getChannelFieldUnit(channel, fieldId); - root[idx][String(channel)][chanName]["d"] = inv->Statistics()->getChannelFieldDigits(channel, fieldId); + root[String(channel)][chanName]["v"] = inv->Statistics()->getChannelFieldValue(channel, fieldId); + root[String(channel)][chanName]["u"] = inv->Statistics()->getChannelFieldUnit(channel, fieldId); + root[String(channel)][chanName]["d"] = inv->Statistics()->getChannelFieldDigits(channel, fieldId); } } @@ -153,8 +156,8 @@ void WebApiWsLiveClass::onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketC void WebApiWsLiveClass::onLivedataStatus(AsyncWebServerRequest* request) { - AsyncJsonResponse* response = new AsyncJsonResponse(true, 40960U); - JsonVariant root = response->getRoot().as(); + AsyncJsonResponse* response = new AsyncJsonResponse(false, 40960U); + JsonVariant root = response->getRoot(); generateJsonResponse(root); diff --git a/webapp/src/types/LiveDataStatus.ts b/webapp/src/types/LiveDataStatus.ts index c004a9a..a57c0d4 100644 --- a/webapp/src/types/LiveDataStatus.ts +++ b/webapp/src/types/LiveDataStatus.ts @@ -31,4 +31,6 @@ export interface Inverter { [key: number]: InverterStatistics, }; -export interface Inverters extends Array{}; \ No newline at end of file +export interface LiveData { + inverters: Inverter[], +} \ No newline at end of file diff --git a/webapp/src/views/HomeView.vue b/webapp/src/views/HomeView.vue index 1a62185..0553633 100644 --- a/webapp/src/views/HomeView.vue +++ b/webapp/src/views/HomeView.vue @@ -332,7 +332,7 @@ import BootstrapAlert from '@/components/BootstrapAlert.vue'; import InverterChannelInfo from "@/components/InverterChannelInfo.vue"; import type { DevInfoStatus } from '@/types/DevInfoStatus'; import type { EventlogItems } from '@/types/EventlogStatus'; -import type { Inverters } from '@/types/LiveDataStatus'; +import type { LiveData, Inverter } from '@/types/LiveDataStatus'; import type { LimitStatus } from '@/types/LimitStatus'; import type { LimitConfig } from '@/types/LimitConfig'; import { formatNumber } from '@/utils'; @@ -361,7 +361,7 @@ export default defineComponent({ heartInterval: 0, dataAgeInterval: 0, dataLoading: true, - inverterData: [] as Inverters, + liveData: {} as LiveData, isFirstFetchAfterConnect: true, eventLogView: {} as bootstrap.Modal, eventLogList: {} as EventlogItems, @@ -435,6 +435,9 @@ export default defineComponent({ }, currentLimitRelative(): string { return formatNumber(this.currentLimitList.limit_relative, 2); + }, + inverterData(): Inverter[] { + return this.liveData.inverters; } }, methods: { @@ -444,7 +447,7 @@ export default defineComponent({ fetch("/api/livedata/status") .then((response) => response.json()) .then((data) => { - this.inverterData = data; + this.liveData = data; this.dataLoading = false; }); }, @@ -459,7 +462,7 @@ export default defineComponent({ this.socket.onmessage = (event) => { console.log(event); - this.inverterData = JSON.parse(event.data); + this.liveData = JSON.parse(event.data); this.dataLoading = false; this.heartCheck(); // Reset heartbeat detection };