Function in .cpp crashes device after 20 seconds (watchdog?)

Hi, I have a function in a .cpp file that runs for a while. I've noticed that after about 20 seconds that it runs the device crushes and restarts - could this be related to the watchdog? Is it possible to disable it when running this function?

Thanks

Do you think it might help if you posted your full sketch so that your question could be seen in context ?

My sketch is very long, this is the relevant function:

String SF1MAIN_FillKOH() {
    Serial.println(">> SF1: Starting KOH Fill Sequence...");
  //Defintions
   // unsigned long SF1_Elapsed_Time = millis();  // Record the start time
    bool UF_Drain_open_triggered = false;      // Track UF drain sequence
    unsigned long MainElapsedTime = 0;  
  
  //Pre-requisite conditions for starting:
    if (readDigitalInput(LVL_P1_LOW) || readDigitalInput(LVL_P1_HIGH)){
      return "SF1 Failed - Panel Level Sensor is HIGH";
    }
    
  //Set-Up
    ValveControl(PIN_OUTLET, HIGH);        //Open Panel Outlet Valve
    setPumpVoltage(0);                     //Set Pump voltage to 0V
    digitalWrite(PIN_PMPC1, LOW);          //Make sure pump is off
    SetValveGroupClosed(PANEL_A1_VALVES);  //Close (HIGH) all Panel A1 Valves
    SetValveGroupClosed(PANEL_A2_VALVES);  //Close (HIGH) all Panel A2 Valves
    SetValveGroupClosed(PANEL_B1_VALVES);  //Close (HIGH) all Panel B1 Valves
    SetValveGroupClosed(PANEL_B2_VALVES);  //Close (HIGH) all Panel B2 Valves
    delay(1000);
    ValveControl(GVA11, HIGH);             //Open (HIGH) GVA11 to feed outlet to UF
    ValveControl(GVA12, HIGH);             //Open (HIGH) GVA12 to feed inlet from KOH tank
    ValveControl(GVB1, LOW);               //Close (LOW) GVB1 to make sure no N is flowing into panel
    ValveControl(GVB2, HIGH);              //Open (HIGH) GVB2 for N flow into KOH tank
    Serial.println(">> SF1: Set-Up Complete");
    delay(10000);
    
  //Start Filling UF first, open UF drains after 5 seconds for 5 seconds then close them and continue for 1 minute before switch to outlet manifold filling
    SF1MAIN_Elapsed_Time = millis();            // Record the start time
    setPumpVoltage(SF1_FILL_VOLTAGE);       // Set Pump voltage 
    digitalWrite(PIN_PMPC1, HIGH);          // Turn pump ON
    Serial.println(SF1MAIN_Elapsed_Time);
  
    // Main fill loop
    MainElapsedTime = (millis() - SF1MAIN_Elapsed_Time);
    while (MainElapsedTime < SF1_UF_FILL_TIME_MS) {
        bool lvlLow  = readDigitalInput(LVL_P1_LOW);
        bool lvlHigh = readDigitalInput(LVL_P1_HIGH);
        // UF drain trigger (only once)
        if (!lvlLow && !lvlHigh && !UF_Drain_open_triggered) {
            Serial.println(">> SF1: UF Fill wDrain");
            delay(5000);
            digitalWrite(PIN_UF_DRAIN, HIGH);       // Open drain
            delay(SF1_UF_DRAIN_TIME_MS);
            digitalWrite(PIN_UF_DRAIN, LOW);        // Close drain
            UF_Drain_open_triggered = true;
            Serial.println(">> SF1: Finished UF Fill wDrain");
        }

        // Exit if either level sensor triggers
        if (lvlLow || lvlHigh) {
            break;
        }
        
ArduinoCloud.update();
  OptaController.update();

      MainElapsedTime = (millis() - SF1MAIN_Elapsed_Time);;
        Serial.println(MainElapsedTime);
        delay(1000);  // avoid tight polling
    }

    Serial.println("Unsigned Long");
    unsigned long fillDuration = millis() - SF1MAIN_Elapsed_Time;
ArduinoCloud.update();
  OptaController.update();
    // Stop pump and close GVA11
    Serial.println(">> SF1: UF Fill wDrain Finished, Pump Off");
    setPumpVoltage(0);
    ValveControl(GVA11, false);

    // Toggle GVA12 (close 3s, reopen)
    ValveControl(GVA12, false);
    delay(3000);
    ValveControl(GVA12, true);

    // Resume pump and open all panels
    setPumpVoltage(3000);
    SetValveGroupOpen(PANEL_A1_VALVES);
    SetValveGroupOpen(PANEL_A2_VALVES);
    SetValveGroupOpen(PANEL_B1_VALVES);
    SetValveGroupOpen(PANEL_B2_VALVES);

    // Wait for final level confirmation
    while (!readDigitalInput(LVL_P1_LOW) && !readDigitalInput(LVL_P1_HIGH)) {
      ArduinoCloud.update();
  OptaController.update();  
      delay(100);
    }

    setPumpVoltage(0);  // Final pump off
    ValveControl(GVA12, false);
    

    // Format fill time as mm:ss
    unsigned long totalSeconds = fillDuration / 1000;
    unsigned int minutes = totalSeconds / 60;
    unsigned int seconds = totalSeconds % 60;

    char timeStr[16];
    snprintf(timeStr, sizeof(timeStr), "%02u:%02u", minutes, seconds);

    Serial.print(">> KOH UF Fill Completed in ");
    Serial.println(timeStr);

    return ("KOH UF Fill Completed in " + String(timeStr));
}

I can say that when I moved it to my main.ino and added ArduinoCloud.update();
OptaController.update(); it stopped crushing. I would rather keep the function in a seperate .cpp file but then I cannot get the ArduinoCloud.update() to work

We tend to recommend not blocking the main loop for too long.

you might benefit from studying state machines. Here is a small introduction to the topic: Yet another Finite State Machine introduction

Hi @dotan_qd-sol.

By default, the Arduino Cloud IoT Thing sketch program will automatically reset the Opta if 33 seconds elapse without the ArduinoCloud.update function being called. So if your sketch program doesn't call ArduinoCloud.update, or if it has code that causes long delays between calls to that function, then it is expected that the Opta will reset.

It is possible to disable the "watchdog" feature:

https://docs.arduino.cc/arduino-cloud/cloud-interface/sketches/#watchdog-timer-wdt

The WDT can however be disabled inside of the setup() function, by adding the false parameter:

ArduinoCloud.begin(ArduinoIoTPreferredConnection, false).

However, it is essential to design your Thing sketch code so that ArduinoCloud.update() is called frequently. The reason is that this function is what handles the syncing of your Arduino Cloud Variables between the device and the Arduino Cloud servers and your dashboards.

If the sketch code causes long intervals to occur during which ArduinoCloud.update() is not called, this will result in problems such as lags in response of the board to actions taken in the Arduino Cloud dashboard and of response of the dashboard to changes made to the Cloud Variable values by the Thing sketch program.

If you redesign the function so that it is non-blocking, as recommended by @J-M-L, then you will be able to do that.

One simple thing to try: add a function in the .ino that does the multi-second delays, while also calling update

void delayWithUpdate(unsigned seconds) {
  while (seconds--) {
    ArduinoCloud.update();
    delay(500);
    OptaController.update();
    delay(500);
  }
}

Then near the top of each separate .cpp, declare that as a function provided by another module

extern void delayWithUpdate(unsigned seconds);

which can then be called whenever

   //...
   delayWithUpdate(5);
   //...
   delayWithUpdate(10);

The linker will tie everything together.

Thank you, this works great