Boolean variable in a while loop (Smart Garden)

Hi to everybody,

I'm working on a smart garden project with an Arduino MkR wifi 1010 and MkR IoT Carrier. In my project I have one water pump connected to a Relay and nothing else. Thanks to the arduino cloud I can manage the pump by mean a boolean variable. In particular I can change its value trough the Dashboard of the cloud (I attach screenshot below).
Everything works well but I would like to improve my code. In the specific I would like to keep opened the Relay (and so give water to the plant) only for a fixed time (that I choose at the beginning of the code). So in a function I have put a "while" loop in order to give water until two conditions are verified: 1) if the boolean variable connected to pump is true 2) if the time is less than the timer set. However, I would like that if I change the value of boolean variable to False before that timer is expired the pump stops. But I can't do it. I don't know why but if the code enters in the while loop, it doesn't exit if I change the waterpump status to false. It is like it doesn't update the variable. I attach also the full code. Someone can help me?
Thanks a lot in advance,
Cheers,
Lorenzo

#include "thingProperties.h"
#include <Arduino_MKRIoTCarrier.h>
MKRIoTCarrier carrier;

int moistPin = A5;
int dry = 1023;
int wet = 0;
unsigned long timer = 100000; //ms

String lightState;
String waterPumpState;

uint32_t lightsOn = carrier.leds.Color(82, 118, 115);
uint32_t lightsOff = carrier.leds.Color(0, 0, 0);

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  //enable only if you work with the pc
  //while (!Serial);
 
  // Defined in thingProperties.h
  initProperties();
 
  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  //Get Cloud Info/errors , 0 (only errors) up to 4
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
 
  //Wait to get cloud connection to init the carrier
  while (ArduinoCloud.connected() != 1) {
    ArduinoCloud.update();
    delay(500);
  }
 
  CARRIER_CASE = true;
  carrier.begin();
  carrier.display.setRotation(0);
  delay(1500);
}

void loop() {
  ArduinoCloud.update();

  //read temperature and humidity
  temperature = carrier.Env.readTemperature();
  humidity = carrier.Env.readHumidity();
  
  //print for debugging
  //Serial.print("T: ");
  //Serial.println(temperature);
  
  //Update touch buttons
  carrier.Buttons.update();
  	
  //function to print out values
  if (carrier.Buttons.onTouchDown(TOUCH0)) {
    printInfo();
  }
  
  if (carrier.Buttons.onTouchDown(TOUCH1)) {
    printInfoRelays();
  }
  
  //read raw moisture value
  int raw_moisture = analogRead(moistPin);

  //map raw moisture to a scale of 0 - 100
  moisture = map(raw_moisture, wet, dry, 100, 0);
  
  //read ambient light
  while (!carrier.Light.colorAvailable()) {
    delay(5);
  }
  int none;
  carrier.Light.readColor(none, none, none, light);
  
  delay(100);
}

void onWaterpumpChange() {
  
  unsigned long dt=0;
  while ((waterpump == true) && (dt <= timer)){
    carrier.Relay2.open();
    waterPumpState = "PUMP: ON";
    updateScreen();
    //set timer [ms] to turn OFF the pump
    delay(1000);
    dt=dt+1000; 
  }
  waterpump = false;
  carrier.Relay2.close();
  waterPumpState = "PUMP: OFF";
  updateScreen();
}

void onArtificialLightChange() {
  if (artificial_light == true) {
    carrier.leds.fill(lightsOn, 0, 5);
    carrier.leds.show();
    lightState = "LIGHTS: ON";
  } else {
    carrier.leds.fill(lightsOff, 0, 5);
    carrier.leds.show();
    lightState = "LIGHTS: OFF";
  }
  updateScreen();
}

//Update displayed Info
void printInfo(){
  carrier.display.fillScreen(ST77XX_BLACK);
  carrier.display.setTextColor(ST77XX_WHITE);
  carrier.display.setTextSize(2);
 
  carrier.display.setCursor(40, 60);
  carrier.display.print("Water: ");
  carrier.display.print(moisture);
  carrier.display.println("%");
  
  carrier.display.setCursor(40, 80);
  carrier.display.print("T: ");
  carrier.display.print(temperature);
  carrier.display.println("C");
  
  carrier.display.setCursor(40, 100);
  carrier.display.print("Hum: ");
  carrier.display.print(humidity);
  carrier.display.println("%");
}

void printInfoRelays(){
  carrier.display.fillScreen(ST77XX_BLACK);
  carrier.display.setTextColor(ST77XX_WHITE);
  
  carrier.display.setTextSize(3);
  carrier.display.setCursor(40, 50);
  carrier.display.print(waterPumpState);
  carrier.display.setCursor(40, 90);
  carrier.display.print(lightState);
}

//Update carrier screen
void updateScreen(){
  printInfoRelays();
}```
  while ((waterpump == true) && (dt <= timer))
  {
    carrier.Relay2.open();
    waterPumpState = "PUMP: ON";
    updateScreen();
    //set timer [ms] to turn OFF the pump
    delay(1000);
    dt = dt + 1000;
  }

What is going to change the state of the waterpump variable in the while loop ?

Don't use a while loop - you simply hang everything off loop(), so that everything can progress as needed.

Think of the program as having states, and store the state in a variable. One state is the pump has been triggered, but hasn't yet timed-out.
Another is the pump has been triggered, timed out and is now off.
Another is the pump has been cancelled.

Various events and time-outs drive the changes to the current state, and these changes perform relevant actions.

This is how event-driven programming using state-machines works, and is what microcontrollers typically do.

Your events are the boolean variable changing, and the timeout completing.
Your actions are controlling the pump and starting/cancelling the timer.

Google "state transition diagram".

I thought to attach a picture, but probably I forgot it. In the Dashboard you can read or write some variables. In this case I can change the value of the waterpump.

Will the value change when the code is actually in the while loop ?

Thanks for you answer. If I understood well, you are saying to remove the function "void onWaterpumpChange()" and write the content in the loop() function, right? Anyway inside the loop I need in any case another "loop" (as a "while" or "for"), because I need that the waterpump stay opened for fixed time. In other case it's not very clear to me with what replace the "while" loop.
So, I should write something like:

void loop() {
  ArduinoCloud.update();

  //read temperature and humidity
  temperature = carrier.Env.readTemperature();
  humidity = carrier.Env.readHumidity();
  if (waterpump == True){
      while(dt <= timer){
           [....]
       }
  }

I hoped yes. But practically not. When I open the waterpump, the code enters in the loop and stay there up to the timer is expired. But if before that I try to set again the waterpump to false (from the dashboard), the code doesn't understand and it remains in the while loop. For me that is a problem, because if for example I turn on the pump by mistake I would like to stop it immediataly from the Dashboard and not wait the ending of the timer.

Change the while loop to an if and let loop() do the looping. That way the code will not be blocked and will be able to respond to external inputs

Thanks a lot. I will try and I will let you know.

Cheers,
Lorenzo

Thanks a lot. I solved my problem!

I am glad that you got it working

Please post your revised code to help anyone with a similar question in the future

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