Temp Controlled Relay with User Setting Stored in EEPROM - SOLVED

I’m using a DHT11 to read temperature to control a relay that will control a fan. When ‘A’ is pressed it allows the user to update the temp value that the relay will go HIGH at. The value is being stored and read to and from the EEPROM but temp sensor value and init_temp value are not the same somehow.
It looks as though it should work as it is since the temp module is returning a 2 digit integer and it looks as though init_pass is returning a 2 digit integer but is only seeing the first digit when comparing in the if statement: if (temp >= init_pass){

I guess the best question I could ask is if the serial monitor is returning a 2 digit integer for Serial.print(init_pass) , one after another after another ie. 252525252525252525 - how different is that from having if(temp >= 25) vs if(temp >= init_pass) ? or is that really an integer that is displaying in the serial monitor? I’m confused.

#include <EEPROM.h>
#include <Keypad.h> 
#include <LiquidCrystal.h>
#include <dht11.h>                  
dht11 DHT;                  

char temperature[2];
char initial_temperature[2];
char new_temperature[2];
char key_pressed=0;
//char init_pass[2];

const int relay = 8;  
const int dht11_data = 6;     
int temp=0;
int relayState = LOW;         
int i=0;
int j=0;
int init_pass = 0;

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the symbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {38, 40, 42, 44}; 
byte colPins[COLS] = {46, 48, 50, 52}; 

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup() {
  Serial.begin(9600);
  pinMode(relay, OUTPUT); 
  digitalWrite(relay, relayState);
  lcd.begin(16,2);
  lcd.print("  Welcome to ");
  lcd.setCursor(0,1);
  lcd.print("     Test 2");
  delay(2000);
  lcd.clear();


}

void loop() {

  DHT.read(dht11_data);
  temp=DHT.temperature;

  lcd.clear();                   
  lcd.setCursor(5,0) ;          
  lcd.print("Temp");            //display"Temp="
  lcd.setCursor(5,1);
  lcd.print(temp);
  //Serial.print(temp);
  lcd.write(0xDF);              //Display custom characters '°'
  lcd.print("C");
  delay(200);                
  initialtemperature();

{
   init_pass=0;
     
   for(int j=0;j<2;j++){ 
     init_pass=init_pass*10; // shifting the digit 1 decimal (first time we are shifting 0 so nothing happens)   
     init_pass += (initial_temperature[j] - '0');   // now we add the digit we are reading  

      if (temp >= init_pass) relayState = HIGH;{      
        digitalWrite(relay,  relayState);           
   }
   
     Serial.print(init_pass);
 }   
  
  key_pressed = customKeypad.getKey();
  if(key_pressed=='A')
  change(); 
   }
   
 }

void change(){
      j=0;
  int i=0;
  lcd.clear();
  lcd.print("FanOn Temp=");
  lcd.print(initial_temperature);  
  lcd.write(0xDF);
  lcd.write("C");   
  lcd.setCursor(0,1);
  lcd.print("New Temp=");
  delay(200);
  while(i<2)

  {

    char pressed=customKeypad.getKey();
    if(pressed){
      new_temperature[i++]=pressed;  
      lcd.print(pressed);
      EEPROM.write(j,pressed);
     // Serial.print(pressed);
      j++;
    }

    pressed=0;

  }
  if(i==2){
    lcd.write(0xDF);
    lcd.write("C");          
    delay(1000);
    lcd.clear();
    lcd.print("Saved");
    delay(1000);
      }
}

void initialtemperature(){


    for (int j = 0; j < 2; j++)
    initial_temperature[j] = EEPROM.read(j);
    

    }

Temp_Hum_Moist_ControllerV8_test.ino (3.26 KB)

  initialtemperature();

I can't even begin to guess what this function is supposed to do. Use a name that reflects what the function actually does.

Commented out code is NOT part of your problem. Delete it before posting.

void change(){
      j=0;
  int i=0;
  Serial.begin(9600);

Serial,begin() belongs in setup()!

The value is being stored and read to and from the EEPROM but the are not being compared properly in the if statement.

In which if statement? You have plenty of if statements.

If the user enters '2' and '5' to define the set point, and the temperature is 27, init_pass is going to be 2 on the first pass through the for loop. 27 is greater than 2, and init_pass is 2, so you diddle with the relay. I can't see how that is supposed to work.

You store two characters in EEPROM, when you should be storing one byte. If the user keys in '2' and ''5, it is dirt simple to get 2 and 5 from that, and get 25 from the 2 and 5. Store 25 in EEPROM, and read that single value, Compare that single value to the current temperature. Job done.

PaulS:  initialtemperature();

I can't even begin to guess what this function is supposed to do. Use a name that reflects what the function actually does.

Commented out code is NOT part of your problem. Delete it before posting.

void change(){
      j=0;
  int i=0;
  Serial.begin(9600);

Serial,begin() belongs in setup()! In which if statement? You have plenty of if statements.

If the user enters '2' and '5' to define the set point, and the temperature is 27, init_pass is going to be 2 on the first pass through the for loop. 27 is greater than 2, and init_pass is 2, so you diddle with the relay. I can't see how that is supposed to work.

You store two characters in EEPROM, when you should be storing one byte. If the user keys in '2' and ''5, it is dirt simple to get 2 and 5 from that, and get 25 from the 2 and 5. Store 25 in EEPROM, and read that single value, Compare that single value to the current temperature. Job done.

My apologies for the confusion. Serial.begin(9600); was put there by accident.

The commented out code was left in to show how I would like it to appear as I will be adding lines for humidity and CO2 within the same braces to control the fan also. ie

if ((temp >= init_pass) && (relayState == LOW)) relayState = HIGH; if ((humi >= init_pass2) && (relayState == LOW)) relayState = HIGH; if ((co2 >= init_pass3) && (relayState == LOW)) relayState = HIGH;

...just to keep it all in the same place if possible

everything works in this sketch up to this point - the problem is in the following if statement and is not comparing as I was expecting ie. if the temperature is 20c and is >= init_pass then relayState = HIGH. Instead it just stays high when any new value is stored.

if (temp >= (init_pass)){

if(init_pass==2) relayState = HIGH; digitalWrite(relay, relayState);

Hope this helps.

This is my first attempt at anything arduino so thank you for your patience. Everything kinda makes sense to me and actually works up to the point of if(temp >= init_pass) and it totally makes sense to write a single byte. Can you provide an example?

Can you provide an example?

I could, but I want you to exercise your gray matter.

If the user presses the key with the 2 on it, what value does getKey() return?

Do you know how to convert the '2' that getKey() returns to a 2?

If the user presses the 5 key next, and you get a 5 from that, do you know how to make 25 from 2 and 5?

PaulS: I could, but I want you to exercise your gray matter.

If the user presses the key with the 2 on it, what value does getKey() return?

Do you know how to convert the '2' that getKey() returns to a 2?

If the user presses the 5 key next, and you get a 5 from that, do you know how to make 25 from 2 and 5?

Truth be told, I thought that using init_pass = (initial_temperature[j] - '0'); was converting the character '2' to integer 2 and as for how to make the 2 and the 5 into 25... I really thought if(init_pass==2) would do that since it looks like that's what is happening here:

 if(i==2){
    lcd.write(0xDF);
    lcd.write("C");          
    delay(1000);
    lcd.clear();
    lcd.print("Saved");
    delay(1000);
      }

but as I type I'm beginning to understand why it wouldn't - I need something that says if init_pass is 2 digits in length or read 2 then 5 and combine them?

as for exercising gray matter, everything up to this point has been fairly intuitive and kinda fun but ever since this little snag I've been getting gray matter all over the fracking place...my brain hurts!

ok… spent a little more time and see a little more clearly what you mean but I still have no solution. I removed the piece of code if(init_pass==2) as I realized it was not doing what I wanted. It just looks like it should work as it is now. The temp module is returning a 2 digit integer and it looks as though init_pass is returning a 2 digit integer but is only seeing the first digit when comparing in the if statement in question. I understand what you are saying that there is a way to get the second digit on the following iteration but I am truly at a loss as to how.

I guess the best question I could ask is if the serial monitor is returning a 2 digit integer for Serial.print(init_pass) , one after another after another ie. 252525252525252525 - how different is that from having if(temp >= 25) vs if(temp >= init_pass) ? or is that really an integer that is displaying in the serial monitor?? i am so confused.

I need something that says if init_pass is 2 digits in length or read 2 then 5 and combine them?

that is your issue, simply put

for(int j=0;j<2;j++){   
   init_pass = (initial_temperature[j] - '0');

is on the right track, but how about before you start comparing init_pass, you make sure you have the proper value

init_pass=0;
for(int j=0;j<2;j++){
   init_pass=init_pass*10; // shifting the digit 1 decimal (first time we are shifting 0 so nothing happens)   
   init_pass += (initial_temperature[j] - '0');   // now we add the digit we are reading
}

This is how to extract digits from characters manually, there are nice functions to do this of course, and yes Paul is correct in saying that you should probably do this before you store your ‘value’ in the EEPROM and retrieve from it.
As it was you were comparing with the single ‘2’ and ‘5’ individually, not the ‘25’.

Deva_Rishi:
that is your issue, simply put

for(int j=0;j<2;j++){   

init_pass = (initial_temperature[j] - ‘0’);


is on the right track, but how about before you start comparing init_pass, you make sure you have the proper value

init_pass=0;
for(int j=0;j<2;j++){
  init_pass=init_pass*10; // shifting the digit 1 decimal (first time we are shifting 0 so nothing happens) 
  init_pass += (initial_temperature[j] - ‘0’);  // now we add the digit we are reading
}


This is how to extract digits from characters manually, there are nice functions to do this of course, and yes Paul is correct in saying that you should probably do this before you store your 'value' in the EEPROM and retrieve from it. 
As it was you were comparing with the single '2' and '5' individually, not the '25'.

Thank you for that as I found something very similar and seemed to make sense but it just returned a long string of nonsense numbers - that was: init_pass = init_pass * 10 + initial_password[j] - '0';

but now with the way you’ve expressed it it at least properly reads the first digit and I confirmed that by replacing temp with a single digit number to compare with init_temp and it toggles… however a few things I noticed, it will only toggle HIGH and not LOW. It will go LOW -only upon reset - if the value of the number in place of temp is <=init_temp. Also, when ‘A’ is pressed there are weird characters that display after the number and before the degrees C symbol - that seem to change depending on what numbers are stored.

so in summary;
returns correct values in serial monitor
but still not reading both digits
will go High when a value less than temp is stored - as would be expected
will only go LOW when a value more than temp is stored and then reset - not as expected
weird characters

this is getting very close though, I can feel it my bones.

BTW this little project will end up being a multi-function home garden controller that monitors and controls temp on/off humidy on/off fan on/off and CO2 on/off - if all goes well I hope to post the finished sketch for all to use.

Thank you Paul and Deva…almost there I think. I took your advise and tried to find a way to store the value as a 2 digit integer beforehand and it appears that is what i’ve done… I only assume because i see it on the way in with Serial.print(new_temp) and I’m getting 2 digit return values by Serial.print(EEPROM.read(j)) also, the FanOn Temp=…°C no longer displays the initial_temperature characters as expected, just garble so I assume that means that the int needs to be converted to char for that to display correctly? and the other thing is, when reading, it only sees the second digit now…arrrg!

am I chasing my tail or is this getting closer?

Here’s what I have…btw init_pass is now init_temp

#include <EEPROM.h>
#include <Keypad.h> 
#include <LiquidCrystal.h>
#include <dht11.h>                  
dht11 DHT;                  

char temperature[2];
char initial_temperature[2];

char new_temperature[2];
char key_pressed=0;
//char init_pass[2];

const int relay = 8;  
const int dht11_data = 6;     
int temp=0;
int relayState = LOW;         
int i=0;
int j=0;
int init_temp = 0;
int new_temp=0;

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the symbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {38, 40, 42, 44}; 
byte colPins[COLS] = {46, 48, 50, 52}; 

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup() {
  Serial.begin(9600);
  pinMode(relay, OUTPUT); 
  digitalWrite(relay, relayState);
  lcd.begin(16,2);
  lcd.print("  Welcome to ");
  lcd.setCursor(0,1);
  lcd.print("     Test 2");
  delay(2000);
  lcd.clear();


}

void loop() {

  DHT.read(dht11_data);
  temp=DHT.temperature;

  lcd.clear();                   
  lcd.setCursor(5,0) ;          
  lcd.print("Temp");            //display"Temp="
  lcd.setCursor(5,1);
  lcd.print(temp);
  //Serial.print(temp);
  lcd.write(0xDF);              //Display custom characters '°'
  lcd.print("C");
  delay(200);                
  initialtemperature();


         for (int j=0;j<2;j++)
          init_temp = EEPROM.read(j);
          
       // Serial.print(EEPROM.read(j));
       // Serial.print(init_temp);     
       // Serial.print(new_temp); 
      
      if (temp >= init_temp) relayState = HIGH;      
        digitalWrite(relay,  relayState);                

        
    

  key_pressed = customKeypad.getKey();
  if(key_pressed=='A')
  change(); 
     
   
 }

void change(){
      j=0;
  int i=0;
  lcd.clear();
  lcd.print("FanOn Temp=");
  lcd.print(initial_temperature);  
  lcd.write(0xDF);
  lcd.write("C");   
  lcd.setCursor(0,1);
  lcd.print("New Temp=");
  delay(200);
  while(i<2)

  {
    //new_temp=0;
    
    char pressed=customKeypad.getKey();
    if(pressed){
     new_temperature[i++] = pressed;       
     lcd.print(pressed);
     new_temp = (pressed);
        

     new_temp=new_temp - '0';   

     
     //Serial.print(new_temp);

      EEPROM.write(j,new_temp);
      
      j++;
     
    }
   
    pressed=0;

  }
  if(i==2){
    lcd.write(0xDF);
    lcd.write("C");          
    delay(1000);
    lcd.clear();
    lcd.print("Saved");
    delay(1000);
      }
}

void initialtemperature(){


    for (int j = 0; j < 2; j++)
    initial_temperature[j] = EEPROM.read(j);
    

    }
         for (int j=0;j<2;j++)
          init_temp = EEPROM.read(j);

You don’t get it, obviously. The value stored in EEPROM should be something like 25, NOT ‘2’ and ‘5’ or 2 and 5.

     new_temperature[i++] = pressed;

You don’t need to use an array to collect the data.

You DO need to test that the value in pressed corresponds to a digit.

To get a 2 digit number:

  byte val = 0;
  byte cnt = 0;
  while(cnt < 2)
  {
    char pressed=customKeypad.getKey();
    if(pressed != NO_KEY)
    {
       if(pressed >= '0' && pressed <= '9')
       {
          val *= 10;
          val += pressed - '0';
          cnt++;
       }
     }
  }

With this code, if you press ‘2’ and ‘5’, val starts at 0, gets multiplied by 10 (so, its still 0) and gets 2 add (so it is now 2), then gets multiplied by 10 (so it is now 20) and gets 5 added to it, so it is now 25.

THAT is the value you store in, and read from, EEPROM, in ONE address.

Now, when you read 27 from the sensor, you can DIRECTLY compare 27 to 25, with NO need to do ANY manipulation of either value.

Thanks Paul, you are a superstar! I got it!

I wouldn’t have been able to without that last little/huge offering but I did work for it and learned much…thank you!!

However, 2 minor things:

      if (temp >= init_temp) relayState = HIGH;{
      if (temp <= init_temp) relayState = LOW;      
        digitalWrite(relay,  relayState);

This worked with just one if statement when comparing with a number ie if(temp>= 25) but now it needs the other to toggle LOW…totally minor but would be nice to find out why just to keep things cleaner when I add the other sensors - humidity, moisture and C02

The other thing - I have to do the inverse of the example you provided, to display the stored value on the LCD - int to char

void change(){
      j=0;
  int i=0;
  byte display_temp = initial_temperature[j] /=10; //with this it displays the first character
  //display_temp +=  initial_temperature[j] + '0';  // trying to get the second digit
  lcd.clear();
  lcd.print("FanOn Temp=");
  lcd.print(display_temp);
  //Serial.print(display_temp);  
  lcd.write(0xDF);
  lcd.write("C");   
  lcd.setCursor(0,1);
  lcd.print("New Temp=");
  delay(200);
  while(i<2)
 
 {

… I did my best to reason through it… I know, I know…please be kind.

Here it is so far…almost, almost there.

#include <EEPROM.h>
#include <Keypad.h> 
#include <LiquidCrystal.h>
#include <dht11.h>                  
dht11 DHT;                  

char temperature[2];
char initial_temperature[2];

char new_temperature[2];
char key_pressed=0;
//char init_pass[2];

const int relay = 8;  
const int dht11_data = 6;     
int temp=0;
int relayState = LOW;         
int i=0;
int j=0;
int init_temp = 0;
int new_temp=0;

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the symbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {38, 40, 42, 44}; 
byte colPins[COLS] = {46, 48, 50, 52}; 

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup() {
  Serial.begin(9600);
  pinMode(relay, OUTPUT); 
  digitalWrite(relay, relayState);
  lcd.begin(16,2);
  lcd.print("  Welcome to ");
  lcd.setCursor(0,1);
  lcd.print("    Success");
  delay(2000);
  lcd.clear();


}

void loop() {

  DHT.read(dht11_data);
  temp=DHT.temperature;

  lcd.clear();                   
  lcd.setCursor(5,0) ;          
  lcd.print("Temp");            //display"Temp="
  lcd.setCursor(5,1);
  lcd.print(temp);
  lcd.write(0xDF);              //Display custom characters '°'
  lcd.print("C");
  delay(200);                
  initial_stored_temp();
{

     initial_temperature[j] = EEPROM.read(j);
     init_temp = initial_temperature[j];
      
      if (temp >= init_temp) relayState = HIGH;{
      if (temp <= init_temp) relayState = LOW;      
        digitalWrite(relay,  relayState);                

        
      }

  key_pressed = customKeypad.getKey();
  if(key_pressed=='A')
  change(); 
      }   
   
 }

void change(){
      j=0;
  int i=0;
  byte display_temp = initial_temperature[j] /=10; //with this it displays the first character
  //display_temp +=  initial_temperature[j] + '0';  // trying to get the second digit
  lcd.clear();
  lcd.print("FanOn Temp=");
  lcd.print(display_temp);
  //Serial.print(display_temp);  
  lcd.write(0xDF);
  lcd.write("C");   
  lcd.setCursor(0,1);
  lcd.print("New Temp=");
  delay(200);
  while(i<2)
 
 { 

  byte val = 0;
  byte cnt = 0;
  while(cnt<2){
    char pressed=customKeypad.getKey();
    if(pressed != NO_KEY)
    {
       
       if(pressed >= '0' && pressed <= '9')
       {
          new_temperature[i++] = pressed;        
          val *= 10;
          val += pressed - '0';
          cnt++;                     
          lcd.print(pressed);
          //Serial.print(val);
          EEPROM.write(j, val);
       } 
                 
    }
      pressed=0;       
  }
 }
  if(i==2){
    delay(200);
    lcd.write(0xDF);
    lcd.write("C");          
    delay(1000);
    lcd.clear();
    lcd.print("Saved");
    delay(1000);
      }
}

void initial_stored_temp(){

    initial_temperature[j] = EEPROM.read(j);

    }
   
    
    }
if (temp >= init_temp) relayState = HIGH;{
      if (temp <= init_temp) relayState = LOW;      
        digitalWrite(relay,  relayState);

Use the CTRL+T auto-format function in the IDE - that will help you see the second if is dependent on the first.

Having relayState fighting with itself on every pass is not good programming style.

lastchancename:

if (temp >= init_temp) relayState = HIGH;{

if (temp <= init_temp) relayState = LOW;     
        digitalWrite(relay,  relayState);



Use the CTRL+T auto-format function in the IDE - that will help you see the second if is dependent on the first.

Having *relayState* fighting with itself on every pass is not good programming style.

Actually, the biggest problem is that if statements don’t end with ; AND appear to have a body.

Another major problem is that you turn the relay off if the temperature is above OR EQUAL TO the setpoint, and you turn it off if the temperature is below OR EQUAL TO the setpoint.

You probably want to google “hysteresis”, and turn the relay on when the temperature is somewhat below the setpoint, and off when it is somewhat above the setpoint. Leave the relay alone (do not change its state) if the temperature IS EQUAL TO the setpoint.

The other thing - I have to do the inverse of the example you provided, to display the stored value on the LCD - int to char

Do you mean something like this

int temperature=25; // as an example
char tempt[2];
tempt[0]=(char) (temperature/10)+'0';
tempt[1]=(char) (temperature%10)+'0';

works for 2 digits..

Leave the relay alone (do not change its state) if the temperature IS EQUAL TO the setpoint.

Not sure what you mean.

But I would like to understand why when it was written with only one if statement using the number value in place of init_temp ie:…

if (temp >= 25) relayState = HIGH;{

vs how it is now

if (temp >= init_temp) relayState = HIGH;{
      if (temp <= init_temp) relayState = LOW;     
        digitalWrite(relay,  relayState);

…that it triggered low without the use of the second if but now with init_temp, it does…what’s going on there?

Also, one more thing I’ve been meaning to ask. How can one tell from the serial monitor if what’s being displayed is a char ‘25’ or a int 25? I think that’s been a big part of my confusion.

what’s going on there?

It’s hard to tell with your poorly formatted snippets.

if (temp >= init_temp) relayState = HIGH;{

There is no reason for that { on that line.

If you put EVERY { om a line BY ITSELF, EVERY } on a line BY ITSELF, used {} after every if statement, and used Tools + Auto Format, you’d see that your code looks like:

if (temp >= init_temp)
{
   relayState = HIGH;
   {
      if (temp <= init_temp)
      {
         relayState = LOW;     
         digitalWrite(relay,  relayState);

Which doesn’t make sense.

Also, one more thing I’ve been meaning to ask. How can one tell from the serial monitor if what’s being displayed is a char ‘25’ or a int 25? I think that’s been a big part of my confusion.

I always just go for what i want to be displayed (I like being in control) so i usually do stuff like

Serial.println(myint, DEC);
Serial.println((char) myint);

and look at the difference in result.

ok, so here is the what I ended up with to display the stored temp when ‘A’ is pressed:

{
    initial_temperature[j] = EEPROM.read(j);
    int intToCharTemp = initial_temperature[j];

    int display_temp = intToCharTemp;
    char b[2];
    String str;
    str = String(display_temp);
    str.toCharArray(b, 2);
    lcd.clear();
    lcd.print("FanOn Temp=");
    lcd.print(display_temp);
  }

… works like a charm…hats off to you guys for all the help and guidance!

and you’ll both be happy to know I finally implemented the magic ctl T and bam!..the clouds lifted.

so, still trying to understand this though - why does this trigger the relay both HIGH and LOW when using a number to compare…

{
    if (temp <= 25) relayState = HIGH;
    digitalWrite(relay,  relayState);
}

…vs this when comparing with the variable - it will not trigger both ways without having both if statements.

{
    initial_temperature[j] = EEPROM.read(j);
    init_temp = initial_temperature[j];

    if (temp >= init_temp) relayState = LOW;
    if (temp <= init_temp) relayState = HIGH;
    digitalWrite(relay,  relayState);
  }

why?

Firstly what is the type and value of the ‘temp’ variable ? this is the main question.
Secondly (and someone mentioned this before)

if (temp >= init_temp) relayState = LOW;
if (temp <= init_temp) relayState = HIGH;

if these are your if statements and temp==init_temp the relayState gets changed twice, though maybe not causing any unpredictable behavior, it is still bad programming practice.

why does this trigger the relay both HIGH and LOW when using a number to compare… it will not trigger both ways without having both if statements.

that must be caused by something elsewhere in your code. (refer to firstly)