Same loop() works different with the cloud and without

I am working with the OPTA and its extenders for an automation project. The same action in the loop behaves differently depending on whether I upload the code using the Arduino IDE or the Arduino Cloud. When executed through the Arduino Cloud, it seems that the loop resets after completing the first delay in the function. However, the same function executes correctly without any issues when uploaded through the Arduino IDE.

void controlCirculation() {
    controlGVA(0,true);
    controlGVA(1,false);
    controlGVA(2,false);
    controlGVA(3,false);
    delay(60000);
    controlGVA(1,true);
    delay(3000);
    controlGVA(0,false);
    delay(60000);
    controlGVA(2,true);
    delay(3000);
    controlGVA(1,false);
    delay(60000);
    controlGVA(3,true);
    delay(3000);
    controlGVA(2,false);
    delay(60000);
    controlGVA(4,true);
    delay(3000);
    controlGVA(3,false);
    delay(60000);
    controlGVA(5,true);
    delay(3000);
    controlGVA(4,false);
    delay(60000);
    controlGVA(0,true);
    controlGVA(1,true);
    controlGVA(2,true);
    controlGVA(3,true);
    controlGVA(5,false);
    delay(1000);
}
void loop() {
  ArduinoCloud.update();
  OptaController.update();
  
    String currentTimeStr1 = getLocalTime();
    int currentHour = hour();
    int currentMinute = minute();
    int currentSecond = second();
    Serial.println(currentTimeStr1);

if (readButtonState(0)) { // Main loop state
    Serial.println("Main loop state");

    // Perform sensor readings and updates
    readRTDs();
    float pressures[3];
    String logString;
    readPressures(pressures, logString);
    String mfm = getMFMReading();
    String irradiance = readPyranometer();

    // Update the "values" string
    values = "Panel Temp: " + String(panelTemp, 2) + "C, " +
             "Ambient Temp: " + String(ambientTemp, 2) + "C, " +
             mfm + irradiance +
             "Panel Pressure: " + String(pressures[0], 2) + ", " +
             "Pump Pressure: " + String(pressures[2], 2);

    Serial.println("Updated values: " + values);

    // Perform other main loop actions
    if (!isPulsing) {
        setPumpVoltage(3000);
    }

    // Handle time-based actions
    if (hour() >= 6 && hour() < 17) {
        handlePumpPulse();
        controlTECWithPID();
        controlDrainValve("timed");
        if (gvb2_open) {
            controlGVB(2, false); // Close GVB 2
            gvb2_open = false;
        }
    } else {
        controlTECWithPID();
        controlDrainValve("timed");
        if (!gvb2_open) {
            controlGVB(2, true); // Open GVB 2
            gvb2_open = true;
        }
    }

    delay(3000);
    return; // Exit loop after handling Button 0
}


    // Button 1: Perform KOH and HS Filling
if (readButtonState(1)) {
        // Perform KOH filling
        SF1kohfilling();
        if (readButtonState(0)) {
            Serial.println("Button 0 pressed. Returning to main loop.");
            return;
        }
        // If Button 0 is not pressed, proceed to HS filling
        String hsFillingResult = SF2_HS_filling();
        Serial.println("HS Filling Result: " + hsFillingResult);
    }

    // Button 3: SF3 State
if (readButtonState(3)) {
        Serial.println("SF3 state");
        SF3_PC_LOAD();
        delay(3000);
        
    }
if (readButtonState(2) ) {
    controlCirculation();
}
    // Handle idle state
if (!readButtonState(0) && !readButtonState(1) && !readButtonState(2) && !readButtonState(3) &&
        readLevelSensor(0) && readLevelSensor(1)) {
        setPumpVoltage(3000);
          // Button 2: SF4 State
        
    }
        if (!gvb2_open) {
            controlGVB(2, true);
            gvb2_open = true;  // Mark GVB as open
        }
        controlDrainValve("manual", "on");

        // Recheck for button presses periodically
        while (!readButtonState(0) && !readButtonState(1) && !readButtonState(2) && !readButtonState(3)) {
            delay(100); // Non-blocking delay
        }

        Serial.println("Button pressed during idle. Returning to main loop.");
        return;
    

    // Ensure GVB is properly closed if not needed
    if (currentHour < 6 || currentHour >= 17) {
        if (gvb2_open) {
            controlGVB(2, false); // Close GVB 2 outside the active hours
            gvb2_open = false;   // Update flag
        }
    }

}

When writing code for Arduino Cloud, take in account that you must to call

in short intervals otherwise the board will be restarted automatically by watchdog.

Side note - your function controlCirculation() is an outstanding example of how not to program. The function completely blocked the controller for more than 6 minutes. At this time, it does not respond to any signals, button presses or parameter changes.
It is not surprising that the Сloud thinks that the program is frozen and resets the controller.

thank you for your answer ill check it .
side note to your side not - while this function executing i want it to block any other actions and only after it done to go back to the rest of the code .
tnx again : ) .

even if it is, it is still a bad way to write programs.
Imagine that you need to abort this function due to an emergency condition. Now, the way you wrote it - you have to wait 6 minutes before you can click the STOP button.

ok im not an expert , if you think its so bad you can propose different approach or how you would write it .
tnx for the info about the short intervals , good day .

You can use flags to block other functions, eg:

if (fun1ended == true) { 
 fun2; 
 fun2ended = true; 
} 

or start different threads (rtos::Thread).
If you want to leave it all in one loop() you can use non blocking delay (with millis()).

1 Like

The author already has everything blocked, he needs to unblock it :slight_smile: