Using 2 channel relay system for year round temperature control

I suppose this could also be put under project guidance but i picked this becuase i am having a lot of confusion about the programming. This is only my second Arduino project. I wanted to use a fridge and a seedling heat mat to make a temperature control system that will maintain a given temperature regardless of the temperature outside the fridge. That's what i mean by year-round. This is my source.

The code from there is 5 years old and not mine. Currently, the problems with the code are to do with the warming and cooling functions. The stuff about Probe02, Temp02SetPoint, Temp02SetDiff, Temp02WarmMaxed is tied into the warming function because the original guy who wrote that wanted to have another probe just outside of the fermenter. Then there is something wrong with how the void loop() ends. It expected something before the curly bracket closing the loop.

I dont understand how to make it work for my case where i only plan on controlling one fermenter with a single DSB18B20 probe. This also means to use the lcd.setCursor() and lcd.print() commands to display only the results of one probe and fermenter show on the LCD. I made the probe and Adafruit LCD work independently with the examples from the library folders. The code i have so far is:

/* Multiple DS18B20 Temperature Sensors on 1 wire
   for controlling heating or cooling of muliple fermenters.
*/   
/*-----( Import needed libraries )-----*/
// Get 1-wire Library here: http://www.pjrc.com/teensy/td_libs_OneWire.html
#include <OneWire.h>

//Get DallasTemperature Library here:  http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library
#include <DallasTemperature.h>

/*-----( Declare Constants and Pin Numbers )-----*/
// Digital pin 2 for all the DS18B20 data lines.
#define ONE_WIRE_BUS_PIN 2

#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>

/*-----( Declare objects )-----*/
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS_PIN);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

/*-----( Declare Variables )-----*/
// Pre-assign the addresses of your 1-Wire temp sensors.
// See the tutorial on how to obtain these addresses:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html
// Uncomment the following lines for preassigning the addresses to the probes variable

DeviceAddress Probe01 = { 0x28, 0xFF, 0xFB, 0x74, 0x44, 0xE0, 0x48, 0x66 }; 
//DeviceAddress Probe02 = {  };
//DeviceAddress Probe03 = {  };
//DeviceAddress Probe04 = {  };
//DeviceAddress Probe05 = {  };

//Relay digital write pins on Arduino
int Relay1 = 5;
int Relay2 = 6;

float Probe01Temp = 0;
///float Probe02Temp = 0;
///float Probe03Temp = 0;

//Limit and floor are Celcius
//Adjust these temperature limits as needed
int Temp01SetPoint = 15;
int Temp01SetDiff = 1;
int Temp02SetPoint = 15;
int Temp02SetDiff = 1;

static bool Temp01CoolMaxed;
static bool Temp01WarmMaxed;
static bool Temp02CoolMaxed;
static bool Temp02WarmMaxed;
static bool Relay01Status;
static bool Relay02Status;

//Adjust the address of the I2C as needed
//See https://github.com/todbot/arduino-i2c-scanner
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

void setup()   /****** SETUP: RUNS ONCE ******/
{
    
  // start lcd to show results
  lcd.begin(20,4);
  lcd.setCursor(0, 0);
  lcd.print("Starting Up");
  
  // Initialize the Temperature measurement library
  sensors.begin();

  // Comment out the following three lines if pre-assigned above
  ///sensors.getAddress(Probe01, 0);
  ///sensors.getAddress(Probe02, 1);
  ///sensors.getAddress(Probe03, 2);
  
  // set the resolution to 10 bit (Can be 9 to 12 bits .. lower is faster)
  sensors.setResolution(Probe01, 10);
  ///sensors.setResolution(Probe02, 9);
  ///sensors.setResolution(Probe03, 9);
  ///sensors.setResolution(Probe04, 10);
  ///sensors.setResolution(Probe05, 10);

  //set the relays
  pinMode(Relay1, OUTPUT);
  pinMode(Relay2, OUTPUT);
  //turn off the relays to start
  digitalWrite(Relay1, HIGH);
  digitalWrite(Relay2, HIGH);

  Temp01CoolMaxed = false;
  Temp01WarmMaxed = false;
  Temp02CoolMaxed = false;
  Temp02WarmMaxed = false;
  Relay01Status = false;
  Relay02Status = false;

  lcd.setCursor(0, 1);
  lcd.print("No sensors:");
  lcd.setCursor(12, 1);
  lcd.print(sensors.getDeviceCount());
  lcd.setCursor(0, 2);
  lcd.print("Getting temperatures");

  delay(500);
  lcd.clear();

 //Set up labels on LCD
 lcd.setCursor(0, 0);
 lcd.print("C");
 lcd.setCursor(1,0);
 lcd.print("T1:");
 lcd.setCursor(6,0);
 lcd.print("-");
 lcd.setCursor(8,0);
 lcd.print("C");
 lcd.setCursor(10,0);
 lcd.print("H");
 lcd.setCursor(11,0);
 lcd.print("T2:");
 lcd.setCursor(16,0);
 lcd.print("+");
 lcd.setCursor(18,0);
 lcd.print("C");
 lcd.setCursor(0, 1);
 lcd.print("Carby1 Carby2 Outsde");
 lcd.setCursor(5, 2);
 lcd.print("C");
 lcd.setCursor(12, 2);
 lcd.print("C");
 lcd.setCursor(19,2);
 lcd.print("C");
 lcd.setCursor(0, 3);
 lcd.print("CL");
 lcd.setCursor(2,3);
 lcd.print("R1:");
 lcd.setCursor(10,3);
 lcd.print("HT");
 lcd.setCursor(12,3);
 lcd.print("R2:"); 

 lcd.setCursor(4,0);
 lcd.print(Temp01SetPoint);
 lcd.setCursor(7,0);
 lcd.print(Temp01SetDiff);
 lcd.setCursor(14,0);
 lcd.print(Temp02SetPoint);
 lcd.setCursor(17,0);
 lcd.print(Temp02SetDiff);

  
}//--(end setup )---

void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  delay(5000);
   
  // Command all devices on bus to read temperature  
  sensors.requestTemperatures();
  //First carboy
  Probe01Temp = sensors.getTempC(Probe01);
  
  //Second carboy
  ///Probe02Temp = sensors.getTempC(Probe02);
  //Outside temperature
  ///Probe03Temp = sensors.getTempC(Probe03);

  //Change calls to triggerCoolingRelay and triggerWarmingRelay
  //as needed such as both Relay01 and Relay02 both call triggerWarmingRelay()
  
  Relay01Status=triggerCoolingRelay(Probe01Temp, Relay1, Temp01SetPoint, Temp01SetDiff, Temp01CoolMaxed);
  Temp01CoolMaxed=Relay01Status;
  Relay02Status=triggerWarmingRelay(Probe02Temp, Relay2, Temp02SetPoint, Temp02SetDiff, Temp02WarmMaxed);
  Temp02WarmMaxed=Relay02Status;

  //Print to LCD
  lcd.setCursor(0,2);
  lcd.print(Probe01Temp - 3.5);

  ///lcd.setCursor(7,2);
  ///lcd.print(Probe02Temp);

  ///lcd.setCursor(14,2);
  ///lcd.print(Probe03Temp);
  
  lcd.setCursor(5,3);
  if (Relay01Status)
    {
      lcd.print("On ");
    }
    else
    {
      lcd.print("Off");
    }
  lcd.setCursor(15,3);
  ///if (Relay02Status)
    ///{
      ///lcd.print("On ");
    ///}
    ///else
    ///{
     /// lcd.print("Off");
    }   
}//--(end main loop )---


/*-----( Declare User-written Functions )-----*/
bool triggerCoolingRelay(float tempC, int Relay, int TempSetLimit, int TempSetDiff, bool TempCoolMaxed)
{
  bool result;
  
    if (TempCoolMaxed)
      {
      if (tempC < (TempSetLimit-TempSetDiff))
        {
        //TempCoolMaxed=false;
        result=false;
        }
      }
    else
      {
      if (tempC > TempSetLimit)
         {
           //TempCoolMaxed=true;
           digitalWrite(Relay, LOW);
           result=true;
         } 
       else 
         {
          digitalWrite(Relay, HIGH);
          result=false;
         }
      }
    return result;
 }// End triggerCoolingRelay

bool triggerWarmingRelay(float tempC, int Relay, int TempSetLimit, int TempSetDiff, bool TempWarmMaxed)
{
  bool result;
  
    if (TempWarmMaxed)
      {
      if (tempC > (TempSetLimit+TempSetDiff))
        {
        //TempWarmMaxed=false;
        result=false;
        }
      }
    else
      {
      if (tempC < TempSetLimit)
         {
         //TempWarmMaxed=true;
         digitalWrite(Relay, LOW);
         result=true;
         } 
        else 
          {
          digitalWrite(Relay, HIGH);
          result=false;
          }
       }
   return result;
   
 }// End triggerWarmingRelay

The error code in red is:

C:\Users\hirde\Desktop\Circuitry projects\projects\all-seasons-temp-controller\all-seasons-temp-controller.ino: In function 'void loop()':
all-seasons-temp-controller:174:17: error: 'triggerCoolingRelay' was not declared in this scope
   Relay01Status=triggerCoolingRelay(Probe01Temp, Relay1, Temp01SetPoint, Temp01SetDiff, Temp01CoolMaxed);
                 ^~~~~~~~~~~~~~~~~~~
all-seasons-temp-controller:176:37: error: 'Probe02Temp' was not declared in this scope
   Relay02Status=triggerWarmingRelay(Probe02Temp, Relay2, Temp02SetPoint, Temp02SetDiff, Temp02WarmMaxed);
                                     ^~~~~~~~~~~
C:\Users\hirde\Desktop\Circuitry projects\projects\all-seasons-temp-controller\all-seasons-temp-controller.ino:176:37: note: suggested alternative: 'Probe01Temp'
   Relay02Status=triggerWarmingRelay(Probe02Temp, Relay2, Temp02SetPoint, Temp02SetDiff, Temp02WarmMaxed);
                                     ^~~~~~~~~~~
                                     Probe01Temp
all-seasons-temp-controller:176:17: error: 'triggerWarmingRelay' was not declared in this scope
   Relay02Status=triggerWarmingRelay(Probe02Temp, Relay2, Temp02SetPoint, Temp02SetDiff, Temp02WarmMaxed);
                 ^~~~~~~~~~~~~~~~~~~
C:\Users\hirde\Desktop\Circuitry projects\projects\all-seasons-temp-controller\all-seasons-temp-controller.ino: At global scope:
all-seasons-temp-controller:207:1: error: expected declaration before '}' token
 }//--(end main loop )---
 ^
exit status 1
'triggerCoolingRelay' was not declared in this scope

Any help is appreciated. Cheers!

Looks to have unmatched left and right brackets.
Paul

Hello
Delete one of them.

If you Auto Format your sketch you will see this at the end of loop():

  ///lcd.print("On ");
  ///}
  ///else
  ///{
  /// lcd.print("Off");
}
}//--(end main loop )---

The fact that two brackets at the end of loop() are at the left edge of the screen means that the first one ended the loop() function and the second one is outside the loop() function.

I did delete the curly bracket and that got rid of the last problem. There is still the design issue with the program. If you don't know how to help me with that, i would be grateful if you could show me where to obtain knowledge so I can understand and modify it myself.

Edit: Then i did what you suggested, but it got me the same result as deleting one of the curly brackets

I think the original guy was onto something when he used a second sensor on the outside of the fermenter. The way you're trying to do it will mean that you are essentially going to make the heating and the cooling systems fight each other. You let the fermenter warm up with the heating mat until it gets too warm, and then the fridge kicks in to cool it down again. So the device will be using energy 24/7, which is wasteful of course. It's a better idea to actually sample temperature outside the box as well so you know if you need to run either the heater or the cooler, since you'll never need both at more or less the same time.

1 Like

I found and fixed a few problems. I think the most important was passing 'Probe02Temp' to triggerWarmingRelay(). I changed a bunch of names to make them more meaningful.

You have the Cooling and Warming setpoint both set to 15 degrees. If the temperature gets to 16 the cooling is going to be on until the temperature gets to 13 but when the temperature gets down to 14 the warmer is going to turn on until the temperature gets up to 17. This means that BOTH are going to be on most of the time. Whichever one is stronger will force the temperature to the outside limit (13 or 17) until it turns off and lets the other do its job. They will then fight again. Perhaps you should make sure that their control ranges don't overlap.

/* Multiple DS18B20 Temperature Sensors on 1 wire
   for controlling heating or cooling of muliple fermenters.
*/
/*-----( Import needed libraries )-----*/
// Get 1-wire Library here: http://www.pjrc.com/teensy/td_libs_OneWire.html
#include <OneWire.h>

//Get DallasTemperature Library here:  http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library
#include <DallasTemperature.h>

/*-----( Declare Constants and Pin Numbers )-----*/
// Digital pin 2 for all the DS18B20 data lines.
#define ONE_WIRE_BUS_PIN 2

#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>

/*-----( Declare objects )-----*/
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS_PIN);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

/*-----( Declare Variables )-----*/
// Pre-assign the addresses of your 1-Wire temp sensors.
// See the tutorial on how to obtain these addresses:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html
// Uncomment the following lines for preassigning the addresses to the probes variable

DeviceAddress Probe01 = { 0x28, 0xFF, 0xFB, 0x74, 0x44, 0xE0, 0x48, 0x66 };
//DeviceAddress Probe02 = {  };
//DeviceAddress Probe03 = {  };
//DeviceAddress Probe04 = {  };
//DeviceAddress Probe05 = {  };

//Relay digital write pins on Arduino
const int CoolingRelayPin = 5;
const int WarmingRelayPin = 6;

float Probe01Temp = 0;

// Limit and floor are Celcius
// Adjust these temperature limits as needed
int CoolingSetPoint = 15;
int CoolingSetDiff = 1;
int WarmingSetPoint = 15;
int WarmingSetDiff = 1;

bool CoolingRelayOn = false;
bool WarmingRelayOn = false;

//Adjust the address of the I2C as needed
//See https://github.com/todbot/arduino-i2c-scanner
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

void setup()   /****** SETUP: RUNS ONCE ******/
{
  // start lcd to show results
  lcd.begin(20, 4);
  lcd.setCursor(0, 0);
  lcd.print("Starting Up");

  // Initialize the Temperature measurement library
  sensors.begin();

  // Comment out the following three lines if pre-assigned above
  ///sensors.getAddress(Probe01, 0);
  ///sensors.getAddress(Probe02, 1);
  ///sensors.getAddress(Probe03, 2);

  // set the resolution to 10 bit (Can be 9 to 12 bits .. lower is faster)
  sensors.setResolution(Probe01, 10);
  ///sensors.setResolution(Probe02, 9);
  ///sensors.setResolution(Probe03, 9);

  //turn off the relays to start
  digitalWrite(CoolingRelayPin, HIGH);
  digitalWrite(WarmingRelayPin, HIGH);

  //set the relay output pins
  pinMode(CoolingRelayPin, OUTPUT);
  pinMode(WarmingRelayPin, OUTPUT);

  lcd.setCursor(0, 1);
  lcd.print("No sensors:");
  lcd.setCursor(12, 1);
  lcd.print(sensors.getDeviceCount());
  lcd.setCursor(0, 2);
  lcd.print("Getting temperatures");

  delay(500);
  lcd.clear();

  //Set up labels on LCD
  lcd.setCursor(0, 0);
  lcd.print("C");
  lcd.setCursor(1, 0);
  lcd.print("T1:");
  lcd.setCursor(6, 0);
  lcd.print("-");
  lcd.setCursor(8, 0);
  lcd.print("C");
  lcd.setCursor(10, 0);
  lcd.print("H");
  lcd.setCursor(11, 0);
  lcd.print("T2:");
  lcd.setCursor(16, 0);
  lcd.print("+");
  lcd.setCursor(18, 0);
  lcd.print("C");
  lcd.setCursor(0, 1);
  lcd.print("Carby1 Carby2 Outsde");
  lcd.setCursor(5, 2);
  lcd.print("C");
  lcd.setCursor(12, 2);
  lcd.print("C");
  lcd.setCursor(19, 2);
  lcd.print("C");
  lcd.setCursor(0, 3);
  lcd.print("CL");
  lcd.setCursor(2, 3);
  lcd.print("R1:");
  lcd.setCursor(10, 3);
  lcd.print("HT");
  lcd.setCursor(12, 3);
  lcd.print("R2:");

  lcd.setCursor(4, 0);
  lcd.print(CoolingSetPoint);
  lcd.setCursor(7, 0);
  lcd.print(CoolingSetDiff);
  lcd.setCursor(14, 0);
  lcd.print(WarmingSetPoint);
  lcd.setCursor(17, 0);
  lcd.print(WarmingSetDiff);
}//--(end setup )---

void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  // Command all devices on bus to read temperature
  sensors.requestTemperatures();

  Probe01Temp = sensors.getTempC(Probe01);

  //Change calls to triggerCoolingRelay and triggerWarmingRelay
  //as needed such as both CoolingRelay and WarmingRelay both call triggerWarmingRelay()

  CoolingRelayOn = triggerCoolingRelay(Probe01Temp, CoolingRelayPin, CoolingSetPoint, CoolingSetDiff, CoolingRelayOn);

  WarmingRelayOn = triggerWarmingRelay(Probe01Temp, WarmingRelayPin, WarmingSetPoint, WarmingSetDiff, WarmingRelayOn);


  //Print to LCD
  lcd.setCursor(0, 2);
  lcd.print(Probe01Temp - 3.5);  // ????

  ///lcd.setCursor(7,2);
  ///lcd.print(Probe02Temp);

  ///lcd.setCursor(14,2);
  ///lcd.print(Probe03Temp);

  lcd.setCursor(5, 3);
  if (CoolingRelayOn)
  {
    lcd.print("On ");
  }
  else
  {
    lcd.print("Off");
  }

  lcd.setCursor(15, 3);
  if (WarmingRelayOn)
  {
    lcd.print("On ");
  }
  else
  {
    lcd.print("Off");
  }
} //--(end main loop )---


/*-----( Declare User-written Functions )-----*/
bool triggerCoolingRelay(float tempC, int RelayPin, int TempSetLimit, int TempSetDiff, bool relayIsOn)
{
  if (relayIsOn)
  {
    // Continue cooling until temperature drops below TempSetLimit - TempSetDiff
    if (tempC < (TempSetLimit - TempSetDiff))
    {
      relayIsOn = false;
    }
  }
  else
  {
    // Start cooling temperature is above TempSetLimit
    if (tempC > TempSetLimit)
    {
      relayIsOn = true;
    }
  }

  if (relayIsOn)
    digitalWrite(RelayPin, LOW);
  else
    digitalWrite(RelayPin, HIGH);

  return relayIsOn;
} // End triggerCoolingRelay

bool triggerWarmingRelay(float tempC, int RelayPin, int TempSetLimit, int TempSetDiff, bool relayIsOn)
{
  if (relayIsOn)
  {
    // Continue warming until temperature is above TempSetLimit + TempSetDiff
    if (tempC > (TempSetLimit + TempSetDiff))
    {
      relayIsOn = false;
    }
  }
  else
  {
    // Start warming if temperature is below TempSetLimit
    if (tempC < TempSetLimit)
    {
      relayIsOn = true;
    }
  }

  if (relayIsOn)
    digitalWrite(RelayPin, LOW);
  else
    digitalWrite(RelayPin, HIGH);

  return relayIsOn;
}// End triggerWarmingRelay
1 Like

yeah ok that makes sense. I will consider using a second probe. I thought that about 12 liters of a liquid that is 90% water will have a gradual temperature change.

Awesome! Thanks for your effort. I will look at it when i am free.

That is really good! It works without errors and makes more sense with the new names for variables and functions. I have set CoolingSetPoint = 13.8, CoolingSetDiff = 0.8, WarmingSetPoint = 12.1, and WarmingSetDiff = 0.8. want to understand these things myself because i want to use the buttons on the Adafruit LCD. That will require more programing. So where do you suggest i start learning C++? Codecademy?

Edit: I wonder why you put

  //set the relay output pins
  pinMode(CoolingRelayPin, OUTPUT);
  pinMode(WarmingRelayPin, OUTPUT);

after

  //turn off the relays to start
  digitalWrite(CoolingRelayPin, HIGH);
  digitalWrite(WarmingRelayPin, HIGH);

Also lcd.print(Probe01Temp - 3.5) is like that because the probe gives the temperatures a bit higher that what they actually are. I tested it with boiling hot water, body temp, and in an ice bath.

Did you change the type from 'int' to 'float'? You can't the decimal fraction part in an 'int'.

It will, but the heater comes on when the temperature is below 15 and doesn't go off until the temperature is above 16. The cooler comes on when the temperature is above 15 and doesn't go off until the temperature is below 14. No matter which one turns on first, the other one will start fighting it before it turns off.

1 Like

yes i used the float. So if there is no overlap between warming and cooling ranges, the system will push the beer's temperature between 12.9 to 13.0 right? Do you think that the gap in-between is too small?

The cooler will come on above 13.8 and cool down to below 13.0. The heater will come on below 12.1 and heat to above 12.9. The gap is only about 1 degree so it is possible overshoot could cause the temperature to ping-pong: the heater overshooting past 13.8 and the cooler overshooting past 12.1

1 Like

Ok that makes sense. I think you meant to say 0.1 degree instead. Thanks again for your time and expertise! :slight_smile: I wouldn't mind sharing some of that homebrew with you if you are around the Vancouver BC area.

No, I meant 1 degree. The heater will stay on until the temperature goes above 12.9 degrees. If the temperature continues to rise past 13.8 degrees (about 1 degree higher) the cooler will come on. Similarly, the cooler will stay on until the temperature is below 13.0. If the temperature continues to drop past 12.1 (about a degree lower) the heater will come on.

Sorry to wake this post from the grave! I finally got all the parts and time to put it together. It doesnt work!

I see two problems. Firstly, the probe gives a result of -129.00. I tried disconnecting the probe but it gives the same result. That means something is wrong with the code. I wonder what could cause this. I will continue searching on Google. I know the probe should be fine because used the same one yesterday for a digital thermometer displaying results on a 0.96" OLED.

Secondly, the Arduino Uno doesnt use the 2 channel relay despite detecting a very low temperature of -129C. I substituted the fridge and heating mat with very small devices because i thought that if something goes wrong it will be less dangerous than a big thing drawing lots of power. I plugged a lamp into one spot on the outlet and called it the fridge. I plugged in my phone in the other spot on the outlet and called it the heating mat. None of them get power. I am baffled because the compiler produced no errors. Was the wiring schematic that i followed wrong?

What suggestions do you have?

The temperature sensor worked before and does not work now. Are you using a probe with a different address? Is there a break in the probe wiring?

The red, black, and yellow wires seem to have a black oxide coating on them where the soldering joint ends. They dont seem to be broken. I can put them into the breadboard just fine like i used to. This is the same probe as i always use so the address cant change.