Consiglio/Problema per codice smart garden

Buongiorno a tutti,

Vorrei un consiglio riguardante il codice per un progetto smart garden.

Sto portando avanti un progetto con un MKR IoT Carrier + Arduino wifi 1010. Ho collegato una pompa ad uno dei due relay del carrier in modalità Normally Open con l'obiettivo di comandare (accendere/spegnere) da remoto la pompa. Non potendo vedere quanta acqua venga fornita alla pianta ho creato una variabile (che ho chiamato timer) inizializzata al numero di secondi corrispondenti al tempo per cui la pompa deve rimanere attiva (per poi spegnersi). Quindi, ho creato questa funzione:

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

Tuttavia non mi sembra che funzioni molto bene: ad esempio se metto su waterpump = false; prima che il timer sia concluso la pompa continua a dare acqua (probabilmente non è scritto bene a livello di codice). Volevo sapere se qualcuno poteva darmi qualche consiglio o delle nuove idee su come svolgere il mio progetto. Per completezza allego il codice completo:

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

int moistPin = A5;
int dry = 1023;
int wet = 0;
int timer = 3000;

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);
  }
 
  delay(500);
  CARRIER_CASE = true;
  carrier.begin();
  carrier.display.setRotation(0);
  carrier.display.enableDisplay(0);
  delay(1500);
}

void loop() {
  ArduinoCloud.update();

  //read temperature and humidity
  temperature = carrier.Env.readTemperature();
  humidity = carrier.Env.readHumidity();
  
  //Update touch buttons
  carrier.Buttons.update();
  	
  //function to print out values
  if (carrier.Buttons.onTouchDown(TOUCH0)) {
    carrier.display.enableDisplay(1);
  }
  
  if (carrier.Buttons.onTouchDown(TOUCH1)) {
    printInfo();
  }
  
  if (carrier.Buttons.onTouchDown(TOUCH2)) {
    printInfoRelays();
  }
  
  if (carrier.Buttons.onTouchDown(TOUCH4)) {
    carrier.display.enableDisplay(0);
  }
  
  //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; //We dont need RGB colors
  carrier.Light.readColor(none, none, none, light);
  
  delay(100);
}

void onWaterpumpChange() {
  
  int t=0;
  
  while (waterpump == true && t <= timer){
    carrier.Relay2.open();
    waterPumpState = "PUMP: ON";
    updateScreen();
    //set timer [ms] to turn OFF the pump
    delay(1000);
    t=t+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();
}

Lorenzo

Non ho capito bene. Dove hai provato a mettere waterpump=false ?
Il ciclo while è corretto, cicla fino a che la variabile è true E t minore o uguale a timer.
Ovviamente quando sei in quel ciclo, sei li dentro, come (e dove) fai a eseguire waterpump=false ??

Glielo comunico come comando esterno attraverso l'IoT Cloud (allego foto).
Utilizzando il bottone nel widget "Pump" cambio il valore della variabile booleana da true a false o viceversa. Probabilmente per come è scritto quel ciclo while, l'unico modo per uscirne è aspettare che finisca il timer. Perchè se mentre lui è in quel loop spengo la pompa tramite quel pulsante nel cloud lui continua ad andare avanti fino allo scadere del timer


. Mi chiedevo se ci fosse un modo sicuro per disattivare velocemente la pompa e l'emissione d'acqua invece di aspettare la fine del timer.

Certo, evitare completamente iterazioni bloccanti come quel while che hai implementato e l'uso dell'istruzione delay() anch'essa bloccante.

Ok! Grazie per la risposta.
Quindi con cosa potrei sostituirli per quello che voglio fare? O anche l'idea di base è sbagliata ed è meglio seguire un'altra strada?
Grazie,
Lorenzo