-
-
Save stefan123t/e4136e984f9a2ff8bf18152b403d31a4 to your computer and use it in GitHub Desktop.
quick and dirty hoymles grid profile parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# | |
# hoymiles grid profile parser | |
# quick and dirty | |
# dyn table/version | |
# | |
# param 1: grid profile | |
# f.ex. python3 _hgp_qd.py 0a002001000c08fc07a3000f09e2001e064a00140a5500140ac8000a09e21003138812c0001413ec0014128e000514500005200000013003025809e207a3139c1356400007d0001050010001139c0190001000006000000109e20a5a021580010000085b012c08b70941099d012c006490000000005fb000000001f4005f700200012710a00200000000cbfe00 | |
# | |
import sys | |
hex_string = sys.argv[1] | |
table_types={ | |
0x00: "Voltage (H/LVRT)", | |
0x10: "Frequency (H/LFRT)", | |
0x20: "Island Detection (ID)", | |
0x30: "Reconnection (RT)", | |
0x40:"Ramp Rates (RR)", | |
0x50: "Frequency Watt (FW)", | |
0x60: "Volt Watt (VW)", | |
0x70: "Active Power Control (APC)", | |
0x80:"Volt Var (VV)", | |
0x90: "Specified Power Factor (SPF)", | |
0xA0: "Reactive Power Control (RPC)", | |
0xB0: "Watt Power Factor (WPF)" | |
} | |
### country / regulations or simple internal DB ID ? ;) | |
# 02 00 - Austria ???? ( empty list ) / IEEE 1547 240V (?) | |
# 03 00 - Germany - DE_VDE4105_2018 (2.0.x) | |
# 03 01 - unknown | |
# 0a 00 - Europe - EN 50549-1:2019 | |
# 0c 00 - Austria - 2.0.x EU_EN50438 | |
# 0d 04 - France - ??? | |
# 12 00 - Poland - 2.0.x (EU_EN50438) | |
# 37 00 - Switzerland - 2.0.x (CH_NA EEA-NE7–CH2020) | |
table_regs={ | |
0x02: { 0x00: "US - IEEE 1547 240V (?)"}, | |
0x03: { 0x00: "Germany - DE_VDE4105_2018"}, | |
0x0a: { 0x00: "European - EN 50549-1:2019"}, | |
0x0c: { 0x00: "AT Tor - EU_EN50438" }, | |
0x0d: { 0x04: "France" }, | |
0x12: { 0x00: "Poland - EU_EN50438" }, | |
0x37: { 0x00: "Swiss - CH_NA EEA-NE7-CH2020"}, | |
} | |
### { table_nr : { table_ver: [["name","unit",divider]] }} | |
tables_struct = { | |
# 0x00: "Voltage (H/LVRT)", | |
0x00 : { | |
# Poland - EU_EN50438 | |
0x00: [ | |
["Nominale Voltage (NV)","V",10], | |
["Low Voltage 1 (LV1)","V",10], | |
["LV1 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 1 (HV1)","V",10], | |
["HV1 Maximum Trip Time (MTT)","s",10], | |
], | |
# Swiss - CH_NA EEA-NE7-CH2020 | |
0x03: [ | |
["Nominale Voltage (NV)","V",10], | |
["Low Voltage 1 (LV1)","V",10], | |
["LV1 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 1 (HV1)","V",10], | |
["HV1 Maximum Trip Time (MTT)","s",10], | |
["Low Voltage 2 (LV2)","V",10], | |
["LV2 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 2 (HV2)","V",10], | |
["HV2 Maximum Trip Time (MTT)","s",10], | |
], | |
# unknown 03 01 | |
0x08: [ | |
["Nominale Voltage (NV)","V",10], | |
["Low Voltage 1 (LV1)","V",10], | |
["LV1 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 1 (HV1)","V",10], | |
["HV1 Maximum Trip Time (MTT)","s",10], | |
["? High Voltage 2 (HV2)","V",10], | |
], | |
# Germany - DE_VDE4105_2018 | |
0x0A: [ | |
["Nominale Voltage (NV)","V",10], | |
["Low Voltage 1 (LV1)","V",10], | |
["LV1 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 1 (HV1)","V",10], | |
["HV1 Maximum Trip Time (MTT)","s",10], | |
["Low Voltage 2 (LV2)","V",10], | |
["LV2 Maximum Trip Time (MTT)","s",10], | |
["10mins Average High Voltage (AHV)","V",10] | |
], | |
# AT Tor - EU_EN50438 | |
0x0B: [ | |
["Nominale Voltage (NV)","V",10], | |
["Low Voltage 1 (LV1)","V",10], | |
["LV1 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 1 (HV1)","V",10], | |
["HV1 Maximum Trip Time (MTT)","s",10], | |
["Low Voltage 2 (LV2)","V",10], | |
["LV2 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 2 (HV2)","V",10], | |
["HV2 Maximum Trip Time (MTT)","s",10], | |
["10mins Average High Voltage (AHV)","V",10] | |
], | |
# European - EN 50549-1:2019 | |
0x0C: [ | |
["Nominale Voltage (NV)","V",10], | |
["Low Voltage 1 (LV1)","V",10], | |
["LV1 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 1 (HV1)","V",10], | |
["HV1 Maximum Trip Time (MTT)","s",10], | |
["Low Voltage 2 (LV2)","V",10], | |
["LV2 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 2 (HV2)","V",10], | |
["HV2 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 3 (HV3)","V",10], | |
["HV3 Maximum Trip Time (MTT)","s",10], | |
["10mins Average High Voltage (AHV)","V",10], | |
], | |
# IEEE 1547 240V (?) | |
0x35: [ | |
["Nominale Voltage (NV)","V",10], | |
["Low Voltage 1 (LV1)","V",10], | |
["LV1 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 1 (HV1)","V",10], | |
["HV1 Maximum Trip Time (MTT)","s",10], | |
["Low Voltage 2 (LV2)","V",10], | |
["LV2 Maximum Trip Time (MTT)","s",10], | |
["High Voltage 2 (HV2)","V",10], | |
["HV2 Maximum Trip Time (MTT)","s",10], | |
["?","",1], | |
["?","",1], | |
["?","",1], | |
["?","",1], | |
], | |
}, | |
# 0x10: "Frequency (H/LFRT)", | |
0x10: { | |
0x00: [ | |
["Nominal Frequency","Hz",100], | |
["Low Frequency 1 (LF1)","Hz",100], | |
["LF1 Maximum Trip Time (MTT)","s",10], | |
["High Frequency 1 (HF1)","Hz",100], | |
["HF1 Maximum Trip time (MTT)","s",10] | |
], | |
0x03: [ | |
["Nominal Frequency","Hz",100], | |
["Low Frequency 1 (LF1)","Hz",100], | |
["LF1 Maximum Trip Time (MTT)","s",10], | |
["High Frequency 1 (HF1)","Hz",100], | |
["HF1 Maximum Trip time (MTT)","s",10], | |
["Low Frequency 2 (LF2)","Hz",100], | |
["LF2 Maximum Trip Time (MTT)","s",10], | |
["High Frequency 2 (HF2)","Hz",100], | |
["HF2 Maximum Trip time (MTT)","s",10], | |
], | |
}, | |
# 0x20: "Island Detection (ID)", | |
0x20: { 0x00: [ | |
["ID Function Activated","bool",1] | |
], | |
}, | |
# 0x30: "Reconnection (RT)", | |
0x30: { | |
0x03: [ | |
["Reconnect Time (RT)","s",10], | |
["Reconnect High Voltage (RHV)","V",10], | |
["Reconnect Low Voltage (RLV)","V",10], | |
["Reconnect High Frequency (RHF)","Hz",100], | |
["Reconnect Low Frequency (RLF)","Hz",100] | |
], | |
0x07: [ | |
["Reconnect Time (RT)","s",10], | |
["Reconnect High Voltage (RHV)","V",10], | |
["Reconnect Low Voltage (RLV)","V",10], | |
["Reconnect High Frequency (RHF)","Hz",100], | |
["Reconnect Low Frequency (RLF)","Hz",100], | |
[" ??? ","?",1], | |
[" ??? ","?",1], | |
], | |
}, | |
# 0x40:"Ramp Rates (RR)", | |
0x40: { 0x00: [ | |
["Normal Ramp up Rate(RUR_NM)","Rated%/s",100], | |
["Soft Start Ramp up Rate (RUR_SS)","Rated%/s",100] | |
], | |
}, | |
# 0x50: "Frequency Watt (FW)", | |
0x50: { 0x00: [ | |
["FW Function Activated","bool",1], | |
["Start of Frequency Watt Droop (Fstart)","Hz",100], | |
["FW Droop Slope (Kpower_Freq)","Pn%/Hz",10], | |
["Recovery Ramp Rate (RRR)","Pn%/s",100], | |
], | |
0x01: [ | |
["FW Function Activated","bool",1], | |
["Start of Frequency Watt Droop (Fstart)","Hz",100], | |
["FW Droop Slope (Kpower_Freq)","Pn%/Hz",10], | |
["Recovery Ramp Rate (RRR)","Pn%/s",100], | |
["Recovery High Frequency (RVHF)","Hz",100], | |
], | |
0x08: [ | |
["FW Function Activated","bool",1], | |
["Start of Frequency Watt Droop (Fstart)","Hz",100], | |
["FW Droop Slope (Kpower_Freq)","Pn%/Hz",10], | |
["Recovery Ramp Rate (RRR)","Pn%/s",100], | |
["Recovery High Frequency (RVHF)","Hz",100], | |
["Recovery Low Frequency (RVLF)","Hz",100] | |
], | |
# ieee | |
0x11: [ | |
["FW Function Activated","bool",1], | |
["Start of Frequency Watt Droop (Fstart)","Hz",100], | |
["FW Droop Slope (Kpower_Freq)","Pn%/Hz",10], | |
["Recovery Ramp Rate (RRR)","Pn%/s",100], | |
["Recovery High Frequency (RVHF)","Hz",100], | |
], | |
}, | |
# 0x60: "Volt Watt (VW)", | |
0x60: { 0x00: [ | |
["VW Function Activated","bool",1], | |
["Start of Voltage Watt Droop (Vstart)","V",10], | |
["End of Voltage Watt Droop (Vend)","V",10], | |
["Droop Slope (Kpower_Volt)","Pn%/V",100] | |
], | |
0x04: [ | |
["VW Function Activated","bool",1], | |
["Start of Voltage Watt Droop (Vstart)","V",10], | |
["End of Voltage Watt Droop (Vend)","V",10], | |
["Droop Slope (Kpower_Volt)","Pn%/V",100] | |
], | |
}, | |
# 0x70: "Active Power Control (APC)", | |
0x70: { 0x00: [ | |
["APC Function Activated","bool",1] | |
], | |
0x02: [ | |
["APC Function Activated","bool",1], | |
["Power Ramp Rate (PRR)","Pn%/s",100] | |
], | |
}, | |
# 0x80:"Volt Var (VV)", | |
0x80: { 0x00: [ | |
["VV Function Activated","bool",1], | |
["Voltage Set Point V1","V",10], | |
["Reactive Set Point Q1","%Pn",10], | |
["Voltage Set Point V2","V",10], | |
["Voltage Set Point V3","V",10], | |
["Voltage Set Point V4","V",10], | |
["Reactive Set Point Q4","%Pn",10] | |
], | |
0x01: [ | |
["VV Function Activated","bool",1], | |
["Voltage Set Point V1","V",10], | |
["Reactive Set Point Q1","%Pn",10], | |
["Voltage Set Point V2","V",10], | |
["Voltage Set Point V3","V",10], | |
["Voltage Set Point V4","V",10], | |
["Reactive Set Point Q4","%Pn",10], | |
["Setting Time (Tr)","s",10] | |
], | |
}, | |
# 0x90: "Specified Power Factor (SPF)", | |
0x90: { 0x00: [ | |
["SPF Function Activated","bool",1], | |
["Power Factor (PF)","",100] | |
], | |
}, | |
# 0xA0: "Reactive Power Control (RPC)", | |
0xA0: { 0x02: [ | |
["RPC Function Activated","bool",1], | |
["Reactive Power (VAR)","%Sn",1] | |
], | |
}, | |
# 0xB0: "Watt Power Factor (WPF)" | |
0xB0: { 0x00: [ | |
["WPF Function Activated","bool",1], | |
["Start of Power of WPF (Pstart)","%Pn",10], | |
["Power Factor ar Rated Power (PFRP)","",100] | |
], | |
} | |
} | |
def modbusCrc(msg:str) -> int: | |
crc = 0xFFFF | |
for n in range(len(msg)): | |
crc ^= msg[n] | |
for i in range(8): | |
if crc & 1: | |
crc >>= 1 | |
crc ^= 0xA001 | |
else: | |
crc >>= 1 | |
return crc | |
binary_string = bytes.fromhex(hex_string) | |
binary_length = len(binary_string) | |
### internal DB ID ( country/regulations ) ??? | |
str_header1 = binary_string[0] | |
str_header2 = binary_string[1] | |
### version ( major.minor / rev ) ??? | |
str_version1 = binary_string[2] | |
str_version2 = binary_string[3] | |
try: | |
print("Grid Profile: %s " % (table_regs[str_header1][str_header2])) | |
except: | |
print("Grid Profile: unknown ( plz report to https://github.com/tbnobody/OpenDTU/wiki/Grid-Profile-Parser )" ) | |
print ("Version: %s.%s.%s" % (((str_version1 >> 4) & 0x0F),(str_version1 & 0x0F),str_version2)) | |
position=4 | |
while (position < binary_length): | |
str_table_n = binary_string[position] | |
str_table_v = binary_string[position+1] | |
try: | |
print("Table Type: " , table_types[str_table_n]) | |
except: | |
pass | |
try: | |
tables_diz=tables_struct[str_table_n][str_table_v] | |
table_length = len(tables_diz) | |
except: | |
crc=bytearray(binary_string[position:position+2]).hex() | |
crc2 = modbusCrc(binary_string[0:position]) | |
crcc = crc2.to_bytes(2, byteorder='big').hex() | |
if crc == crcc: | |
print("CRC (ok): ",crcc) | |
else: | |
print("CRC (?): ",crc) | |
print("CRC calced: %s " % (crcc)) | |
print(" - possible unknown table (module), plz report to https://github.com/tbnobody/OpenDTU/wiki/Grid-Profile-Parser") | |
print("end") | |
break | |
table_pos=0 | |
#print("str_table_n: %s, str_table_v: %s, table_length: %s" % (str_table_n,str_table_v,table_length)) | |
position += 2 | |
for x in range(table_length): | |
try: | |
table_diz=tables_diz[table_pos] | |
except: | |
table_diz=["","",1] | |
table_pos += 1 | |
str_work = binary_string[position:position+2] | |
str_hex = str_work.hex() | |
str_int = int(str_hex,16) | |
str_val = str_int / table_diz[2] | |
print("position: %s \t: %s \t %s \t %s\t[%s]\t\t[%s]" % (position,str_hex,str_int,str_val,table_diz[1],table_diz[0])) | |
position += 2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment