Test the Rs232 Communication and SunEzy Communication Protocol
After some time of searching on the internet for wisdom how to pull data from the SunEzy 2800, I came across this Python module: https://pv.codeplex.com/. It describes the communication protocol in detail. Looking into the Python sources, one can immediately see that this is professionally written software. For me as a Python beginner it was clear I would use this module, study it and hopefully learn a lot from it. But first I have to verify that the communication protocol works with my Sunezy 2800.
As I had to wait for Raspberry Pi to arrive, I first connected the SunEzy to my PC using a USB-RS232 cable and verified that the Sunezy Control Software worked. It took some time though, this piece of software is thought to connect to and manage multiple inverters.
The first test without this software was to query the serial number from the Sunezy inverter. Sounds simple. Send some bytes to the inverter, and read some bytes back – for this purpose there are terminal programs available, like TeraTerm. This sequence – expressed as hexadecimal numbers is to be sent to the inverter:
aa aa 01 00 00 00 00 04 00 01 59
Unfortunately, when I open a terminal in TeraTerm, I can send only characters that are available on the keyboard. But already the first character to send is hexadecimal ‘aa’ (representation of the ASCII character number 170, or binary 10101010). The normal Alphabet is represented by ASCII codes between 32 and 127. Some language specific characters can be represented by values between 128 and 255, but not all values can be generated easily with the keyboard. Worse, values below 32 are control characters, for example LF (line feed, ASCII code 10) or CR (carriage return, ASCII code 13).
The solution to this is: use a Hex Editor like Pspad, save the hex string to a to a file, start TeraTerm, and send data from this file.
Playing with this method wasn’t satisfying because I had to connect the inverter with my PC with a 3m cable in that very small boxroom where the heating is.
Below is a code snippet that demonstrates the serial connection to a CMS / Sunezy inverter. It does the following:
- the serial port is opened. We use a normal 9600 Bd, 8N1 connection type.
- A reset is sent and then the serial number is queried. The programming approach is like a C programmer coming to learn Python (like myself) would do it.
- A reset is sent and then the serial number is queried. The programming is more “pythonic”.
#!/usr/bin/env python import serial import time #Oeffne Seriellen Port port = serial.Serial('/dev/ttyAMA0',9600, timeout=0.2) # timeout? if not port.isOpen(): print "cannot connect to Sunezy." sys.exit(1) print "Port opened." """ THIS IS THE BEGINNERS WAY OF SENDING A STRING OF ASCII CODES TO THE DEVICE AND RECEIVING THE SERIAL NUMBER AS A HUMAN READABLE STRING. """ #Reset ''' | sync | src | dst | cmd | len | payload | checksum | | 2B | 2B | 2B | 2B | 1B | len B | 2B | aaaa 0100 0000 0004 00 0159 ''' SYNC = chr(0xaa) + chr(0xaa) SRC = chr(0x01) + chr(0x00) DST = chr(0x00) + chr(0x0) cmd = chr(0x00) + chr(0x04) leng = chr(0x00) chksum = chr(0x01) + chr(0x59) send = SYNC + SRC + DST + cmd + leng + chksum print "Reset - % i Bytes written." % port.write(send) time.sleep(0.2) #Query serial number """ 2B 2B 2B 2B 1B len B 2B aaaa 0100 0000 0000 00 0155 """ cmd = chr(0x00) + chr(0x00) leng = chr(0x00) chksum = chr(0x01) + chr(0x55) send = SYNC + SRC + DST + cmd + leng + chksum print "Query - %i Bytes written." % port.write(send) time.sleep(.2) raw_line ="" if port.inWaiting() > 0: raw_line = port.read(port.inWaiting()) if len(raw_line) > 10: sn = raw_line[9:-2] print "Serial Number: %s" % sn else: print len(raw_line) ''' PYTHON PROVIDES SOME POWERFUL METHODS TO SIMPLIFY THE STRING OPERATIONS WITH ASCII CODES ''' import struct SYNC = 0xaaaa SRC = 0x0100 DST = 0x0000 CMD_RST = 0x0004 #Reset CMD_DSC = 0x0000 #Discover - query serial number data = struct.pack('!HHHHB', SYNC, SRC, DST, CMD_RST, 0x00) checksum = struct.pack('!H', sum(map(ord, data))) # sum over the entire data string without the checksum itself data = data + checksum if port.write(data) is len(data): print"--> ", data.encode('hex_codec') data = struct.pack('!HHHHB', SYNC, SRC, DST, CMD_DSC, 0x00) checksum = struct.pack('!H', sum(map(ord, data))) data = data + checksum if port.write(data) is len(data): print"--> ", data.encode('hex_codec') time.sleep(.2) in_data ="" if port.inWaiting() > 0: in_data = port.read(port.inWaiting()) print "<-- ", in_data.encode('hex_codec') if len(in_data) > 10: sn = in_data[9:-2] print "Serial Number: %s" % sn else: print "Bytes received: %i" % len(in_data) port.close()