I have following piece of python code which works via VS Code:
import sys
import socket
import binascii
import libscrc
import json
import os
def padhex(s):
return '0x' + s[2:].zfill(4)
def hex_zfill(intval):
hexvalue=hex(intval)
return '0x' + str(hexvalue)[2:].zfill(4)
os.chdir(os.path.dirname(sys.argv[0]))
inverter_ip=str('192.168.0.50')
inverter_port=int(8899)
inverter_sn=int(5645241030)
lang=str('EN')
verbose=str('1')
# END CONFIG
# PREPARE & SEND DATA TO INVERTER via LOGGER MODULE
output="{" # initialise json output
pini=33029 # START REGISTER
pfin=33084 # END REGISTER
SN="\""
SV="\""
HV="\""
DSPV="\""
# Data logger frame begin
start = binascii.unhexlify('A5') # Logger Start code
length=binascii.unhexlify('1700') # Logger frame DataLength
controlcode= binascii.unhexlify('1045') # Logger ControlCode
serial=binascii.unhexlify('0000') # Serial
datafield = binascii.unhexlify('020000000000000000000000000000') # com.igen.localmode.dy.instruction.send.SendDataField
# Modbus request begin
pos_ini=str(hex_zfill(pini)[2:])
pos_fin=str(hex_zfill(pfin-pini+1)[2:])
businessfield= binascii.unhexlify('0104' + pos_ini + pos_fin) # Modbus data to count crc
if verbose=="1": print('Modbus request: 0104 ' + pos_ini + " " + pos_fin +" "+str(padhex(hex(libscrc.modbus(businessfield)))[4:6])+str(padhex(hex(libscrc.modbus(businessfield)))[2:4]))
crc=binascii.unhexlify(str(padhex(hex(libscrc.modbus(businessfield)))[4:6])+str(padhex(hex(libscrc.modbus(businessfield)))[2:4])) # CRC16modbus
# Modbus request end
checksum=binascii.unhexlify('00') #checksum F2
endCode = binascii.unhexlify('15')# Logger End code
inverter_sn2 = bytearray.fromhex(hex(inverter_sn)[8:10] + hex(inverter_sn)[6:8] + hex(inverter_sn)[4:6] + hex(inverter_sn)[2:4])
frame = bytearray(start + length + controlcode + serial + inverter_sn2 + datafield + businessfield + crc + checksum + endCode)
if verbose=="1":
print("Hex string to send: A5 1700 1045 0000 " + hex(inverter_sn)[8:10] + hex(inverter_sn)[6:8] + hex(inverter_sn)[4:6] + hex(inverter_sn)[2:4] + " 020000000000000000000000000000 " + "0104" + pos_ini + pos_fin + str(hex(libscrc.modbus(businessfield))[3:5]) + str(hex(libscrc.modbus(businessfield))[2:3].zfill(2)) + " 00 15")
if verbose=="1": print("Data sent: ", frame);
# Data logger frame end
checksum = 0
frame_bytes = bytearray(frame)
for i in range(1, len(frame_bytes) - 2, 1):
checksum += frame_bytes[i] & 255
frame_bytes[len(frame_bytes) - 2] = int((checksum & 255))
# OPEN SOCKET
for res in socket.getaddrinfo(inverter_ip, inverter_port, socket.AF_INET, socket.SOCK_STREAM):
family, socktype, proto, canonname, sockadress = res
try:
clientSocket= socket.socket(family,socktype,proto);
clientSocket.settimeout(15);
clientSocket.connect(sockadress);
except socket.error as msg:
print("Could not open socket - inverter/logger turned off");
if prometheus=="1": prometheus_file.close();
sys.exit(1)
# SEND DATA
clientSocket.sendall(frame_bytes);
ok=False;
while (not ok):
try:
data = clientSocket.recv(1024);
ok=True
try:
data
except:
print("No data - Exit")
sys.exit(1) #Exit, no data
except socket.timeout as msg:
print("Connection timeout - inverter and/or gateway is off");
sys.exit(1) #Exit
# PARSE RESPONSE (start position 56, end position 60)
if verbose=="1": print("Data received: ", data);
i=pfin-pini # Number of registers
a=0 # Loop counter
response=str(''.join(hex(ord(chr(x)))[2:].zfill(2) for x in bytearray(data))) #+' '+re.sub('[^\x20-\x7f]', '', '')));
if verbose=="1":
hexstr=str(' '.join(hex(ord(chr(x)))[2:].zfill(2) for x in bytearray(data)))
print("Hex string received:",hexstr.upper())
with open("./SOFARHWMap.xml") as txtfile:
parameters=json.loads(txtfile.read())
while a<=i:
p1=56+(a*4)
p2=60+(a*4)
responsereg=response[p1:p2]
val1=chr(int(str(responsereg[0:2]),16))
val2=chr(int(str(responsereg[2:4]),16))
hexpos=str("0x") + str(hex(a+pini)[2:].zfill(4)).upper()
if verbose=="1": print("Register:",hexpos+" ("+str(int(hexpos,16))+"), Value: "+str("0x"+responsereg)+" ("+str(int(str(responsereg),16))+")");
for parameter in parameters:
for item in parameter["items"]:
if lang=="PL":
title=item["titlePL"]
else:
title=item["titleEN"]
value_type=item["value_type"]
for register in item["registers"]:
if register==hexpos:
for option in item["optionRanges"]:
if option["key"] == int(str(responsereg),16):
if lang=="PL":
output=output+"\""+ title + "\":" + str('"'+option["valuePL"]+'"')+","
else:
output=output+"\""+ title + "\":" + str('"'+option["valueEN"]+'"')+","
if value_type=="SN": SN+=val1+val2;
if value_type=="SV": SV+=val1+val2;
if value_type=="HV": HV+=val1+val2;
if value_type=="DSPV": DSPV+=val1+val2;
a+=1
if lang=="PL":
output=output+"\"Numer seryjny" + "\":" + SN +"\","
output=output+"\"Wersja oprogramowania" + "\":" + SV +"\","
output=output+"\"Wersja sprzętowa" + "\":" + HV +"\","
output=output+"\"Wersja DSP" + "\":" + DSPV +"\","
else:
output=output+"\"Serial Number" + "\":" + SN +"\","
output=output+"\"Software Version" + "\":" + SV +"\","
output=output+"\"Hardware Version" + "\":" + HV +"\","
output=output+"\"DSP Version" + "\":" + DSPV +"\","
output=output[:-1]+"}"
jsonoutput=json.loads(output)
print(json.dumps(jsonoutput, indent=4, sort_keys=False, ensure_ascii=False))
I need to find a way to be able to call this/run it from HA. Can you guys please advise if something like that is even possible.
I have tried node-red but no luck because of the imports.