Feature: Allow setting of the Reachable Threshold per inverter

This commit is contained in:
Thomas Basler 2023-09-01 19:17:12 +02:00
parent c5f9f460cd
commit 2c41be106e
11 changed files with 46 additions and 3 deletions

View File

@ -45,6 +45,7 @@ struct INVERTER_CONFIG_T {
bool Poll_Enable_Night;
bool Command_Enable;
bool Command_Enable_Night;
uint8_t ReachableThreshold;
CHANNEL_CONFIG_T channel[INV_MAX_CHAN_COUNT];
};

View File

@ -94,4 +94,6 @@
#define DISPLAY_SCREENSAVER true
#define DISPLAY_ROTATION 2U
#define DISPLAY_CONTRAST 60U
#define DISPLAY_LANGUAGE 0U
#define DISPLAY_LANGUAGE 0U
#define REACHABLE_THRESHOLD 2U

View File

@ -73,7 +73,7 @@ bool InverterAbstract::isProducing()
bool InverterAbstract::isReachable()
{
return _enablePolling && Statistics()->getRxFailureCount() <= MAX_ONLINE_FAILURE_COUNT;
return _enablePolling && Statistics()->getRxFailureCount() <= _reachableThreshold;
}
void InverterAbstract::setEnablePolling(bool enabled)
@ -96,6 +96,16 @@ bool InverterAbstract::getEnableCommands()
return _enableCommands;
}
void InverterAbstract::setReachableThreshold(uint8_t threshold)
{
_reachableThreshold = threshold;
}
uint8_t InverterAbstract::getReachableThreshold()
{
return _reachableThreshold;
}
bool InverterAbstract::sendChangeChannelRequest()
{
return false;

View File

@ -24,7 +24,6 @@ enum {
};
#define MAX_RF_FRAGMENT_COUNT 13
#define MAX_ONLINE_FAILURE_COUNT 2
class CommandAbstract;
@ -49,6 +48,9 @@ public:
void setEnableCommands(bool enabled);
bool getEnableCommands();
void setReachableThreshold(uint8_t threshold);
uint8_t getReachableThreshold();
void clearRxFragmentBuffer();
void addRxFragment(uint8_t fragment[], uint8_t len);
uint8_t verifyAllFragments(CommandAbstract* cmd);
@ -87,6 +89,8 @@ private:
bool _enablePolling = true;
bool _enableCommands = true;
uint8_t _reachableThreshold = 3;
std::unique_ptr<AlarmLogParser> _alarmLogParser;
std::unique_ptr<DevInfoParser> _devInfoParser;
std::unique_ptr<PowerCommandParser> _powerCommandParser;

View File

@ -110,6 +110,7 @@ bool ConfigurationClass::write()
inv["poll_enable_night"] = config.Inverter[i].Poll_Enable_Night;
inv["command_enable"] = config.Inverter[i].Command_Enable;
inv["command_enable_night"] = config.Inverter[i].Command_Enable_Night;
inv["reachable_threshold"] = config.Inverter[i].ReachableThreshold;
JsonArray channel = inv.createNestedArray("channel");
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
@ -258,6 +259,7 @@ bool ConfigurationClass::read()
config.Inverter[i].Poll_Enable_Night = inv["poll_enable_night"] | true;
config.Inverter[i].Command_Enable = inv["command_enable"] | true;
config.Inverter[i].Command_Enable_Night = inv["command_enable_night"] | true;
config.Inverter[i].ReachableThreshold = inv["reachable_threshold"] | REACHABLE_THRESHOLD;
JsonArray channel = inv["channel"];
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {

View File

@ -71,6 +71,7 @@ void InverterSettingsClass::init()
config.Inverter[i].Serial);
if (inv != nullptr) {
inv->setReachableThreshold(config.Inverter[i].ReachableThreshold);
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
inv->Statistics()->setStringMaxPower(c, config.Inverter[i].channel[c].MaxChannelPower);
inv->Statistics()->setChannelFieldOffset(TYPE_DC, static_cast<ChannelNum_t>(c), FLD_YT, config.Inverter[i].channel[c].YieldTotalOffset);

View File

@ -7,6 +7,7 @@
#include "MqttHandleHass.h"
#include "WebApi.h"
#include "WebApi_errors.h"
#include "defaults.h"
#include "helper.h"
#include <AsyncJson.h>
#include <Hoymiles.h>
@ -57,6 +58,7 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request)
obj["poll_enable_night"] = config.Inverter[i].Poll_Enable_Night;
obj["command_enable"] = config.Inverter[i].Command_Enable;
obj["command_enable_night"] = config.Inverter[i].Command_Enable_Night;
obj["reachable_threshold"] = config.Inverter[i].ReachableThreshold;
auto inv = Hoymiles.getInverterBySerial(config.Inverter[i].Serial);
uint8_t max_channels;
@ -281,6 +283,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
inverter.Poll_Enable_Night = root["poll_enable_night"] | true;
inverter.Command_Enable = root["command_enable"] | true;
inverter.Command_Enable_Night = root["command_enable_night"] | true;
inverter.ReachableThreshold = root["reachable_threshold"] | REACHABLE_THRESHOLD;
arrayCount++;
}
@ -311,6 +314,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
if (inv != nullptr) {
inv->setEnablePolling(inverter.Poll_Enable);
inv->setEnableCommands(inverter.Command_Enable);
inv->setReachableThreshold(inverter.ReachableThreshold);
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
inv->Statistics()->setStringMaxPower(c, inverter.channel[c].MaxChannelPower);
inv->Statistics()->setChannelFieldOffset(TYPE_DC, static_cast<ChannelNum_t>(c), FLD_YT, inverter.channel[c].YieldTotalOffset);

View File

@ -454,6 +454,7 @@
"EditInverter": "Wechselrichter bearbeiten",
"General": "Allgemein",
"String": "String",
"Advanced": "Erweitert",
"InverterSerial": "Wechselrichter Seriennummer:",
"InverterName": "Wechselrichter Name:",
"InverterNameHint": "Hier kann ein eigener Namen für den Wechselrichter angeben werden.",
@ -469,6 +470,8 @@
"StringYtOffset": "Ertragsversatz String {num}:",
"StringYtOffsetHint": "Dieser Offset wird beim Auslesen des Gesamtertragswertes des Wechselrichters angewendet. Damit kann der Gesamtertrag des Wechselrichters auf Null gesetzt werden, wenn ein gebrauchter Wechselrichter verwendet wird.",
"InverterHint": "*) Geben Sie die W<sub>p</sub> des Ports ein, um die Einstrahlung zu errechnen.",
"ReachableThreshold": "Erreichbarkeit Schwellenwert:",
"ReachableThresholdHint": "Legt fest, wie viele Anfragen fehlschlagen dürfen, bis der Wechselrichter als unerreichbar eingestuft wird.",
"Cancel": "@:maintenancereboot.Cancel",
"Save": "@:dtuadmin.Save",
"DeleteMsg": "Soll der Wechselrichter \"{name}\" mit der Seriennummer {serial} wirklich gelöscht werden?",

View File

@ -454,6 +454,7 @@
"EditInverter": "Edit inverter",
"General": "General",
"String": "String",
"Advanced": "Advanced",
"InverterSerial": "Inverter Serial:",
"InverterName": "Inverter Name:",
"InverterNameHint": "Here you can specify a custom name for your inverter.",
@ -469,6 +470,8 @@
"StringYtOffset": "Yield total offset string {num}:",
"StringYtOffsetHint": "This offset is applied the read yield total value from the inverter. This can be used to set the yield total of the inverter to zero if a used inverter is used. But you can still try polling data.",
"InverterHint": "*) Enter the W<sub>p</sub> of the channel to calculate irradiation.",
"ReachableThreshold": "Reachable Threshold:",
"ReachableThresholdHint": "Defines how many requests are allowed to fail until the inverter is treated is not reachable.",
"Cancel": "@:maintenancereboot.Cancel",
"Save": "@:dtuadmin.Save",
"DeleteMsg": "Are you sure you want to delete the inverter \"{name}\" with serial number {serial}?",

View File

@ -454,6 +454,7 @@
"EditInverter": "Modifier l'onduleur",
"General": "Général",
"String": "Ligne",
"Advanced": "Advanced",
"InverterSerial": "Numéro de série de l'onduleur",
"InverterName": "Nom de l'onduleur :",
"InverterNameHint": "Ici, vous pouvez spécifier un nom personnalisé pour votre onduleur.",
@ -469,6 +470,8 @@
"StringYtOffset": "Décalage du rendement total de la ligne {num} :",
"StringYtOffsetHint": "Ce décalage est appliqué à la valeur de rendement total lue sur le variateur. Il peut être utilisé pour mettre le rendement total du variateur à zéro si un variateur usagé est utilisé.",
"InverterHint": "*) Entrez le W<sub>p</sub> du canal pour calculer l'irradiation.",
"ReachableThreshold": "Reachable Threshold:",
"ReachableThresholdHint": "Defines how many requests are allowed to fail until the inverter is treated is not reachable.",
"Cancel": "@:maintenancereboot.Cancel",
"Save": "@:dtuadmin.Save",
"DeleteMsg": "Êtes-vous sûr de vouloir supprimer l'onduleur \"{name}\" avec le numéro de série \"{serial}\" ?",

View File

@ -88,6 +88,8 @@
}}</button>
<button class="nav-link" id="nav-string-tab" data-bs-toggle="tab" data-bs-target="#nav-string"
type="button" role="tab" aria-controls="nav-string">{{ $t('inverteradmin.String') }}</button>
<button class="nav-link" id="nav-advanced-tab" data-bs-toggle="tab" data-bs-target="#nav-advanced"
type="button" role="tab" aria-controls="nav-advanced">{{ $t('inverteradmin.Advanced') }}</button>
</div>
</nav>
<div class="tab-content" id="nav-tabContent">
@ -174,6 +176,13 @@
<div :id="`inverter-customizer`" class="form-text" v-html="$t('inverteradmin.InverterHint')">
</div>
</div>
<div class="tab-pane fade show" id="nav-advanced" role="tabpanel" aria-labelledby="nav-advanced-tab" tabindex="0">
<InputElement :label="$t('inverteradmin.ReachableThreshold')"
v-model="selectedInverterData.reachable_threshold"
type="number" min="1" max="100"
:tooltip="$t('inverteradmin.ReachableThresholdHint')" wide />
</div>
</div>
</form>
@ -247,6 +256,7 @@ declare interface Inverter {
poll_enable_night: boolean;
command_enable: boolean;
command_enable_night: boolean;
reachable_threshold: number;
channel: Array<Channel>;
}