Trouble with Multiple Conditions in an IF statement

I imagine that there is a better category to post this but didn’t see a category for coding. This is also my first post so please tell me how I can do this better. Seems like my code should be inside some kind of code block.

Anyway, I am building a solar thermal controller and am having trouble getting all the logic in the IF statements to work correctly. It is a simple drainback system that has one pump, a few temp sensors.
The circulation pump needs to turn on when:

*Solar Panel temp >90F but not hotter than 175F

  • and Room Temp < setpoint (70F)

Once it turns on it takes a while for the system to equalize, like 10 min, then it checks for the conditions to turn it off:

  • Supply temp < return temp + offset
  • or the room temp < roomtemp setpoint + offset

I can post the whole code if necessary but I think my issues are in parentheses or just the formatting of the IF statement. The pump does turn on in the morning when the panel gets hots but even turns on when the room temp is 72. The pump does not turn off at the end of the day when the supply temp drops below the return temp or the room temp exceeds the SP.
Variables and constants defined in program:
PanelOnTemp = 90F
RoomTempSP = 70F
panelHot = 175F
panelOffDifferential = 3
publish_delay = 600000
solarFlag is a flag used for keeping track of the system state: true = pump on, false = pump off. Program starts with solarFlag = false
supplyT and returnT are DS1820 sensors

//Control sequence - does not run when in override mode from button press
if(solarFlag == false && (panelT > PanelOnTemp) && (roomT < (RoomTempSP)) && (panelT < panelHot)) // if panel is hot but not too hot, rm temp is below SP,then turn on pump
{
solarFlag = true;
digitalWrite(Relay, HIGH); //turn pump on
}
if ((now - lastTime) >= publish_delay) //wait for system “on” to stabilize before checking for “off” conditions, check every ten minutes
{
if (solarFlag == true) //if pump is already running
{
if (supplyT < (returnT + PanelOffDifferential) || roomT > (RoomTempSP+2)) //if supplyT drops below (returnT plus diff) or roomT < (sp+2)
{
solarFlag = false;
lastTime=now;
}
}

EDIT: I think I was looking at the wrong if statement…

You say you want roomT < (sp+2),

but in your code you have:

roomT > (RoomTempSP+2)

You seem to have flipped the less-than sign.


Also, you can make a code block like this:

image

And it will appear as this:

int myVar = 0;
blah();

Thanks for the response. And thanks for the tip on the code block.

Yes, the mistake was in the coment where the sign was changed.

I want the pump to turn on when the roomT < RoomTempSP and turn off when the temp is satisfied: roomT > (RoomTempSP+2), with that 2 being the offset so it doesn’t keep flipping.

Thanks for catching that. So the question now is about whether I have the syntax correct for the conditional statement, that the parentheses are properly placed so that all the conditions are considered, especially the && and ||.

I forgot to mention that it publishes to thingSpeak. You can see thecurrent live data feed there at Solar thermal system data

Here is the whole code of the controller:

// Solar Thermal Radiant Floor Controller, Drainback system

#include <Adafruit_DHT.h>
#include <OneWire.h>
#include <Serial_LCD_SparkFun.h>
#include <spark-dallas-temperature.h>

//System Operational Parameters
#define PanelOnTemp             90  // Panels must be this hot to turn on 
#define RoomTempSP              69  // Room temperature setpoint
#define PanelOffDifferential     3  // If Panels are only this much warmer than return temp, turn off
#define FREEZE_LIMIT            10  // don't operate if outside temp is below this temperature
#define Print_Delay           4000   // delay in between LCD printouts
#define flowCalibrationFactor   4.5 // how many pulses per gallon
#define panelHot                175 // if panels are hotter than this do not turn on pump
#define DHTTYPE DHT22    	// DHT 22 (AM2302)
// DHT22 sensor pinout:
// Pin 1 (on the left): +3.3V
// Pin 2: output
// Pin 4 (on the right): GROUND
#define DHT_SENSOR_PIN D7 //room Temp
DHT dht(DHT_SENSOR_PIN, DHTTYPE);
//
#define Relay D3
#define buttonPin A2
#define PT1000SensorInput A1
#define flowSensor D2
// DS18b20 setup
//one wire bus is D4,  can connect multiple DS1820s here
OneWire oneWire(D4 );
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature dallas(&oneWire);
// Create a variables 
int rawPanel12bit;
int panelT = 0;     //PT1000
int supplyT = 0;    //ds1820
int returnT = 0;    //ds1820
int osaTemp = 0;    //ds1820
int btus = 0;
int roomT = 72;
float flowRate = 0.9;
int pulseCount = 0;
int buttonState = 0;         // variable for reading the pushbutton status
float flowGPM   = 0;
bool solarFlag = false;     //flag for pump startup
int buttonPressFlag = 0; 
unsigned long lastTime = 0;
unsigned long lastTime2 = 0;
unsigned long publish_delay=600000;
unsigned long publish_delay_test=30000;
//LCD
Serial_LCD_SparkFun lcd = Serial_LCD_SparkFun();
 //

void setup() {
    // initialize some stuff
    pinMode(Relay, OUTPUT);
    pinMode(buttonPin, INPUT);
    digitalWrite(Relay, LOW);
    pinMode(flowSensor, INPUT);
    digitalWrite(flowSensor, HIGH);

    //digitalWrite(DHT_5V_PIN, HIGH);
    rawPanel12bit = analogRead(PT1000SensorInput);
    attachInterrupt(buttonPin, buttonPressInterrupt, RISING); 
    // Initialize DHT22 sensor
    dht.begin();
    delay (2000);
}

void loop() 
{
   
      // read PT1000 sensor input
  rawPanel12bit = analogRead(PT1000SensorInput);
    //adjust raw value
  panelT = (rawPanel12bit*rawPanel12bit)*0.000264+(rawPanel12bit*0.614173)-396.53;
  //DS1820 read supply and Return temps
  dallas.begin();
  dallas.requestTemperatures();
  // get the temperature in Celcius
  float sat = dallas.getTempCByIndex(0);
  float rat = dallas.getTempCByIndex(1);
  float osat  = dallas.getTempCByIndex(2);
  // convert to double
  supplyT = (double)sat;
  returnT = (double)rat;
  osaTemp = (double)osat;
  // convert to Fahrenheit
  float tempFs = DallasTemperature::toFahrenheit( sat );
  float tempFr = DallasTemperature::toFahrenheit( rat );
  float tempOSAT = DallasTemperature::toFahrenheit( osat );
  // convert to double
 supplyT = (int)tempFs;
 returnT = (int)tempFr;
 osaTemp = (int)tempOSAT;
  
  //DHT22 read
    double temperature = dht.getTempCelcius();
    //double humidity = dht.getHumidity();
    int tempF = (temperature * 1.8) + 32;
    if(tempF!=0)
    {
        roomT= tempF;
    }
    
    btus = (supplyT-returnT)*500*flowRate;
    //Particle publish to thingspeak
   unsigned long now = millis();
	if ((now - lastTime) >= publish_delay) 
	{
	    // field 1 = roomtemp
	    // field 2 = supplytemp
	    // field 3 = returntemp
	    // field 4 = paneltemp
	    // field 5 = btus
	    // field 6 = osatemp
	    // field 7 = pump
        char json[256];
        snprintf(json, sizeof(json), "{\"roomtemp\":\"%i\",\"supplytemp\":\"%i\",\"returntemp\":\"%i\",\"paneltemp\":\"%i\",\"btus\":\"%i\",\"osatemp\":\"%i\",\"pump\":\"%d\"}", roomT, supplyT ,returnT, panelT, btus, osaTemp,solarFlag);
        Particle.publish("solarTemps", json, PRIVATE);
  	    lastTime = now;
	}
// Display values
	// clear the display first
	lcd.clear();
	if(buttonPressFlag == 1)
	{
	Serial1.print("Override:");
	lcd.selectLine(2);
	Serial1.print("        Pump OFF");
	digitalWrite(Relay, LOW);
	}
	if(buttonPressFlag == 2)
	{
	Serial1.print("Override: ");
	lcd.selectLine(2);
	Serial1.print("        Pump ON");
	digitalWrite(Relay, HIGH);
	}
	if(buttonPressFlag == 4)
	{
	Serial1.print("Failure: ");
	lcd.selectLine(2);
	Serial1.print("     No Flow");
	}
	if(buttonPressFlag == 0)    
	{                               //display data and run control program only when button is in normal mode (0)
	    lcd.clear();
	    if(solarFlag==false)  
	    {
	    digitalWrite(Relay, LOW);
	    }
	    else
	    {
	    digitalWrite(Relay, HIGH);
	    }
	    // We have to print to Serial1
	    Serial1.print("Panel Temp: ");
	    Serial1.print(panelT);
	    //
	    lcd.selectLine(2);
        Serial1.print("Room Temp:  ");
	    Serial1.print(roomT);
	    delay(Print_Delay);
	    lcd.clear();
	    //SAT and Rat on one screen
	    Serial1.print("Supply Temp: ");
	    Serial1.print(supplyT);
        //RAT
	    lcd.selectLine(2);
	    Serial1.print("Return Temp: ");
	    Serial1.print(returnT);	
	    delay(Print_Delay);
        lcd.clear();
        //btus
        Serial1.print("BTUs:  ");
	    Serial1.print(btus);
	    // 
	    lcd.selectLine(2);
	    Serial1.print("flag:  ");
	    Serial1.print(solarFlag);
	    delay(Print_Delay);
        lcd.clear();
        //Control sequence - does not run when in override mode from button press
        if(solarFlag == false && (panelT > PanelOnTemp) && (roomT < (RoomTempSP)) && (panelT < panelHot)) //  if panel is hot but not too hot, rm temp is below SP,then turn on pump 
        { 
        solarFlag = true;
        }
        if ((now - lastTime) >= publish_delay) //wait for system "on" to stabilize before checking for "off" conditions, check every ten minutes
        {
            if (solarFlag == true)  //if pump is already running
            {
                if (supplyT < (returnT + PanelOffDifferential) || roomT > (RoomTempSP+2))    //if supplyT drops below (returnT plus diff) or roomT < (sp+2)
                {
                solarFlag = false;
                lastTime=now;
                }
            }
        }
        /*if (flowRate < 0.2)
        {                // if no flow then shut down pump
        digitalWrite(Relay, LOW);
        buttonPressFlag = 4;
        }*/
	}
}
 void buttonPressInterrupt()
    {                           //button interrupt routine     
        static unsigned long last_interrupt_time = 0;
        unsigned long interrupt_time = millis();
        if (interrupt_time - last_interrupt_time > 50)  // debounce time = 50milliseconds
        {
        buttonPressFlag = buttonPressFlag +1;
        }
        last_interrupt_time = interrupt_time;
        if (buttonPressFlag >2)
        buttonPressFlag = 0;
    }
1 Like

Interesting.

I think your best option would be to create a Finite State Machine (FSM) for managing solarFlag and lastTime. This could be implemented with an enum of states and a function to check/update state. Other functions would then check the current state to determine if particular code should run.

I also have a few more suggestions:

  • Use Serial1.printf to make your code more consise.
  • Break loop() into separate functions for reading, publishing, displaying, and state management.
  • Use structs to encapsulate related data together.
  • Use a switch on buttonPressFlag instead of a series of if statements.

Also since solarFlag is a boolean you can directly use it in your conditions. Meaning that solarFlag == true can be shortened to solarFlag and solarFlag == false can be shortend to !solarFlag.


Looking at your conditionals again they look correct at second glance, but there are some redundant parentheses.


Your first state conditional:


if(solarFlag == false && (panelT > PanelOnTemp) && (roomT < (RoomTempSP)) && (panelT < panelHot))
{ 
        solarFlag = true;
}

could likely be flattened to:

solarFlag = !solarFlag && panelT > PanelOnTemp && roomT < RoomTempSP && panelT < panelHot;

Nrobinson, thank you for your help and the programming suggestions. The state machine solution is a good one and more elegant than my IF statements. I will incorporate that and the multiple loop functions. I looked at structs briefly and will read more.

I put in some dummy values for the temps and ran it until I got it working, adding more conditions as I went. Turned out it was not getting past the
if ((now - lastTime) >= publish_delay)
for some reason, so I just used a hard delay for the time being. At least it all works now. I also incorporated the slarFlag suggestion you offered. I will keep working on this to clean it up and read more about the C++ functions I should be using.

1 Like