Managing Boron Cellular Connectivity to Save Power

All, I have been working through the best way to use the AB1805 real time clock / watchdog timer to improve my devices power consumption and reliability. This work is based on @rickkas7 library:

I am looking at the section on cellular connection and taking action in the case of a device not connecting in a reasonable amount of time - in this case 11 minutes. The library includes example code which tracks connection time in mSec and does a power off reset if connectivity is lost for over 2 hours. This code seems to be intended to monitor connection status in the main loop and detect and correct a loss of connectivity. This is perfect for devices that are intended to be connected as my utility powered sensors are.

My code takes a slightly different tack my solar powered sensors only connect every hour to report data and are otherwise disconnected. So, I have moved this code out of the main loop() and put it in a function. Also, sinnce cellular connections take a long time, I am ok with accuracy measured in seconds.

Here is the code I use to connect to Particle:

/**
 * @brief Connects to Particle or take steps to recover.
 * 
 * @details You can configure the amount of time to fail to connect to the cloud before doing 
 * a deep power off for 30 seconds. The default is 11 minutes, and you should not set it less 
 * than 10. You can set it higher if you want.
 * Code modified from the application watchdog app note: https://github.com/rickkas7/AB1805_RK
 * 
 * @return 1 if successful, 0 if uncessful or resets device if it has been over two hours
 */
bool connectToParticle() {
  unsigned int maxConnectionSeconds = 11 * 60;                             // Should not be less than 10 minutes
  unsigned long connectionStartTime = Time.now();                 // Start the clock
  char connectionStr[32];

  Cellular.on();                                                  // Needed until they fix this: https://github.com/particle-iot/device-os/issues/1631
  Particle.connect();

  for (unsigned int retry = 0; retry < maxConnectionSeconds && !waitFor(Particle.connected,1000); retry++) {   // wait a second and repeat
    if(sensorDetect) recordCount();                               // service the interrupt every second
    Particle.process();                                           // Keeps the device responsive as it is not traversing the main loop
    ab1805.setWDT(-1);                                            // Pet the watchdog as we are out of the main loop for a long time.
  }

  if (Particle.connected()) {
    sysStatus.connectedStatus = true;
    sysStatus.lastConnection = Time.now();
    snprintf(connectionStr, sizeof(connectionStr),"Connected in %lu secs",Time.now()-connectionStartTime);
    Log.info(connectionStr);
    if (sysStatus.verboseMode) publishQueue.publish("Cellular",connectionStr,PRIVATE);
    systemStatusWriteNeeded = true;
    return 1;                                                     // Were able to connect successfully
  }
  else {
    sysStatus.connectedStatus = false;
    Log.info("cloud connection unsuccessful");
    if (Time.now() - sysStatus.lastConnection > maxConnectionSeconds) {
        fram.put(FRAM::systemStatusAddr,sysStatus);
        Log.info("failed to connect to cloud, doing deep reset");
        delay(100);
        ab1805.deepPowerDown();
    }
    systemStatusWriteNeeded = true;
    return 0;                                                     // Failed to connect
  }
}

and here is how I disconnect:

bool disconnectFromParticle()                                     // Ensures we disconnect cleanly from Particle
{
  Particle.disconnect();
  waitFor(notConnected, 15000);                                   // make sure before turning off the cellular modem
  Cellular.off();
  sysStatus.connectedStatus = false;
  systemStatusWriteNeeded = true;
  delay(2000);                                                    // Bummer but only should happen once an hour
  return true;
}

bool notConnected() {                                             // Companion function for disconnectFromParticle
  return !Particle.connected();
}

I have a few questions and am always open to input on how to do this better:

  1. In the docs, thee is a comment that Cellular.on() and Cellular.off() are required but that this is a big that should be fixed. Yet, when you follow that link, the issue has been closed.

https://docs.particle.io/reference/device-os/firmware/boron/#connect--1

  1. Eleven minutes seems like a very long time to try to connect. In this code, I will be collecting connection time data which I plan to add to my webhook and send to Particle. I was wondering what types of Boron LTE connection times others are seeing.

  2. I am a bit worried about taking program flow out of the main loop for so long. I believe this is OK since I am monitoring the watchdog and the counter but, I wonder if there is a way to do this as a function and still keep transiting the main program loop?

Thank you,

Chip

1 Like