Skip to content

Commit a623be0

Browse files
committed
add limit cross-check
added a limit cross-check (real DTU Limit is cross-checked vs. Set Limit +/- 5%) (#223)
1 parent 7094361 commit a623be0

3 files changed

Lines changed: 45 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## V 1.98
4+
### script
5+
* added a limit cross-check (real DTU Limit is cross-checked vs. Set Limit +/- 5%) (https://github.com/reserve85/HoymilesZeroExport/issues/223)
6+
37
## V 1.97
48
### script
59
* add support for MQTT meter and intermediate meter

HoymilesZeroExport.py

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1616

1717
__author__ = "Tobias Kraft"
18-
__version__ = "1.97"
18+
__version__ = "1.98"
1919

2020
import time
2121
from requests.sessions import Session
@@ -110,6 +110,7 @@ def SetLimitWithPriority(pLimit):
110110

111111
if (SetLimitWithPriority.LastLimit == CastToInt(pLimit)) and SetLimitWithPriority.LastLimitAck:
112112
logger.info("Inverterlimit was already accepted at %s Watt",CastToInt(pLimit))
113+
CrossCheckLimit()
113114
return
114115
if (SetLimitWithPriority.LastLimit == CastToInt(pLimit)) and not SetLimitWithPriority.LastLimitAck:
115116
logger.info("Inverterlimit %s Watt was previously not accepted by at least one inverter, trying again...",CastToInt(pLimit))
@@ -170,6 +171,7 @@ def SetLimitMixedModeWithPriority(pLimit):
170171

171172
if (SetLimitMixedModeWithPriority.LastLimit == CastToInt(pLimit)) and SetLimitMixedModeWithPriority.LastLimitAck:
172173
logger.info("Inverterlimit was already accepted at %s Watt",CastToInt(pLimit))
174+
CrossCheckLimit()
173175
return
174176
if (SetLimitMixedModeWithPriority.LastLimit == CastToInt(pLimit)) and not SetLimitMixedModeWithPriority.LastLimitAck:
175177
logger.info("Inverterlimit %s Watt was previously not accepted by at least one inverter, trying again...",CastToInt(pLimit))
@@ -309,6 +311,7 @@ def SetLimit(pLimit):
309311

310312
if (SetLimit.LastLimit == CastToInt(pLimit)) and SetLimit.LastLimitAck:
311313
logger.info("Inverterlimit was already accepted at %s Watt",CastToInt(pLimit))
314+
CrossCheckLimit()
312315
return
313316
if (SetLimit.LastLimit == CastToInt(pLimit)) and not SetLimit.LastLimitAck:
314317
logger.info("Inverterlimit %s Watt was previously not accepted by at least one inverter, trying again...",CastToInt(pLimit))
@@ -570,6 +573,20 @@ def ApplyLimitsToMaxInverterLimits(pInverter, pSetpoint):
570573
pSetpoint = GetMinWatt(pInverter)
571574
return pSetpoint
572575

576+
def CrossCheckLimit():
577+
try:
578+
for i in range(INVERTER_COUNT):
579+
if AVAILABLE[i]:
580+
DTULimitInW = DTU.GetActualLimitInW(i)
581+
LimitMax = float(CURRENT_LIMIT[i] + HOY_INVERTER_WATT[i] * 0.05)
582+
LimitMin = float(CURRENT_LIMIT[i] - HOY_INVERTER_WATT[i] * 0.05)
583+
if not (min(LimitMax, LimitMin) < DTULimitInW < max(LimitMax, LimitMin)):
584+
logger.info("CrossCheckLimit: DTU ({DTULimitInW:.1f}) <> SetLimit ({CURRENT_LIMIT[i]:.1f}). Resend limit to DTU")
585+
DTU.SetLimit(i, CURRENT_LIMIT[i])
586+
except:
587+
logger.error("Exception at CrossCheckLimit")
588+
raise
589+
573590
# Max possible Watts, can be reduced on battery mode
574591
def GetMaxWattFromAllInverters():
575592
maxWatt = 0
@@ -886,7 +903,10 @@ def CheckMinVersion(self):
886903

887904
def GetAvailable(self, pInverterId: int):
888905
raise NotImplementedError()
889-
906+
907+
def GetActualLimitInW(self, pInverterId: int):
908+
raise NotImplementedError()
909+
890910
def GetInfo(self, pInverterId: int):
891911
raise NotImplementedError()
892912

@@ -921,7 +941,7 @@ def GetJson(self, path):
921941
data = session.get(url, timeout=10).json()
922942
retry_count -= 1
923943
return data
924-
944+
925945
def GetResponseJson(self, path, obj):
926946
url = f'http://{self.ip}{path}'
927947
return session.post(url, json = obj, timeout=10).json()
@@ -931,11 +951,14 @@ def GetACPower(self, pInverterId):
931951
ActualPower_index = ParsedData["ch0_fld_names"].index("P_AC")
932952
ParsedData = self.GetJson(f'/api/inverter/id/{pInverterId}')
933953
return CastToInt(ParsedData["ch"][0][ActualPower_index])
934-
954+
935955
def CheckMinVersion(self):
936956
MinVersion = '0.8.80'
937957
ParsedData = self.GetJson('/api/system')
938-
AhoyVersion = str((ParsedData["version"]))
958+
try:
959+
AhoyVersion = str((ParsedData["version"]))
960+
except:
961+
AhoyVersion = str((ParsedData["generic"]["version"]))
939962
logger.info('Ahoy: Current Version: %s',AhoyVersion)
940963
if version.parse(AhoyVersion) < version.parse(MinVersion):
941964
logger.error('Error: Your AHOY Version is too old! Please update at least to Version %s - you can find the newest dev-releases here: https://github.com/lumapu/ahoy/actions',MinVersion)
@@ -946,7 +969,13 @@ def GetAvailable(self, pInverterId: int):
946969
Available = bool(ParsedData["inverter"][pInverterId]["is_avail"])
947970
logger.info('Ahoy: Inverter "%s" Available: %s',NAME[pInverterId], Available)
948971
return Available
949-
972+
973+
def GetActualLimitInW(self, pInverterId: int):
974+
ParsedData = self.GetJson(f'/api/inverter/id/{pInverterId}')
975+
LimitInPercent = float(ParsedData['power_limit_read'])
976+
LimitInW = HOY_INVERTER_WATT[pInverterId] * LimitInPercent / 100
977+
return LimitInW
978+
950979
def GetInfo(self, pInverterId: int):
951980
ParsedData = self.GetJson('/api/live')
952981
temp_index = ParsedData["ch0_fld_names"].index("Temp")
@@ -1083,6 +1112,12 @@ def GetAvailable(self, pInverterId: int):
10831112
logger.info('OpenDTU: Inverter "%s" reachable: %s',NAME[pInverterId],Reachable)
10841113
return Reachable
10851114

1115+
def GetActualLimitInW(self, pInverterId: int):
1116+
ParsedData = self.GetJson('/api/limit/status')
1117+
limit_relative = float(ParsedData[SERIAL_NUMBER[pInverterId]]['limit_relative'])
1118+
LimitInW = HOY_INVERTER_WATT[pInverterId] * limit_relative / 100
1119+
return LimitInW
1120+
10861121
def GetInfo(self, pInverterId: int):
10871122
if SERIAL_NUMBER[pInverterId] == '':
10881123
ParsedData = self.GetJson('/api/livedata/status')
24 KB
Binary file not shown.

0 commit comments

Comments
 (0)