From e3f953b300978ee7690a493913530bc6fc470573 Mon Sep 17 00:00:00 2001 From: reserve85 <111107925+reserve85@users.noreply.github.com> Date: Wed, 10 Jan 2024 09:53:00 +0100 Subject: [PATCH 1/5] add average MinPanelVoltage ## V1.66 ### script * calculates an average of the "MinPanelVoltage", rel https://github.com/reserve85/HoymilesZeroExport/issues/120 ### Config * add: `INVERTER_x`: `HOY_BATTERY_AVERAGE_CNT` --- CHANGELOG.md | 6 ++++++ HoymilesZeroExport.py | 22 +++++++++++++++++++--- HoymilesZeroExport_Config.ini | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b38f2a9..ad12a15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## V1.66 +### script +* calculates an average of the "MinPanelVoltage", rel https://github.com/reserve85/HoymilesZeroExport/issues/120 +### Config +* add: `INVERTER_x`: `HOY_BATTERY_AVERAGE_CNT` + ## V1.65 ### script * bugfix set limit retry diff --git a/HoymilesZeroExport.py b/HoymilesZeroExport.py index e2d5c5d..2fd14c8 100644 --- a/HoymilesZeroExport.py +++ b/HoymilesZeroExport.py @@ -15,7 +15,7 @@ # along with this program. If not, see . __author__ = "Tobias Kraft" -__version__ = "1.65" +__version__ = "1.66" import requests import time @@ -425,15 +425,23 @@ def GetHoymilesPanelMinVoltageOpenDTU(pInverterId): return max_value def GetHoymilesPanelMinVoltage(pInverterId): + if not hasattr(GetHoymilesPanelMinVoltage, "HoymilesPanelMinVoltageArray"): + GetHoymilesPanelMinVoltage.HoymilesPanelMinVoltageArray = [] try: if not AVAILABLE[pInverterId]: return 0 if USE_AHOY: - return GetHoymilesPanelMinVoltageAhoy(pInverterId) + HOY_PANEL_MIN_VOLTAGE_HISTORY_LIST[pInverterId].append(GetHoymilesPanelMinVoltageAhoy(pInverterId)) elif USE_OPENDTU: - return GetHoymilesPanelMinVoltageOpenDTU(pInverterId) + HOY_PANEL_MIN_VOLTAGE_HISTORY_LIST[pInverterId].append(GetHoymilesPanelMinVoltageOpenDTU(pInverterId)) else: raise Exception("Error: DTU Type not defined") + + # calculate mean over last x values + if len(HOY_PANEL_MIN_VOLTAGE_HISTORY_LIST[pInverterId]) > 5: + HOY_PANEL_MIN_VOLTAGE_HISTORY_LIST[pInverterId].pop(0) + from statistics import mean + return mean(HOY_PANEL_MIN_VOLTAGE_HISTORY_LIST[pInverterId]) except: logger.error("Exception at GetHoymilesPanelMinVoltage, Inverter %s not reachable", pInverterId) raise @@ -1063,6 +1071,8 @@ def GetPriorityMode(): HOY_BATTERY_IGNORE_PANELS = [] HOY_BATTERY_PRIORITY = [] HOY_PANEL_VOLTAGE_LIST = [] +HOY_PANEL_MIN_VOLTAGE_HISTORY_LIST = [] +HOY_BATTERY_AVERAGE_CNT = [] for i in range(INVERTER_COUNT): SERIAL_NUMBER.append(str('yet unknown')) NAME.append(str('yet unknown')) @@ -1086,11 +1096,17 @@ def GetPriorityMode(): HOY_BATTERY_IGNORE_PANELS.append(config.get('INVERTER_' + str(i + 1), 'HOY_BATTERY_IGNORE_PANELS')) HOY_BATTERY_PRIORITY.append(config.getint('INVERTER_' + str(i + 1), 'HOY_BATTERY_PRIORITY')) HOY_PANEL_VOLTAGE_LIST.append([]) + HOY_PANEL_MIN_VOLTAGE_HISTORY_LIST.append([]) + HOY_BATTERY_AVERAGE_CNT.append(config.getint('INVERTER_' + str(i + 1), 'HOY_BATTERY_AVERAGE_CNT')) SLOW_APPROX_LIMIT = CastToInt(GetMaxWattFromAllInverters() * config.getint('COMMON', 'SLOW_APPROX_LIMIT_IN_PERCENT') / 100) try: logger.info("---Init---") newLimitSetpoint = 0 + + GetHoymilesPanelMinVoltage(0) + + if USE_AHOY: CheckAhoyVersion() AHOY_FACTOR = GetAhoyLimitFactor() diff --git a/HoymilesZeroExport_Config.ini b/HoymilesZeroExport_Config.ini index 7b29449..a1ad15c 100644 --- a/HoymilesZeroExport_Config.ini +++ b/HoymilesZeroExport_Config.ini @@ -19,7 +19,7 @@ # --------------------------------------------------------------------- [VERSION] -VERSION = 1.64 +VERSION = 1.66 [SELECT_DTU] # --- define your DTU (only one) --- @@ -261,6 +261,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_2] # power rating of your inverter @@ -296,6 +298,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_3] # power rating of your inverter @@ -331,6 +335,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_4] # power rating of your inverter @@ -366,6 +372,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_5] # power rating of your inverter @@ -401,6 +409,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_6] # power rating of your inverter @@ -436,6 +446,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_7] # power rating of your inverter @@ -471,6 +483,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_8] # power rating of your inverter @@ -506,6 +520,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_9] # power rating of your inverter @@ -541,6 +557,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_10] # power rating of your inverter @@ -576,6 +594,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_11] # power rating of your inverter @@ -611,6 +631,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_12] # power rating of your inverter @@ -646,6 +668,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_13] # power rating of your inverter @@ -681,6 +705,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_14] # power rating of your inverter @@ -716,6 +742,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_15] # power rating of your inverter @@ -751,6 +779,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 [INVERTER_16] # power rating of your inverter @@ -786,6 +816,8 @@ HOY_BATTERY_IGNORE_PANELS = # set limit of 1100W -> inverter 1 is set to 1000W and inverter 2 is set to 100W # set limit of 300W -> inverter 1 is set to 300W and inverter 2 is powered off HOY_BATTERY_PRIORITY = 1 +# Number of measured values for the moving average of the min panel voltage +HOY_BATTERY_AVERAGE_CNT = 1 # grid power # ... From 19a19ba82f8d37caa31d884febf00ecda39f788b Mon Sep 17 00:00:00 2001 From: reserve85 <111107925+reserve85@users.noreply.github.com> Date: Wed, 10 Jan 2024 12:57:47 +0100 Subject: [PATCH 2/5] log average min voltage log average min voltage --- HoymilesZeroExport.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HoymilesZeroExport.py b/HoymilesZeroExport.py index 2fd14c8..98db88a 100644 --- a/HoymilesZeroExport.py +++ b/HoymilesZeroExport.py @@ -421,7 +421,6 @@ def GetHoymilesPanelMinVoltageOpenDTU(pInverterId): if (max_value is None or num > max_value): max_value = num - logger.info('Lowest panel voltage inverter "%s": %s Volt',NAME[pInverterId],max_value) return max_value def GetHoymilesPanelMinVoltage(pInverterId): @@ -441,6 +440,8 @@ def GetHoymilesPanelMinVoltage(pInverterId): if len(HOY_PANEL_MIN_VOLTAGE_HISTORY_LIST[pInverterId]) > 5: HOY_PANEL_MIN_VOLTAGE_HISTORY_LIST[pInverterId].pop(0) from statistics import mean + + logger.info('Average min-panel voltage, inverter "%s": %s Volt',NAME[pInverterId], mean(HOY_PANEL_MIN_VOLTAGE_HISTORY_LIST[pInverterId])) return mean(HOY_PANEL_MIN_VOLTAGE_HISTORY_LIST[pInverterId]) except: logger.error("Exception at GetHoymilesPanelMinVoltage, Inverter %s not reachable", pInverterId) From cbb56b33bd4c9e24f08fbc849f1f0fe70ecbda53 Mon Sep 17 00:00:00 2001 From: reserve85 <111107925+reserve85@users.noreply.github.com> Date: Mon, 22 Jan 2024 12:19:13 +0100 Subject: [PATCH 3/5] Improved LimitRetry ## V1.67 ### script * Limit-Handling improved (if not acknowledged -> retransmit) --- CHANGELOG.md | 4 ++ HoymilesZeroExport.py | 137 +++++++++++++++++++++--------------------- 2 files changed, 72 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad12a15..8bc036e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## V1.67 +### script +* Limit-Handling improved (if not acknowledged -> retransmit) + ## V1.66 ### script * calculates an average of the "MinPanelVoltage", rel https://github.com/reserve85/HoymilesZeroExport/issues/120 diff --git a/HoymilesZeroExport.py b/HoymilesZeroExport.py index 98db88a..afd5d59 100644 --- a/HoymilesZeroExport.py +++ b/HoymilesZeroExport.py @@ -15,7 +15,7 @@ # along with this program. If not, see . __author__ = "Tobias Kraft" -__version__ = "1.66" +__version__ = "1.67" import requests import time @@ -115,59 +115,61 @@ def SetLimitAhoy(pInverterId, pLimit): CURRENT_LIMIT[pInverterId] = pLimit def WaitForAckAhoy(pInverterId, pTimeoutInS): - url = f'http://{AHOY_IP}/api/inverter/id/{pInverterId}' - timeout = pTimeoutInS - timeout_start = time.time() - while time.time() < timeout_start + timeout: - time.sleep(0.5) - ParsedData = requests.get(url, timeout=pTimeoutInS).json() - ack = bool(ParsedData['power_limit_ack']) + try: + url = f'http://{AHOY_IP}/api/inverter/id/{pInverterId}' + timeout = pTimeoutInS + timeout_start = time.time() + while time.time() < timeout_start + timeout: + time.sleep(0.5) + ParsedData = requests.get(url, timeout=pTimeoutInS).json() + ack = bool(ParsedData['power_limit_ack']) + if ack: + break if ack: - break - if ack: - logger.info('Ahoy: Inverter "%s": Limit acknowledged', NAME[pInverterId]) - else: + logger.info('Ahoy: Inverter "%s": Limit acknowledged', NAME[pInverterId]) + else: + logger.info('Ahoy: Inverter "%s": Limit timeout!', NAME[pInverterId]) + return ack + except: logger.info('Ahoy: Inverter "%s": Limit timeout!', NAME[pInverterId]) - return ack + return False def WaitForAckOpenDTU(pInverterId, pTimeoutInS): - url = f'http://{OPENDTU_IP}/api/limit/status' - timeout = pTimeoutInS - timeout_start = time.time() - while time.time() < timeout_start + timeout: - time.sleep(0.5) - ParsedData = requests.get(url, auth=HTTPBasicAuth(OPENDTU_USER, OPENDTU_PASS), timeout=10).json() - ack = (ParsedData[SERIAL_NUMBER[pInverterId]]['limit_set_status'] == 'Ok') + try: + url = f'http://{OPENDTU_IP}/api/limit/status' + timeout = pTimeoutInS + timeout_start = time.time() + while time.time() < timeout_start + timeout: + time.sleep(0.5) + ParsedData = requests.get(url, auth=HTTPBasicAuth(OPENDTU_USER, OPENDTU_PASS), timeout=10).json() + ack = (ParsedData[SERIAL_NUMBER[pInverterId]]['limit_set_status'] == 'Ok') + if ack: + break if ack: - break - if ack: - logger.info('OpenDTU: Inverter "%s": Limit acknowledged', NAME[pInverterId]) - else: + logger.info('OpenDTU: Inverter "%s": Limit acknowledged', NAME[pInverterId]) + else: + logger.info('OpenDTU: Inverter "%s": Limit timeout!', NAME[pInverterId]) + return ack + except: logger.info('OpenDTU: Inverter "%s": Limit timeout!', NAME[pInverterId]) - return ack + return False def SetLimitWithPriority(pLimit): try: - if SET_LIMIT_RETRY != -1: - if not hasattr(SetLimitWithPriority, "LastLimit"): - SetLimitWithPriority.LastLimit = CastToInt(0) - if not hasattr(SetLimitWithPriority, "SameLimitCnt"): - SetLimitWithPriority.SameLimitCnt = CastToInt(0) - if not hasattr(SetLimitWithPriority, "LastLimitAck"): - SetLimitWithPriority.LastLimitAck = bool(False) - if (SetLimitWithPriority.LastLimit == CastToInt(pLimit)) and SetLimitWithPriority.LastLimitAck: - logger.info("Inverterlimit already at %s Watt",CastToInt(pLimit)) - return - if (SetLimitWithPriority.LastLimit == CastToInt(pLimit)): - SetLimitWithPriority.SameLimitCnt = SetLimitWithPriority.SameLimitCnt + 1 - else: - SetLimitWithPriority.LastLimit = CastToInt(pLimit) - SetLimitWithPriority.SameLimitCnt = 0 - if SetLimitWithPriority.SameLimitCnt >= SET_LIMIT_RETRY: - logger.info("Retry Counter exceeded: Inverterlimit already at %s Watt",CastToInt(pLimit)) - time.sleep(SET_LIMIT_DELAY_IN_SECONDS) - return + if not hasattr(SetLimitWithPriority, "LastLimit"): + SetLimitWithPriority.LastLimit = CastToInt(0) + if not hasattr(SetLimitWithPriority, "LastLimitAck"): + SetLimitWithPriority.LastLimitAck = bool(False) + + if (SetLimitWithPriority.LastLimit == CastToInt(pLimit)) and SetLimitWithPriority.LastLimitAck: + logger.info("Inverterlimit was already accepted at %s Watt",CastToInt(pLimit)) + return + if (SetLimitWithPriority.LastLimit == CastToInt(pLimit)) and not SetLimitWithPriority.LastLimitAck: + logger.info("Inverterlimit %s Watt was previously not accepted by the inverter, trying again...",CastToInt(pLimit)) + return + logger.info("setting new limit to %s Watt",CastToInt(pLimit)) + SetLimitWithPriority.LastLimit = CastToInt(pLimit) SetLimitWithPriority.LastLimitAck = True if (CastToInt(pLimit) <= GetMinWattFromAllInverters()): pLimit = 0 # set only minWatt for every inv. @@ -179,7 +181,7 @@ def SetLimitWithPriority(pLimit): LimitPrio = GetMaxWattFromAllInvertersSamePrio(j) else: LimitPrio = RemainingLimit - RemainingLimit = RemainingLimit - LimitPrio + RemainingLimit = RemainingLimit - LimitPrio for i in range(INVERTER_COUNT): if (not AVAILABLE[i]) or (not HOY_BATTERY_GOOD_VOLTAGE[i]): @@ -215,26 +217,19 @@ def SetLimit(pLimit): SetLimitWithPriority(CastToInt(pLimit)) return - if SET_LIMIT_RETRY != -1: - if not hasattr(SetLimit, "LastLimit"): - SetLimit.LastLimit = CastToInt(0) - if not hasattr(SetLimit, "SameLimitCnt"): - SetLimit.SameLimitCnt = CastToInt(0) - if not hasattr(SetLimit, "LastLimitAck"): - SetLimit.LastLimitAck = bool(False) - if (SetLimit.LastLimit == CastToInt(pLimit)) and SetLimit.LastLimitAck: - logger.info("Inverterlimit already at %s Watt",CastToInt(pLimit)) - return - if (SetLimit.LastLimit == CastToInt(pLimit)): - SetLimit.SameLimitCnt = SetLimit.SameLimitCnt + 1 - else: - SetLimit.LastLimit = CastToInt(pLimit) - SetLimit.SameLimitCnt = 0 - if SetLimit.SameLimitCnt >= SET_LIMIT_RETRY: - logger.info("Retry Counter exceeded: Inverterlimit already at %s Watt",CastToInt(pLimit)) - time.sleep(SET_LIMIT_DELAY_IN_SECONDS) - return + if not hasattr(SetLimit, "LastLimit"): + SetLimit.LastLimit = CastToInt(0) + if not hasattr(SetLimit, "LastLimitAck"): + SetLimit.LastLimitAck = bool(False) + + if (SetLimit.LastLimit == CastToInt(pLimit)) and SetLimit.LastLimitAck: + logger.info("Inverterlimit was already accepted at %s Watt",CastToInt(pLimit)) + return + if (SetLimit.LastLimit == CastToInt(pLimit)) and not SetLimit.LastLimitAck: + logger.info("Inverterlimit %s Watt was previously not accepted by the inverter, trying again...",CastToInt(pLimit)) + logger.info("setting new limit to %s Watt",CastToInt(pLimit)) + SetLimit.LastLimit = CastToInt(pLimit) SetLimit.LastLimitAck = True if (CastToInt(pLimit) <= GetMinWattFromAllInverters()): pLimit = 0 # set only minWatt for every inv. @@ -292,6 +287,14 @@ def GetHoymilesAvailable(): if AVAILABLE[i]: GetHoymilesAvailable = True if not WasAvail: + if hasattr(SetLimit, "LastLimit"): + SetLimit.LastLimit = CastToInt(0) + if hasattr(SetLimit, "LastLimitAck"): + SetLimit.LastLimitAck = bool(False) + if hasattr(SetLimitWithPriority, "LastLimit"): + SetLimitWithPriority.LastLimit = CastToInt(0) + if hasattr(SetLimitWithPriority, "LastLimitAck"): + SetLimitWithPriority.LastLimitAck = bool(False) GetHoymilesInfo() except Exception as e: AVAILABLE[i] = False @@ -304,7 +307,7 @@ def GetHoymilesAvailable(): except: logger.error('Exception at GetHoymilesAvailable') raise - + def CheckAhoyVersion(): MinVersion = '0.7.29' url = f'http://{AHOY_IP}/api/system' @@ -1104,10 +1107,6 @@ def GetPriorityMode(): try: logger.info("---Init---") newLimitSetpoint = 0 - - GetHoymilesPanelMinVoltage(0) - - if USE_AHOY: CheckAhoyVersion() AHOY_FACTOR = GetAhoyLimitFactor() From 9ff64daa915b65795bba05a52dc6dbfba1f97e49 Mon Sep 17 00:00:00 2001 From: reserve85 <111107925+reserve85@users.noreply.github.com> Date: Tue, 23 Jan 2024 11:31:07 +0100 Subject: [PATCH 4/5] Repeat limit for specific inverter ## V1.67 ### script * Only repeat limit for the specific inverter (where limit was not acknowledged) ### Config * renamed `SET_LIMIT_RETRY` to `SET_POWERSTATUS_CNT` --- CHANGELOG.md | 6 ++++++ HoymilesZeroExport.py | 23 ++++++++++++++++++----- HoymilesZeroExport_Config.ini | 6 +++--- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bc036e..2e268f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## V1.67 +### script +* Only repeat limit for the specific inverter (where limit was not acknowledged) +### Config +* renamed `SET_LIMIT_RETRY` to `SET_POWERSTATUS_CNT` + ## V1.67 ### script * Limit-Handling improved (if not acknowledged -> retransmit) diff --git a/HoymilesZeroExport.py b/HoymilesZeroExport.py index afd5d59..3d8a8ed 100644 --- a/HoymilesZeroExport.py +++ b/HoymilesZeroExport.py @@ -15,7 +15,7 @@ # along with this program. If not, see . __author__ = "Tobias Kraft" -__version__ = "1.67" +__version__ = "1.68" import requests import time @@ -226,7 +226,10 @@ def SetLimit(pLimit): logger.info("Inverterlimit was already accepted at %s Watt",CastToInt(pLimit)) return if (SetLimit.LastLimit == CastToInt(pLimit)) and not SetLimit.LastLimitAck: - logger.info("Inverterlimit %s Watt was previously not accepted by the inverter, trying again...",CastToInt(pLimit)) + logger.info("Inverterlimit %s Watt was previously not accepted by at least one inverter, trying again...",CastToInt(pLimit)) + lclRepeatLimit = True + else: + lclRepeatLimit = False logger.info("setting new limit to %s Watt",CastToInt(pLimit)) SetLimit.LastLimit = CastToInt(pLimit) @@ -243,14 +246,21 @@ def SetLimit(pLimit): logger.info('Ahoy: Inverter "%s": compensate Limit from %s Watt to %s Watt', NAME[i], CastToInt(NewLimit), CastToInt(NewLimit*HOY_COMPENSATE_WATT_FACTOR[i])) NewLimit = CastToInt(NewLimit * HOY_COMPENSATE_WATT_FACTOR[i]) NewLimit = ApplyLimitsToMaxInverterLimits(i, NewLimit) + + if lclRepeatLimit and LASTLIMITACKNOWLEDGED[i]: + continue + if USE_AHOY: SetLimitAhoy(i, NewLimit) + LASTLIMITACKNOWLEDGED[i] = True if not WaitForAckAhoy(i, SET_LIMIT_TIMEOUT_SECONDS): SetLimit.LastLimitAck = False + LASTLIMITACKNOWLEDGED[i] = False elif USE_OPENDTU: SetLimitOpenDTU(i, NewLimit) if not WaitForAckOpenDTU(i, SET_LIMIT_TIMEOUT_SECONDS): SetLimit.LastLimitAck = False + LASTLIMITACKNOWLEDGED[i] = False else: raise Exception("Error: DTU Type not defined") except: @@ -295,6 +305,7 @@ def GetHoymilesAvailable(): SetLimitWithPriority.LastLimit = CastToInt(0) if hasattr(SetLimitWithPriority, "LastLimitAck"): SetLimitWithPriority.LastLimitAck = bool(False) + LASTLIMITACKNOWLEDGED[i] = False GetHoymilesInfo() except Exception as e: AVAILABLE[i] = False @@ -474,7 +485,7 @@ def SetHoymilesPowerStatus(pInverterId, pActive): try: if not AVAILABLE[pInverterId]: return - if SET_LIMIT_RETRY != -1: + if SET_POWERSTATUS_CNT > 0: if not hasattr(SetHoymilesPowerStatus, "LastPowerStatus"): SetHoymilesPowerStatus.LastPowerStatus = [] SetHoymilesPowerStatus.LastPowerStatus = [False for i in range(INVERTER_COUNT)] @@ -486,7 +497,7 @@ def SetHoymilesPowerStatus(pInverterId, pActive): else: SetHoymilesPowerStatus.LastPowerStatus[pInverterId] = pActive SetHoymilesPowerStatus.SamePowerStatusCnt[pInverterId] = 0 - if SetHoymilesPowerStatus.SamePowerStatusCnt[pInverterId] >= SET_LIMIT_RETRY: + if SetHoymilesPowerStatus.SamePowerStatusCnt[pInverterId] > SET_POWERSTATUS_CNT: if pActive: logger.info("Retry Counter exceeded: Inverter PowerStatus already ON") else: @@ -1046,7 +1057,7 @@ def GetPriorityMode(): POLL_INTERVAL_IN_SECONDS = config.getint('COMMON', 'POLL_INTERVAL_IN_SECONDS') ON_GRID_USAGE_JUMP_TO_LIMIT_PERCENT = config.getint('COMMON', 'ON_GRID_USAGE_JUMP_TO_LIMIT_PERCENT') MAX_DIFFERENCE_BETWEEN_LIMIT_AND_OUTPUTPOWER = config.getint('COMMON', 'MAX_DIFFERENCE_BETWEEN_LIMIT_AND_OUTPUTPOWER') -SET_LIMIT_RETRY = config.getint('COMMON', 'SET_LIMIT_RETRY') +SET_POWERSTATUS_CNT = config.getint('COMMON', 'SET_POWERSTATUS_CNT') SLOW_APPROX_FACTOR_IN_PERCENT = config.getint('COMMON', 'SLOW_APPROX_FACTOR_IN_PERCENT') LOG_TEMPERATURE = config.getboolean('COMMON', 'LOG_TEMPERATURE') POWERMETER_TARGET_POINT = config.getint('CONTROL', 'POWERMETER_TARGET_POINT') @@ -1063,6 +1074,7 @@ def GetPriorityMode(): HOY_MIN_WATT = [] CURRENT_LIMIT = [] AVAILABLE = [] +LASTLIMITACKNOWLEDGED = [] HOY_BATTERY_GOOD_VOLTAGE = [] HOY_COMPENSATE_WATT_FACTOR = [] HOY_BATTERY_MODE = [] @@ -1086,6 +1098,7 @@ def GetPriorityMode(): HOY_MIN_WATT.append(int(HOY_MAX_WATT[i] * config.getint('INVERTER_' + str(i + 1), 'HOY_MIN_WATT_IN_PERCENT') / 100)) CURRENT_LIMIT.append(int(0)) AVAILABLE.append(bool(False)) + LASTLIMITACKNOWLEDGED.append(bool(False)) HOY_BATTERY_GOOD_VOLTAGE.append(bool(True)) HOY_BATTERY_MODE.append(config.getboolean('INVERTER_' + str(i + 1), 'HOY_BATTERY_MODE')) HOY_BATTERY_THRESHOLD_OFF_LIMIT_IN_V.append(config.getfloat('INVERTER_' + str(i + 1), 'HOY_BATTERY_THRESHOLD_OFF_LIMIT_IN_V')) diff --git a/HoymilesZeroExport_Config.ini b/HoymilesZeroExport_Config.ini index a1ad15c..6f80e06 100644 --- a/HoymilesZeroExport_Config.ini +++ b/HoymilesZeroExport_Config.ini @@ -19,7 +19,7 @@ # --------------------------------------------------------------------- [VERSION] -VERSION = 1.66 +VERSION = 1.68 [SELECT_DTU] # --- define your DTU (only one) --- @@ -208,8 +208,8 @@ MAX_DIFFERENCE_BETWEEN_LIMIT_AND_OUTPUTPOWER = 100 ENABLE_LOG_TO_FILE = false # how many logfiles you wish to keep LOG_BACKUP_COUNT = 30 -# defines how often a identical limit will be set, set it to "-1" for disabled (infinite repeat) -SET_LIMIT_RETRY = 10 +# defines how often the Inverter Power Status will be set, set it to "-1" for disabled (infinite repeat) +SET_POWERSTATUS_CNT = 10 # log the inverter temperature LOG_TEMPERATURE = false # delay time after turning the inverter off or on From 6f0f941c4dbdb09fc1f9576226591925a654811a Mon Sep 17 00:00:00 2001 From: reserve85 <111107925+reserve85@users.noreply.github.com> Date: Tue, 23 Jan 2024 14:43:52 +0100 Subject: [PATCH 5/5] fix limit retry ## V1.69 ### script * try to fix: Only repeat limit for the specific inverter (where limit was not acknowledged) --- CHANGELOG.md | 6 +++++- HoymilesZeroExport.py | 28 ++++++++++++++++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e268f5..daaeb25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog -## V1.67 +## V1.69 +### script +* try to fix: Only repeat limit for the specific inverter (where limit was not acknowledged) + +## V1.68 ### script * Only repeat limit for the specific inverter (where limit was not acknowledged) ### Config diff --git a/HoymilesZeroExport.py b/HoymilesZeroExport.py index 3d8a8ed..2c0f446 100644 --- a/HoymilesZeroExport.py +++ b/HoymilesZeroExport.py @@ -15,7 +15,7 @@ # along with this program. If not, see . __author__ = "Tobias Kraft" -__version__ = "1.68" +__version__ = "1.69" import requests import time @@ -166,7 +166,6 @@ def SetLimitWithPriority(pLimit): return if (SetLimitWithPriority.LastLimit == CastToInt(pLimit)) and not SetLimitWithPriority.LastLimitAck: logger.info("Inverterlimit %s Watt was previously not accepted by the inverter, trying again...",CastToInt(pLimit)) - return logger.info("setting new limit to %s Watt",CastToInt(pLimit)) SetLimitWithPriority.LastLimit = CastToInt(pLimit) @@ -182,28 +181,35 @@ def SetLimitWithPriority(pLimit): else: LimitPrio = RemainingLimit RemainingLimit = RemainingLimit - LimitPrio - + for i in range(INVERTER_COUNT): if (not AVAILABLE[i]) or (not HOY_BATTERY_GOOD_VOLTAGE[i]): continue if HOY_BATTERY_PRIORITY[i] != j: continue - Factor = HOY_MAX_WATT[i] / GetMaxWattFromAllInvertersSamePrio(j) - + Factor = HOY_MAX_WATT[i] / GetMaxWattFromAllInvertersSamePrio(j) NewLimit = CastToInt(LimitPrio*Factor) NewLimit = ApplyLimitsToSetpointInverter(i, NewLimit) if HOY_COMPENSATE_WATT_FACTOR[i] != 1: logger.info('Ahoy: Inverter "%s": compensate Limit from %s Watt to %s Watt', NAME[i], CastToInt(NewLimit), CastToInt(NewLimit*HOY_COMPENSATE_WATT_FACTOR[i])) NewLimit = CastToInt(NewLimit * HOY_COMPENSATE_WATT_FACTOR[i]) NewLimit = ApplyLimitsToMaxInverterLimits(i, NewLimit) + + if (NewLimit == CastToInt(CURRENT_LIMIT[i])) and LASTLIMITACKNOWLEDGED[i]: + continue + + LASTLIMITACKNOWLEDGED[i] = True + if USE_AHOY: SetLimitAhoy(i, NewLimit) if not WaitForAckAhoy(i, SET_LIMIT_TIMEOUT_SECONDS): SetLimitWithPriority.LastLimitAck = False + LASTLIMITACKNOWLEDGED[i] = False elif USE_OPENDTU: SetLimitOpenDTU(i, NewLimit) if not WaitForAckOpenDTU(i, SET_LIMIT_TIMEOUT_SECONDS): SetLimitWithPriority.LastLimitAck = False + LASTLIMITACKNOWLEDGED[i] = False else: raise Exception("Error: DTU Type not defined") except: @@ -227,9 +233,6 @@ def SetLimit(pLimit): return if (SetLimit.LastLimit == CastToInt(pLimit)) and not SetLimit.LastLimitAck: logger.info("Inverterlimit %s Watt was previously not accepted by at least one inverter, trying again...",CastToInt(pLimit)) - lclRepeatLimit = True - else: - lclRepeatLimit = False logger.info("setting new limit to %s Watt",CastToInt(pLimit)) SetLimit.LastLimit = CastToInt(pLimit) @@ -246,13 +249,14 @@ def SetLimit(pLimit): logger.info('Ahoy: Inverter "%s": compensate Limit from %s Watt to %s Watt', NAME[i], CastToInt(NewLimit), CastToInt(NewLimit*HOY_COMPENSATE_WATT_FACTOR[i])) NewLimit = CastToInt(NewLimit * HOY_COMPENSATE_WATT_FACTOR[i]) NewLimit = ApplyLimitsToMaxInverterLimits(i, NewLimit) - - if lclRepeatLimit and LASTLIMITACKNOWLEDGED[i]: + + if (NewLimit == CastToInt(CURRENT_LIMIT[i])) and LASTLIMITACKNOWLEDGED[i]: continue - + + LASTLIMITACKNOWLEDGED[i] = True + if USE_AHOY: SetLimitAhoy(i, NewLimit) - LASTLIMITACKNOWLEDGED[i] = True if not WaitForAckAhoy(i, SET_LIMIT_TIMEOUT_SECONDS): SetLimit.LastLimitAck = False LASTLIMITACKNOWLEDGED[i] = False