From 8fc86bf080a88a86d8bd5586c55c93c301887e3c Mon Sep 17 00:00:00 2001 From: "tamato27@gmail.com" Date: Fri, 22 Apr 2022 11:13:26 +0200 Subject: [PATCH 1/9] Updated Battery SOC sensor line 127 --- deye_logger/Dockerfile | 1 - deye_logger/InverterData.py | 259 ++++++++++++++++++++---------------- 2 files changed, 142 insertions(+), 118 deletions(-) diff --git a/deye_logger/Dockerfile b/deye_logger/Dockerfile index 882e724..b104754 100755 --- a/deye_logger/Dockerfile +++ b/deye_logger/Dockerfile @@ -17,7 +17,6 @@ RUN \ libc6-compat \ git \ py3-pip && \ - # Install requirements for add-on pip3 install --no-cache-dir wheel && \ pip3 install --no-cache-dir paho-mqtt && \ diff --git a/deye_logger/InverterData.py b/deye_logger/InverterData.py index 878322c..5bfc2c0 100755 --- a/deye_logger/InverterData.py +++ b/deye_logger/InverterData.py @@ -6,135 +6,160 @@ import json import paho.mqtt.client as paho import os +import configparser +import datetime + def twosComplement_hex(hexval): bits = 16 val = int(hexval, bits) - if val & (1 << (bits-1)): + if val & (1 << (bits - 1)): val -= 1 << bits return val -#os.chdir(os.path.dirname(sys.argv[0])) -# CONFIG -with open('data/options.json', 'r') as f: - config = json.load(f) +# os.chdir(os.path.dirname(sys.argv[0])) +os.chdir(os.getcwd()) +# CONFIG +configParser = configparser.RawConfigParser() +configFilePath = 'config.cfg' +configParser.read(configFilePath) -inverter_ip=config['inverter_ip'] -inverter_port=int(config['inverter_port']) -inverter_sn=int(config['inverter_sn']) -mqtt=bool(config['mqtt']) -mqtt_server=config['mqtt_server'] -mqtt_port=int(config['mqtt_port']) -mqtt_topic=config['mqtt_topic'] -mqtt_username=config['mqtt_username'] -mqtt_passwd=config['mqtt_passwd'] +inverter_ip = configParser.get('DeyeInverter', 'inverter_ip') +inverter_port = int(configParser.get('DeyeInverter', 'inverter_port')) +inverter_sn = int(configParser.get('DeyeInverter', 'inverter_sn')) +installed_power = int(configParser.get('DeyeInverter', 'installed_power')) +mqtt = int(configParser.get('DeyeInverter', 'mqtt')) +mqtt_server = configParser.get('DeyeInverter', 'mqtt_server') +mqtt_port = int(configParser.get('DeyeInverter', 'mqtt_port')) +mqtt_topic = configParser.get('DeyeInverter', 'mqtt_topic') +mqtt_username = configParser.get('DeyeInverter', 'mqtt_username') +mqtt_passwd = configParser.get('DeyeInverter', 'mqtt_passwd') # END CONFIG # PREPARE & SEND DATA TO THE INVERTER -output="{" # initialise json output -pini=59 -pfin=112 -chunks=0 -while chunks<2: - if chunks==-1: # testing initialisation - pini=235 - pfin=235 - print("Initialise Connection") - start = binascii.unhexlify('A5') #start - length=binascii.unhexlify('1700') # datalength - controlcode= binascii.unhexlify('1045') #controlCode - serial=binascii.unhexlify('0000') # serial - datafield = binascii.unhexlify('020000000000000000000000000000') #com.igen.localmode.dy.instruction.send.SendDataField - pos_ini=str(hex(pini)[2:4].zfill(4)) - pos_fin=str(hex(pfin-pini+1)[2:4].zfill(4)) - businessfield= binascii.unhexlify('0103' + pos_ini + pos_fin) # sin CRC16MODBUS - crc=binascii.unhexlify(str(hex(libscrc.modbus(businessfield))[4:6])+str(hex(libscrc.modbus(businessfield))[2:4])) # CRC16modbus - checksum=binascii.unhexlify('00') #checksum F2 - endCode = binascii.unhexlify('15') - - 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) - - 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(10); - clientSocket.connect(sockadress); - except socket.error as msg: - print("Could not open socket"); - break - - # SEND DATA - #print(chunks) - clientSocket.sendall(frame_bytes); - - ok=False; - while (not ok): - try: - data = clientSocket.recv(1024); - ok=True - try: - data - except: - print("No data - Die") - sys.exit(1) #die, no data - except socket.timeout as msg: - print("Connection timeout"); - sys.exit(1) #die - - # PARSE RESPONSE (start position 56, end position 60) - totalpower=0 - i=pfin-pini - a=0 - while a<=i: - p1=56+(a*4) - p2=60+(a*4) - response=twosComplement_hex(str(''.join(hex(ord(chr(x)))[2:].zfill(2) for x in bytearray(data))+' '+re.sub('[^\x20-\x7f]', '', ''))[p1:p2]) - hexpos=str("0x") + str(hex(a+pini)[2:].zfill(4)).upper() - with open("./DYRealTime.txt") as txtfile: - parameters=json.loads(txtfile.read()) - for parameter in parameters: - for item in parameter["items"]: - title=item["titleHA"] - ratio=item["ratio"] - unit=item["unit"] - for register in item["registers"]: - if register==hexpos and chunks!=-1: - #print(hexpos+"-"+title+":"+str(response*ratio)+unit) - if title.find("Temperature")!=-1: - response=round(response*ratio-100,2) - else: - response=round(response*ratio,2) - output=output+"\""+ title + "_" + unit + "\":" + str(response)+"," - if hexpos=='0x00BA': totalpower+=response*ratio; - if hexpos=='0x00BB': totalpower+=response*ratio; - a+=1 - pini=150 - pfin=195 - chunks+=1 -output=output[:-1]+"}" -if mqtt==True: - # Initialise MQTT if configured - client=paho.Client("inverter") - if mqtt_username!="": - #client.tls_set() # <--- even without arguments - client.username_pw_set(username=mqtt_username, password=mqtt_passwd) - client.connect(mqtt_server, mqtt_port) - client.publish(mqtt_topic,totalpower) - client.publish(mqtt_topic+"/attributes",output) - print("Ok") +output = "{" # initialise json output +pini = 59 +pfin = 112 +chunks = 0 +while chunks < 2: + if chunks == -1: # testing initialisation + pini = 235 + pfin = 235 + print("Initialise Connection") + + start = binascii.unhexlify('A5') # start + length = binascii.unhexlify('1700') # datalength + controlcode = binascii.unhexlify('1045') # controlCode + serial = binascii.unhexlify('0000') # serial + datafield = binascii.unhexlify('020000000000000000000000000000') # com.igen.localmode.dy.instruction.send.SendDataField + pos_ini = str(hex(pini)[2:4].zfill(4)) + pos_fin = str(hex(pfin - pini + 1)[2:4].zfill(4)) + businessfield = binascii.unhexlify('0103' + pos_ini + pos_fin) # sin CRC16MODBUS + crc = binascii.unhexlify(str(hex(libscrc.modbus(businessfield))[4:6]) + str(hex(libscrc.modbus(businessfield))[2:4])) # CRC16modbus + checksum = binascii.unhexlify('00') # checksum F2 + endCode = binascii.unhexlify('15') + 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) + + 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(10) + clientSocket.connect(sockadress) + except socket.error as msg: + print("Could not open socket") + break + + # SEND DATA + # print(chunks) + clientSocket.sendall(frame_bytes) + + ok = False + while (not ok): + try: + data = clientSocket.recv(1024) + ok = True + try: + data + except: + print("No data - Die") + sys.exit(1) # die, no data + except socket.timeout as msg: + print("Connection timeout") + sys.exit(1) # die + + # PARSE RESPONSE (start position 56, end position 60) + totalpower = 0 + i = pfin - pini + a = 0 + while a <= i: + p1 = 56 + (a * 4) + p2 = 60 + (a * 4) + response = twosComplement_hex(str(''.join(hex(ord(chr(x)))[2:].zfill(2) for x in bytearray(data)) + ' ' + re.sub('[^\x20-\x7f]', '', ''))[p1:p2]) + hexpos = str("0x") + str(hex(a + pini)[2:].zfill(4)).upper() + with open("./DYRealTime.txt") as txtfile: + parameters = json.loads(txtfile.read()) + for parameter in parameters: + for item in parameter["items"]: + title = item["titleEN"] + ratio = item["ratio"] + unit = item["unit"] + for register in item["registers"]: + if register == hexpos and chunks != -1: + # print(hexpos+"-"+title+":"+str(response*ratio)+unit) + if title.find("Temperature") != -1: + response = round(response * ratio - 100, 2) + else: + response = round(response * ratio, 2) + + # Change battery Soc unit to percentage so python doesnt use the modulus operator + if unit == '%': + unit = 'perc' + + output = output + "\"" + title + "(" + unit + ")" + "\":" + str(response) + "," + + if hexpos == '0x00BA': + totalpower += response * ratio + if hexpos == '0x00BB': + totalpower += response * ratio + a += 1 + pini = 150 + pfin = 195 + chunks += 1 + +output = output[:-1] + "}" +if totalpower < installed_power + 1000: + if mqtt == 1: + # Initialise MQTT if configured + client = paho.Client("inverter") + if mqtt_username != "": + client.tls_set() # <--- even without arguments + client.username_pw_set(username=mqtt_username, password=mqtt_passwd) + client.connect(mqtt_server, mqtt_port) + client.publish(mqtt_topic, totalpower) + client.publish(mqtt_topic + "/attributes", output) + print(f"MQTT Topic:{mqtt_topic}'/attributes' Output:{output}") + print("Ok") + else: + print(output) else: - print(output) + # open text file + text_file = open("picos_potencia.txt", "a") + + # write string to file + text_file.write(datetime.datetime.now().strftime('%d/%m/%y %I:%M %S %p') + '\n') + text_file.write(output + '\n' + '\n') + + # close file + text_file.close() From 6fe2751f712d25602ddfaf3ae98394104658b1b4 Mon Sep 17 00:00:00 2001 From: "tamato27@gmail.com" Date: Fri, 22 Apr 2022 11:15:54 +0200 Subject: [PATCH 2/9] added Soc sensor for configuration.yml --- deye_logger/DOCS.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/deye_logger/DOCS.md b/deye_logger/DOCS.md index edeef78..df97d0e 100755 --- a/deye_logger/DOCS.md +++ b/deye_logger/DOCS.md @@ -80,6 +80,15 @@ Ensure you create the required mqtt sensors in the homeassistant configuration.y device_class: energy state_class: total_increasing + # Added batery % Soc sensor + - platform: mqtt + name: "solar_battery_soc_perc" + state_topic: "/sunsynk/attributes" + unit_of_measurement: "%" + value_template: "{{ value_json.battery_soc_perc }}" + device_class: energy + state_class: measurement + Once these sensors are added to the Home assistant configuration you can use them in the Energy Dashboard to monotor energy usage. [//]: # "![Home Assistant Energy Config](images/energy_config.png)" From 06f80f27f031e0c46408622dd0b0efb3ddc9e581 Mon Sep 17 00:00:00 2001 From: "tamato27@gmail.com" Date: Fri, 22 Apr 2022 11:24:31 +0200 Subject: [PATCH 3/9] Set to poll 2 mins --- deye_logger/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deye_logger/run.sh b/deye_logger/run.sh index c47011c..305c9ed 100755 --- a/deye_logger/run.sh +++ b/deye_logger/run.sh @@ -19,9 +19,9 @@ mqtt_topic="$(bashio::config 'mqtt_topic')" bashio::log.info "Starting InverterData.py" -# Run the script every 5 minutes +# Run the script every 2 minutes # TODO: make this value configurable through config.yaml -watch -n 300 'python3 InverterData.py' +watch -n 120 'python3 InverterData.py' #echo "$(bashio::config 'inverter_ip')" #echo "$(bashio::config 'inverter_port')" From e906ea8ba9780212c1bfe90876aeb3388a77b579 Mon Sep 17 00:00:00 2001 From: "tamato27@gmail.com" Date: Fri, 22 Apr 2022 11:42:55 +0200 Subject: [PATCH 4/9] testing --- .gitignore | 1 + InverterData.py | 233 +++++++++++++++++++++++++----------------------- 2 files changed, 120 insertions(+), 114 deletions(-) diff --git a/.gitignore b/.gitignore index 7103328..133dca0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.cfg +config.cfg diff --git a/InverterData.py b/InverterData.py index 244f620..6bdc8e5 100644 --- a/InverterData.py +++ b/InverterData.py @@ -16,7 +16,8 @@ def twosComplement_hex(hexval): val -= 1 << bits return val -os.chdir(os.path.dirname(sys.argv[0])) +# os.chdir(os.path.dirname(sys.argv[0])) +os.chdir(os.getcwd()) # CONFIG configParser = configparser.RawConfigParser() @@ -39,122 +40,126 @@ def twosComplement_hex(hexval): # PREPARE & SEND DATA TO THE INVERTER -output="{" # initialise json output -pini=59 -pfin=112 -chunks=0 -while chunks<2: - if chunks==-1: # testing initialisation - pini=235 - pfin=235 - print("Initialise Connection") - start = binascii.unhexlify('A5') #start - length=binascii.unhexlify('1700') # datalength - controlcode= binascii.unhexlify('1045') #controlCode - serial=binascii.unhexlify('0000') # serial - datafield = binascii.unhexlify('020000000000000000000000000000') #com.igen.localmode.dy.instruction.send.SendDataField - pos_ini=str(hex(pini)[2:4].zfill(4)) - pos_fin=str(hex(pfin-pini+1)[2:4].zfill(4)) - businessfield= binascii.unhexlify('0103' + pos_ini + pos_fin) # sin CRC16MODBUS - crc=binascii.unhexlify(str(hex(libscrc.modbus(businessfield))[4:6])+str(hex(libscrc.modbus(businessfield))[2:4])) # CRC16modbus - checksum=binascii.unhexlify('00') #checksum F2 - endCode = binascii.unhexlify('15') - - 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) - - 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(10); - clientSocket.connect(sockadress); - except socket.error as msg: - print("Could not open socket"); - break - - # SEND DATA - #print(chunks) - clientSocket.sendall(frame_bytes); - - ok=False; - while (not ok): - try: - data = clientSocket.recv(1024); - ok=True - try: - data - except: - print("No data - Die") - sys.exit(1) #die, no data - except socket.timeout as msg: - print("Connection timeout"); - sys.exit(1) #die - - # PARSE RESPONSE (start position 56, end position 60) - totalpower=0 - i=pfin-pini - a=0 - while a<=i: - p1=56+(a*4) - p2=60+(a*4) - response=twosComplement_hex(str(''.join(hex(ord(chr(x)))[2:].zfill(2) for x in bytearray(data))+' '+re.sub('[^\x20-\x7f]', '', ''))[p1:p2]) - hexpos=str("0x") + str(hex(a+pini)[2:].zfill(4)).upper() - with open("./DYRealTime.txt") as txtfile: - parameters=json.loads(txtfile.read()) - for parameter in parameters: - for item in parameter["items"]: - title=item["titleEN"] - ratio=item["ratio"] - unit=item["unit"] - for register in item["registers"]: - if register==hexpos and chunks!=-1: - #print(hexpos+"-"+title+":"+str(response*ratio)+unit) - if title.find("Temperature")!=-1: - response=round(response*ratio-100,2) - else: - response=round(response*ratio,2) - output=output+"\""+ title + "(" + unit + ")" + "\":" + str(response)+"," - if hexpos=='0x00BA': totalpower+=response*ratio; - if hexpos=='0x00BB': totalpower+=response*ratio; - a+=1 - pini=150 - pfin=195 - chunks+=1 -output=output[:-1]+"}" -if totalpower Date: Fri, 22 Apr 2022 12:30:46 +0200 Subject: [PATCH 5/9] config commented out --- deye_logger/InverterData.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deye_logger/InverterData.py b/deye_logger/InverterData.py index 5bfc2c0..67fa57b 100755 --- a/deye_logger/InverterData.py +++ b/deye_logger/InverterData.py @@ -19,7 +19,7 @@ def twosComplement_hex(hexval): # os.chdir(os.path.dirname(sys.argv[0])) -os.chdir(os.getcwd()) +# os.chdir(os.getcwd()) # CONFIG configParser = configparser.RawConfigParser() configFilePath = 'config.cfg' From 825c8e8a6db2a69042e09fe971471a8779d6b211 Mon Sep 17 00:00:00 2001 From: "tamato27@gmail.com" Date: Fri, 22 Apr 2022 12:39:52 +0200 Subject: [PATCH 6/9] repaired docker config --- deye_logger/InverterData.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/deye_logger/InverterData.py b/deye_logger/InverterData.py index 67fa57b..c3835e6 100755 --- a/deye_logger/InverterData.py +++ b/deye_logger/InverterData.py @@ -21,20 +21,18 @@ def twosComplement_hex(hexval): # os.chdir(os.path.dirname(sys.argv[0])) # os.chdir(os.getcwd()) # CONFIG -configParser = configparser.RawConfigParser() -configFilePath = 'config.cfg' -configParser.read(configFilePath) - -inverter_ip = configParser.get('DeyeInverter', 'inverter_ip') -inverter_port = int(configParser.get('DeyeInverter', 'inverter_port')) -inverter_sn = int(configParser.get('DeyeInverter', 'inverter_sn')) -installed_power = int(configParser.get('DeyeInverter', 'installed_power')) -mqtt = int(configParser.get('DeyeInverter', 'mqtt')) -mqtt_server = configParser.get('DeyeInverter', 'mqtt_server') -mqtt_port = int(configParser.get('DeyeInverter', 'mqtt_port')) -mqtt_topic = configParser.get('DeyeInverter', 'mqtt_topic') -mqtt_username = configParser.get('DeyeInverter', 'mqtt_username') -mqtt_passwd = configParser.get('DeyeInverter', 'mqtt_passwd') +with open('data/options.json', 'r') as f: + config = json.load(f) + +inverter_ip=config['inverter_ip'] +inverter_port=int(config['inverter_port']) +inverter_sn=int(config['inverter_sn']) +mqtt=bool(config['mqtt']) +mqtt_server=config['mqtt_server'] +mqtt_port=int(config['mqtt_port']) +mqtt_topic=config['mqtt_topic'] +mqtt_username=config['mqtt_username'] +mqtt_passwd=config['mqtt_passwd'] # END CONFIG @@ -61,6 +59,7 @@ def twosComplement_hex(hexval): crc = binascii.unhexlify(str(hex(libscrc.modbus(businessfield))[4:6]) + str(hex(libscrc.modbus(businessfield))[2:4])) # CRC16modbus checksum = binascii.unhexlify('00') # checksum F2 endCode = binascii.unhexlify('15') + 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) From f702e8368cd87251a52e988fbd8d4ae7fc55bf4f Mon Sep 17 00:00:00 2001 From: "tamato27@gmail.com" Date: Fri, 22 Apr 2022 12:54:57 +0200 Subject: [PATCH 7/9] testing --- deye_logger/InverterData.py | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/deye_logger/InverterData.py b/deye_logger/InverterData.py index c3835e6..2ce9597 100755 --- a/deye_logger/InverterData.py +++ b/deye_logger/InverterData.py @@ -59,7 +59,7 @@ def twosComplement_hex(hexval): crc = binascii.unhexlify(str(hex(libscrc.modbus(businessfield))[4:6]) + str(hex(libscrc.modbus(businessfield))[2:4])) # CRC16modbus checksum = binascii.unhexlify('00') # checksum F2 endCode = binascii.unhexlify('15') - + 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) @@ -138,27 +138,16 @@ def twosComplement_hex(hexval): chunks += 1 output = output[:-1] + "}" -if totalpower < installed_power + 1000: - if mqtt == 1: - # Initialise MQTT if configured - client = paho.Client("inverter") - if mqtt_username != "": - client.tls_set() # <--- even without arguments - client.username_pw_set(username=mqtt_username, password=mqtt_passwd) +if mqtt == True: + # Initialise MQTT if configured + client = paho.Client("inverter") + if mqtt_username != "": + client.tls_set() # <--- even without arguments + client.username_pw_set(username=mqtt_username, password=mqtt_passwd) client.connect(mqtt_server, mqtt_port) client.publish(mqtt_topic, totalpower) client.publish(mqtt_topic + "/attributes", output) print(f"MQTT Topic:{mqtt_topic}'/attributes' Output:{output}") print("Ok") else: - print(output) -else: - # open text file - text_file = open("picos_potencia.txt", "a") - - # write string to file - text_file.write(datetime.datetime.now().strftime('%d/%m/%y %I:%M %S %p') + '\n') - text_file.write(output + '\n' + '\n') - - # close file - text_file.close() + print(output) \ No newline at end of file From 5a554f476319dc9151cc350d217691b12af8e1db Mon Sep 17 00:00:00 2001 From: "tamato27@gmail.com" Date: Fri, 22 Apr 2022 14:12:35 +0200 Subject: [PATCH 8/9] disables tls/ssl --- deye_logger/InverterData.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deye_logger/InverterData.py b/deye_logger/InverterData.py index 2ce9597..3fd5ea8 100755 --- a/deye_logger/InverterData.py +++ b/deye_logger/InverterData.py @@ -142,7 +142,7 @@ def twosComplement_hex(hexval): # Initialise MQTT if configured client = paho.Client("inverter") if mqtt_username != "": - client.tls_set() # <--- even without arguments + #client.tls_set() # <--- even without arguments client.username_pw_set(username=mqtt_username, password=mqtt_passwd) client.connect(mqtt_server, mqtt_port) client.publish(mqtt_topic, totalpower) From 4bc159dc419c6e5a450c17f745bbf0e351f3ef69 Mon Sep 17 00:00:00 2001 From: "tamato27@gmail.com" Date: Fri, 22 Apr 2022 18:07:19 +0200 Subject: [PATCH 9/9] Added Battery SOC (Tested) --- InverterData.py | 3 +- deye_logger/DOCS.md | 15 ++++----- deye_logger/InverterData.py | 62 +++++++++++++++++-------------------- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/InverterData.py b/InverterData.py index 6bdc8e5..bc7ee49 100644 --- a/InverterData.py +++ b/InverterData.py @@ -127,7 +127,8 @@ def twosComplement_hex(hexval): if unit == '%': unit = 'perc' - output = output + "\"" + title + "(" + unit + ")" + "\":" + str(response) + "," + # output = output + "\"" + title + "(" + unit + ")" + "\":" + str(response) + "," + output=output+"\""+ title + "_" + unit + "\":" + str(response)+"," if hexpos == '0x00BA': totalpower += response * ratio diff --git a/deye_logger/DOCS.md b/deye_logger/DOCS.md index df97d0e..d21e9e8 100755 --- a/deye_logger/DOCS.md +++ b/deye_logger/DOCS.md @@ -7,6 +7,7 @@ The Solarman Wifi Logger must be reachable via an ip address on the network wher Using the Home Assistant Mosquitto broker add-on as the mqtt destination works really well. I have been using add-on on my Raspberry Pi v4 Home Assistant setup without issues for about a month now. This add-on is possible thanks to the work of @jlopez77 https://github.com/jlopez77/DeyeInverter +And Modded according, added Battery SOC % ## Solarman Wifi Logger ## @@ -47,9 +48,10 @@ Ensure you configure the add-on before starting it. Setting the mqtt flag to fal Ensure you create the required mqtt sensors in the homeassistant configuration.yaml to interpret the stats received on the /sunsynk mqtt topic. + # Solar Inverter sensors setup and all mqtt platforms sensor: - platform: mqtt - name: "solarpower" + name: "Solarpower" state_topic: "/sunsynk" unit_of_measurement: "W" json_attributes_topic: "/sunsynk/attributes" @@ -57,7 +59,7 @@ Ensure you create the required mqtt sensors in the homeassistant configuration.y state_class: measurement - platform: mqtt - name: "solar_daily_energy_bought_kwh" + name: "Solar Daily Energy Bought KWH" state_topic: "/sunsynk/attributes" unit_of_measurement: "kWh" value_template: "{{ value_json.daily_energy_bought_kwh }}" @@ -65,7 +67,7 @@ Ensure you create the required mqtt sensors in the homeassistant configuration.y state_class: total_increasing - platform: mqtt - name: "solar_daily_energy_sold_kwh" + name: "Solar Daily Energy Sold KWH" state_topic: "/sunsynk/attributes" unit_of_measurement: "kWh" value_template: "{{ value_json.daily_energy_sold_kwh }}" @@ -73,19 +75,18 @@ Ensure you create the required mqtt sensors in the homeassistant configuration.y state_class: total_increasing - platform: mqtt - name: "solar_daily_production_KWH" + name: "Solar Daily Production KWH" state_topic: "/sunsynk/attributes" unit_of_measurement: "kWh" value_template: "{{ value_json.daily_production_KWH }}" device_class: energy state_class: total_increasing - # Added batery % Soc sensor - platform: mqtt - name: "solar_battery_soc_perc" + name: "Solar Battery SOC" state_topic: "/sunsynk/attributes" unit_of_measurement: "%" - value_template: "{{ value_json.battery_soc_perc }}" + value_template: "{{ value_json.battery_soc_soc }}" device_class: energy state_class: measurement diff --git a/deye_logger/InverterData.py b/deye_logger/InverterData.py index 3fd5ea8..64fe6d1 100755 --- a/deye_logger/InverterData.py +++ b/deye_logger/InverterData.py @@ -6,8 +6,6 @@ import json import paho.mqtt.client as paho import os -import configparser -import datetime def twosComplement_hex(hexval): @@ -19,20 +17,20 @@ def twosComplement_hex(hexval): # os.chdir(os.path.dirname(sys.argv[0])) -# os.chdir(os.getcwd()) # CONFIG + with open('data/options.json', 'r') as f: config = json.load(f) -inverter_ip=config['inverter_ip'] -inverter_port=int(config['inverter_port']) -inverter_sn=int(config['inverter_sn']) -mqtt=bool(config['mqtt']) -mqtt_server=config['mqtt_server'] -mqtt_port=int(config['mqtt_port']) -mqtt_topic=config['mqtt_topic'] -mqtt_username=config['mqtt_username'] -mqtt_passwd=config['mqtt_passwd'] +inverter_ip = config['inverter_ip'] +inverter_port = int(config['inverter_port']) +inverter_sn = int(config['inverter_sn']) +mqtt = bool(config['mqtt']) +mqtt_server = config['mqtt_server'] +mqtt_port = int(config['mqtt_port']) +mqtt_topic = config['mqtt_topic'] +mqtt_username = config['mqtt_username'] +mqtt_passwd = config['mqtt_passwd'] # END CONFIG @@ -47,7 +45,7 @@ def twosComplement_hex(hexval): pini = 235 pfin = 235 print("Initialise Connection") - + start = binascii.unhexlify('A5') # start length = binascii.unhexlify('1700') # datalength controlcode = binascii.unhexlify('1045') # controlCode @@ -70,7 +68,9 @@ def twosComplement_hex(hexval): 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): + + 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) @@ -95,13 +95,14 @@ def twosComplement_hex(hexval): print("No data - Die") sys.exit(1) # die, no data except socket.timeout as msg: - print("Connection timeout") + print("Connection timeout"); sys.exit(1) # die # PARSE RESPONSE (start position 56, end position 60) totalpower = 0 i = pfin - pini a = 0 + while a <= i: p1 = 56 + (a * 4) p2 = 60 + (a * 4) @@ -111,7 +112,7 @@ def twosComplement_hex(hexval): parameters = json.loads(txtfile.read()) for parameter in parameters: for item in parameter["items"]: - title = item["titleEN"] + title = item["titleHA"] ratio = item["ratio"] unit = item["unit"] for register in item["registers"]: @@ -121,33 +122,26 @@ def twosComplement_hex(hexval): response = round(response * ratio - 100, 2) else: response = round(response * ratio, 2) - - # Change battery Soc unit to percentage so python doesnt use the modulus operator if unit == '%': unit = 'perc' - - output = output + "\"" + title + "(" + unit + ")" + "\":" + str(response) + "," - - if hexpos == '0x00BA': - totalpower += response * ratio - if hexpos == '0x00BB': - totalpower += response * ratio + output = output + "\"" + title + "_" + unit + "\":" + str(response) + "," + if hexpos == '0x00BA': totalpower += response * ratio; + if hexpos == '0x00BB': totalpower += response * ratio; a += 1 pini = 150 pfin = 195 chunks += 1 - output = output[:-1] + "}" + if mqtt == True: # Initialise MQTT if configured client = paho.Client("inverter") if mqtt_username != "": - #client.tls_set() # <--- even without arguments + # client.tls_set() # <--- even without arguments client.username_pw_set(username=mqtt_username, password=mqtt_passwd) - client.connect(mqtt_server, mqtt_port) - client.publish(mqtt_topic, totalpower) - client.publish(mqtt_topic + "/attributes", output) - print(f"MQTT Topic:{mqtt_topic}'/attributes' Output:{output}") - print("Ok") - else: - print(output) \ No newline at end of file + client.connect(mqtt_server, mqtt_port) + client.publish(mqtt_topic, totalpower) + client.publish(mqtt_topic + "/attributes", output) + print("Ok") +else: + print(output)