From 2c41be106e4b1412c1e1ff8b4f2759c1d58019c6 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Fri, 1 Sep 2023 19:17:12 +0200 Subject: [PATCH] Feature: Allow setting of the Reachable Threshold per inverter --- include/Configuration.h | 1 + include/defaults.h | 4 +++- lib/Hoymiles/src/inverters/InverterAbstract.cpp | 12 +++++++++++- lib/Hoymiles/src/inverters/InverterAbstract.h | 6 +++++- src/Configuration.cpp | 2 ++ src/InverterSettings.cpp | 1 + src/WebApi_inverter.cpp | 4 ++++ webapp/src/locales/de.json | 3 +++ webapp/src/locales/en.json | 3 +++ webapp/src/locales/fr.json | 3 +++ webapp/src/views/InverterAdminView.vue | 10 ++++++++++ 11 files changed, 46 insertions(+), 3 deletions(-) diff --git a/include/Configuration.h b/include/Configuration.h index c233eb5e..464fbcfb 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -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]; }; diff --git a/include/defaults.h b/include/defaults.h index e702c4ad..35753b91 100644 --- a/include/defaults.h +++ b/include/defaults.h @@ -94,4 +94,6 @@ #define DISPLAY_SCREENSAVER true #define DISPLAY_ROTATION 2U #define DISPLAY_CONTRAST 60U -#define DISPLAY_LANGUAGE 0U \ No newline at end of file +#define DISPLAY_LANGUAGE 0U + +#define REACHABLE_THRESHOLD 2U \ No newline at end of file diff --git a/lib/Hoymiles/src/inverters/InverterAbstract.cpp b/lib/Hoymiles/src/inverters/InverterAbstract.cpp index 2383f5fc..f78be233 100644 --- a/lib/Hoymiles/src/inverters/InverterAbstract.cpp +++ b/lib/Hoymiles/src/inverters/InverterAbstract.cpp @@ -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; diff --git a/lib/Hoymiles/src/inverters/InverterAbstract.h b/lib/Hoymiles/src/inverters/InverterAbstract.h index e12211d3..63a61c54 100644 --- a/lib/Hoymiles/src/inverters/InverterAbstract.h +++ b/lib/Hoymiles/src/inverters/InverterAbstract.h @@ -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; std::unique_ptr _devInfoParser; std::unique_ptr _powerCommandParser; diff --git a/src/Configuration.cpp b/src/Configuration.cpp index fdd1e1b6..d7aeba05 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -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++) { diff --git a/src/InverterSettings.cpp b/src/InverterSettings.cpp index c7318ba9..60470828 100644 --- a/src/InverterSettings.cpp +++ b/src/InverterSettings.cpp @@ -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(c), FLD_YT, config.Inverter[i].channel[c].YieldTotalOffset); diff --git a/src/WebApi_inverter.cpp b/src/WebApi_inverter.cpp index c6e692b0..ad9fd2c8 100644 --- a/src/WebApi_inverter.cpp +++ b/src/WebApi_inverter.cpp @@ -7,6 +7,7 @@ #include "MqttHandleHass.h" #include "WebApi.h" #include "WebApi_errors.h" +#include "defaults.h" #include "helper.h" #include #include @@ -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(c), FLD_YT, inverter.channel[c].YieldTotalOffset); diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 0e7e9ba5..5f4410f2 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -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 Wp 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?", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index 314f57ff..d6c74e18 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -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 Wp 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}?", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index cfd2abd3..ae6574ef 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -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 Wp 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}\" ?", diff --git a/webapp/src/views/InverterAdminView.vue b/webapp/src/views/InverterAdminView.vue index 1c94b70a..c7c798a3 100644 --- a/webapp/src/views/InverterAdminView.vue +++ b/webapp/src/views/InverterAdminView.vue @@ -88,6 +88,8 @@ }} + + + @@ -247,6 +256,7 @@ declare interface Inverter { poll_enable_night: boolean; command_enable: boolean; command_enable_night: boolean; + reachable_threshold: number; channel: Array; }