APsystems APS ECU R local inverters data pull

@ksheumaker got some better script to work with from other guy that had interest, maybe helps you too.

import socket
import struct
import binascii
import json
import datetime
from struct import unpack
 
myIPadress = "192.168.?.?"
myMACadress = "" #May be search for this if ipadres doesn't react, later
output = {}
 
def APSint(codec,start):
    return int(binascii.b2a_hex(codec[(start):(start+2)]),16)
   
def APSbool(codec,start):
    return bool(binascii.b2a_hex(codec[(start):(start+2)]))
 
def APSuid(codec,start):
    return str(binascii.b2a_hex(codec[(start):(start+12)]))[2:14]
 
def APSstr(codec,start,amount):
    return str(codec[start:(start+amount)])[2:(amount+2)]
 
def APStimestamp(codec,start,amount):
    timestr=str(binascii.b2a_hex(codec[start:(start+amount)]))[2:(amount+2)]
    return timestr[0:4]+"-"+timestr[4:6]+"-"+timestr[6:8]+" "+timestr[8:10]+":"+timestr[10:12]+":"+timestr[12:14]
 
#initialize socket
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((myIPadress,8899))
 
#get ECUID
ECU_R = 'APS1100160001END'
ECU_Rsend = ECU_R.encode('utf-8')
soc.send(ECU_Rsend)
ECU_Rreceive = soc.recv(1024)
# print ("\nAsking for ECUID number: ")
# print(ECU_Rreceive)
# Decoded explanation
# APS 1100940001 = Open sentence and answer notation
# 216000026497 = ECU_R nummer
# 01 =text unkown
# 00 00 (a7 90)=42896[167,144] 00 00 00 00 00 00 00
# 8x status of UID ca=202 d0=208 d0 d0 d0 d0 d0 d0
# 0008=(aantal UID) maximaal (16)
# 0000=integer unkown
# 10012 = text unkown
# ECU_R_1.2.13009 = Version
# Etc/GMT-8 = ETC ipv UTC Timezone server op lokatie met -8 uur?
# 80 97 1b 01 5d 1e 00 00 00 00 00 00
# END\n
myECUID = APSstr(ECU_Rreceive,13,12) #216000026497
output["ECU_R_ID"] = myECUID
output["maxUID"] = APSint(ECU_Rreceive,46)
output["Version"] = APSstr(ECU_Rreceive,55,15)
output["TimeZone"] = APSstr(ECU_Rreceive,70,9)
#print(output)
 
#get data from UID
ECU_R = 'APS1100280002'+myECUID+"END"  # 2 extra?
ECU_Rsend = ECU_R.encode('utf-8')
soc.send(ECU_Rsend)
ECU_Rreceive = soc.recv(2048)
#print("\nAsking for UID numbers and data: "+str(len(ECU_Rreceive)))
#print(ECU_Rreceive)
#print("\n")
#print(binascii.b2a_hex(ECU_Rreceive))
 
if (len(ECU_Rreceive)>16) :
    #base data valid for all UID
    output["timestamp"] = APStimestamp(ECU_Rreceive,19,14)
    counter = 1
    maxcounter = APSint(ECU_Rreceive,17) #number of inverters
    offset=26
    while counter <= maxcounter:
        # Records will pass for each inverter on this ECU_R (UID)
        # 1-3 APS
        # 4-18 UID
        # 19 number of inverters?
        #------------------------
        # 20-32 Inverter ID (UID)
        # 33 0 or 1 Marks online status of inverter instance
        # 34 unkown "0"
        # 35 unkown "1" Could be country because of 31 (Netherlands)
        # 36-37 Frequency multiplied by 10
        # 38-39 Temperature Celsius Bit 7 of second byte is signbit (1=+, 0=-)?
        # 40-41 Power A Channel A on Inverter
        # 42-43 Voltage A Chanel A on Inverter
        # 44-45 Power B Channel B on Inverter
        # 46-47 Voltage B Chanel B on Inverter
        # 48-51 END or channel C and D till END
        #pick up data for this inverter
        # output={}
        output["UID"+str(counter)] = APSuid(ECU_Rreceive,offset)
        #you can also use UID as index in dictonary
        uid=output["UID"+str(counter)][7:12]
        output["Online"+uid] = APSbool(ECU_Rreceive,offset+6)
        output["Something"+uid] = APSstr(ECU_Rreceive,offset+7,2)
        output["Frequentie"+uid] = APSint(ECU_Rreceive,offset+9)/10.0
        output["Temperature"+uid] = APSint(ECU_Rreceive,offset+11)-100 # check later if sign is bit 7 64 and fahrenheit
        step = 13
        channel = 1
        while (channel <= 2): #QS1 must have 4 times, so C and D but how to see the difference
            output["Power"+uid+"-"+str(channel)] = APSint(ECU_Rreceive,offset+step)
            output["Volt"+uid+"-"+str(channel)] = APSint(ECU_Rreceive,offset+step+2)
            step += 4
            channel += 1
            # print(output)
            #end while channel
 
        offset += step #how big is UID block
        counter += 1
        #print(output)
        #end while UID
    #print(output)
else:
    output["Error"] = "No inverters active"
print(json.dumps(output))

heads up on above, seems to mess up a bit in QS1 data, the bytes per UID are longer for QS1