VE.Direct live view enhancements (#269)
* add calculated values to VE.Direct data solar current, battery output power, and the charger's efficiency can be calculated from the values reported by the charger. the efficiency must be taken with a grain of salt. it seems that the solar power value and the battery output voltage/current are not always in sync. for that reason a moving average is used to smooth out the calculated efficiency value. * show calculated VE.Direct values in web live view order the values and translations similarly for the input and output, starting with power at the top, then voltage, then current as the last of these three. * VE.Direct live view: use 'd' as unit for days 'd' is the SI unit symbol for days and does not need translation, which is desirable as units are not translated throughout the project. * refactor VE.Direct live view * move Dynamic Power Limiter data into its own type. * split VE.Direct data into three types: "device", "input", and "output". hence all input and output values are now ValueObject, which allows to iterate over them using a loop without typing issues. * generate the tables with input and output values using a loop, rather than defining each row individually. * localize numbers using $n (vue method), which fixes switching the number format (dot vs. comma) when switching the language. * use no decimal point for power values (they are integers), three decimal points for kWh values (charger only reports two decimal places, but three are easier to read since the unit is *kilo* Wh), one decimal point for the efficiency, and two for voltage and current. * update language tokens to avoid mapping JSON keys to language keys (use the JSON keys to access the language tokens). * re-structure language tokes so the brief keys took over from VeDirectFrameHandler always make sense (nest into "input" and "output"). * order values similarly from top to bottom: power, then voltage, then current. this is following the order of the inverters' details. * group values by type/unit (yield and max. power) and order them "newest" to "oldest" from top to bottom. * increase the DynamicJsonDocument as it was too small to hold the newly added data. * update webapp_dist to include VE.Direct live view refactoring
This commit is contained in:
parent
016e30ec00
commit
9995c1172e
@ -259,6 +259,19 @@ void VeDirectFrameHandler::textRxEvent(char * name, char * value) {
|
|||||||
*/
|
*/
|
||||||
void VeDirectFrameHandler::frameEndEvent(bool valid) {
|
void VeDirectFrameHandler::frameEndEvent(bool valid) {
|
||||||
if ( valid ) {
|
if ( valid ) {
|
||||||
|
_tmpFrame.P = _tmpFrame.V * _tmpFrame.I;
|
||||||
|
|
||||||
|
_tmpFrame.IPV = 0;
|
||||||
|
if ( _tmpFrame.VPV > 0) {
|
||||||
|
_tmpFrame.IPV = _tmpFrame.PPV / _tmpFrame.VPV;
|
||||||
|
}
|
||||||
|
|
||||||
|
_tmpFrame.E = 0;
|
||||||
|
if ( _tmpFrame.PPV > 0) {
|
||||||
|
_efficiency.addNumber(static_cast<double>(_tmpFrame.P * 100) / _tmpFrame.PPV);
|
||||||
|
_tmpFrame.E = _efficiency.getAverage();
|
||||||
|
}
|
||||||
|
|
||||||
veFrame = _tmpFrame;
|
veFrame = _tmpFrame;
|
||||||
setLastUpdate();
|
setLastUpdate();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,10 +36,13 @@ typedef struct {
|
|||||||
uint32_t OR; // off reason
|
uint32_t OR; // off reason
|
||||||
uint8_t MPPT; // state of MPP tracker
|
uint8_t MPPT; // state of MPP tracker
|
||||||
uint32_t HSDS; // day sequence number 1...365
|
uint32_t HSDS; // day sequence number 1...365
|
||||||
|
int32_t P; // battery output power in W (calculated)
|
||||||
double V; // battery voltage in V
|
double V; // battery voltage in V
|
||||||
double I; // battery current in A
|
double I; // battery current in A
|
||||||
double VPV; // panel voltage in V
|
double E; // efficiency in percent (calculated, moving average)
|
||||||
int32_t PPV; // panel power in W
|
int32_t PPV; // panel power in W
|
||||||
|
double VPV; // panel voltage in V
|
||||||
|
double IPV; // panel current in A (calculated)
|
||||||
double H19; // yield total kWh
|
double H19; // yield total kWh
|
||||||
double H20; // yield today kWh
|
double H20; // yield today kWh
|
||||||
int32_t H21; // maximum power today W
|
int32_t H21; // maximum power today W
|
||||||
@ -47,6 +50,38 @@ typedef struct {
|
|||||||
int32_t H23; // maximum power yesterday W
|
int32_t H23; // maximum power yesterday W
|
||||||
} veStruct;
|
} veStruct;
|
||||||
|
|
||||||
|
template<typename T, size_t WINDOW_SIZE>
|
||||||
|
class MovingAverage {
|
||||||
|
public:
|
||||||
|
MovingAverage()
|
||||||
|
: _sum(0)
|
||||||
|
, _index(0)
|
||||||
|
, _count(0) { }
|
||||||
|
|
||||||
|
void addNumber(T num) {
|
||||||
|
if (_count < WINDOW_SIZE) {
|
||||||
|
_count++;
|
||||||
|
} else {
|
||||||
|
_sum -= _window[_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
_window[_index] = num;
|
||||||
|
_sum += num;
|
||||||
|
_index = (_index + 1) % WINDOW_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
double getAverage() const {
|
||||||
|
if (_count == 0) { return 0.0; }
|
||||||
|
return static_cast<double>(_sum) / _count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<T, WINDOW_SIZE> _window;
|
||||||
|
T _sum;
|
||||||
|
size_t _index;
|
||||||
|
size_t _count;
|
||||||
|
};
|
||||||
|
|
||||||
class VeDirectFrameHandler {
|
class VeDirectFrameHandler {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -82,6 +117,7 @@ private:
|
|||||||
char _name[VE_MAX_VALUE_LEN]; // buffer for the field name
|
char _name[VE_MAX_VALUE_LEN]; // buffer for the field name
|
||||||
char _value[VE_MAX_VALUE_LEN]; // buffer for the field value
|
char _value[VE_MAX_VALUE_LEN]; // buffer for the field value
|
||||||
veStruct _tmpFrame{}; // private struct for received name and value pairs
|
veStruct _tmpFrame{}; // private struct for received name and value pairs
|
||||||
|
MovingAverage<double, 5> _efficiency;
|
||||||
unsigned long _pollInterval;
|
unsigned long _pollInterval;
|
||||||
unsigned long _lastPoll;
|
unsigned long _lastPoll;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -61,7 +61,7 @@ void WebApiWsVedirectLiveClass::loop()
|
|||||||
String buffer;
|
String buffer;
|
||||||
// free JsonDocument as soon as possible
|
// free JsonDocument as soon as possible
|
||||||
{
|
{
|
||||||
DynamicJsonDocument root(1024);
|
DynamicJsonDocument root(2048);
|
||||||
JsonVariant var = root;
|
JsonVariant var = root;
|
||||||
generateJsonResponse(var);
|
generateJsonResponse(var);
|
||||||
serializeJson(root, buffer);
|
serializeJson(root, buffer);
|
||||||
@ -88,47 +88,64 @@ void WebApiWsVedirectLiveClass::loop()
|
|||||||
void WebApiWsVedirectLiveClass::generateJsonResponse(JsonVariant& root)
|
void WebApiWsVedirectLiveClass::generateJsonResponse(JsonVariant& root)
|
||||||
{
|
{
|
||||||
// device info
|
// device info
|
||||||
root["data_age"] = (millis() - VeDirect.getLastUpdate() ) / 1000;
|
root["device"]["data_age"] = (millis() - VeDirect.getLastUpdate() ) / 1000;
|
||||||
root["age_critical"] = !VeDirect.isDataValid();
|
root["device"]["age_critical"] = !VeDirect.isDataValid();
|
||||||
root["PID"] = VeDirect.getPidAsString(VeDirect.veFrame.PID);
|
root["device"]["PID"] = VeDirect.getPidAsString(VeDirect.veFrame.PID);
|
||||||
root["SER"] = VeDirect.veFrame.SER;
|
root["device"]["SER"] = VeDirect.veFrame.SER;
|
||||||
root["FW"] = VeDirect.veFrame.FW;
|
root["device"]["FW"] = VeDirect.veFrame.FW;
|
||||||
root["LOAD"] = VeDirect.veFrame.LOAD == true ? "ON" : "OFF";
|
root["device"]["LOAD"] = VeDirect.veFrame.LOAD == true ? "ON" : "OFF";
|
||||||
root["CS"] = VeDirect.getCsAsString(VeDirect.veFrame.CS);
|
root["device"]["CS"] = VeDirect.getCsAsString(VeDirect.veFrame.CS);
|
||||||
root["ERR"] = VeDirect.getErrAsString(VeDirect.veFrame.ERR);
|
root["device"]["ERR"] = VeDirect.getErrAsString(VeDirect.veFrame.ERR);
|
||||||
root["OR"] = VeDirect.getOrAsString(VeDirect.veFrame.OR);
|
root["device"]["OR"] = VeDirect.getOrAsString(VeDirect.veFrame.OR);
|
||||||
root["MPPT"] = VeDirect.getMpptAsString(VeDirect.veFrame.MPPT);
|
root["device"]["MPPT"] = VeDirect.getMpptAsString(VeDirect.veFrame.MPPT);
|
||||||
root["HSDS"]["v"] = VeDirect.veFrame.HSDS;
|
root["device"]["HSDS"]["v"] = VeDirect.veFrame.HSDS;
|
||||||
root["HSDS"]["u"] = "Days";
|
root["device"]["HSDS"]["u"] = "d";
|
||||||
|
|
||||||
// battery info
|
// battery info
|
||||||
root["V"]["v"] = VeDirect.veFrame.V;
|
root["output"]["P"]["v"] = VeDirect.veFrame.P;
|
||||||
root["V"]["u"] = "V";
|
root["output"]["P"]["u"] = "W";
|
||||||
root["I"]["v"] = VeDirect.veFrame.I;
|
root["output"]["P"]["d"] = 0;
|
||||||
root["I"]["u"] = "A";
|
root["output"]["V"]["v"] = VeDirect.veFrame.V;
|
||||||
|
root["output"]["V"]["u"] = "V";
|
||||||
|
root["output"]["V"]["d"] = 2;
|
||||||
|
root["output"]["I"]["v"] = VeDirect.veFrame.I;
|
||||||
|
root["output"]["I"]["u"] = "A";
|
||||||
|
root["output"]["I"]["d"] = 2;
|
||||||
|
root["output"]["E"]["v"] = VeDirect.veFrame.E;
|
||||||
|
root["output"]["E"]["u"] = "%";
|
||||||
|
root["output"]["E"]["d"] = 1;
|
||||||
|
|
||||||
// panel info
|
// panel info
|
||||||
root["VPV"]["v"] = VeDirect.veFrame.VPV;
|
root["input"]["PPV"]["v"] = VeDirect.veFrame.PPV;
|
||||||
root["VPV"]["u"] = "V";
|
root["input"]["PPV"]["u"] = "W";
|
||||||
root["PPV"]["v"] = VeDirect.veFrame.PPV;
|
root["input"]["PPV"]["d"] = 0;
|
||||||
root["PPV"]["u"] = "W";
|
root["input"]["VPV"]["v"] = VeDirect.veFrame.VPV;
|
||||||
root["H19"]["v"] = VeDirect.veFrame.H19;
|
root["input"]["VPV"]["u"] = "V";
|
||||||
root["H19"]["u"] = "kWh";
|
root["input"]["VPV"]["d"] = 2;
|
||||||
root["H20"]["v"] = VeDirect.veFrame.H20;
|
root["input"]["IPV"]["v"] = VeDirect.veFrame.IPV;
|
||||||
root["H20"]["u"] = "kWh";
|
root["input"]["IPV"]["u"] = "A";
|
||||||
root["H21"]["v"] = VeDirect.veFrame.H21;
|
root["input"]["IPV"]["d"] = 2;
|
||||||
root["H21"]["u"] = "W";
|
root["input"]["YieldToday"]["v"] = VeDirect.veFrame.H20;
|
||||||
root["H22"]["v"] = VeDirect.veFrame.H22;
|
root["input"]["YieldToday"]["u"] = "kWh";
|
||||||
root["H22"]["u"] = "kWh";
|
root["input"]["YieldToday"]["d"] = 3;
|
||||||
root["H23"]["v"] = VeDirect.veFrame.H23;
|
root["input"]["YieldYesterday"]["v"] = VeDirect.veFrame.H22;
|
||||||
root["H23"]["u"] = "W";
|
root["input"]["YieldYesterday"]["u"] = "kWh";
|
||||||
|
root["input"]["YieldYesterday"]["d"] = 3;
|
||||||
|
root["input"]["YieldTotal"]["v"] = VeDirect.veFrame.H19;
|
||||||
|
root["input"]["YieldTotal"]["u"] = "kWh";
|
||||||
|
root["input"]["YieldTotal"]["d"] = 3;
|
||||||
|
root["input"]["MaximumPowerToday"]["v"] = VeDirect.veFrame.H21;
|
||||||
|
root["input"]["MaximumPowerToday"]["u"] = "W";
|
||||||
|
root["input"]["MaximumPowerToday"]["d"] = 0;
|
||||||
|
root["input"]["MaximumPowerYesterday"]["v"] = VeDirect.veFrame.H23;
|
||||||
|
root["input"]["MaximumPowerYesterday"]["u"] = "W";
|
||||||
|
root["input"]["MaximumPowerYesterday"]["d"] = 0;
|
||||||
|
|
||||||
// power limiter state
|
// power limiter state
|
||||||
|
root["dpl"]["PLSTATE"] = -1;
|
||||||
if (Configuration.get().PowerLimiter_Enabled)
|
if (Configuration.get().PowerLimiter_Enabled)
|
||||||
root["PLSTATE"] = PowerLimiter.getPowerLimiterState();
|
root["dpl"]["PLSTATE"] = PowerLimiter.getPowerLimiterState();
|
||||||
else
|
root["dpl"]["PLLIMIT"] = PowerLimiter.getLastRequestedPowewrLimit();
|
||||||
root["PLSTATE"] = -1;
|
|
||||||
root["PLLIMIT"] = PowerLimiter.getLastRequestedPowewrLimit();
|
|
||||||
|
|
||||||
if (VeDirect.getLastUpdate() > _newestVedirectTimestamp) {
|
if (VeDirect.getLastUpdate() > _newestVedirectTimestamp) {
|
||||||
_newestVedirectTimestamp = VeDirect.getLastUpdate();
|
_newestVedirectTimestamp = VeDirect.getLastUpdate();
|
||||||
|
|||||||
@ -34,21 +34,21 @@
|
|||||||
<div class="btn-group me-2" role="group">
|
<div class="btn-group me-2" role="group">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="btn btn-sm" v-tooltip :title="$t('vedirecthome.PowerLimiterState')">
|
class="btn btn-sm" v-tooltip :title="$t('vedirecthome.PowerLimiterState')">
|
||||||
<div v-if="vedirectData.PLSTATE == 0">
|
<div v-if="dplData.PLSTATE == 0">
|
||||||
<BIconXCircleFill style="font-size:24px;" />
|
<BIconXCircleFill style="font-size:24px;" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="vedirectData.PLSTATE == 1">
|
<div v-else-if="dplData.PLSTATE == 1">
|
||||||
<BIconBatteryCharging style="font-size:24px;" />
|
<BIconBatteryCharging style="font-size:24px;" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="vedirectData.PLSTATE == 2">
|
<div v-else-if="dplData.PLSTATE == 2">
|
||||||
<BIconSun style="font-size:24px;" />
|
<BIconSun style="font-size:24px;" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="vedirectData.PLSTATE == 3">
|
<div v-else-if="dplData.PLSTATE == 3">
|
||||||
<BIconBatteryHalf style="font-size:24px;" />
|
<BIconBatteryHalf style="font-size:24px;" />
|
||||||
</div>
|
</div>
|
||||||
<span v-if="vedirectData.PLSTATE != -1"
|
<span v-if="dplData.PLSTATE != -1"
|
||||||
class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-bg-info">
|
class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-bg-info">
|
||||||
{{ vedirectData.PLLIMIT }} W
|
{{ dplData.PLLIMIT }} W
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -119,15 +119,15 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr v-for="(prop, key) in vedirectOutput">
|
||||||
<th scope="row">{{ $t('vedirecthome.BatteryVoltage') }}</th>
|
<th scope="row">{{ $t('vedirecthome.output.' + key) }}</th>
|
||||||
<td style="text-align: right">{{formatNumber(vedirectData.V.v)}}</td>
|
<td style="text-align: right">
|
||||||
<td>{{vedirectData.V.u}}</td>
|
{{ $n(prop.v, 'decimal', {
|
||||||
</tr>
|
minimumFractionDigits: prop.d,
|
||||||
<tr>
|
maximumFractionDigits: prop.d})
|
||||||
<th scope="row">{{ $t('vedirecthome.BatteryCurrent') }}</th>
|
}}
|
||||||
<td style="text-align: right">{{formatNumber(vedirectData.I.v)}}</td>
|
</td>
|
||||||
<td>{{vedirectData.I.u}}</td>
|
<td>{{prop.u}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -149,40 +149,15 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr v-for="(prop, key) in vedirectInput">
|
||||||
<th scope="row">{{ $t('vedirecthome.PanelVoltage') }}</th>
|
<th scope="row">{{ $t('vedirecthome.input.' + key) }}</th>
|
||||||
<td style="text-align: right">{{formatNumber(vedirectData.VPV.v)}}</td>
|
<td style="text-align: right">
|
||||||
<td>{{vedirectData.VPV.u}}</td>
|
{{ $n(prop.v, 'decimal', {
|
||||||
</tr>
|
minimumFractionDigits: prop.d,
|
||||||
<tr>
|
maximumFractionDigits: prop.d})
|
||||||
<th scope="row">{{ $t('vedirecthome.PanelPower') }}</th>
|
}}
|
||||||
<td style="text-align: right">{{formatNumber(vedirectData.PPV.v)}}</td>
|
</td>
|
||||||
<td>{{vedirectData.PPV.u}}</td>
|
<td>{{prop.u}}</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ $t('vedirecthome.YieldTotal') }}</th>
|
|
||||||
<td style="text-align: right">{{formatNumber(vedirectData.H19.v)}}</td>
|
|
||||||
<td>{{vedirectData.H19.u}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ $t('vedirecthome.YieldToday') }}</th>
|
|
||||||
<td style="text-align: right">{{formatNumber(vedirectData.H20.v)}}</td>
|
|
||||||
<td>{{vedirectData.H20.u}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ $t('vedirecthome.MaximumPowerToday') }}</th>
|
|
||||||
<td style="text-align: right">{{formatNumber(vedirectData.H21.v)}}</td>
|
|
||||||
<td>{{vedirectData.H21.u}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ $t('vedirecthome.YieldYesterday') }}</th>
|
|
||||||
<td style="text-align: right">{{formatNumber(vedirectData.H22.v)}}</td>
|
|
||||||
<td>{{vedirectData.H22.u}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ $t('vedirecthome.MaximumPowerYesterday') }}</th>
|
|
||||||
<td style="text-align: right">{{formatNumber(vedirectData.H23.v)}}</td>
|
|
||||||
<td>{{vedirectData.H23.u}}</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -203,7 +178,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import type { Vedirect } from '@/types/VedirectLiveDataStatus';
|
import type { DynamicPowerLimiter, VedirectDevice, VedirectOutput, VedirectInput } from '@/types/VedirectLiveDataStatus';
|
||||||
import { handleResponse, authHeader, authUrl } from '@/utils/authentication';
|
import { handleResponse, authHeader, authUrl } from '@/utils/authentication';
|
||||||
import {
|
import {
|
||||||
BIconSun,
|
BIconSun,
|
||||||
@ -226,7 +201,10 @@ export default defineComponent({
|
|||||||
heartInterval: 0,
|
heartInterval: 0,
|
||||||
dataAgeInterval: 0,
|
dataAgeInterval: 0,
|
||||||
dataLoading: true,
|
dataLoading: true,
|
||||||
vedirectData: {} as Vedirect,
|
dplData: {} as DynamicPowerLimiter,
|
||||||
|
vedirectData: {} as VedirectDevice,
|
||||||
|
vedirectOutput: {} as VedirectOutput,
|
||||||
|
vedirectInput: {} as VedirectInput,
|
||||||
isFirstFetchAfterConnect: true,
|
isFirstFetchAfterConnect: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -244,8 +222,11 @@ export default defineComponent({
|
|||||||
this.dataLoading = true;
|
this.dataLoading = true;
|
||||||
fetch("/api/vedirectlivedata/status", { headers: authHeader() })
|
fetch("/api/vedirectlivedata/status", { headers: authHeader() })
|
||||||
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
||||||
.then((data) => {
|
.then((root) => {
|
||||||
this.vedirectData = data;
|
this.dplData = root["dpl"];
|
||||||
|
this.vedirectData = root["device"];
|
||||||
|
this.vedirectOutput = root["output"];
|
||||||
|
this.vedirectInput = root["input"];
|
||||||
this.dataLoading = false;
|
this.dataLoading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -261,7 +242,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
this.socket.onmessage = (event) => {
|
this.socket.onmessage = (event) => {
|
||||||
console.log(event);
|
console.log(event);
|
||||||
this.vedirectData = JSON.parse(event.data);
|
var root = JSON.parse(event.data);
|
||||||
|
this.dplData = root["dpl"];
|
||||||
|
this.vedirectData = root["device"];
|
||||||
|
this.vedirectOutput = root["output"];
|
||||||
|
this.vedirectInput = root["input"];
|
||||||
this.dataLoading = false;
|
this.dataLoading = false;
|
||||||
this.heartCheck(); // Reset heartbeat detection
|
this.heartCheck(); // Reset heartbeat detection
|
||||||
};
|
};
|
||||||
|
|||||||
@ -147,17 +147,24 @@
|
|||||||
"OffReason": "Grund für das Ausschalten",
|
"OffReason": "Grund für das Ausschalten",
|
||||||
"ErrorCode": "Fehlerbeschreibung",
|
"ErrorCode": "Fehlerbeschreibung",
|
||||||
"DaySequenceNumber": "Anzahl der Tage (0..364)",
|
"DaySequenceNumber": "Anzahl der Tage (0..364)",
|
||||||
"Battery": "Batterie",
|
"Battery": "Ausgang (Batterie)",
|
||||||
"BatteryVoltage": "Spannung",
|
"output": {
|
||||||
"BatteryCurrent": "Strom",
|
"P": "Leistung (berechnet)",
|
||||||
"Panel": "Panel",
|
"V": "Spannung",
|
||||||
"PanelVoltage": "Spannung",
|
"I": "Strom",
|
||||||
"PanelPower": "Leistung",
|
"E": "Effizienz (berechnet)"
|
||||||
"YieldTotal": "Gesamtertrag (durch Benutzer zurücksetzbar)",
|
},
|
||||||
"YieldToday": "Ertrag heute",
|
"Panel": "Eingang (Solarpanele)",
|
||||||
"MaximumPowerToday": "Maximale Leistung heute",
|
"input": {
|
||||||
"YieldYesterday": "Ertrag gestern",
|
"PPV": "Leistung",
|
||||||
"MaximumPowerYesterday": "Maximale Leistung gestern",
|
"VPV": "Spannung",
|
||||||
|
"IPV": "Strom (berechnet)",
|
||||||
|
"YieldToday": "Ertrag heute",
|
||||||
|
"YieldYesterday": "Ertrag gestern",
|
||||||
|
"YieldTotal": "Gesamtertrag (durch Benutzer zurücksetzbar)",
|
||||||
|
"MaximumPowerToday": "Maximale Leistung heute",
|
||||||
|
"MaximumPowerYesterday": "Maximale Leistung gestern"
|
||||||
|
},
|
||||||
"PowerLimiterState": "Power limiter Status [aus (laden), nur die Sonne nutzen, Nutzung der Batterie]"
|
"PowerLimiterState": "Power limiter Status [aus (laden), nur die Sonne nutzen, Nutzung der Batterie]"
|
||||||
},
|
},
|
||||||
"eventlog": {
|
"eventlog": {
|
||||||
|
|||||||
@ -147,17 +147,24 @@
|
|||||||
"OffReason": "Off reason",
|
"OffReason": "Off reason",
|
||||||
"ErrorCode": "Error code",
|
"ErrorCode": "Error code",
|
||||||
"DaySequenceNumber": "Day sequence number (0..364)",
|
"DaySequenceNumber": "Day sequence number (0..364)",
|
||||||
"Battery": "Battery",
|
"Battery": "Output (Battery)",
|
||||||
"BatteryVoltage": "Voltage",
|
"output": {
|
||||||
"BatteryCurrent": "Current",
|
"P": "Power (calculated)",
|
||||||
"Panel": "Panel",
|
"V": "Voltage",
|
||||||
"PanelVoltage": "Voltage",
|
"I": "Current",
|
||||||
"PanelPower": "Power",
|
"E": "Efficiency (calculated)"
|
||||||
"YieldTotal": "Yield total (user resettable counter)",
|
},
|
||||||
"YieldToday": "Yield today",
|
"Panel": "Input (Solar Panels)",
|
||||||
"MaximumPowerToday": "Maximum power today",
|
"input": {
|
||||||
"YieldYesterday": "Yield yesterday",
|
"PPV": "Power",
|
||||||
"MaximumPowerYesterday": "Maximum power yesterday",
|
"VPV": "Voltage",
|
||||||
|
"IPV": "Current (calculated)",
|
||||||
|
"YieldToday": "Yield today",
|
||||||
|
"YieldYesterday": "Yield yesterday",
|
||||||
|
"YieldTotal": "Yield total (user resettable counter)",
|
||||||
|
"MaximumPowerToday": "Maximum power today",
|
||||||
|
"MaximumPowerYesterday": "Maximum power yesterday"
|
||||||
|
},
|
||||||
"PowerLimiterState": "Power limiter state [off (charging), solar passthrough, on battery]"
|
"PowerLimiterState": "Power limiter state [off (charging), solar passthrough, on battery]"
|
||||||
},
|
},
|
||||||
"eventlog": {
|
"eventlog": {
|
||||||
|
|||||||
@ -147,17 +147,25 @@
|
|||||||
"OffReason": "Off reason",
|
"OffReason": "Off reason",
|
||||||
"ErrorCode": "Error code",
|
"ErrorCode": "Error code",
|
||||||
"DaySequenceNumber": "Day sequence number (0..364)",
|
"DaySequenceNumber": "Day sequence number (0..364)",
|
||||||
"Battery": "Battery",
|
"Battery": "Output (Battery)",
|
||||||
"BatteryVoltage": "Voltage",
|
"output": {
|
||||||
"BatteryCurrent": "Current",
|
"P": "Power (calculated)",
|
||||||
"Panel": "Panel",
|
"V": "Voltage",
|
||||||
"PanelVoltage": "Voltage",
|
"I": "Current",
|
||||||
"PanelPower": "Power",
|
"E": "Efficiency (calculated)"
|
||||||
"YieldTotal": "Yield total (user resettable counter)",
|
},
|
||||||
"YieldToday": "Yield today",
|
"Panel": "Input (Solar Panels)",
|
||||||
"MaximumPowerToday": "Maximum power today",
|
"input": {
|
||||||
"YieldYesterday": "Yield yesterday",
|
"PPV": "Power",
|
||||||
"MaximumPowerYesterday": "Maximum power yesterday"
|
"VPV": "Voltage",
|
||||||
|
"IPV": "Current (calculated)",
|
||||||
|
"YieldToday": "Yield today",
|
||||||
|
"YieldYesterday": "Yield yesterday",
|
||||||
|
"YieldTotal": "Yield total (user resettable counter)",
|
||||||
|
"MaximumPowerToday": "Maximum power today",
|
||||||
|
"MaximumPowerYesterday": "Maximum power yesterday"
|
||||||
|
},
|
||||||
|
"PowerLimiterState": "Power limiter state [off (charging), solar passthrough, on battery]"
|
||||||
},
|
},
|
||||||
"eventlog": {
|
"eventlog": {
|
||||||
"Start": "Départ",
|
"Start": "Départ",
|
||||||
@ -716,4 +724,4 @@
|
|||||||
"highVoltage": "High voltage",
|
"highVoltage": "High voltage",
|
||||||
"bmsInternal": "BMS internal"
|
"bmsInternal": "BMS internal"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
import type { ValueObject } from '@/types/LiveDataStatus';
|
import type { ValueObject } from '@/types/LiveDataStatus';
|
||||||
|
|
||||||
// Ve.Direct
|
export interface DynamicPowerLimiter {
|
||||||
export interface Vedirect {
|
PLSTATE: number;
|
||||||
|
PLLIMIT: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VedirectDevice {
|
||||||
SER: string;
|
SER: string;
|
||||||
PID: string;
|
PID: string;
|
||||||
FW: string;
|
FW: string;
|
||||||
@ -13,15 +17,22 @@ export interface Vedirect {
|
|||||||
OR: ValueObject;
|
OR: ValueObject;
|
||||||
ERR: ValueObject;
|
ERR: ValueObject;
|
||||||
HSDS: ValueObject;
|
HSDS: ValueObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VedirectOutput {
|
||||||
|
P: ValueObject;
|
||||||
V: ValueObject;
|
V: ValueObject;
|
||||||
I: ValueObject;
|
I: ValueObject;
|
||||||
VPV: ValueObject;
|
E: ValueObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VedirectInput {
|
||||||
PPV: ValueObject;
|
PPV: ValueObject;
|
||||||
|
VPV: ValueObject;
|
||||||
|
IPV: ValueObject;
|
||||||
H19: ValueObject;
|
H19: ValueObject;
|
||||||
H20: ValueObject;
|
H20: ValueObject;
|
||||||
H21: ValueObject;
|
H21: ValueObject;
|
||||||
H22: ValueObject;
|
H22: ValueObject;
|
||||||
H23: ValueObject;
|
H23: ValueObject;
|
||||||
PLSTATE: number;
|
}
|
||||||
PLLIMIT: number;
|
|
||||||
}
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user