Feature: Inverter radio statistics (rx/tx statistics)
The statistics are shown in the WebApp and published via MQTT. Statistics are reset at midnight.
This commit is contained in:
parent
1115418ce1
commit
a54b19bf5b
@ -145,6 +145,7 @@ void HoymilesClass::loop()
|
|||||||
if (inv->getClearEventlogOnMidnight()) {
|
if (inv->getClearEventlogOnMidnight()) {
|
||||||
inv->EventLog()->clearBuffer();
|
inv->EventLog()->clearBuffer();
|
||||||
}
|
}
|
||||||
|
inv->resetRadioStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
lastWeekDay = currentWeekDay;
|
lastWeekDay = currentWeekDay;
|
||||||
|
|||||||
@ -66,16 +66,25 @@ void HoymilesRadio::handleReceivedPackage()
|
|||||||
|
|
||||||
} else if (verifyResult == FRAGMENT_ALL_MISSING_TIMEOUT) {
|
} else if (verifyResult == FRAGMENT_ALL_MISSING_TIMEOUT) {
|
||||||
Hoymiles.getMessageOutput()->println("Nothing received, resend count exeeded");
|
Hoymiles.getMessageOutput()->println("Nothing received, resend count exeeded");
|
||||||
|
// Statistics: Count RX Fail No Answer
|
||||||
|
inv->RadioStats.RxFailNoAnswer++;
|
||||||
|
|
||||||
_commandQueue.pop();
|
_commandQueue.pop();
|
||||||
_busyFlag = false;
|
_busyFlag = false;
|
||||||
|
|
||||||
} else if (verifyResult == FRAGMENT_RETRANSMIT_TIMEOUT) {
|
} else if (verifyResult == FRAGMENT_RETRANSMIT_TIMEOUT) {
|
||||||
Hoymiles.getMessageOutput()->println("Retransmit timeout");
|
Hoymiles.getMessageOutput()->println("Retransmit timeout");
|
||||||
|
// Statistics: Count RX Fail Partial Answer
|
||||||
|
inv->RadioStats.RxFailPartialAnswer++;
|
||||||
|
|
||||||
_commandQueue.pop();
|
_commandQueue.pop();
|
||||||
_busyFlag = false;
|
_busyFlag = false;
|
||||||
|
|
||||||
} else if (verifyResult == FRAGMENT_HANDLE_ERROR) {
|
} else if (verifyResult == FRAGMENT_HANDLE_ERROR) {
|
||||||
Hoymiles.getMessageOutput()->println("Packet handling error");
|
Hoymiles.getMessageOutput()->println("Packet handling error");
|
||||||
|
// Statistics: Count RX Fail Corrupt Data
|
||||||
|
inv->RadioStats.RxFailCorruptData++;
|
||||||
|
|
||||||
_commandQueue.pop();
|
_commandQueue.pop();
|
||||||
_busyFlag = false;
|
_busyFlag = false;
|
||||||
|
|
||||||
@ -83,17 +92,24 @@ void HoymilesRadio::handleReceivedPackage()
|
|||||||
// Perform Retransmit
|
// Perform Retransmit
|
||||||
Hoymiles.getMessageOutput()->print("Request retransmit: ");
|
Hoymiles.getMessageOutput()->print("Request retransmit: ");
|
||||||
Hoymiles.getMessageOutput()->println(verifyResult);
|
Hoymiles.getMessageOutput()->println(verifyResult);
|
||||||
|
// Statistics: Count TX Re-Request Fragment
|
||||||
|
inv->RadioStats.TxReRequestFragment++;
|
||||||
|
|
||||||
sendRetransmitPacket(verifyResult);
|
sendRetransmitPacket(verifyResult);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Successful received all packages
|
// Successful received all packages
|
||||||
Hoymiles.getMessageOutput()->println("Success");
|
Hoymiles.getMessageOutput()->println("Success");
|
||||||
|
// Statistics: Count RX Success
|
||||||
|
inv->RadioStats.RxSuccess++;
|
||||||
|
|
||||||
_commandQueue.pop();
|
_commandQueue.pop();
|
||||||
_busyFlag = false;
|
_busyFlag = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If inverter was not found, assume the command is invalid
|
// If inverter was not found, assume the command is invalid
|
||||||
Hoymiles.getMessageOutput()->println("RX: Invalid inverter found");
|
Hoymiles.getMessageOutput()->println("RX: Invalid inverter found");
|
||||||
|
// Statistics: Count RX Fail Unknown Data
|
||||||
_commandQueue.pop();
|
_commandQueue.pop();
|
||||||
_busyFlag = false;
|
_busyFlag = false;
|
||||||
}
|
}
|
||||||
@ -105,6 +121,9 @@ void HoymilesRadio::handleReceivedPackage()
|
|||||||
auto inv = Hoymiles.getInverterBySerial(cmd->getTargetAddress());
|
auto inv = Hoymiles.getInverterBySerial(cmd->getTargetAddress());
|
||||||
if (nullptr != inv) {
|
if (nullptr != inv) {
|
||||||
inv->clearRxFragmentBuffer();
|
inv->clearRxFragmentBuffer();
|
||||||
|
// Statistics: TX Requests
|
||||||
|
inv->RadioStats.TxRequestData++;
|
||||||
|
|
||||||
sendEsbPacket(*cmd);
|
sendEsbPacket(*cmd);
|
||||||
} else {
|
} else {
|
||||||
Hoymiles.getMessageOutput()->println("TX: Invalid inverter found");
|
Hoymiles.getMessageOutput()->println("TX: Invalid inverter found");
|
||||||
|
|||||||
@ -272,3 +272,8 @@ uint8_t InverterAbstract::verifyAllFragments(CommandAbstract& cmd)
|
|||||||
|
|
||||||
return FRAGMENT_OK;
|
return FRAGMENT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InverterAbstract::resetRadioStats()
|
||||||
|
{
|
||||||
|
RadioStats = {};
|
||||||
|
}
|
||||||
|
|||||||
@ -65,6 +65,28 @@ public:
|
|||||||
void addRxFragment(const uint8_t fragment[], const uint8_t len);
|
void addRxFragment(const uint8_t fragment[], const uint8_t len);
|
||||||
uint8_t verifyAllFragments(CommandAbstract& cmd);
|
uint8_t verifyAllFragments(CommandAbstract& cmd);
|
||||||
|
|
||||||
|
void resetRadioStats();
|
||||||
|
|
||||||
|
struct {
|
||||||
|
// TX Request Data
|
||||||
|
uint32_t TxRequestData;
|
||||||
|
|
||||||
|
// TX Re-Request Fragment
|
||||||
|
uint32_t TxReRequestFragment;
|
||||||
|
|
||||||
|
// RX Success
|
||||||
|
uint32_t RxSuccess;
|
||||||
|
|
||||||
|
// RX Fail Partial Answer
|
||||||
|
uint32_t RxFailPartialAnswer;
|
||||||
|
|
||||||
|
// RX Fail No Answer
|
||||||
|
uint32_t RxFailNoAnswer;
|
||||||
|
|
||||||
|
// RX Fail Corrupt Data
|
||||||
|
uint32_t RxFailCorruptData;
|
||||||
|
} RadioStats = {};
|
||||||
|
|
||||||
virtual bool sendStatsRequest() = 0;
|
virtual bool sendStatsRequest() = 0;
|
||||||
virtual bool sendAlarmLogRequest(const bool force = false) = 0;
|
virtual bool sendAlarmLogRequest(const bool force = false) = 0;
|
||||||
virtual bool sendDevInfoRequest() = 0;
|
virtual bool sendDevInfoRequest() = 0;
|
||||||
|
|||||||
@ -50,6 +50,14 @@ void MqttHandleInverterClass::loop()
|
|||||||
// Name
|
// Name
|
||||||
MqttSettings.publish(subtopic + "/name", inv->name());
|
MqttSettings.publish(subtopic + "/name", inv->name());
|
||||||
|
|
||||||
|
// Radio Statistics
|
||||||
|
MqttSettings.publish(subtopic + "/radio/tx_request", String(inv->RadioStats.TxRequestData));
|
||||||
|
MqttSettings.publish(subtopic + "/radio/tx_re_request", String(inv->RadioStats.TxReRequestFragment));
|
||||||
|
MqttSettings.publish(subtopic + "/radio/rx_success", String(inv->RadioStats.RxSuccess));
|
||||||
|
MqttSettings.publish(subtopic + "/radio/rx_fail_nothing", String(inv->RadioStats.RxFailNoAnswer));
|
||||||
|
MqttSettings.publish(subtopic + "/radio/rx_fail_partial", String(inv->RadioStats.RxFailPartialAnswer));
|
||||||
|
MqttSettings.publish(subtopic + "/radio/rx_fail_corrupt", String(inv->RadioStats.RxFailCorruptData));
|
||||||
|
|
||||||
if (inv->DevInfo()->getLastUpdate() > 0) {
|
if (inv->DevInfo()->getLastUpdate() > 0) {
|
||||||
// Bootloader Version
|
// Bootloader Version
|
||||||
MqttSettings.publish(subtopic + "/device/bootloaderversion", String(inv->DevInfo()->getFwBootloaderVersion()));
|
MqttSettings.publish(subtopic + "/device/bootloaderversion", String(inv->DevInfo()->getFwBootloaderVersion()));
|
||||||
|
|||||||
@ -134,6 +134,12 @@ void WebApiWsLiveClass::generateInverterCommonJsonResponse(JsonObject& root, std
|
|||||||
} else {
|
} else {
|
||||||
root["limit_absolute"] = -1;
|
root["limit_absolute"] = -1;
|
||||||
}
|
}
|
||||||
|
root["radio_stats"]["tx_request"] = inv->RadioStats.TxRequestData;
|
||||||
|
root["radio_stats"]["tx_re_request"] = inv->RadioStats.TxReRequestFragment;
|
||||||
|
root["radio_stats"]["rx_success"] = inv->RadioStats.RxSuccess;
|
||||||
|
root["radio_stats"]["rx_fail_nothing"] = inv->RadioStats.RxFailNoAnswer;
|
||||||
|
root["radio_stats"]["rx_fail_partial"] = inv->RadioStats.RxFailPartialAnswer;
|
||||||
|
root["radio_stats"]["rx_fail_corrupt"] = inv->RadioStats.RxFailCorruptData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebApiWsLiveClass::generateInverterChannelJsonResponse(JsonObject& root, std::shared_ptr<InverterAbstract> inv)
|
void WebApiWsLiveClass::generateInverterChannelJsonResponse(JsonObject& root, std::shared_ptr<InverterAbstract> inv)
|
||||||
|
|||||||
@ -141,7 +141,14 @@
|
|||||||
"Unknown": "Unbekannt",
|
"Unknown": "Unbekannt",
|
||||||
"ShowGridProfile": "Zeige Grid Profil",
|
"ShowGridProfile": "Zeige Grid Profil",
|
||||||
"GridProfile": "Grid Profil",
|
"GridProfile": "Grid Profil",
|
||||||
"LoadingInverter": "Warte auf Daten... (kann bis zu 10 Sekunden dauern)"
|
"LoadingInverter": "Warte auf Daten... (kann bis zu 10 Sekunden dauern)",
|
||||||
|
"RadioStats": "Funkstatistik",
|
||||||
|
"TxRequest": "Gesendete Anfragen",
|
||||||
|
"RxSuccess": "Empfang Erfolgreich",
|
||||||
|
"RxFailNothing": "Empfang Fehler: Nichts empfangen",
|
||||||
|
"RxFailPartial": "Empfang Fehler: Teilweise empfangen",
|
||||||
|
"RxFailCorrupt": "Empfang Fehler: Beschädigt empfangen",
|
||||||
|
"TxReRequest": "Gesendete Fragment Wiederanforderungen"
|
||||||
},
|
},
|
||||||
"eventlog": {
|
"eventlog": {
|
||||||
"Start": "Beginn",
|
"Start": "Beginn",
|
||||||
|
|||||||
@ -141,7 +141,14 @@
|
|||||||
"Unknown": "Unknown",
|
"Unknown": "Unknown",
|
||||||
"ShowGridProfile": "Show Grid Profile",
|
"ShowGridProfile": "Show Grid Profile",
|
||||||
"GridProfile": "Grid Profile",
|
"GridProfile": "Grid Profile",
|
||||||
"LoadingInverter": "Waiting for data... (can take up to 10 seconds)"
|
"LoadingInverter": "Waiting for data... (can take up to 10 seconds)",
|
||||||
|
"RadioStats": "Radio Statistics",
|
||||||
|
"TxRequest": "TX Request Count",
|
||||||
|
"RxSuccess": "RX Success",
|
||||||
|
"RxFailNothing": "RX Fail: Receive Nothing",
|
||||||
|
"RxFailPartial": "RX Fail: Receive Partial",
|
||||||
|
"RxFailCorrupt": "RX Fail: Receive Corrupt",
|
||||||
|
"TxReRequest": "TX Re-Request Fragment"
|
||||||
},
|
},
|
||||||
"eventlog": {
|
"eventlog": {
|
||||||
"Start": "Start",
|
"Start": "Start",
|
||||||
|
|||||||
@ -141,7 +141,14 @@
|
|||||||
"Unknown": "Inconnu",
|
"Unknown": "Inconnu",
|
||||||
"ShowGridProfile": "Show Grid Profile",
|
"ShowGridProfile": "Show Grid Profile",
|
||||||
"GridProfile": "Grid Profile",
|
"GridProfile": "Grid Profile",
|
||||||
"LoadingInverter": "Waiting for data... (can take up to 10 seconds)"
|
"LoadingInverter": "Waiting for data... (can take up to 10 seconds)",
|
||||||
|
"RadioStats": "Radio Statistics",
|
||||||
|
"TxRequest": "TX Request Count",
|
||||||
|
"RxSuccess": "RX Success",
|
||||||
|
"RxFailNothing": "RX Fail: Receive Nothing",
|
||||||
|
"RxFailPartial": "RX Fail: Receive Partial",
|
||||||
|
"RxFailCorrupt": "RX Fail: Receive Corrupt",
|
||||||
|
"TxReRequest": "TX Re-Request Fragment"
|
||||||
},
|
},
|
||||||
"eventlog": {
|
"eventlog": {
|
||||||
"Start": "Départ",
|
"Start": "Départ",
|
||||||
|
|||||||
@ -21,6 +21,15 @@ export interface InverterStatistics {
|
|||||||
Irradiation?: ValueObject;
|
Irradiation?: ValueObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RadioStatistics {
|
||||||
|
tx_request: number;
|
||||||
|
tx_re_request: number;
|
||||||
|
rx_success: number;
|
||||||
|
rx_fail_nothing: number;
|
||||||
|
rx_fail_partial: number;
|
||||||
|
rx_fail_corrupt: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Inverter {
|
export interface Inverter {
|
||||||
serial: string;
|
serial: string;
|
||||||
name: string;
|
name: string;
|
||||||
@ -35,6 +44,7 @@ export interface Inverter {
|
|||||||
AC: InverterStatistics[];
|
AC: InverterStatistics[];
|
||||||
DC: InverterStatistics[];
|
DC: InverterStatistics[];
|
||||||
INV: InverterStatistics[];
|
INV: InverterStatistics[];
|
||||||
|
radio_stats: RadioStatistics;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Total {
|
export interface Total {
|
||||||
|
|||||||
@ -201,6 +201,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BootstrapAlert class="m-3" :show="!inverter.hasOwnProperty('INV')">
|
<BootstrapAlert class="m-3" :show="!inverter.hasOwnProperty('INV')">
|
||||||
<div class="d-flex justify-content-center align-items-center">
|
<div class="d-flex justify-content-center align-items-center">
|
||||||
<div class="spinner-border m-1" role="status">
|
<div class="spinner-border m-1" role="status">
|
||||||
@ -209,6 +210,93 @@
|
|||||||
<span>{{ $t('home.LoadingInverter') }}</span>
|
<span>{{ $t('home.LoadingInverter') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</BootstrapAlert>
|
</BootstrapAlert>
|
||||||
|
|
||||||
|
<div class="accordion mt-5" id="accordionExample">
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header">
|
||||||
|
<button
|
||||||
|
class="accordion-button collapsed"
|
||||||
|
type="button"
|
||||||
|
data-bs-toggle="collapse"
|
||||||
|
data-bs-target="#collapseStats"
|
||||||
|
aria-expanded="true"
|
||||||
|
aria-controls="collapseStats"
|
||||||
|
>
|
||||||
|
{{ $t('home.RadioStats') }}
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div
|
||||||
|
id="collapseStats"
|
||||||
|
class="accordion-collapse collapse"
|
||||||
|
data-bs-parent="#accordionExample"
|
||||||
|
>
|
||||||
|
<div class="accordion-body">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('home.TxRequest') }}</td>
|
||||||
|
<td>{{ $n(inverter.radio_stats.tx_request) }}</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('home.RxSuccess') }}</td>
|
||||||
|
<td>{{ $n(inverter.radio_stats.rx_success) }}</td>
|
||||||
|
<td>
|
||||||
|
{{
|
||||||
|
ratio(
|
||||||
|
inverter.radio_stats.rx_success,
|
||||||
|
inverter.radio_stats.tx_request
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('home.RxFailNothing') }}</td>
|
||||||
|
<td>{{ $n(inverter.radio_stats.rx_fail_nothing) }}</td>
|
||||||
|
<td>
|
||||||
|
{{
|
||||||
|
ratio(
|
||||||
|
inverter.radio_stats.rx_fail_nothing,
|
||||||
|
inverter.radio_stats.tx_request
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('home.RxFailPartial') }}</td>
|
||||||
|
<td>{{ $n(inverter.radio_stats.rx_fail_partial) }}</td>
|
||||||
|
<td>
|
||||||
|
{{
|
||||||
|
ratio(
|
||||||
|
inverter.radio_stats.rx_fail_partial,
|
||||||
|
inverter.radio_stats.tx_request
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('home.RxFailCorrupt') }}</td>
|
||||||
|
<td>{{ $n(inverter.radio_stats.rx_fail_corrupt) }}</td>
|
||||||
|
<td>
|
||||||
|
{{
|
||||||
|
ratio(
|
||||||
|
inverter.radio_stats.rx_fail_corrupt,
|
||||||
|
inverter.radio_stats.tx_request
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('home.TxReRequest') }}</td>
|
||||||
|
<td>{{ $n(inverter.radio_stats.tx_re_request) }}</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -786,6 +874,12 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
return total;
|
return total;
|
||||||
},
|
},
|
||||||
|
ratio(val_small: number, val_large: number): string {
|
||||||
|
if (val_large == 0) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return this.$n(val_small / val_large, 'percent');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user