Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. Hardware
  3. RCS RS485 thermostat

RCS RS485 thermostat

Scheduled Pinned Locked Moved Hardware
21 Posts 4 Posters 6.8k Views 5 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P pjr

    @dbemowsk
    These are not supported yet by domoticz:

    • V_HVAC_FLOW_STATE
    • V_HVAC_FLOW_MODE
    • V_HVAC_SPEED

    Thats why I'm using V_LIGHT (ON/OFF) currently at the code.

    You can check it from here: https://github.com/domoticz/domoticz/blob/master/hardware/MySensorsBase.cpp#L70
    Those are not mentioned anywhere but the one list.

    dbemowskD Offline
    dbemowskD Offline
    dbemowsk
    wrote on last edited by
    #12

    @pjr OK, that helps me understand your code better. I am assuming that the "onModbusProcessed" method is to process incoming messages sent by the modbus network and sending them to Domoticz, correct? Processing incoming messages from the RS485 network is where some of my problems are in my setup. I will try tonight to make some code changes to see if I can get it working. My main problem was my cooling set point was not updating in Domoticz correctly. The Heat set point and temp seemed to work. I'll post my findings.

    1 Reply Last reply
    0
    • P Offline
      P Offline
      pjr
      wrote on last edited by pjr
      #13

      @dbemowsk said:

      @pjr OK, that helps me understand your code better. I am assuming that the "onModbusProcessed" method is to process incoming messages sent by the modbus network and sending them to Domoticz, correct?

      Thats correct. There I handle the result of a modbus query.
      I'm not handling decimals since the heat pump controller supports only full numbers..

      1 Reply Last reply
      0
      • dbemowskD Offline
        dbemowskD Offline
        dbemowsk
        wrote on last edited by
        #14

        So last night I figured out my issue with why my code was not updating the set point cool value. Turns out it was the way I was parsing the string passed from the RS485 side to it's key/value pairs. The string that it was working on was this:

        A=0 O=01 T=73.4 SPH=72.1 SPC=70.0\r
        

        The code I had was only taking the key/value pairs up to the last one because I had it keying off of the space character. Since there was no trailing space in the string, the last pair got skipped which was the cooling set point.

        I will post some updated code once I get a little more done.

        1 Reply Last reply
        0
        • dbemowskD Offline
          dbemowskD Offline
          dbemowsk
          wrote on last edited by dbemowsk
          #15

          OK, so I had this project on hold for a while and am getting back to it. My issue now is that for some reason I am not receiving messages from Domoticz for this node. If I send a temp set point or status from the RS485 side, it updates in Domoticz, but if I try to change a set point or status in Domoticz, the MySensors node doesn't receive it. The code is a bit messy right now, but it should work with what I have. If someone could look it over and advise, that would be a big help. The sketch is a MySensors 1.5.4 sketch.

           /*
            RCS Thermostat for MySensors
          
            Arduino RCS RS485 thermostat control
          
            July 7,2016
          
            This is a gateway bridge to allow an RCS serial thermostat to be accessible to a MySensors
            gateway.  The thermostat being used to test this is an RCS TR40 RS485 thermostat.  The published
            protocol for RCS thermostats can be found at the following address;
            http://www.rcstechnology.com/oldsite/docs/thermostats/serial/SERIAL%20PROTOCOL%20REV%204.3%20%20150-00225-43.pdf
            
            This sketch features the following:
          
            Add features here
           */
          
          // Import needed libraries
          #include <SPI.h>
          #include <MySensor.h>  
          #include <SoftwareSerial.h>
          
          #define SKETCH_NAME "RCS TR40 Thermostat"
          #define SKETCH_VERSION "1.1"
          
          #define CHILD_ID_HVAC    0 // S_HVAC
          #define CHILD_ID_STATE   1 // S_LIGHT
          
          // Declare Constants and Pin Numbers
          #define SSerialRX        5  //Serial Receive pin 8
          #define SSerialTX        3  //Serial Transmit pin 7
          
          #define SSerialTxControl 4  //RS485 Direction control
          
          #define RS485Transmit    HIGH
          #define RS485Receive     LOW
          
          // Declare objects
          SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
          
          MySensor gw;
          
          // Sensor values
          MyMessage msgStatus ( CHILD_ID_STATE,  V_LIGHT );
          MyMessage msgTemp   ( CHILD_ID_HVAC,   V_TEMP );
          MyMessage msgSetCool( CHILD_ID_HVAC,   V_HVAC_SETPOINT_COOL );
          MyMessage msgSetHeat( CHILD_ID_HVAC,   V_HVAC_SETPOINT_HEAT );
          
          // Declare Variables
          int byteReceived;
          int byteSend;
          String rcvString;
          String sndString;
          //This is for storing the last command that was sent 
          String lastSent;
          //the last sent set point
          String setPoint;
          
          String mode;
          //This is the RS485 address of this node that gets sent to the thermostat
          String serialAddr = "1";
          //Placeholder for the last command sent
          String LastSent = "";
          
          void setup() {
            Serial.begin(9600);
            
            gw.begin( incomingMessage, AUTO, false );
            
            gw.sendSketchInfo( SKETCH_NAME, SKETCH_VERSION );
            
            // Register the thermostat with the gateway
            gw.present( CHILD_ID_HVAC,  S_HVAC );
            gw.present( CHILD_ID_STATE, S_LIGHT );
            
            // put your setup code here, to run once:
            pinMode( SSerialTxControl, OUTPUT );
            digitalWrite( SSerialTxControl, RS485Receive );  // Init Transceiver
            
            // Start the software serial port, to another device
            RS485Serial.begin(9600);   // set the data rate
          } //End setup
          
          void loop() {
            String dataIn;
            
            if (RS485Serial.available()) {
              dataIn = RS485Serial.readStringUntil('\n');
              ParseReceived(dataIn);
            }
          } //End loop
          
          void ParseReceived(String Message) {
            String StatusData;
            //int Count;
            String StatusString;
            String Status;
            String Type;
            String Value;
          
            int Index;
            int Start;
            int End;
            int StatIndex;
          
            Index = Message.indexOf(' ');
            Start = 0;
            
            Serial.println("Message: " + Message);
            
            if (Message.startsWith("A=")) {
              while (End != Message.length()) {
                End = (Index == -1) ? Message.length() : Index;
                //Get the status string to process
                StatusString = Message.substring(Start, End);
                //Change our start position to 1 over the last space found
                Start = Index + 1;
                //Find the end of the next status string
                Index = Message.indexOf(' ', Start);
            
                //Now we need to process the status string into it's Type and Value
                StatIndex = StatusString.indexOf('=');
                Type = StatusString.substring(0, StatIndex);
                Value = StatusString.substring(StatIndex + 1);
                ParseStatus(Type, Value);
              } 
            } else {
              SendCmd(LastSent);
            }
          } //End ParseReceived
          
          void ParseStatus(String Type, String Value) {
            //
            
            if (Type == "OA") {
                //Outside Air not used
            } else if (Type == "Z") {
                //Zone not used
            } else if (Type == "T") {
                Serial.println("T: " + Value);
                gw.send(msgTemp.set( F2C( Value.toFloat() ), 2 ));
            } else if (Type == "SP") {
                Serial.println("SP: " + Value);
                gw.send(msgSetCool.set( F2C( Value.toFloat() ), 2 ));
            } else if (Type == "SPH") {
                Serial.println("SPH: " + Value);
                gw.send(msgSetHeat.set( F2C( Value.toFloat() ), 2 ));
            } else if (Type == "SPC") {
                Serial.println("SPC: " + Value);
                gw.send(msgSetCool.set( F2C( Value.toFloat() ), 2 ));
            } else if (Type == "M") {
                //Serial.println("M: " + Value);
                //gw.send(msgFlowMode.set(Value.c_str()));
            } else if (Type == "FM") {
                //Serial.println("FM: " + Value);
                //gw.send(msgFlowMode.set(Value.c_str()));
              //Type 2 status message types
            } else if (Type == "H1A") {
                Serial.println("H1A: " + Value);
                if (Value == "1") {
                  //gw.send(msgHvacSpeed.set("Min"));
                } else {
                  //gw.send(msgHvacSpeed.set("Auto"));
                }
            } else if (Type == "H2A") {
                Serial.println("H2A: " + Value);
                if (Value == "1") {
                  //gw.send(msgHvacSpeed.set("Normal"));
                } else {
                  //gw.send(msgHvacSpeed.set("Auto"));
                }
            } else if (Type == "H3A") {
                Serial.println("H3A: " + Value);
                if (Value == "1") {
                  //gw.send(msgHvacSpeed.set("Max"));
                } else {
                  //gw.send(msgHvacSpeed.set("Auto"));
                }
            } else if (Type == "C1A") {
                Serial.println("C1A: " + Value);
                if (Value == "1") {
                  //gw.send(msgHvacSpeed.set("Min"));
                } else {
                  //gw.send(msgHvacSpeed.set("Auto"));
                }
            } else if (Type == "C2A") {
                Serial.println("C2A: " + Value);
                if (Value == "1") {
                  //gw.send(msgHvacSpeed.set("Normal"));
                } else {
                  //gw.send(msgHvacSpeed.set("Auto"));
                }
            } else if (Type == "FA") {
                Serial.println("FA: " + Value);
                if (Value == "1") {
                  //gw.send(msgFlowMode.set("ContinuousOn"));
                } else {
                  //gw.send(msgHvacSpeed.set("Auto"));
                }
            } else if (Type == "VA") {
                //Vent damper not used
            } else if (Type == "D1") {
                //Damper #1 not used
            } else if (Type == "SCP") {
                String stg1 = Value.substring(0, 1);
                String stg2 = Value.substring(0, Value.length() - 1);
          
                //logging.AddToLog("MOT/MRT stage 1: " & stg1, True)
                //Deal with minimum off time and minimum run times 
                //for stage 1
          
                //logging.AddToLog("MOT/MRT stage 2: " & stg2, True)
                //Deal with minimum off time and minimum run times 
                //for stage 2
            } else if (Type == "SM") {
                //logging.AddToLog("System mode: " & Value, True)
                String FlowState;
                
                if (Value == "O") {
                  FlowState = "Off";
                } else if (Value == "H") {
                  FlowState = "HeatOn";
                } else if (Value == "C") {
                  FlowState = "CoolOn";
                } else {
                  FlowState = "AutoChangeOver";
                }
                //Serial.println("SM: " + FlowState);
                //gw.send(msgFlowState.set(FlowState.c_str()));
            } else if (Type == "SF") {
                //logging.AddToLog("System fan: " & Value, True) 
                Serial.println("SF: " + Value);
                gw.send(msgStatus.set(Value.toInt()));
            }
          } //End ParseStatus
          
          float F2C(float Fahrenheit) {
            return (5.0f/9.0f) * (Fahrenheit-32);
          } //End F2C
          
          float C2F(float Celsius) {
            return (Celsius * 9.0f) / 5.0f + 32.0f;
          } //End C2F
          
          void SendCmd(String cmd) {
            String commandStr;
            commandStr = "A=" + serialAddr + " O=00 " + cmd;
          
            Serial.println("Writing to serial port: " + commandStr);
            
            // Enable RS485 Transmit only for the duration of the send
            digitalWrite(SSerialTxControl, RS485Transmit);
            RS485Serial.print(commandStr + "\r");
            LastSent = cmd;
            //Return to RS485 receive mode  
            digitalWrite(SSerialTxControl, RS485Receive);
          } //End SendCmd
          
          /**
           * incomingMessage - Process the incoming messages.
           */
          void incomingMessage(const MyMessage &message) {
            Serial.println("message received");//String(message.type));
            //Serial.println(message.data);
            // We only expect one type of message from controller. But we better check anyway.
            if (message.isAck()) {
               Serial.println("This is an ack from gateway");
            }
            Serial.println("Temp: " + String(message.data) + " -- " + message.type);
            
            if ( message.type == V_TEMP ) {
              //
              Serial.println("Temp: " + String(message.data)); 
            } //End V_TEMP
            
            if ( message.type == V_STATUS ) {
              //
              Serial.println("Status: " + String(message.data)); 
            } //End V_STATUS
            
            if ( message.type == V_HVAC_FLOW_STATE ) {
              //
              Serial.println("Flow State: " + String(message.data)); 
            } //End V_HVAC_FLOW_STATE
            
            if ( message.type == V_HVAC_SPEED ) {
              //
              Serial.println("Speed: " + String(message.data)); 
            } //End V_HVAC_SPEED
          
            if (message.type == V_HVAC_SETPOINT_COOL) {
               Serial.println("Message received");
               String setPoint = String(C2F(atoi(message.data)));
               Serial.println("New Set Temp is : " + String(setPoint));
               SendCmd("SPC=" + setPoint + " R=1");
              
               // Write some debug info
               Serial.print("Incoming change for sensor:");
               Serial.print(message.sensor);
               Serial.print(", New status: ");
               Serial.println(message.data);
            } //End V_HVAC_SETPOINT_COOL
          
            if (message.type == V_HVAC_SETPOINT_HEAT) {
               Serial.println("Message received");
               String setPoint = String(C2F(atoi(message.data))); //.toInt();
               Serial.println("New Set Temp is : " + String(setPoint));
               SendCmd("SPH=" + setPoint + " R=1");
              
               // Write some debug info
               Serial.print("Incoming change for sensor:");
               Serial.print(message.sensor);
               Serial.print(", New status: ");
               Serial.println(message.data);
            } //End V_HVAC_SETPOINT_HEAT
            
            if ( (message.type == V_HVAC_FLOW_MODE) ) {
              //
              Serial.println("Flow Mode: " + String(message.data)); 
            } //End V_HVAC_FLOW_MODE
          } //End incomingMessage
          

          Thanks

          AWIA 2 Replies Last reply
          0
          • dbemowskD dbemowsk

            OK, so I had this project on hold for a while and am getting back to it. My issue now is that for some reason I am not receiving messages from Domoticz for this node. If I send a temp set point or status from the RS485 side, it updates in Domoticz, but if I try to change a set point or status in Domoticz, the MySensors node doesn't receive it. The code is a bit messy right now, but it should work with what I have. If someone could look it over and advise, that would be a big help. The sketch is a MySensors 1.5.4 sketch.

             /*
              RCS Thermostat for MySensors
            
              Arduino RCS RS485 thermostat control
            
              July 7,2016
            
              This is a gateway bridge to allow an RCS serial thermostat to be accessible to a MySensors
              gateway.  The thermostat being used to test this is an RCS TR40 RS485 thermostat.  The published
              protocol for RCS thermostats can be found at the following address;
              http://www.rcstechnology.com/oldsite/docs/thermostats/serial/SERIAL%20PROTOCOL%20REV%204.3%20%20150-00225-43.pdf
              
              This sketch features the following:
            
              Add features here
             */
            
            // Import needed libraries
            #include <SPI.h>
            #include <MySensor.h>  
            #include <SoftwareSerial.h>
            
            #define SKETCH_NAME "RCS TR40 Thermostat"
            #define SKETCH_VERSION "1.1"
            
            #define CHILD_ID_HVAC    0 // S_HVAC
            #define CHILD_ID_STATE   1 // S_LIGHT
            
            // Declare Constants and Pin Numbers
            #define SSerialRX        5  //Serial Receive pin 8
            #define SSerialTX        3  //Serial Transmit pin 7
            
            #define SSerialTxControl 4  //RS485 Direction control
            
            #define RS485Transmit    HIGH
            #define RS485Receive     LOW
            
            // Declare objects
            SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
            
            MySensor gw;
            
            // Sensor values
            MyMessage msgStatus ( CHILD_ID_STATE,  V_LIGHT );
            MyMessage msgTemp   ( CHILD_ID_HVAC,   V_TEMP );
            MyMessage msgSetCool( CHILD_ID_HVAC,   V_HVAC_SETPOINT_COOL );
            MyMessage msgSetHeat( CHILD_ID_HVAC,   V_HVAC_SETPOINT_HEAT );
            
            // Declare Variables
            int byteReceived;
            int byteSend;
            String rcvString;
            String sndString;
            //This is for storing the last command that was sent 
            String lastSent;
            //the last sent set point
            String setPoint;
            
            String mode;
            //This is the RS485 address of this node that gets sent to the thermostat
            String serialAddr = "1";
            //Placeholder for the last command sent
            String LastSent = "";
            
            void setup() {
              Serial.begin(9600);
              
              gw.begin( incomingMessage, AUTO, false );
              
              gw.sendSketchInfo( SKETCH_NAME, SKETCH_VERSION );
              
              // Register the thermostat with the gateway
              gw.present( CHILD_ID_HVAC,  S_HVAC );
              gw.present( CHILD_ID_STATE, S_LIGHT );
              
              // put your setup code here, to run once:
              pinMode( SSerialTxControl, OUTPUT );
              digitalWrite( SSerialTxControl, RS485Receive );  // Init Transceiver
              
              // Start the software serial port, to another device
              RS485Serial.begin(9600);   // set the data rate
            } //End setup
            
            void loop() {
              String dataIn;
              
              if (RS485Serial.available()) {
                dataIn = RS485Serial.readStringUntil('\n');
                ParseReceived(dataIn);
              }
            } //End loop
            
            void ParseReceived(String Message) {
              String StatusData;
              //int Count;
              String StatusString;
              String Status;
              String Type;
              String Value;
            
              int Index;
              int Start;
              int End;
              int StatIndex;
            
              Index = Message.indexOf(' ');
              Start = 0;
              
              Serial.println("Message: " + Message);
              
              if (Message.startsWith("A=")) {
                while (End != Message.length()) {
                  End = (Index == -1) ? Message.length() : Index;
                  //Get the status string to process
                  StatusString = Message.substring(Start, End);
                  //Change our start position to 1 over the last space found
                  Start = Index + 1;
                  //Find the end of the next status string
                  Index = Message.indexOf(' ', Start);
              
                  //Now we need to process the status string into it's Type and Value
                  StatIndex = StatusString.indexOf('=');
                  Type = StatusString.substring(0, StatIndex);
                  Value = StatusString.substring(StatIndex + 1);
                  ParseStatus(Type, Value);
                } 
              } else {
                SendCmd(LastSent);
              }
            } //End ParseReceived
            
            void ParseStatus(String Type, String Value) {
              //
              
              if (Type == "OA") {
                  //Outside Air not used
              } else if (Type == "Z") {
                  //Zone not used
              } else if (Type == "T") {
                  Serial.println("T: " + Value);
                  gw.send(msgTemp.set( F2C( Value.toFloat() ), 2 ));
              } else if (Type == "SP") {
                  Serial.println("SP: " + Value);
                  gw.send(msgSetCool.set( F2C( Value.toFloat() ), 2 ));
              } else if (Type == "SPH") {
                  Serial.println("SPH: " + Value);
                  gw.send(msgSetHeat.set( F2C( Value.toFloat() ), 2 ));
              } else if (Type == "SPC") {
                  Serial.println("SPC: " + Value);
                  gw.send(msgSetCool.set( F2C( Value.toFloat() ), 2 ));
              } else if (Type == "M") {
                  //Serial.println("M: " + Value);
                  //gw.send(msgFlowMode.set(Value.c_str()));
              } else if (Type == "FM") {
                  //Serial.println("FM: " + Value);
                  //gw.send(msgFlowMode.set(Value.c_str()));
                //Type 2 status message types
              } else if (Type == "H1A") {
                  Serial.println("H1A: " + Value);
                  if (Value == "1") {
                    //gw.send(msgHvacSpeed.set("Min"));
                  } else {
                    //gw.send(msgHvacSpeed.set("Auto"));
                  }
              } else if (Type == "H2A") {
                  Serial.println("H2A: " + Value);
                  if (Value == "1") {
                    //gw.send(msgHvacSpeed.set("Normal"));
                  } else {
                    //gw.send(msgHvacSpeed.set("Auto"));
                  }
              } else if (Type == "H3A") {
                  Serial.println("H3A: " + Value);
                  if (Value == "1") {
                    //gw.send(msgHvacSpeed.set("Max"));
                  } else {
                    //gw.send(msgHvacSpeed.set("Auto"));
                  }
              } else if (Type == "C1A") {
                  Serial.println("C1A: " + Value);
                  if (Value == "1") {
                    //gw.send(msgHvacSpeed.set("Min"));
                  } else {
                    //gw.send(msgHvacSpeed.set("Auto"));
                  }
              } else if (Type == "C2A") {
                  Serial.println("C2A: " + Value);
                  if (Value == "1") {
                    //gw.send(msgHvacSpeed.set("Normal"));
                  } else {
                    //gw.send(msgHvacSpeed.set("Auto"));
                  }
              } else if (Type == "FA") {
                  Serial.println("FA: " + Value);
                  if (Value == "1") {
                    //gw.send(msgFlowMode.set("ContinuousOn"));
                  } else {
                    //gw.send(msgHvacSpeed.set("Auto"));
                  }
              } else if (Type == "VA") {
                  //Vent damper not used
              } else if (Type == "D1") {
                  //Damper #1 not used
              } else if (Type == "SCP") {
                  String stg1 = Value.substring(0, 1);
                  String stg2 = Value.substring(0, Value.length() - 1);
            
                  //logging.AddToLog("MOT/MRT stage 1: " & stg1, True)
                  //Deal with minimum off time and minimum run times 
                  //for stage 1
            
                  //logging.AddToLog("MOT/MRT stage 2: " & stg2, True)
                  //Deal with minimum off time and minimum run times 
                  //for stage 2
              } else if (Type == "SM") {
                  //logging.AddToLog("System mode: " & Value, True)
                  String FlowState;
                  
                  if (Value == "O") {
                    FlowState = "Off";
                  } else if (Value == "H") {
                    FlowState = "HeatOn";
                  } else if (Value == "C") {
                    FlowState = "CoolOn";
                  } else {
                    FlowState = "AutoChangeOver";
                  }
                  //Serial.println("SM: " + FlowState);
                  //gw.send(msgFlowState.set(FlowState.c_str()));
              } else if (Type == "SF") {
                  //logging.AddToLog("System fan: " & Value, True) 
                  Serial.println("SF: " + Value);
                  gw.send(msgStatus.set(Value.toInt()));
              }
            } //End ParseStatus
            
            float F2C(float Fahrenheit) {
              return (5.0f/9.0f) * (Fahrenheit-32);
            } //End F2C
            
            float C2F(float Celsius) {
              return (Celsius * 9.0f) / 5.0f + 32.0f;
            } //End C2F
            
            void SendCmd(String cmd) {
              String commandStr;
              commandStr = "A=" + serialAddr + " O=00 " + cmd;
            
              Serial.println("Writing to serial port: " + commandStr);
              
              // Enable RS485 Transmit only for the duration of the send
              digitalWrite(SSerialTxControl, RS485Transmit);
              RS485Serial.print(commandStr + "\r");
              LastSent = cmd;
              //Return to RS485 receive mode  
              digitalWrite(SSerialTxControl, RS485Receive);
            } //End SendCmd
            
            /**
             * incomingMessage - Process the incoming messages.
             */
            void incomingMessage(const MyMessage &message) {
              Serial.println("message received");//String(message.type));
              //Serial.println(message.data);
              // We only expect one type of message from controller. But we better check anyway.
              if (message.isAck()) {
                 Serial.println("This is an ack from gateway");
              }
              Serial.println("Temp: " + String(message.data) + " -- " + message.type);
              
              if ( message.type == V_TEMP ) {
                //
                Serial.println("Temp: " + String(message.data)); 
              } //End V_TEMP
              
              if ( message.type == V_STATUS ) {
                //
                Serial.println("Status: " + String(message.data)); 
              } //End V_STATUS
              
              if ( message.type == V_HVAC_FLOW_STATE ) {
                //
                Serial.println("Flow State: " + String(message.data)); 
              } //End V_HVAC_FLOW_STATE
              
              if ( message.type == V_HVAC_SPEED ) {
                //
                Serial.println("Speed: " + String(message.data)); 
              } //End V_HVAC_SPEED
            
              if (message.type == V_HVAC_SETPOINT_COOL) {
                 Serial.println("Message received");
                 String setPoint = String(C2F(atoi(message.data)));
                 Serial.println("New Set Temp is : " + String(setPoint));
                 SendCmd("SPC=" + setPoint + " R=1");
                
                 // Write some debug info
                 Serial.print("Incoming change for sensor:");
                 Serial.print(message.sensor);
                 Serial.print(", New status: ");
                 Serial.println(message.data);
              } //End V_HVAC_SETPOINT_COOL
            
              if (message.type == V_HVAC_SETPOINT_HEAT) {
                 Serial.println("Message received");
                 String setPoint = String(C2F(atoi(message.data))); //.toInt();
                 Serial.println("New Set Temp is : " + String(setPoint));
                 SendCmd("SPH=" + setPoint + " R=1");
                
                 // Write some debug info
                 Serial.print("Incoming change for sensor:");
                 Serial.print(message.sensor);
                 Serial.print(", New status: ");
                 Serial.println(message.data);
              } //End V_HVAC_SETPOINT_HEAT
              
              if ( (message.type == V_HVAC_FLOW_MODE) ) {
                //
                Serial.println("Flow Mode: " + String(message.data)); 
              } //End V_HVAC_FLOW_MODE
            } //End incomingMessage
            

            Thanks

            AWIA Offline
            AWIA Offline
            AWI
            Hero Member
            wrote on last edited by
            #16

            @dbemowsk What does the serial log of the node tell you? Does it show messages coming in?

            dbemowskD 1 Reply Last reply
            0
            • dbemowskD dbemowsk

              OK, so I had this project on hold for a while and am getting back to it. My issue now is that for some reason I am not receiving messages from Domoticz for this node. If I send a temp set point or status from the RS485 side, it updates in Domoticz, but if I try to change a set point or status in Domoticz, the MySensors node doesn't receive it. The code is a bit messy right now, but it should work with what I have. If someone could look it over and advise, that would be a big help. The sketch is a MySensors 1.5.4 sketch.

               /*
                RCS Thermostat for MySensors
              
                Arduino RCS RS485 thermostat control
              
                July 7,2016
              
                This is a gateway bridge to allow an RCS serial thermostat to be accessible to a MySensors
                gateway.  The thermostat being used to test this is an RCS TR40 RS485 thermostat.  The published
                protocol for RCS thermostats can be found at the following address;
                http://www.rcstechnology.com/oldsite/docs/thermostats/serial/SERIAL%20PROTOCOL%20REV%204.3%20%20150-00225-43.pdf
                
                This sketch features the following:
              
                Add features here
               */
              
              // Import needed libraries
              #include <SPI.h>
              #include <MySensor.h>  
              #include <SoftwareSerial.h>
              
              #define SKETCH_NAME "RCS TR40 Thermostat"
              #define SKETCH_VERSION "1.1"
              
              #define CHILD_ID_HVAC    0 // S_HVAC
              #define CHILD_ID_STATE   1 // S_LIGHT
              
              // Declare Constants and Pin Numbers
              #define SSerialRX        5  //Serial Receive pin 8
              #define SSerialTX        3  //Serial Transmit pin 7
              
              #define SSerialTxControl 4  //RS485 Direction control
              
              #define RS485Transmit    HIGH
              #define RS485Receive     LOW
              
              // Declare objects
              SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
              
              MySensor gw;
              
              // Sensor values
              MyMessage msgStatus ( CHILD_ID_STATE,  V_LIGHT );
              MyMessage msgTemp   ( CHILD_ID_HVAC,   V_TEMP );
              MyMessage msgSetCool( CHILD_ID_HVAC,   V_HVAC_SETPOINT_COOL );
              MyMessage msgSetHeat( CHILD_ID_HVAC,   V_HVAC_SETPOINT_HEAT );
              
              // Declare Variables
              int byteReceived;
              int byteSend;
              String rcvString;
              String sndString;
              //This is for storing the last command that was sent 
              String lastSent;
              //the last sent set point
              String setPoint;
              
              String mode;
              //This is the RS485 address of this node that gets sent to the thermostat
              String serialAddr = "1";
              //Placeholder for the last command sent
              String LastSent = "";
              
              void setup() {
                Serial.begin(9600);
                
                gw.begin( incomingMessage, AUTO, false );
                
                gw.sendSketchInfo( SKETCH_NAME, SKETCH_VERSION );
                
                // Register the thermostat with the gateway
                gw.present( CHILD_ID_HVAC,  S_HVAC );
                gw.present( CHILD_ID_STATE, S_LIGHT );
                
                // put your setup code here, to run once:
                pinMode( SSerialTxControl, OUTPUT );
                digitalWrite( SSerialTxControl, RS485Receive );  // Init Transceiver
                
                // Start the software serial port, to another device
                RS485Serial.begin(9600);   // set the data rate
              } //End setup
              
              void loop() {
                String dataIn;
                
                if (RS485Serial.available()) {
                  dataIn = RS485Serial.readStringUntil('\n');
                  ParseReceived(dataIn);
                }
              } //End loop
              
              void ParseReceived(String Message) {
                String StatusData;
                //int Count;
                String StatusString;
                String Status;
                String Type;
                String Value;
              
                int Index;
                int Start;
                int End;
                int StatIndex;
              
                Index = Message.indexOf(' ');
                Start = 0;
                
                Serial.println("Message: " + Message);
                
                if (Message.startsWith("A=")) {
                  while (End != Message.length()) {
                    End = (Index == -1) ? Message.length() : Index;
                    //Get the status string to process
                    StatusString = Message.substring(Start, End);
                    //Change our start position to 1 over the last space found
                    Start = Index + 1;
                    //Find the end of the next status string
                    Index = Message.indexOf(' ', Start);
                
                    //Now we need to process the status string into it's Type and Value
                    StatIndex = StatusString.indexOf('=');
                    Type = StatusString.substring(0, StatIndex);
                    Value = StatusString.substring(StatIndex + 1);
                    ParseStatus(Type, Value);
                  } 
                } else {
                  SendCmd(LastSent);
                }
              } //End ParseReceived
              
              void ParseStatus(String Type, String Value) {
                //
                
                if (Type == "OA") {
                    //Outside Air not used
                } else if (Type == "Z") {
                    //Zone not used
                } else if (Type == "T") {
                    Serial.println("T: " + Value);
                    gw.send(msgTemp.set( F2C( Value.toFloat() ), 2 ));
                } else if (Type == "SP") {
                    Serial.println("SP: " + Value);
                    gw.send(msgSetCool.set( F2C( Value.toFloat() ), 2 ));
                } else if (Type == "SPH") {
                    Serial.println("SPH: " + Value);
                    gw.send(msgSetHeat.set( F2C( Value.toFloat() ), 2 ));
                } else if (Type == "SPC") {
                    Serial.println("SPC: " + Value);
                    gw.send(msgSetCool.set( F2C( Value.toFloat() ), 2 ));
                } else if (Type == "M") {
                    //Serial.println("M: " + Value);
                    //gw.send(msgFlowMode.set(Value.c_str()));
                } else if (Type == "FM") {
                    //Serial.println("FM: " + Value);
                    //gw.send(msgFlowMode.set(Value.c_str()));
                  //Type 2 status message types
                } else if (Type == "H1A") {
                    Serial.println("H1A: " + Value);
                    if (Value == "1") {
                      //gw.send(msgHvacSpeed.set("Min"));
                    } else {
                      //gw.send(msgHvacSpeed.set("Auto"));
                    }
                } else if (Type == "H2A") {
                    Serial.println("H2A: " + Value);
                    if (Value == "1") {
                      //gw.send(msgHvacSpeed.set("Normal"));
                    } else {
                      //gw.send(msgHvacSpeed.set("Auto"));
                    }
                } else if (Type == "H3A") {
                    Serial.println("H3A: " + Value);
                    if (Value == "1") {
                      //gw.send(msgHvacSpeed.set("Max"));
                    } else {
                      //gw.send(msgHvacSpeed.set("Auto"));
                    }
                } else if (Type == "C1A") {
                    Serial.println("C1A: " + Value);
                    if (Value == "1") {
                      //gw.send(msgHvacSpeed.set("Min"));
                    } else {
                      //gw.send(msgHvacSpeed.set("Auto"));
                    }
                } else if (Type == "C2A") {
                    Serial.println("C2A: " + Value);
                    if (Value == "1") {
                      //gw.send(msgHvacSpeed.set("Normal"));
                    } else {
                      //gw.send(msgHvacSpeed.set("Auto"));
                    }
                } else if (Type == "FA") {
                    Serial.println("FA: " + Value);
                    if (Value == "1") {
                      //gw.send(msgFlowMode.set("ContinuousOn"));
                    } else {
                      //gw.send(msgHvacSpeed.set("Auto"));
                    }
                } else if (Type == "VA") {
                    //Vent damper not used
                } else if (Type == "D1") {
                    //Damper #1 not used
                } else if (Type == "SCP") {
                    String stg1 = Value.substring(0, 1);
                    String stg2 = Value.substring(0, Value.length() - 1);
              
                    //logging.AddToLog("MOT/MRT stage 1: " & stg1, True)
                    //Deal with minimum off time and minimum run times 
                    //for stage 1
              
                    //logging.AddToLog("MOT/MRT stage 2: " & stg2, True)
                    //Deal with minimum off time and minimum run times 
                    //for stage 2
                } else if (Type == "SM") {
                    //logging.AddToLog("System mode: " & Value, True)
                    String FlowState;
                    
                    if (Value == "O") {
                      FlowState = "Off";
                    } else if (Value == "H") {
                      FlowState = "HeatOn";
                    } else if (Value == "C") {
                      FlowState = "CoolOn";
                    } else {
                      FlowState = "AutoChangeOver";
                    }
                    //Serial.println("SM: " + FlowState);
                    //gw.send(msgFlowState.set(FlowState.c_str()));
                } else if (Type == "SF") {
                    //logging.AddToLog("System fan: " & Value, True) 
                    Serial.println("SF: " + Value);
                    gw.send(msgStatus.set(Value.toInt()));
                }
              } //End ParseStatus
              
              float F2C(float Fahrenheit) {
                return (5.0f/9.0f) * (Fahrenheit-32);
              } //End F2C
              
              float C2F(float Celsius) {
                return (Celsius * 9.0f) / 5.0f + 32.0f;
              } //End C2F
              
              void SendCmd(String cmd) {
                String commandStr;
                commandStr = "A=" + serialAddr + " O=00 " + cmd;
              
                Serial.println("Writing to serial port: " + commandStr);
                
                // Enable RS485 Transmit only for the duration of the send
                digitalWrite(SSerialTxControl, RS485Transmit);
                RS485Serial.print(commandStr + "\r");
                LastSent = cmd;
                //Return to RS485 receive mode  
                digitalWrite(SSerialTxControl, RS485Receive);
              } //End SendCmd
              
              /**
               * incomingMessage - Process the incoming messages.
               */
              void incomingMessage(const MyMessage &message) {
                Serial.println("message received");//String(message.type));
                //Serial.println(message.data);
                // We only expect one type of message from controller. But we better check anyway.
                if (message.isAck()) {
                   Serial.println("This is an ack from gateway");
                }
                Serial.println("Temp: " + String(message.data) + " -- " + message.type);
                
                if ( message.type == V_TEMP ) {
                  //
                  Serial.println("Temp: " + String(message.data)); 
                } //End V_TEMP
                
                if ( message.type == V_STATUS ) {
                  //
                  Serial.println("Status: " + String(message.data)); 
                } //End V_STATUS
                
                if ( message.type == V_HVAC_FLOW_STATE ) {
                  //
                  Serial.println("Flow State: " + String(message.data)); 
                } //End V_HVAC_FLOW_STATE
                
                if ( message.type == V_HVAC_SPEED ) {
                  //
                  Serial.println("Speed: " + String(message.data)); 
                } //End V_HVAC_SPEED
              
                if (message.type == V_HVAC_SETPOINT_COOL) {
                   Serial.println("Message received");
                   String setPoint = String(C2F(atoi(message.data)));
                   Serial.println("New Set Temp is : " + String(setPoint));
                   SendCmd("SPC=" + setPoint + " R=1");
                  
                   // Write some debug info
                   Serial.print("Incoming change for sensor:");
                   Serial.print(message.sensor);
                   Serial.print(", New status: ");
                   Serial.println(message.data);
                } //End V_HVAC_SETPOINT_COOL
              
                if (message.type == V_HVAC_SETPOINT_HEAT) {
                   Serial.println("Message received");
                   String setPoint = String(C2F(atoi(message.data))); //.toInt();
                   Serial.println("New Set Temp is : " + String(setPoint));
                   SendCmd("SPH=" + setPoint + " R=1");
                  
                   // Write some debug info
                   Serial.print("Incoming change for sensor:");
                   Serial.print(message.sensor);
                   Serial.print(", New status: ");
                   Serial.println(message.data);
                } //End V_HVAC_SETPOINT_HEAT
                
                if ( (message.type == V_HVAC_FLOW_MODE) ) {
                  //
                  Serial.println("Flow Mode: " + String(message.data)); 
                } //End V_HVAC_FLOW_MODE
              } //End incomingMessage
              

              Thanks

              AWIA Offline
              AWIA Offline
              AWI
              Hero Member
              wrote on last edited by AWI
              #17

              @dbemowsk And... (sorry to bother you with things you didn't ask for) Your sketch is loaded with String object definitions and therefore open fora lot of problems. String looks like an easy solution but not really suited for real time (MySensors) purposes.
              An interesting article/ opinion background on the subject...

              My advice: Forget about String and get back to comprehensible char arrays. (unless somebody can convince me otherwise) .

              dbemowskD 1 Reply Last reply
              1
              • AWIA AWI

                @dbemowsk What does the serial log of the node tell you? Does it show messages coming in?

                dbemowskD Offline
                dbemowskD Offline
                dbemowsk
                wrote on last edited by dbemowsk
                #18

                @AWI said:

                @dbemowsk What does the serial log of the node tell you? Does it show messages coming in?

                I put the first Serial.println in the incomingMessage function to test and see if it was even hitting that function. I am not even seeing that in the serial monitor. That was the thing that prompted me to post this.

                The set-up I have for testing right now is I have my node connected to the FTDI usb cable on one end (COM5). On the RS485 end (COM10) I have it looped back to my laptop through a USB to RS485 adapter. I then use a serial terminal program to transmit and receive strings similar to what would come from my thermostat. As I mentioned in my post, if I send a command on the RS485 side as if my thermostat controller sent it, it goes through ParseReceived and ParseStatus normally and the gw.send commands push it to Domoticz just fine.

                I just can't think of any reason why the incoming messages from Domoticz are not being seen by the node. One thing I did find strange was that in order to see the Serial.println messages in the arduino serial monitor, I have it set to a baud of 115200 bps. The thing that confused me was that I have the first line in set-up as :

                Serial.begin(9600);
                

                I did this because that is the baud rate that my thermostat communicates at on the RS485 side of things. I realize that this is for the RS232 serial side on the arduino which is why I was confused.

                1 Reply Last reply
                0
                • AWIA AWI

                  @dbemowsk And... (sorry to bother you with things you didn't ask for) Your sketch is loaded with String object definitions and therefore open fora lot of problems. String looks like an easy solution but not really suited for real time (MySensors) purposes.
                  An interesting article/ opinion background on the subject...

                  My advice: Forget about String and get back to comprehensible char arrays. (unless somebody can convince me otherwise) .

                  dbemowskD Offline
                  dbemowskD Offline
                  dbemowsk
                  wrote on last edited by
                  #19

                  @AWI said:

                  @dbemowsk And... (sorry to bother you with things you didn't ask for) Your sketch is loaded with String object definitions and therefore open fora lot of problems. String looks like an easy solution but not really suited for real time (MySensors) purposes.
                  An interesting article/ opinion background on the subject...

                  My advice: Forget about String and get back to comprehensible char arrays. (unless somebody can convince me otherwise) .

                  No need to appologize. C and C++ are languages that I have not done much programming in. Well, a very limited amount of C++ and I have never used C (until getting into arduino which seems to be more C based). As I have been working in my arduuino stuff I have been seeing more people using char and char* definitions. That and converting to these using c_str(). As mentioned, I am new to these languages, so if you know of any good tutorials on how to use these versus String, I am open to suggestions. I have not yet looked at the link you posted, but will shortly. If this is the more proper way to do things in arduino, I would like to shift my thinking in that direction.

                  1 Reply Last reply
                  0
                  • dbemowskD Offline
                    dbemowskD Offline
                    dbemowsk
                    wrote on last edited by
                    #20

                    @awi I am part way through your article on strings describing the stack and the heap. GREAT article. I have not finished it yet, but what I have read so far is excellent info.

                    1 Reply Last reply
                    0
                    • dbemowskD Offline
                      dbemowskD Offline
                      dbemowsk
                      wrote on last edited by
                      #21
                      This post is deleted!
                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      27

                      Online

                      11.7k

                      Users

                      11.2k

                      Topics

                      113.1k

                      Posts


                      Copyright 2025 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • MySensors
                      • OpenHardware.io
                      • Categories
                      • Recent
                      • Tags
                      • Popular