Problem with coding - Things that are in an if statement that's not true keeps executing anyways

Hello people!
I'm developing a system that controls the ph of a water tank for an hydroponic crop with an ESP32 (38 pins version).
My program reads the voltage value of the sensor and calculates pH. For stability, it takes a read from sensor one time per second over sixty seconds and makes an average of those reads.
The program can also calibrate the sensor. For this it takes the voltage read from the sensor one time per second over a minute, takes the average, it does the same with the other calibration solution and makes the calculations to find the calibration values.
This is the code: (it is a short version using just the serial to comunicate, but the real program has a web page and web sockets to comunicate. I chop it down first to see if my problem was in other part of code and second to not make you read +600 lines of code).

#include <Adafruit_ADS1X15.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
//Adafruit_ADS1115 ads;

unsigned long timer_cal = 0;
unsigned long caltime = 1000;
float volt4 = 0;
float volt7 = 0;
bool adsConnected = false;
int solution = 0;
float calval2=21.37079;
float calval1=-5.69721;
float volt_prom_cal;
float volt_suma_cal;
float lastph;
float prom;
float phtr;
float suma;
float phmaximo = 8;
float phminimo = 4;
unsigned long sample = 1000;
unsigned int cal_counter = 0;
unsigned int cal_rem_counter = 60;
unsigned int contador_medicion = 0;
unsigned long tiempoanterior = 0;
unsigned long timer_medicion = 0;
bool calibrating = false;
char* _SSID = "Fibra";
char* PSK = "12345679";

void calcRecta(float x1, float x2) {
  float m = (6.86 - 4) / (x2 - x1);
  float ord = 4 - (m * x1);
  calval1 = ord;
  calval2 = m;
  
}

float truncate(float val, byte dec)
{
  float x = val * pow(10, dec);
  float y = round(x);
  float z = x - y;
  if ((int)z == 5)
  {
    y++;
  } else {}
  x = y / pow(10, dec);
  return x;
}
/*float read_to_cal(){
  int16_t adc0;
  adc0 = ads.readADC_SingleEnded(0);
  float volt = ads.computeVolts(adc0);
  float voltTr = truncate(volt, 3);
  return voltTr;
}*/
void setup() {
  Serial.setTimeout(3000);
  Serial.begin(115200);
  WiFi.mode(WIFI_AP_STA);
  WiFi.disconnect();
  Serial.print("Conectando a la red Wifi...");
  WiFi.begin(_SSID, PSK);
  delay(5000);
  if (WiFi.status() == WL_CONNECTED) {
    Serial.printf("Conectado a la red. IP: ");
    IPAddress IPSTA = WiFi.localIP();
    Serial.println(IPSTA);
  }
  else{
    Serial.println("No se pudo conectar a una red wifi. Estableciendo modo Punto de acceso.");
    WiFi.softAP("ESP32", "123456789");
    IPAddress ip = WiFi.softAPIP();
    Serial.println("Punto de acceso generado.");
    Serial.print("IP: ");
    Serial.println(ip);
  }
  /*if (!ads.begin()) {
    Serial.println("No se pudo inicializar el ADC.");
    adsConnected = false;
  }
  else {
    Serial.println("ADC inicializado correctamente.");
    adsConnected = true;
  }*/
  adsConnected = true;
}
void loop() {
  int option = Serial.parseInt();
  if (option == 0){
    Serial.println("Midiendo.");
    calibrating = false;
  }
  if (option == 1){
    calibrating = true;
    Serial.println(calibrating);
    Serial.println("Ingrese solución de calibración: ");
    while (Serial.available() == 0){
    }
    
    solution = Serial.parseFloat();
    Serial.println(solution);
  }
  while (Serial.available() == 0){
    if (calibrating == false){
    if (millis() >= timer_medicion + sample) {
      if (adsConnected == true) {
        if(contador_medicion <60){
          /*int16_t adc0;
          adc0 = ads.readADC_SingleEnded(0);*/
          float volt = 2.48;//ads.computeVolts(adc0);
          Serial.print("Voltaje del sensor: ");
          Serial.println(volt);
          float voltTr = truncate(volt, 3);
          float phfinal = calval1 * voltTr + calval2;
          phtr = truncate(phfinal, 2);
          suma += phtr;
          Serial.print("pH: ");
          Serial.println(phtr);
          contador_medicion++;
        }
        else{
          prom = suma/60;
          contador_medicion = 0;
          Serial.print("Promedio: ");
          Serial.println(prom);
          suma = 0;
        }
        if (prom > phmaximo && lastph <= phmaximo) {
          Serial.println("pH HIGH!");
        }
        else if (prom < phminimo && lastph >= phminimo) {
          Serial.println("pH LOW");
        }
        lastph = prom;
        timer_medicion += sample;
    }
    else {//If ADS1115 not connected
      }
    }
    }
    if (calibrating == true){
      if(millis() >= timer_medicion + sample){
        if(adsConnected == true){
          if(solution == 4){
            if(cal_counter < 60){
              float volt_val = 2.9;//read_to_cal();
              volt_suma_cal += volt_val;
              timer_cal += caltime;
              cal_counter ++;
              Serial.print("Voltaje: ");
              Serial.println(volt_val);
          }
          if(cal_counter == 60){
            volt_prom_cal = volt_suma_cal / cal_counter;
            cal_counter = 0;
            volt4 = volt_prom_cal;
            Serial.println("Calibración pH 4: finalizada");
            volt_suma_cal = 0;
            solution = 0;
            break;
          }
        }
        if(solution == 7){
          if(cal_counter < 60){
            float volt_val = 2.48;//read_to_cal();
            volt_suma_cal += volt_val;
            timer_cal += caltime;
            cal_counter ++;
            Serial.print("Voltaje: ");
            Serial.println(volt_val);
          }
          if(cal_counter == 60){
            volt_prom_cal = volt_suma_cal / cal_counter;
            cal_counter = 0;
            volt7 = volt_prom_cal;
            Serial.print("Volt prom: ");
            Serial.println(volt7);
            Serial.println("Calibración solucion 7 finalizada.");
            volt_suma_cal = 0;
            solution = 0;
            cal_counter = 0;
            break;
          }
        }
        
        if(volt4 != 0 && volt7 != 0){
          calcRecta(volt4, volt7);
          Serial.print("New Calibration Values: ");
          Serial.print("Calval1: ");
          Serial.println(calval1);
          Serial.print("Calval2: ");
          Serial.println(calval2);
          volt4 = 0;
          volt7 = 0;
          break;
        }
      }
      else{//Si ads no funciona
      }
    }
  }
  }
}

The problem that i'm facing is that both calibration == true and calibration == false are still executing even when the other is running. I notice this because when you try to calibrate after a few minutes the program has started all the measures appear instantly. And when return to measuring mode, all measures of pH apear instantly.
I have no clue why this is happening since even inside if (calibrating == true){} there is another if that is not supposed to get executed until I enter a solution number.

I'm sorry for the long post.
Hope you can throw me an idea for where to start because i don't even know how can this be possible. xD
Thanks in advance!

Edit: I changed the code to spare the need of ads and pH sensor, using fixed values. So anyone can load the code and see if the error is reproducible.
Also, i recorded a video of the serial monitor, but i can't upload it here. So im uploading it to youtube and posting it here soon.
**Here is the video: Problem with if statements executing on background when they shouldn't - YouTube **

At the start of loop(), you try to read a number from Serial. If you don't send a number within one second, the number you get is zero, which sets calibrating = false;

If you send a 1 for option 1 to set calibrating = true, the next time you get to the top of loop() and have not sent a 1, it will see a zero again.

It is very unlikely that the tests are not working

Have you tried printing the value of the variable that you are testing before it is tested ?

Yes. I tried. And are ok. That's what trips me off.
The solution variable goes to 0 after calibrating.
And also, calibrating variable changes as expected. i know this because program alternates between measuring and calibrating mode as expected.
The problem seems that despite what mode is in, the program still executes the other mode in background.

It doesn't matter. This program alternates just fine between modes. And also the real program uses websockets to change the calibrating variable, and the problem is the same.

I strongly suspect that the values that you are testing are not what you think they are, rather the logic of your sketch is wrong

I know that might be something wrong.
But It scapes me what.
AFAIK what happens in an If, It should not be happening in the other if that compares the same variable. It's like it's happening on background.

So we've ruled out "the compiler is broken". I suggest you revisit post # 2, I think you're making passes through the code with oscillations between true and false.

To prove that, maybe stretch the timeout on Serial so that parseint doesn't timeout so often, it's default is 1 second I think.

Ok. That's a good start, thanks I'm gonna see what can i do to avoid that. But i think that problem is belong to this particular extrat since my original code is getting the value from a web page via web socket.

Maybe, but the case where a timeout happens is always possible, no? So rethink the strategy a bit.
C

hi , I does not know where is problem with calibrating, but testing float for equality is very bad idea, because this condition has very little chance of returning true.

Good to know. I'm gonna try changing It to a int.
But anyways, the sketch seems to correctly detect that variable because when i enter calibration mode and enter the solución number, sketch does what's expected. It's Just makes every read in less than one second. And the same happens when i return to measuring mode: all measurings that happened when in calibrating mode appears at once.
Probably later today I'm gonna upload a video of the serial monitor that shows the problem.

I tried changing that variable to an int, and still the program does the same. :confused:
I'm gonna try to change order of if's to see if that helps. And in the meantime i'm uploading a video to illustrate the problem I'm facing.

When you do, post your latest code too.

I uploaded the video and edited the code to the last code used. :wink:

I discarded that the ESP32 was the problem using another ESP32 from another manufacturer.
I suspected that had nothing to do with the ESP, but worth the try. xD

I tried changing order of if's leaving just one timer, and the adsConnected if right after. But problem persists.

void loop() {
  int option = Serial.parseInt();
  if (option == 0){
    Serial.println("Midiendo.");
    calibrating = false;
  }
  if (option == 1){
    calibrating = true;
    Serial.println(calibrating);
    Serial.println("Ingrese solución de calibración: ");
    while (Serial.available() == 0){
    }

    solution = Serial.parseFloat();
    Serial.println(solution);
  }
  while (Serial.available() == 0){
    if (millis() >= timer_medicion + sample) {
      if (adsConnected == true) {
        if (calibrating == false){
          if(contador_medicion <60){
          /*int16_t adc0;
          adc0 = ads.readADC_SingleEnded(0);*/
          float volt = 2.48;//ads.computeVolts(adc0);
          Serial.print("Voltaje del sensor: ");
          Serial.println(volt);
          float voltTr = truncate(volt, 3);
          float phfinal = calval1 * voltTr + calval2;
          phtr = truncate(phfinal, 2);
          suma += phtr;
          Serial.print("pH: ");
          Serial.println(phtr);
          contador_medicion++;
        }
          else{
          prom = suma/60;
          contador_medicion = 0;
          Serial.print("Promedio: ");
          Serial.println(prom);
          suma = 0;
        }
          if (prom > phmaximo && lastph <= phmaximo) {
          Serial.println("pH HIGH!");
        }
          else if (prom < phminimo && lastph >= phminimo) {
            Serial.println("pH LOW");
          }
          lastph = prom;
          timer_medicion += sample;
        }
      if (calibrating == true){
          if(solution == 4){
            if(cal_counter < 60){
              float volt_val = 2.9;//read_to_cal();
              volt_suma_cal += volt_val;
              timer_cal += caltime;
              cal_counter ++;
              Serial.print("Voltaje: ");
              Serial.println(volt_val);
          }
          if(cal_counter == 60){
            volt_prom_cal = volt_suma_cal / cal_counter;
            cal_counter = 0;
            volt4 = volt_prom_cal;
            Serial.println("Calibración pH 4: finalizada");
            volt_suma_cal = 0;
            solution = 0;
            break;
          }
        }
        if(solution == 7){
          if(cal_counter < 60){
            float volt_val = 2.48;//read_to_cal();
            volt_suma_cal += volt_val;
            timer_cal += caltime;
            cal_counter ++;
            Serial.print("Voltaje: ");
            Serial.println(volt_val);
          }
          if(cal_counter == 60){
            volt_prom_cal = volt_suma_cal / cal_counter;
            cal_counter = 0;
            volt7 = volt_prom_cal;
            Serial.print("Volt prom: ");
            Serial.println(volt7);
            Serial.println("Calibración solucion 7 finalizada.");
            volt_suma_cal = 0;
            solution = 0;
            cal_counter = 0;
            break;
          }
        }

        if(volt4 != 0 && volt7 != 0){
          calcRecta(volt4, volt7);
          Serial.print("New Calibration Values: ");
          Serial.print("Calval1: ");
          Serial.println(calval1);
          Serial.print("Calval2: ");
          Serial.println(calval2);
          volt4 = 0;
          volt7 = 0;
          break;
        }
      }
    }
    else{//Si ads no funciona
    }
  }
  }
}

Hi!

I did some changes in your code.

Try it:

#include <Arduino.h>

#define READING_INTERVAL 1000 // Interval between readins in ms
#define READING_AMOUNT 10     // Amount of sample for the average

float volt4 = 0;
float volt7 = 0;
bool adsConnected = true;
int solution = 0;
float calval2 = 21.37079;
float calval1 = -5.69721;
float volt_prom_cal;
float volt_suma_cal;
float lastph;
float prom;
float phtr;
float suma;
float phmaximo = 8;
float phminimo = 4;
unsigned int cal_counter = 0;
unsigned int cal_rem_counter = 60;
unsigned int contador_medicion = 0;
unsigned long tiempoanterior = 0;
unsigned long previousMillis = 0;
bool calibrating = false;

void calcRecta(float x1, float x2)
{
  float m = (6.86 - 4) / (x2 - x1);
  float ord = 4 - (m * x1);
  calval1 = ord;
  calval2 = m;

}

float truncate(float val, byte dec)
{
  float x = val * pow(10, dec);
  float y = round(x);
  float z = x - y;
  if ((int)z == 5)
  {
    y++;
  }
  else
  {
  }
  x = y / pow(10, dec);
  return x;
}

void setup()
{
  Serial.setTimeout(3000);
  Serial.begin(115200);
}

void loop()
{
  int option = 0;

  if(Serial.available() > 0)
  {
    option = Serial.parseInt();

    if (option == 0)
    {
      Serial.println("Midiendo.");
      calibrating = false;
    }
    if (option == 1)
    {
      calibrating = true;
      Serial.println(calibrating);
      Serial.println("Ingrese solución de calibración: ");
      while (Serial.available() == 0)
      {
      }
      solution = Serial.parseFloat();
      Serial.println(solution);
    }
  }

  if (calibrating == false)
  {
    if (adsConnected == true)
    {
      if(contador_medicion < READING_AMOUNT)
      {
        if ((millis() - previousMillis) > READING_INTERVAL)
        {
          float volt = 2.48;
          Serial.print("Voltaje del sensor: ");
          Serial.println(volt);
          float voltTr = truncate(volt, 3);
          float phfinal = calval1 * voltTr + calval2;
          phtr = truncate(phfinal, 2);
          suma += phtr;
          Serial.print("pH: ");
          Serial.println(phtr);
          contador_medicion++;
          previousMillis = millis();
        }
      }
      else
      {
        prom = suma / READING_AMOUNT;
        contador_medicion = 0;
        Serial.print("Promedio: ");
        Serial.println(prom);
        suma = 0;
      }
      if ((prom > phmaximo) && (lastph <= phmaximo) )
      {
        Serial.println("pH HIGH!");
      }
      else if ((prom < phminimo) && (lastph >= phminimo) )
      {
        Serial.println("pH LOW");
      }
      lastph = prom;
    }
    else    // If ADS1115 not connected
    {
    }
  }
  else if (calibrating == true)
  {
    if(adsConnected == true)
    {
      if(solution == 4)
      {
        if(cal_counter < READING_AMOUNT)
        {
          if ((millis() - previousMillis) > READING_INTERVAL)
          {
            float volt_val = 2.9;   // read_to_cal();
            volt_suma_cal += volt_val;
            cal_counter++;
            Serial.print("Voltaje: ");
            Serial.println(volt_val);
            previousMillis = millis();
          }
        }
        else
        {
          volt_prom_cal = volt_suma_cal / cal_counter;
          cal_counter = 0;
          volt4 = volt_prom_cal;
          Serial.println("Calibración pH 4: finalizada");
          volt_suma_cal = 0;
          solution = 0;
          calibrating = false;
        }
      }
      if(solution == 7)
      {
        if(cal_counter < READING_AMOUNT)
        {
          if ((millis() - previousMillis) > READING_INTERVAL)
          {
            float volt_val = 2.48;  // read_to_cal();
            volt_suma_cal += volt_val;
            cal_counter++;
            Serial.print("Voltaje: ");
            Serial.println(volt_val);
            previousMillis = millis();
          }
        }
        else
        {
          volt_prom_cal = volt_suma_cal / READING_AMOUNT;
          cal_counter = 0;
          volt7 = volt_prom_cal;
          Serial.print("Volt prom: ");
          Serial.println(volt7);
          Serial.println("Calibración solucion 7 finalizada.");
          volt_suma_cal = 0;
          solution = 0;
          cal_counter = 0;
          calibrating = false;
        }
      }

      if((volt4 != 0) && (volt7 != 0))
      {
        calcRecta(volt4, volt7);
        Serial.print("New Calibration Values: ");
        Serial.print("Calval1: ");
        Serial.println(calval1);
        Serial.print("Calval2: ");
        Serial.println(calval2);
        volt4 = 0;
        volt7 = 0;
      }
    }
    else    // Si ads no funciona
    {
    }
  }
}

The output is:

Voltaje del sensor: 2.48
pH: 7.24
Voltaje del sensor: 2.48
pH: 7.24
Promedio: 7.24
Voltaje del sensor: 2.48
pH: 7.24
Voltaje del sensor: 2.48
pH: 7.24
Voltaje del sensor: 2.48
pH: 7.24
Voltaje del sensor: 2.48
pH: 7.24
Voltaje del sensor: 2.48
pH: 7.24
Voltaje del sensor: 2.48
pH: 7.24
Voltaje del sensor: 2.48
pH: 7.24
1
Ingrese solución de calibración: 
4
Voltaje: 2.90
Voltaje: 2.90
Voltaje: 2.90
Voltaje: 2.90
Voltaje: 2.90
Voltaje: 2.90
Voltaje: 2.90
Voltaje: 2.90
Voltaje: 2.90
Voltaje: 2.90
Calibración pH 4: finalizada
Voltaje del sensor: 2.48
pH: 7.24
Voltaje del sensor: 2.48
pH: 7.24
Voltaje del sensor: 2.48
pH: 7.24

Removing calibrating = false after finish the calibration the code won't print anything more.

Best regards.

1 Like

Thank you very much. As soon as i get home from work, I'll test it and let you know how it went. n.m