ArduinoCloud.update interrupt workaround?

Hi!

I use Arduino MKR GSM 1400 and the SIM card (along with some Milone eTape) to turn on and off pumps when their tanks get to a certain level and report that value to a Google sheet for my records. A few weeks ago the Arduino would lose connection to the cloud and when it did the code stopped working entirely, causing the code to interrupt, and it flooded my lab overnight. This happened several times over the course of a week. It was irritating and somewhat dangerous. :frowning:

Since removing the ArduinoCloud.update(); line everything has worked perfectly and my lab has not flooded. However, this defeats the purpose of subscribing to the cloud service, and I want to be able to view the values on the sheet again so we’re trying to troubleshoot.

I am assuming because of this that there is some sort of interrupt in ArduinoCloud.update(); that happens if connection is lost. As such, I’m trying to put in an if statement to only call ArduinoCloud.update(); if the connection is right, or something like this:

if ( ArduinoIoTPreferredConnection.getStatus() == (NetworkConnectionState::CONNECTED)) {
  ArduinoCloud.update();
  Serial.print("Update Success");
  }

However, with this, ArduinoCloud.update(); somehow never gets called. If I remove the if statement and just leave ArduinoCloud.update(); there alone, the cloud updates and my Google sheet gives me the value I entered, but then we’re back where we were, not knowing if the lab will flood if connection is lost.

Here is all my code:

#include "thingProperties.h"

#define LEVEL0_PIN A1
#define LEVEL1_PIN A2

// declare floats to hold measured voltages and calculated resistances
float r0_ref = 0;
float r0_sense = 0;
float v0_ref = 0;
float v0_sense = 0;
float r1_ref = 0;
float r1_sense = 0;
float v1_ref = 0;
float v1_sense = 0;

// declare arrays to hold values of sensors
int numSamples = 10;
int arrV0_ref[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int arrV0_sense[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int arrV1_sense[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

// declare avg values and related vars
float avgRef0_numerator = 0;
float avgSense0_numerator = 0;
float avgRef0 = 0;
float avgSense0 = 0;
float avgSense1_numerator = 0;
float avgSense1 = 0;
float supplyVoltage = 3.3;
float adcToVoltage = supplyVoltage / 1023;

//declare constants and variables for converting voltage to level
int refR1 = 560;
int senseR1 = 560;
float refRCalc = 0;
float senseR0Calc = 0;
float senseR1Calc = 0;
float totalLength = 12.4;   //length of tape in inches
float currentResPerInch = 0;
float level_0 = 0;
float level_1 = 0;
float R_min = 400;
float correction0 = 0;     //value is consistently an amount off
float correction1 = 1.5;    //value is consistently an amount off

//declare variables related to controlling relay
float maxLevel0 = 8;        //value on level_0 that will trigger relay to turn off pumps
float minLevel0 = 5;        //value on level_0 that will trigger relay to turn on pumps

float maxLevel1 = 6;        //value on level_1 that will trigger relay to turn off pumps
float minLevel1 = 3;        //value on level_1 that will trigger relay to turn on pumps


void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1000);

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);

  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
  */
  setDebugMessageLevel(3);
  ArduinoCloud.printDebugInfo();

  //define pins
  pinMode(A0, INPUT);
  pinMode(LEVEL0_PIN, INPUT);
  pinMode(LEVEL1_PIN, INPUT);
  pinMode(5, OUTPUT);
  digitalWrite(5, LOW);
  pinMode(7, OUTPUT);
  digitalWrite(7, LOW);

}

void loop() {

 if ( ArduinoIoTPreferredConnection.getStatus() == (NetworkConnectionState::CONNECTED)) {
  ArduinoCloud.update();
  Serial.print("Update Success");
  }


  avgRef0_numerator = 0;
  avgSense0_numerator = 0;
  avgSense1_numerator = 0;
  avgRef0 = 0;
  avgSense0 = 0;
  avgSense1 = 0;

  // read the analog pins and print them into arrays
  for (int idx = 0; idx < 10; idx++) {

    //take measurements
    //arrV0_ref[idx] = analogRead(refPin);
    //arrV0_sense[idx] = analogRead(sensePin);
    arrV0_ref[idx] = analogRead(A0);
    arrV0_sense[idx] = analogRead(LEVEL0_PIN);
    arrV1_sense[idx] = analogRead(LEVEL1_PIN);

    //add values to running averages
    avgRef0_numerator = avgRef0_numerator + arrV0_ref[idx];
    avgSense0_numerator = avgSense0_numerator + arrV0_sense[idx];
    avgSense1_numerator = avgSense1_numerator + arrV1_sense[idx];

    delay(100);  //100 ms delay means data should be output appx every second

  } //for sensing arrays

  //calculate averages
  avgRef0 = avgRef0_numerator / numSamples;
  avgSense0 = avgSense0_numerator / numSamples;
  avgSense1 = avgSense1_numerator / numSamples;

  //convert adc count value to voltage
  avgRef0 = adcToVoltage * avgRef0;
  avgSense0 = adcToVoltage * avgSense0;
  avgSense1 = adcToVoltage * avgSense1;

  //convert voltages to resistance
  refRCalc = avgRef0 * refR1 / (supplyVoltage - avgRef0);
  senseR0Calc = avgSense0 * senseR1 / (supplyVoltage - avgSense0);
  senseR1Calc = avgSense1 * senseR1 / (supplyVoltage - avgSense1);

  //get scale
  currentResPerInch = (refRCalc - R_min) / totalLength;

  //convert resistances to level and correct for small but consistent error
  level_0 = totalLength - ((senseR0Calc - R_min) / currentResPerInch);
  level_0 = level_0 + correction0;
  level_1 = totalLength - ((senseR1Calc - R_min) / currentResPerInch);
  level_1 = level_1 + correction1;

  if (level_0 > maxLevel0) {
    digitalWrite(5, HIGH);
  } //using the normally on option of the relay, so writing a high will switch it off
  if (level_1 > maxLevel1) {
    digitalWrite(7, HIGH);

  } //if level > maxLevel turn off pump


  if (level_0 < minLevel0) {
    digitalWrite(5, LOW);
  }
  if (level_1 < minLevel1) {
    digitalWrite(7, LOW); //using the normally on option of the relay, so writing a low will switch it on

  } //if level < minLevel turn on pump

  //output to arduino Serial Monitor for review
  
  Serial.print("Ref V= ");
  Serial.print(refRCalc, 1);
  Serial.println("; ");

  Serial.print("V0= ");
  Serial.print(senseR0Calc, 1);
  Serial.print("; ");
  Serial.print("V1= ");
  Serial.print(senseR1Calc, 1);
  Serial.println(';');
  Serial.print("Level 0:");
  Serial.print(level_0, 1);
  Serial.println(';');
  Serial.print("Level 1:");
  Serial.print(level_1, 1);
  Serial.println(';');
  Serial.print(currentResPerInch, 1);
  Serial.println(' ');
  
  
  reportedlevel0 = level_0;
  reportedlevel1 = level_1;

}

Thank you for your help, if you take the time to look. I’m at my wits’ end on this… I’m a beginner user (and a water chemist, not a programmer by training!!) so I’m doing my best! Thank you! ★

Hi stormwater,

I was struggling with the same issue. Anytime my MKR GSM 1400 would loose connection, the code would stop completely and I would have to reset it. I originally thought that it was my GPS logic that was stopping the loop when it lost GPS signal but it was ArduinoCloud.update() anytime the cell dropped out.

I added the below callbacks to call a function anytime the GSMConnectionHandler connects or disconnects:

void setup() {

ArduinoIoTPreferredConnection.addConnectCallback(onNetworkConnect);

ArduinoIoTPreferredConnection.addDisconnectCallback(onNetworkDisconnect);

}

I setup two functions onNetworkConnect & onNetworkDisconnect. Basically i attempt to reconnect and if not successful i reboot the Arduino.

I cannot figure out how to reconnect after there has been a disconnect to save my life. I have been unsuccessful using ArduinoIoTPreferredConnection.update() to reconnect. I can simulate network disconnects by removing the antenna. every time i disconnected, i would get a "SIM card error" and it would never recover.

It seems for now the only way i can recover from an event like this is to do a reboot. That is probably not what you want to do considering you are kicking on and off pumps... but you might have more luck than me reconnecting after adding in the connection callbacks... Let me know what you find out.

void onNetworkConnect(void *_arg) {
Serial.println(">>>> CONNECTED to network");
netstate = true;
digitalWrite(LED_BUILTIN, LOW);
}

void onNetworkDisconnect(void *_arg) {
Serial.println(">>>> DISCONNECTED from network");
netstate = false;
digitalWrite(LED_BUILTIN, HIGH);

delay(30000);
if(netstate == false){
Serial.println("Attempting first GPRS reconnect");
ArduinoIoTPreferredConnection.update();
}
delay(30000);
if(netstate == false){
Serial.println("Attempting second GPRS reconnect");
ArduinoIoTPreferredConnection.update();
}
delay(120000);
if(netstate == false){
reboot();
}
}

void reboot() {
Serial.println("Rebooting...");
NVIC_SystemReset();
}