USNAP (ANSI/CEA-2045) Smart-Grid interface
-
I have a hybrid hot water heater with what appears to be an AC CEA-2045 interface (which I assume is a USNAP interface). It looks like this:
https://usnap.memberclicks.net/assets/images/Connectors/ac_connector.png
It appears to have A120V AC on one side, and RS-485 on the other.
I snooped the RS485 @ 19200BPS And I can see data transmission. I haven't spent too much time analyzing it yet, but I believe I can see the target temperature, current temperature, and state info in the data stream. I don't expect it to be too hard to extract the relevant info and build a sensor to monitor the port. However, The heater has a 'power save' mode which apparently lets the Smart-grid control the water-heater (I assume switch it from efficiency to all-electric mode?). That sounds like something I want to play with. I'd love to be able to use some home-automation technology to control when the heater is in all-electric mode, and when it is in hybrid, efficiency or vacation mode.
But I don't know the protocol to change the state.
I found this document that indicates how to build a receiver, and that it is likely using a MODBUS protocol:
http://sunspec.org/wp-content/uploads/2015/07/SunSpec-CEA-2045-Inverter-Adaptor-Architecture.pdfThis seems to correlate to what I've seen as well (The data is 9N1, with the 1st bit indicating the start of a frame wth a checksum at the end...Figuring out how to read this with a UART was a little fun)
But I still don't know what (most of) the data in the packet means, and more importantly how to send data back to the heater.
Has anyone done any work with USNAP / CEA-2045?
-
I think I got confused somewhere along the way. I do not think the protocol is actually MODBUS as Modbus does not appear to use a start-of frame bit and specifies a CRC rather than a simple checksum.
The water heater is a Reliance DHPST hybrid water heater (electric + Heat Pump)
Data on RS485 is transmitted at 19200 baud
Data is 1 startbit, 8 data bits, 1 'start of frame' bit, and 1 stop bit/
The 'start of frame' bit is 1 for the 1st byte, and 0 for all remaining bytes.
The last byte is a single 1-byte sum of all previous bytes of the frame.
This represents most of the packets I have seen (I have removed the 'start of packet' bit:(3) : 90 00 90 (64) : 40 08 1e 00 00 00 03 00 78 00 00 00 00 00 00 71 44 74 6a 49 47 30 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 69 cd 00 00 00 00 16 02 00 00 00 09 00 00 00 00 00 00 41 08 00 00 50 00 26 (30) : 40 0b 0d 02 00 62 00 5a 00 5e 00 52 00 00 00 ff ff 00 00 00 00 00 00 00 00 00 01 00 02 c7 (3) : 8c 00 8c (3) : 82 00 82 (8) : 40 00 02 05 00 b2 00 f9 (28) : 40 0d 0c 00 01 00 3c 00 00 00 10 00 78 00 78 01 01 00 00 00 00 00 01 00 00 00 00 99
For anyone interested, the easiest way to read this in linux is to set the
INPCK and PARMRK, and then read with 'SPACE' parity. this will generate an error whenever the parity bit is set, that can then be converted into a 'start of frame' bit.
Here is some example python code:import serial import termios i ser = serial.Serial(port, 19200, parity=serial.PARITY_SPACE) iflag, oflag, cflag, lflag, ispeed, ospeed, cc = termios.tcgetattr(ser) iflag |= termios.INPCK | termios.PARMRK termios.tcsetattr(ser, termios.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]) buf = [] while True: try: b = ord(ser.read(1)) if b == 0xff : b = ord(ser.read(1)) if b == 0x00: b = 0x100 | ord(ser.read()) buf.append(b) except SerialException as e: print(e)
I'll follow-up with the bytes I've figured out so far.