HVAC - ClimateTalk Protocol

Oh, I see. Yes, there was a perl program. Here it is :

pollClimateTalk.py:

import socket
import sys
import datetime
import time
import pygame
from pygame.locals import *

# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

w, h = 8, 16 
SessionID = [[0 for x in range(w)] for y in range(h)]
MacID = [[0 for x in range(w)] for y in range(h)]

quitapp=0
outdoortemp=0

# Connect the socket to the port where the server is listening
#server_address = ('192.168.1.167', 23)
#server_address = ('50.246.121.173', 8023)
server_address = ('10.88.64.134', 23)
print 'connecting to %s port %s\r\n' % server_address,

pygame.init()
pygame.display.set_mode((100,100))
print 'Press ESC in the black open window form to quit\r\n',

state=0  # 0=sync, else decode
oldstate=state+1

try:
    
  while quitapp==0:
    for event in pygame.event.get():
        if event.type == QUIT: sys.exit()
        if event.type == KEYDOWN and event.dict['key'] == 27:
            quitapp=1
    pygame.event.pump()
    if state==0:
        if oldstate!=state:
            print "Opening Socket\r\n",
            oldstate=state
        try:
            sock.connect(server_address)
            state=1
        except socket.error as msg:
            #time.sleep(10)
            oldstate=state+1  #reprint Opening info
            continue
            
    if state==1:
        if oldstate!=state:
            print "Sync Begin\r\n",
            oldstate=state
            seqcnt = 0   # 0=looking for $A0, 1=looking for $11, 2 thru 2+$11+2=waiting to finish sync
        try:
            # get in sync, look for $A0 then $11, then wait $11+2 bytes
            data = sock.recv(1)
            print data.encode('hex'),
            if seqcnt>=20:
                print '\r\nsync finished\r\n',
                state=2
            else:
                if seqcnt>=2:
                    seqcnt+=1
                else:
                    if seqcnt==1:
                        if data[0]==chr(0x11):
                            seqcnt+=1
                        else:
                            seqcnt=0
                    else:  #if seqcnt==0:
                        if data[0]==chr(0xA0):
                            seqcnt+=1
                        else:
                            seqcnt=0
        except socket.error as msg:
            socket.close()
            state=0

    if state==2:
        if oldstate!=state:
            print "Decode Begin\r\n",
            oldstate=state
            seqcnt=0
            payload=0
            command=bytearray()
            heatstart=heatend=0
            coolstart=coolend=0
            fanstart=fanend=0
            altheatstart=altheatend=0
            heaton=coolon=fanon=altheaton=0
        try:
            data = sock.recv(1)
            #if ord(data[0])!=0xFF or payload==2 or payload==1: # or len(command)>=8:
            if True:
              command.append(data[0])
              if seqcnt>9:
                  seqcnt+=1
                  if payload>0:
                      payload-=1
                  if payload==0:
                      lrc1 = 0xAA
                      lrc2 = 0
                      for b in command:
                          lrc1 += b
                          if lrc1>= 255:
                              lrc1 -= 255
                          lrc2 += lrc1
                          if lrc2>= 255:
                              lrc2 -= 255
                      if lrc1!=0:
                          state=1 # resync
                          print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S "),
                          print '(%02x,%02x) ' % (lrc1,lrc2),
                          print ' '.join('{:02x}'.format(x) for x in command),
                          command[8]=0xFF #dummy command
                          continue
                      if (command[8]&0x80)==0:
                          if command[7]!=0x79: #don't print the NODE queries
                              if len(command)>0:
                                print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S "),
                                print '(%02x,%02x) ' % (lrc1,lrc2),
                                print ' '.join('{:02x}'.format(x) for x in command),
                          #else:
                          #    print "NODE query",
                          if command[7]==0xF9:
                              print "NODEDISCOVERY reply",
                          if command[7]==0x7A:
                              print "SETADDR request",
                          if command[7]==0xFA:
                              print "SETADDR reply",
                          if command[7]==0x7B:
                              print "GETNODEID request",
                          if command[7]==0xFB:
                              print "GETNODEID reply",
                          if command[7]==0x14:
                              print "NODELST request",
                          if command[7]==0x94:
                              print "NODELST reply",
                          if command[7]==0x02:
                              print "GETSTATUS request",
                          if command[7]==0x82:
                              print "GETSTATUS reply",
                          if command[7]==0x01:
                              print "GETCFG request",
                          if command[7]==0x81:
                              print "GETCFG reply",
                          if command[7]==0x05:
                              print "DIAG request",
                          if command[7]==0x85:
                              print "DIAG reply",
                          if command[7]==0x07:
                              print "OAT request",
                          if command[7]==0x87:
                              val=(command[13]&0x3F)*16
                              val+=(command[12]>>4)
                              frac=((command[12]&0x0f)*10)/16
                              outdoortemp=val
                              if (command[13]&0x40)>0:
                                outdoortemp*=-1
                                val*=-1
                              print "OAT reply %d.%dF" % (val,frac),
                          if command[7]==0x03:
                              if command[10]==0x69:
                                  print "AltHeat request ",
                                  val=command[13]/2
                                  if val==0:
                                      if altheaton==1:
                                        altheaton=0
                                        print("OFF,OAT={}F,".format(int(outdoortemp))),
                                        #altheatend = time.time()
                                        #if altheatstart==0: altheatstart=altheatend
                                        #hours, rem = divmod(altheatend-altheatstart, 3600)
                                        #minutes, seconds = divmod(rem, 60)
                                        #if seconds>(60-minutes*2): minutes+=1
                                        #print("OnDuration={:0>2}:{:0>2}".format(int(hours),int(minutes))),
                                  else:
                                      print "%d%%," % val,
                                      if altheaton==0:
                                        altheaton=1
                                        #altheatstart=time.time()
                                        #if altheatend==0: altheatend=altheatstart
                                        #hours, rem = divmod(altheatstart-altheatend, 3600)
                                        #minutes, seconds = divmod(rem, 60)
                                        #if seconds>(60-minutes*2): minutes+=1
                                        #print("OffDuration={:0>2}:{:0>2}".format(int(hours),int(minutes))),
                              if command[10]==0x66:
                                  print "Fan request ",
                                  val=command[14]/2
                                  if val==0:
                                      if fanon==1:
                                        fanon=0
                                        print("OFF,OAT={}F,".format(int(outdoortemp))),
                                        #fanend = time.time()
                                        #if fanstart==0: fanstart=fanend
                                        #hours, rem = divmod(fanend-fanstart, 3600)
                                        #minutes, seconds = divmod(rem, 60)
                                        #if seconds>(60-minutes*2): minutes+=1
                                        #print("OnDuration={:0>2}:{:0>2}".format(int(hours),int(minutes))),
                                  else:
                                      print "%d%%," % val,
                                      if fanon==0:
                                        fanon=1
                                        #fanstart=time.time()
                                        #if fanend==0: fanend=fanstart
                                        #hours, rem = divmod(fanstart-fanend, 3600)
                                        #minutes, seconds = divmod(rem, 60)
                                        #if seconds>(60-minutes*2): minutes+=1
                                        #print("OffDuration={:0>2}:{:0>2}".format(int(hours),int(minutes))),
                              if command[10]==0x65:
                                  print "Cool request",
                                  val=command[13]/2
                                  if val==0:
                                      if coolon==1:
                                        coolon=0
                                        print("OFF,OAT={}F,".format(int(outdoortemp))),
                                        #coolend = time.time()
                                        #if coolstart==0: coolstart=coolend
                                        #hours, rem = divmod(coolend-coolstart, 3600)
                                        #minutes, seconds = divmod(rem, 60)
                                        #if seconds>(60-minutes*2): minutes+=1
                                        #print("OnDuration={:0>2}:{:0>2}".format(int(hours),int(minutes))),
                                  else:
                                      print "%d%%," % val,
                                      if coolon==0:
                                        coolon=1
                                        #coolstart=time.time()
                                        #if coolend==0: coolend=coolstart
                                        #hours, rem = divmod(coolstart-coolend, 3600)
                                        #minutes, seconds = divmod(rem, 60)
                                        #if seconds>(60-minutes*2): minutes+=1
                                        #print("OffDuration={:0>2}:{:0>2}".format(int(hours),int(minutes))),
                              if command[10]==0x64:
                                  print "Heat request",
                                  val=command[13]/2
                                  if val==0:
                                      if heaton==1:
                                        heaton=0
                                        print("OFF,OAT={}F,".format(int(outdoortemp))),
                                        #heatend = time.time()
                                        #if heatstart==0: heatstart=heatend
                                        #hours, rem = divmod(heatend-heatstart, 3600)
                                        #minutes, seconds = divmod(rem, 60)
                                        #if seconds>(60-minutes*2): minutes+=1
                                        #print("OnDuration={:0>2}:{:0>2}".format(int(hours),int(minutes))),
                                  else:
                                      print "%d%%," % val,
                                      if heaton==0:
                                        heaton=1
                                        #heatstart=time.time()
                                        #if heatend==0: heatend=heatstart
                                        #hours, rem = divmod(heatstart-heatend, 3600)
                                        #minutes, seconds = divmod(rem, 60)
                                        #if seconds>(60-minutes*2): minutes+=1
                                        #print("OnDuration={:0>2}:{:0>2}".format(int(hours),int(minutes))),
                          if command[7]==0x83:
                              print "ACK reply",
                          if command[7]!=0x79: #don't print the NODE queries
                              print '\r\n',
                      else:
                          # test
                          #print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S "),
                          #print '(%02x,%02x) ' % (lrc1,lrc2),
                          #print ' '.join('{:02x}'.format(x) for x in command),
                          #print '\r\n',
                          
                          if command[6]<10 :
                            device=command[6]&0x0F  # get deviceID
                            match=1
                            if len(command)>=27 and command[8]==0xA0:
                                for x in range(0,8):
                                    if SessionID[device][x]!=command[19+x]:
                                        match=0
                            if match==0:
                                # test
                                #print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S "),
                                #print '(%02x,%02x) ' % (lrc1,lrc2),
                                #print 'Old SessionID[%d] ' % device,
                                #for x in range(0,8):
                                #    print "%02X" % SessionID[device][x],
                                #print '\r\n',

                                print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S "),
                                print '(%02x,%02x) ' % (lrc1,lrc2),
                                print 'New SessionID[%d] ' % device,
                                for x in range(0,8):
                                    SessionID[device][x]=command[19+x]
                                    print "%02X" % SessionID[device][x],
                                print '\r\n',
                                
                            match=1
                            if len(command)>=27 and command[8]==0xA0:
                                for x in range(0,8):
                                    if MacID[device][x]!=command[11+x]:
                                        match=0
                            if match==0:
                                print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S "),
                                print '(%02x,%02x) ' % (lrc1,lrc2),
                                print 'New MacID[%d] ' % device,
                                for x in range(0,8):
                                    MacID[device][x]=command[11+x]
                                    print "%02X" % MacID[device][x],
                                print '\r\n',
                      #cmdlen=len(command)
                      #for x in range(0,cmdlen):
                      #    command.pop(0)
                      command=bytearray()
                      seqcnt=0
              else:
                  if seqcnt==9:
                      payload=ord(data[0])+2
                      seqcnt+=1
                      #print data.encode('hex'),
                  else:
                      seqcnt+=1
                      #print data.encode('hex'),
        except socket.error as msg:
            socket.close()
            state=0

finally:
    print >>sys.stderr, 'closing socket\r\n',
    sock.close()

I am going to be working on a python library for communicating with climatetalk devices. I have already had conversations with kevin_peck about it and I am sure we will be having many more in the future, I am currently waiting for my MAX rs485 dev boards to be delivered. I am expecting them on Saturday, then I will be in “full” development mode until I either burn out and need a break or I am able to complete it. Which ever comes first LOL.

I am going to be attaching the MAX485 to an ESP32 running MicroPython using the ESP32 as an RS485 to IP bridge so I will be able to develop code more easily this way.

Here is a link to a support forum for a piece of software I write. This link is going to bring you to the forum topic I want you to post in. Let me know you are from here I will remove the locks so you will be able to upload your log files.

http://www.eventghost.net/forum/viewtopic.php?f=9&t=10469

[root@marge ~]# python pollClimateTalk.py
File “pollClimateTalk.py”, line 43
print ‘connecting to %s port %s\r\n’ % server_address, end=" “)
^
SyntaxError: Missing parentheses in call to ‘print’. Did you mean print(‘connecting to %s port %s\r\n’ % server_address, end=” “))?
[root@marge ~]# vim pollClimateTalk.py
[root@marge ~]# python pollClimateTalk.py
File “pollClimateTalk.py”, line 51
print ‘Press ESC in the black open window form to quit\r\n’,
^
SyntaxError: Missing parentheses in call to ‘print’. Did you mean print(‘Press ESC in the black open window form to quit\r\n’, end=” “)?
[root@marge ~]# vim pollClimateTalk.py
[root@marge ~]# python pollClimateTalk.py
File “pollClimateTalk.py”, line 81
print “Opening Socket\r\n”,
^
SyntaxError: Missing parentheses in call to ‘print’. Did you mean print(“Opening Socket\r\n”, end=” ")?
[root@marge ~]#

Sync Begin
01 ff 02 00 00 00 a5 00 a0 11 00 00 00 09 10 04 1c 2b 50 02 8d 73 5f c2 b6 ef 34 48 fd 
sync finished
Decode Begin
2020-04-11 12:25:46  (00,00)  New SessionID[1]  A1 63 6A 64 2D 28 95 17 
2020-04-11 12:25:46  (00,00)  New MacID[1]  00 00 13 43 54 33 30 30 
2020-04-11 12:25:46  (00,00)  New SessionID[5]  05 6B 38 70 0A 7B E7 EA 
2020-04-11 12:25:46  (00,00)  New MacID[5]  00 00 09 0F 06 16 28 11 
2020-04-11 12:25:50  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:25:51  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:26:20  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:26:20  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:26:31  (00,00)  ff 01 02 02 02 00 01 03 20 05 66 00 60 00 20 86 b7 Fan request  16%, 
2020-04-11 12:26:31  (00,00)  01 ff 02 02 02 00 02 83 20 05 66 00 60 00 20 f6 c5 ACK reply 
2020-04-11 12:26:35  (00,00)  ff 01 02 02 02 00 01 03 20 05 66 00 60 00 32 62 c9 Fan request  25%, 
2020-04-11 12:26:35  (00,00)  01 ff 02 02 02 00 02 83 20 05 66 00 60 00 32 d2 d7 ACK reply 
2020-04-11 12:26:35  (00,00)  ff 01 02 02 02 00 01 03 20 04 64 00 60 00 78 e8 Heat request 
2020-04-11 12:26:36  (00,00)  01 ff 02 02 02 00 02 83 20 04 64 00 60 00 6a 75 ACK reply 
2020-04-11 12:26:36  (00,00)  ff 01 02 02 05 00 01 03 20 04 64 00 60 00 57 07 Heat request 
2020-04-11 12:26:36  (00,00)  02 ff 02 02 05 00 01 03 20 04 64 00 60 00 47 16 Heat request 
2020-04-11 12:26:37  (00,00)  ff 02 02 02 05 00 05 83 20 04 64 00 60 00 21 b7 ACK reply 
2020-04-11 12:26:37  (00,00)  01 ff 02 02 05 00 05 83 20 04 64 00 60 00 2e ab ACK reply 
2020-04-11 12:26:52  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:26:52  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:27:12  (00,00)  ff 01 02 02 05 00 01 07 20 00 d9 49 OAT request 
2020-04-11 12:27:12  (00,00)  02 ff 02 02 05 00 01 07 20 00 cd 54 OAT request 
2020-04-11 12:27:13  (00,00)  ff 02 02 02 05 00 05 87 20 04 00 02 42 83 42 8f OAT reply 52.1F 
2020-04-11 12:27:13  (00,00)  01 ff 02 02 05 00 05 87 20 04 00 02 42 83 4f 83 OAT reply 52.1F 
2020-04-11 12:27:18  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:27:19  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:27:48  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:27:48  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:28:17  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:28:18  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:28:32  (00,00)  ff 01 02 02 02 00 01 03 20 05 66 00 60 00 20 86 b7 Fan request  16%, 
2020-04-11 12:28:32  (00,00)  01 ff 02 02 02 00 02 83 20 05 66 00 60 00 20 f6 c5 ACK reply 
2020-04-11 12:28:32  (00,00)  ff 01 02 02 02 00 01 03 20 04 64 00 60 00 78 e8 Heat request 
2020-04-11 12:28:33  (00,00)  01 ff 02 02 02 00 02 83 20 04 64 00 60 00 6a 75 ACK reply 
2020-04-11 12:28:39  (00,00)  ff 02 02 02 01 00 05 05 20 04 05 00 00 00 3f db DIAG request 
2020-04-11 12:28:39  (00,00)  01 ff 02 02 01 00 05 05 20 04 05 00 00 00 4c cf DIAG request 
2020-04-11 12:28:39  (00,00)  ff 01 02 02 01 00 01 85 20 02 ac 06 33 c0 DIAG reply 
2020-04-11 12:28:40  (00,00)  02 ff 02 02 01 00 01 85 20 02 ac 06 25 cd DIAG reply 
2020-04-11 12:28:40  (00,00)  ff 01 02 02 05 00 01 02 20 00 ed 3a GETSTATUS request 
2020-04-11 12:28:40  (00,00)  02 ff 02 02 05 00 01 02 20 00 e1 45 GETSTATUS request 
2020-04-11 12:28:41  (00,00)  ff 02 02 02 05 00 05 82 20 0e 00 0c 00 00 00 00 00 00 00 00 00 0f 00 00 ec 8c GETSTATUS reply 
2020-04-11 12:28:41  (00,00)  01 ff 02 02 05 00 05 82 20 0e 00 0c 00 00 00 00 00 00 00 00 00 0f 00 00 04 76 GETSTATUS reply 
2020-04-11 12:28:50  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:28:51  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:29:20  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:29:20  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:29:50  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:29:50  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:30:19  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:30:20  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:30:49  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:30:49  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:31:18  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:31:19  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:31:24  (00,00)  ff 01 02 02 02 00 01 03 20 05 66 00 60 00 22 82 b9 Fan request  17%, 
2020-04-11 12:31:24  (00,00)  01 ff 02 02 02 00 02 83 20 05 66 00 60 00 22 f2 c7 ACK reply 
2020-04-11 12:31:25  (00,00)  ff 01 02 02 05 00 01 03 20 04 64 00 60 22 13 29 Heat request 17%, 
2020-04-11 12:31:25  (00,00)  02 ff 02 02 05 00 01 03 20 04 64 00 60 22 03 38 Heat request 17%, 
2020-04-11 12:31:25  (00,00)  ff 02 02 02 05 00 05 83 20 04 64 00 60 22 dc d9 ACK reply 
2020-04-11 12:31:26  (00,00)  01 ff 02 02 05 00 05 83 20 04 64 00 60 22 e9 cd ACK reply 
2020-04-11 12:31:30  (00,00)  ff 01 02 02 05 00 01 07 20 00 d9 49 OAT request 
2020-04-11 12:31:30  (00,00)  02 ff 02 02 05 00 01 07 20 00 cd 54 OAT request 
2020-04-11 12:31:30  (00,00)  ff 02 02 02 05 00 05 87 20 04 00 02 4a 83 2a 9f OAT reply 52.6F 
2020-04-11 12:31:31  (00,00)  01 ff 02 02 05 00 05 87 20 04 00 02 4a 83 37 93 OAT reply 52.6F 
2020-04-11 12:31:32  (00,00)  ff 02 02 01 66 00 05 03 20 06 66 00 60 02 36 0f 0d a0 Fan request  27%, 
2020-04-11 12:31:32  (00,00)  02 ff 02 01 66 00 02 83 20 06 66 00 60 02 36 0f 27 09 ACK reply 
2020-04-11 12:31:52  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:31:52  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:32:02  (00,00)  ff 02 02 01 66 00 05 03 20 06 66 00 60 02 6d 0f 67 0f Fan request  54%, 
2020-04-11 12:32:02  (00,00)  02 ff 02 01 66 00 02 83 20 06 66 00 60 02 6d 0f 81 77 ACK reply 
2020-04-11 12:32:07  (00,00)  ff 02 02 01 66 00 05 02 20 00 2e 94 GETSTATUS request 
2020-04-11 12:32:07  (00,00)  02 ff 02 01 66 00 02 82 20 18 00 16 00 00 00 00 02 6d 0f 00 00 00 00 00 00 af 04 00 00 6d 0f 00 00 00 7e e9 GETSTATUS reply 
2020-04-11 12:32:22  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:32:22  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:32:27  (00,00)  ff 01 02 02 02 00 01 03 20 05 66 00 60 00 24 7e bb Fan request  18%, 
2020-04-11 12:32:27  (00,00)  01 ff 02 02 02 00 02 83 20 05 66 00 60 00 24 ee c9 ACK reply 
2020-04-11 12:32:27  (00,00)  ff 01 02 02 05 00 01 03 20 04 64 00 60 24 0f 2b Heat request 18%, 
2020-04-11 12:32:28  (00,00)  02 ff 02 02 05 00 01 03 20 04 64 00 60 24 fe 3a Heat request 18%, 
2020-04-11 12:32:28  (00,00)  ff 02 02 02 05 00 05 83 20 04 64 00 60 24 d8 db ACK reply 
2020-04-11 12:32:28  (00,00)  01 ff 02 02 05 00 05 83 20 04 64 00 60 24 e5 cf ACK reply 
2020-04-11 12:32:34  (00,00)  ff 02 02 01 66 00 05 02 20 00 2e 94 GETSTATUS request 
2020-04-11 12:32:35  (00,00)  02 ff 02 01 66 00 02 82 20 18 00 16 00 00 00 00 02 6d 00 00 00 00 00 00 00 af 04 00 00 6d 0f 00 00 00 7e f8 GETSTATUS reply 
2020-04-11 12:32:49  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:32:49  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:33:04  (00,00)  ff 02 02 01 66 00 05 02 20 00 2e 94 GETSTATUS request 
2020-04-11 12:33:05  (00,00)  02 ff 02 01 66 00 02 82 20 18 00 16 00 00 00 00 02 6d 00 00 00 00 00 00 00 af 04 00 00 6d 0f 00 00 00 7e f8 GETSTATUS reply 
2020-04-11 12:33:19  (00,00)  01 ff 02 02 01 00 02 01 20 00 08 24 GETCFG request 
2020-04-11 12:33:19  (00,00)  ff 01 02 02 01 00 01 81 20 14 00 12 00 ff 00 00 00 00 00 00 63 2d b0 00 80 00 00 00 00 00 a3 21 GETCFG reply 
2020-04-11 12:33:24  (00,00)  ff 01 02 02 02 00 01 03 20 05 66 00 60 00 26 7a bd Fan request  19%, 
2020-04-11 12:33:25  (00,00)  01 ff 02 02 02 00 02 83 20 05 66 00 60 00 26 ea cb ACK reply
1 Like

thank you @sipvoip! Very handy indeed, this data. Have you noticed by chance, that the dump as it is, has the ‘data flow’ messages filtered out? These are messages that control/sustain the communications between the functional devices like thermostat or furnace, etc. I’m still in the weeds on enabling this control messaging but making steady progress on getting to the ‘doing’ stuff of which this data log shows.

Hello! I have a Comfort Net controller and I’d like to help provide data. I tried to register at the website you provided but never got an email.

Well it could be my setup. I have 3 systems all the same, 4 Ton 2 stage heat pump for cooling and heating and a variable-speed gas furnace. The heat pump, and furnace are connected to a 3 zone controller connected to zwave CT100 thermostats (not comfort net). My house has 21 thermostats in total connected to 21 zones with 3 largest on each floor being controlled by zone controller. The rest are controlled by OpenHab.

This is a longer log with heat pump cooling and heating, as well as gas furnace heating.

https://drive.google.com/open?id=1nXqHIlJZ575PLV09L8xztcxrhtp6sKi1

I think it’s been a few years since I looked at this thread.

I’ve been monitoring my Daikin HVAC for the past year or so and creating daily logs using an RS485 data monitor and a modified version of that python script that’s been posted a few times. I modified it to create a simple CSV file of all the communications, and an excel spreadsheet that will import those CSV files and graph all the main performance variables (e.g., heat or AC %, fan speed, outdoor temp, humidification on/off, etc.).

I run the logging 24/7 on an always on file server and it just dumps them into daily log files. If it would be helpful I can log the full communications using whatever logger anyone wants. I haven’t used swift before, but I’ll take a look at that code and see if I can get it running if anyone wants to see some logs.

One thing I’ll point out, that I haven’t seen mentioned here, is that with a multi-zone system (which I have) the thermostats communicate with the zone controller, and the zone controller communicates separately with the furnace, and the furnace communicates separately with the inverting AC outdoor unit. All of those are on separate busses, so I can only monitor one at a time. I generally monitor the zone controller <-> furnace bus, because that’s what I’ve mostly cared about. But when my unit is doing things I don’t understand I often wish I could see the requests coming from the thermostats.

I’m a little surprised the system is set up like this, since the RS485 bus and the ClimateTalk protocol should be perfectly capable of handling all of that on one bus.

Hi Xentex,

I can confirm my EWC3000 zone board, the Goodman Climatetalk+Comfortbridge Furnace and the Outdoor Climatetalk+Comfortbridge unit are all on the same bus. The Daikin One+ is on Zone 1.

I was hoping to add an ‘economizer’, opening a large fresh air vent when the outdoor temperature is cooler than the indoor setpoint and there is a cooling call. Is this something that the existing Python code could do? By that I mean; do we have the sensor data decrypted?

All,

What is the latest on this? Was a ClimateTalk/ComfortNet stack ever built? Is someone actively working on this? Seems like activity slowed down a bit.

I have an Amana AVXC20 with Zoning that I am planning on trying to control with an OpenHAB system running on a RaspPi or similar.

I have some time to work on this, so I will be contributing to this development and Net485 on Github as much as I can.

any update?

Has anyone made major progress on this yet?

I wish
 :frowning:

Do you know if Rheem Econet is using the climate talk protocol?

Yes, I believe it is the same thing.

If you guys want some help on the component profiles, safe operational standards, timing, temperatures, pressures, superheat, subcool, sequence of operation, and HVAC fundamentals, give me a shout.

Yes, please. john.chavez@johnstonesupply.com

We have made a ton of progress on decrypting econet on discord for anyone interested. I’m the only one with econet HVAC and a water heater. 2 others just have water heaters. A lot of progress is being made. We were able to set our water heater temperature and read it among many other sensors.

If anyone is interested in helping figure this out please join the discord.

1 Like