Spa Temp Control

First off, I'm very new to coding and Arduino. This is probably a bigger undertaking than I should be starting with but I learn best when I have a practical application for the knowledge.

I am working on a temperature control unit that I am using to control a spa. So far I have some code I found and modified to be able to control an LED (which will be replaced by a relay in real use) and LCD display to state the water temp and if the pump is ON above 75 degrees or OFF if its below 75.

My goal right now is figuring out how I can make the pump turn on at 75 degrees but stay on for say 1 minute regardless of the water temp dropping below 75 which currently turns it off. I like that the water temp is constantly updating and if I add a delay to the else statement it slows down data collection on water temp which isn't how I would like it to work.

This is 1 layer of multiple functions I want to have happen based on water temp but figuring this out will allow me to go a little further on my own I think, I hope...

Any help or advice appreciated!

Current Code for reference:

#include <LiquidCrystal.h>

int ThermistorPin = 0;
int Vo;
float R1 = 10000;
float logR2, R2, T;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

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

void setup() {
   lcd.begin(16,2);
   analogWrite(9,10); // Generate PWM signal at pin D9 to control LCD contrast
   analogWrite(10,255); // Generate PWM signal at pin D10 to control LCD brightness
   pinMode (7, OUTPUT); // Output going to LED (to be replaced by relay in real use)
   Serial.begin(9600);
}

void loop() {

  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
  T = T - 273.15;
  T = (T * 9.0)/ 5.0 + 32.0; 

  //Serial.print("Temperature: ");
  //Serial.print(T);
  //Serial.println(" F"); 

   lcd.setCursor(0,0);
  lcd.print("temp = ");
  lcd.print(T);   
  lcd.print(" F");

{
  if (T > 75) {
  lcd.setCursor(0,1); // Sets the location at which subsequent text written to the LCD will be displayed 
 lcd.print("Pump ON"); 
 digitalWrite(7, HIGH); // This turns on the LED, eventually the relay
 delay(500); 
  }
  if (T < 75) {
    lcd.setCursor(0,1);
    lcd.print("Pump OFF"); 
    digitalWrite(7, LOW);
 }
}
  delay(500);            
  lcd.clear();
}
1 Like

You will need to restructure your code using millis() to keep track of time rather than delay(). Also I think you would benefit from using a state machine and it would make it easy to add functionality later on as well.

Look at the following tutorials:

State Machine

Example-code for timing based on millis()

You have not said so specifically but are you trying to prevent the situation whereby the temperature hunts up and down around 75 degrees constantly turning on and off ?

If so, then there is an easy way to do it that does not involve timing anything

Hello jordanc15

Do yourself a favor and take some time, study the IPO model and take a piece of paper plus a pencil and design a program structure for your multi-layer-project.
Identify modules could to be coded and tested separetly. Merge after sucessfull testing all modules together to the needed project.
It is highly recommented to take a view into some powerful C++ instructions like STRUCT, ENUM, ARRAY, CASE/SWITCH,UDT, RANGE-BASED-FOR-LOOP, etc, too.

Have a nice day and enjoy coding in C++ and learning.

As mentioned, learn how to use millis.

Once a second (or whatever) display the temperature so that it's not flickering so much a human can't read it.

Once a minute, set the relay on or off based on the temperature.

I know that you know that your variable T stores the temperature, but single letter variable names are so seventies. Give it a proper name.

I would set up a countdown timer that uses mills for timing. Set the time when you get the temperature to turn it on and let it time. When it gets to zero turn it off. Each time you read the temperature and it is above setpoint reset the time and let it cund down from there.

Millis as above plus take a look at the DS18B20 data sheet.
These are cheap and come as a waterproof unit as well as a descrete device and have "alarm trip points" you can program.
Easy to display temp also and are rather accurate.

Huge thank you everyone. Lots of reading and I've been working on wrapping my head around a lot of this with some success.

I've moved over to a millis() code getting rid of the delay related issues. I have it reading temperature perfectly fine. How I have the code now it won't turn the pump on until the Arduino has been on for 10 seconds but I want it to specifically wait 10 seconds from the time temp goes over 78 before the pump can turn on.

Im still struggling with the millis system. I understand millis is constantly running since Arduino is on so I guess im trying to understand how I should be measuring the amount of time temp is over 78. Im trying to figure this out on my own... but with most cases online being a little different and my skill level being low its a lot to digest!

#include <LiquidCrystal.h>

unsigned long lastTimeTempCollected = millis(); //These phrases meant only for temp sensor data
unsigned long delayBetweenTemp = 500;
byte SensorState = LOW;

unsigned long lastTimePumpRan = millis(); //These phrases meant only for Water Pump
unsigned long delayBetweenPumpRunning = 10000;
byte PumpState = LOW;

#define WaterPump 7
int TempSensor = 0;
int Vo;
float R1 = 10000;
float logR2, R2, T;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

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

void setup() {
  lcd.begin(16,2);
  analogWrite(9,10); // Generate PWM signal at pin D9 to control LCD contrast
  analogWrite(10,255); // Generate PWM signal at pin D10 to control LCD brightness
  pinMode (WaterPump, OUTPUT); // Output going to LED (to be replaced by relay in real use)
  pinMode(TempSensor, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  unsigned long timeNow = millis();
  if (timeNow - lastTimeTempCollected > delayBetweenTemp)
  {
    if (SensorState == LOW)
    {
      SensorState = HIGH;
    }
    else
    {
      SensorState = LOW;
    }
    digitalWrite(TempSensor, SensorState);
    lastTimeTempCollected = timeNow;

      Vo = analogRead(TempSensor);
      R2 = R1 * (1023.0 / (float)Vo - 1.0);
      logR2 = log(R2);
      T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
      T = T - 273.15;
      T = (T * 9.0)/ 5.0 + 32.0; 

    Serial.print("Temperature: ");
    Serial.print(T);
    Serial.println(" F"); 

       lcd.setCursor(0,0);
       lcd.print("temp = ");
       lcd.print(T);   
       lcd.print(" F");
  }

  if(T > 78 && (timeNow - lastTimePumpRan > delayBetweenPumpRunning))
      {
        lcd.setCursor(0,1); // Sets the location at which subsequent text written to the LCD will be displayed 
        lcd.leftToRight();
        lcd.print("WP-ON "); 
        digitalWrite(WaterPump, HIGH); // This turns on the LED, eventually the relay
        PumpState = HIGH;

     digitalWrite(WaterPump, PumpState);
     lastTimePumpRan = timeNow;
    }

  else if(T < 78)
    {
       lcd.setCursor(0,1);
       lcd.leftToRight();
       lcd.print("WP-OFF");
       digitalWrite(WaterPump, LOW);
       PumpState = LOW;
     
    }
  }

When the temp goes over 78 save the value of millis() as the start time. At any point in the code after that if you need to know how much time has passed, subtract the start time from the current value of millis() and the difference is how long it is since the temp went over 78

What should happen if the temp drops below 78 before the period ends ?

How do I save that value of millis at the time of it hitting 78? If I reference millis it just pulls whatever time millis is at, I cant figure out how to pluck that single value out and store it for reference. I always just end up with them being the same value.

unsigned long CurrentTime = millis();
unsigned long delayBetweenPumpRunning = 10000;

  if(T > 78)
      {
        unsigned long StartTime = millis(); //Time when temp hits 78
        
        Serial.print("StartTime = ");
        Serial.print(StartTime);
        Serial.print(" / CurrentTime = ");
        Serial.print(CurrentTime);
        Serial.print(" / Time pump is on! = ");
        Serial.println(StartTime - CurrentTime);
        
          if(StartTime - CurrentTime > delayBetweenPumpRunning)
        {

        lcd.setCursor(0,1); 
        lcd.leftToRight();
        lcd.print("P-ON "); 
        digitalWrite(WaterPump, HIGH); // This turns on the LED, eventually the relay
        PumpState = HIGH;

        digitalWrite(WaterPump, PumpState);
    }
      }

All to change:

delay(500);

to

delay(60000); // wait 1 minute (60000 ms)
Full code (tap arrow)
#include <LiquidCrystal.h>

const int relayPin = 7; // or other pin
const int thermistorPin = 0;
float R1 = 10000;
float logR2, R2, T;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

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

void setup() {
   lcd.begin(16,2);
   analogWrite(9,10); // Generate PWM signal at pin D9 to control LCD contrast
   analogWrite(10,255); // Generate PWM signal at pin D10 to control LCD brightness
   pinMode (7, OUTPUT); // Output going to LED (to be replaced by relay in real use)
   Serial.begin(9600);
}

void loop() {

  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
  T = T - 273.15;
  T = (T * 9.0)/ 5.0 + 32.0; 

  // Serial.print("Temperature: ");
  // Serial.print(T);
  // Serial.println(" F"); 

  lcd.setCursor(0,0);
  lcd.print("temp = ");
  lcd.print(T);   
  lcd.print(" F");

{
  if (T > 75) {
  lcd.setCursor(0,1); // Sets the location at which subsequent text written to the LCD will be displayed 
 lcd.print("Pump ON"); 
 digitalWrite(7, HIGH); // This turns on the LED, eventually the relay
 delay(60000); // New code, waits 1 minute (60000 milliseconds)
  }
  if (T < 75) {
    lcd.setCursor(0,1);
    lcd.print("Pump OFF"); 
    digitalWrite(7, LOW);
 }
}
  delay(500);            
  lcd.clear();
}

tinkerer9 :grinning:

if (currentTemp >= 78 && previousTemp <  78)  / /temp **became** greater than 78
{
  startTime = millis();
}

Have you tried adding some hysteresis (deadband)?

if(temp >= 79)
  digitalWrite(pumpPin,HIGH); // pump ON
else if(temp <= 77)
  digitalWrite(pumpPin,LOW); // pump OFF

If I were doing it I would want to be able to adjust both the temperature I want it on and the hysteresis. I would have a variable for tempSet and a variable for hysteresis. Then you use the same code as the post above but with your tempSet variable anywhere there is the on temperature number and you calculate the off temperature based on the hysteresis variable. You can set these as global variables and adjust them in code to get best functionality but eventually I would want them to be the output of a function controlled by a physical knob or button on the control panel

if(temp >= tempSet)
  digitalWrite(pumpPin,HIGH); // pump ON
else if(temp <= tempSet-hysteresis)
  digitalWrite(pumpPin,LOW); // pump OFF

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.