Complex IF statements with boolean

Progressing well on my little first time Arduino project (weather warning device with 3G connection)

The warning I am trying to generate is based on a published table and I'm trying to do this with an IF statement where I compare a range of values and act on the result.

This is what I have come up with but its not acting quite how I would expect

Verbosely what its meant to do:
If the TEMP is between certain values, and the RH is between certain values and the wind speed (x) is above a certain value send the alert where there are a range of humidity values and wind speeds for each temp range.

So I have set the temp range first, then AND that with a humidity and temp combination, and then OR'd the various other Humidity & Wind combos to trigger the alert
There are 7 of these "blocks" or code with the various table values as required.
It seems to trigger at the required point but then send 7 alerts - not one!

Can anyone spot what might be the issue? Remember I'm new to Arduino and struggling with some of the concepts but I think I've done alright to have this thing doing what its doing so far!

if ((DHT.temperature) >=20 && (DHT.temperature) <25 &&             //TEMP BETWEEN 20 & 25
          ((DHT.humidity) >=5 && (DHT.humidity) <10  && (x) >=29)    
       || ((DHT.humidity) >=10 && (DHT.humidity) <15 && (x) >=33)
       || ((DHT.humidity) >=15 && (DHT.humidity) <20 && (x) >=36)
       || ((DHT.humidity) >=20 && (DHT.humidity) <25 && (x) >=38)
       || ((DHT.humidity) >=25 && (DHT.humidity) <30 && (x) >=40)
       || ((DHT.humidity) >=30 && (DHT.humidity) <40 && (x) >=43)
       || ((DHT.humidity) >=40 && (DHT.humidity) <50 && (x) >=46)
       || ((DHT.humidity) >=50 && (DHT.humidity) <60 && (x) >=50)
       || ((DHT.humidity) >=60 && (DHT.humidity) <65 && (x) >=53)
       || ((DHT.humidity) >=65 && (x) >=55)
       )
     {
       Serial.println("message sent");
       ALERT();
     }

That is one crazy nasty if statement. I'd be inclined to ditch it and use a look-up table.

The one easy common factor between each row of that if statement is the DHT.humidity value. Take that, divide it by 5, as that is the range of each step, and you get an index...

As integers:

5 / 5 = 1
6 / 5 = 1
7 / 5 = 1
8 / 5 = 1
9 / 5 = 1
10 / 5 = 2
... etc

See where I'm going with that?

int index = DHT.humidity / 5;

Then you use that index to look up an "x" value, whatever that is:

int8_t xvals[] = { -1, 29, 33, 36, 38, 40,  43, 46, 50, 53 };

if (index > 9) index = 9; // limit the index to the number of entries.
if (x >= xvals[index]) {
  Serial.println("message sent");
  ALERT();
}

You could pop most of that into a function and pass it a table to run the comparison against as a parameter to the function.

int8_t xvals[] = { -1, 29, 33, 36, 38, 40,  43, 46, 50, 53 };

doAlert(x, xvals, 9);

void doAlert(int x, int8_t *tab, int entries) {
  int index = DHT.humidity / 5;
  if (index >= entries) index = entries-1; // limit the index to the number of entries.
  if (x >= tab[index]) {
    Serial.println("message sent");
    ALERT();
  }
}

All code is untested, but it should give you ideas...

Simplify that block of syntactic pudding just so you can understand your own code.

You repeat the first checks, also writing it backwards save re checking the same thing over and over.

This is just an example, you can cram it all inline like yours if you like.

if( DHT.humidity >= 65 ){

}else if( DHT.humidity >= 60 ){  //The check above implies that the value is less than 65, therefore no need to check.

}else if( DHT.humidity >= 50 ){  //Ditto

}

If you are getting more than one alert, it is the code surrounding it that we need, there is clearly only one alert message here.

(DHT.temperature) <25

The parenthesis are doing nothing here. Put them around the whole expression, and do the same for all the other comparison expressions:

(DHT.temperature <25)

I don't know whether that will fix your problem, but it will get you closer to sensible code.

OK - this is still same code but with a tidy up - at least its a bit easier for me to read

With other blocks commented out this block works - so I am looking at what interaction i might be getting between the "blocks" that is causing the multiple alerts once once block triggered

if (temp >=20 && temp <25 &&                  //When TEMP range between 20 & 25
          (rh >=5 && rh <10  && wind >=29)    //with RH between 5 & 10% with wind greater than 29
       || (rh >=10 && rh <15 && wind >=33)    //OR with RH between 10 & 15% with wind greater than 33
       || (rh >=15 && rh <20 && wind >=36)    //OR with RH between 15 & 20% with wind greater than 36
       || (rh >=20 && rh <25 && wind >=38)    //OR with RH between 20 & 25% with wind greater than 38
       || (rh >=25 && rh <30 && wind >=40)    //OR with RH between 25 & 30% with wind greater than 40
       || (rh >=30 && rh <40 && wind >=43)    //OR with RH between 30 & 40% with wind greater than 43
       || (rh >=40 && rh <50 && wind >=46)    //OR with RH between 40 & 50% with wind greater then 46
       || (rh >=50 && rh <60 && wind >=50)    //OR with RH between 50 & 60% with wind greater than 50
       || (rh >=60 && rh <65 && wind >=53)    //OR with RH between 60 & 65% with wind greater than 53
       || (rh >=65 && wind >=55)              //OR with RH above 65% and wind greater than 55
       )
     {
       Serial.println("message sent");
       ALERT();
     }
[code]

[/code]

majenko:
That is one crazy nasty if statement. I'd be inclined to ditch it and use a look-up table.

The one easy common factor between each row of that if statement is the DHT.humidity value. Take that, divide it by 5, as that is the range of each step, and you get an index...

As integers:

5 / 5 = 1
6 / 5 = 1
7 / 5 = 1
8 / 5 = 1
9 / 5 = 1
10 / 5 = 2
... etc

See where I'm going with that?

int index = DHT.humidity / 5;

Then you use that index to look up an "x" value, whatever that is:

int8_t xvals[] = { -1, 29, 33, 36, 38, 40,  43, 46, 50, 53 };

if (index > 9) index = 9; // limit the index to the number of entries.
if (x >= xvals[index]) {
  Serial.println("message sent");
  ALERT();
}



You could pop most of that into a function and pass it a table to run the comparison against as a parameter to the function.


int8_t xvals[] = { -1, 29, 33, 36, 38, 40,  43, 46, 50, 53 };

doAlert(x, xvals, 9);

void doAlert(int x, int8_t *tab, int entries) {
  int index = DHT.humidity / 5;
  if (index >= entries) index = entries-1; // limit the index to the number of entries.
  if (x >= tab[index]) {
    Serial.println("message sent");
    ALERT();
  }
}



All code is untested, but it should give you ideas...

Thanks Majenko :slight_smile:

I am implementing your idea as follows (note this only shows two of the 7 temp/wind factor ranges i have to test for)
Am i following you suggestion correctly?

if (temp >=15 && temp <20)
        {
          int index = rh/5;
          int8_t windvals[] = {-1,31,35,38,40,43,45,49,53,56};
          if (index >9) index =9;
          if (wind >= windvals[index])
           {
           Serial.println("message");
           ALERT();
           }
        }
        
   if (temp >=20 && temp <25)
        {
          int index = rh/5;
          int8_t windvals[] = {-1,29,33,36,38,40,43,46,50,53,};
          if (index >9) index =9;
          if (wind >= windvals[index])
           {
           Serial.println("message");
           ALERT();
           }
        }

Just realised that last code doesn't quite fit my needs as the humidity ranges are not linear but I'll play with the code to see if I can work around it. AT least it give me something to learn about the use of lookup tables and I might be able to adapt so thank you again.

For info the Humidity ranges need to be:
5-10
10-15
15-20
20-25
25-30
30-40
40-50
50-60
65 and above

So break it down into the lowest common denominator and repeat entries as you need (it was late last night and I didn't notice the non-linearity).

Instead of 40-49 = A, 50-59 = B, have 40-44 = A, 45-49 = A, 50-54 = B, 55-59 = B, etc.

Thank you Majenko - that's what I worked out to do to make it work :slight_smile: