Logic for operating an actuator based on temperature

Hi,
I’m trying to write logic to control a linear actuator to open and close a greenhouse vent depending on the inside temperature and I’m unsure how to write it. I’m new to Arduinos and coding. I’m using an UNO, a 2 channel 5v relay, a DS18B20 temperature probe and an actuator. I attempted the logic and got part of the way. I’m not sure how to structure it so it only tries to retract the actuator when it is extended. Here is the logic I want written out:

check temp every 3 minutes
If temp > x; (open vent)
after (open vent), check temperature every 3 minutes and if temp < x; (close vent)

My problem is that it tries to retract the actuator every 3 minutes when it reads that the temp is > x.

My main questions are:
What should the logic look like?
should it go in setup or loop?

Here is the code. I started with the sketch called Simple from Dallastemperature.h

#include <OneWire.h>
#include <DallasTemperature.h>
 
// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 2
 
// Setup a oneWire instance to communicate with any OneWire devices 
// (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
 
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

const int relay1 = 6;   //Arduino pin that triggers relay #1
const int relay2 = 7;   //Arduino pin that triggers relay #2
 
void setup(void)
{
  // start serial port
  Serial.begin(9600);
  Serial.println("Dallas Temperature IC Control Library Demo");

  // Start up the library
  sensors.begin();

  //Set pinMode to OUTPUT for the two relay pins
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
}
 void extendActuator() {
    digitalWrite(relay1, HIGH);
    digitalWrite(relay2, LOW);
}

void retractActuator() {
    digitalWrite(relay1, LOW);
    digitalWrite(relay2, HIGH);
}

void stopActuator() {
    digitalWrite(relay1, LOW);
    digitalWrite(relay2, LOW);
}

void loop(void)
{
  // call sensors.requestTemperatures() to issue a global temperature
  // request to all devices on the bus
  Serial.print(" Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");

  Serial.print("Temperature for Device 1 is: ");
  Serial.print(sensors.getTempCByIndex(0)); // Why "byIndex"?

    if (sensors.getTempCByIndex(0) > 32)
  {extendActuator();
    delay(20000);
    stopActuator();
    delay(60000);sensors.requestTemperatures();};
    if (sensors.getTempCByIndex(0) < 32)
    {retractActuator(); delay(20000); stopActuator();}
  else
   {stopActuator();}
   delay(60000);
  
}
    // You can have more than one IC on the same bus. 
    // 0 refers to the first IC on the wire

To code is missing the most important part... The content of the loop() :wink:

And links to the specific libraries is a most as well. Just tons of Dallas libraries...

When checking the temperature, check also whether the actuator is extended or retracted. If it's already where it should be, do nothing.

septillion:
To code is missing the most important part... The content of the loop() :wink:

And links to the specific libraries is a most as well. Just tons of Dallas libraries...

I didnt realize the logic was not in the code when I copied it! I updated it.
Here is where I got the library: GitHub - milesburton/Arduino-Temperature-Control-Library: Arduino Temperature Library

DKWatson:
When checking the temperature, check also whether the actuator is extended or retracted. If it's already where it should be, do nothing.

I don't have a sensor to tell me whether the actuator is extended or retracted. I was hoping to be able to get around that in the code by having it check temp after extending, and retract if it is lower than x.

Try this.

Put this up top somewhere,

enum __attribute__ ((__packed__)) {extended, retracted} actuator;

then change your loop. You don't need a sensor to check on the actuator, you are controlling it.

void loop(void)
{
	// call sensors.requestTemperatures() to issue a global temperature
	// request to all devices on the bus
	Serial.print(" Requesting temperatures...");
	sensors.requestTemperatures(); // Send the command to get temperatures
	Serial.println("DONE");

	Serial.print("Temperature for Device 1 is: ");
	Serial.print(sensors.getTempCByIndex(0)); // Why "byIndex"?

	enum {extended, retracted} actuator;
	
	if ((sensors.getTempCByIndex(0) > 32) && (actuator == retracted))
	{
		extendActuator();
		delay(20000);
		stopActuator();
		delay(60000);sensors.requestTemperatures();
		actuator = extended;
	}
	
	if ((sensors.getTempCByIndex(0) < 32) && (actuator == extended))
	{
		retractActuator(); 
		delay(20000); 
		stopActuator();
		actuator = retracted;
	}
	else
	{
		stopActuator();
	}
	delay(60000);

}

dkw

DIYDAN:
I don't have a sensor to tell me whether the actuator is extended or retracted.

You don't need that, just remember it :wink:

bool actuatorExtended;

void extendActuator() {
  digitalWrite(relay1, HIGH);
  digitalWrite(relay2, LOW);
  actuatorExtended = true;
}

void retractActuator() {
  digitalWrite(relay1, LOW);
  digitalWrite(relay2, HIGH);
  actuatorExtended =  false;
}

And that actuator can't damage anything if extending and retracting is only done by timing it?

  Serial.print(sensors.getTempCByIndex(0)); // Why "byIndex"?

    if (sensors.getTempCByIndex(0) > 32)

Why do you call this really slow function twice? Call it ONCE. Store the result. Print the stored result. Test the stored result.

I gave up trying to read your code. I'll bet you'd spend 3 days searching for an example that looked worse than that mess.

There is reason that every example in the IDE puts a carriage return after every ;. You'd do well to follow that convention.

DKWatson:
Try this.

Thank you for the help. I added your code but it did not function. Is it because I have stopActuator() before the assignment "actuator = extended"? stopActuator() sets both relays to zero volts. I realized that I don't actually need stopActuator() since the actuator has internal limit switches that stop it at the stroke limits, and I don't plan on stopping it mid-stroke.

I modified my code and added a temp buffer to 29 degrees and it seemed to work

 if (sensors.getTempCByIndex(0) > 32)
  {extendActuator();
  delay(180000);}
    else if (sensors.getTempCByIndex(0) > 29)
    {extendActuator();}
    else
   {retractActuator();
   delay(20000);}

septillion:
And that actuator can't damage anything if extending and retracting is only done by timing it?

Thanks for the help. The actuator has internal limit switches so it stops at the stroke limits and won't damage anything.

Okay, so actually there is no need for a stopActuator() and you could have just used a single relay :wink:

But see reply #6, you can just remember the position of the actuator.

I have another question. The greenhouse is sealed tight in order to keep heat in, so in order to let fresh air in during extended periods when the vent stays closed I want to be able to add a periodic operation to extend and retract the actuator on a time interval. For example, once an hour it extends open for a minute and then retracts closed. The only way I know how to do this is to add an hour delay in the code, but then that will disrupt the temperature operation, correct? I assume I could do it by adding a real time clock, but is there a simple way of doing it without a clock?

Since the timing is not down-to-the-second crucial, you can just check elapsed time with millis() and skip the RTC. You will not be using delay so that your code can continue functioning.
do something like

currentMillis = millis()

if( currentMillis - previousMillis > hourInTermsOfMillis)
do that thing you want
previousMillis = millis()

INTP:
Since the timing is not down-to-the-second crucial, you can just check elapsed time with millis() and skip the RTC. You will not be using delay so that your code can continue functioning.
do something like

currentMillis = millis()

if( currentMillis - previousMillis > hourInTermsOfMillis)
do that thing you want
previousMillis = millis()

Thank You!! That's great, I will add this to my code.