Xenon firmware corrupting during sleep

I’ve been trying to use a Xenon as a temperature sensor that will wake up every 10 minutes, take a temperature reading from a DS18B20, publish it, and go back to sleep.

It works flawlessly for 1-3 days and then the Xenon will just stop reporting a temperature. I can see that the Xenon does continue to wake up every 10 minutes because the LED starts blinking like it’s connecting to the cloud but it goes back to sleep without ever connecting. Once it’s failed, rebooting will not get the Xenon to work again. The only thing that seems to help is putting the Xenon into safe mode and then re-flashing the firmware. Then it works again for another 1-3 days. That’s why I think the firmware is being damaged somehow

I’ve tried with 2 different Xenons with the same result. I’m using an Argon as a gateway, both devices are on 1.5.2 device OS, but I’ve been struggling with this for months and kept my devices on the latest firmware.

Here is the code I have on the Xenon:

#include "DS18B20"

SYSTEM_MODE(SEMI_AUTOMATIC);
SYSTEM_THREAD(ENABLED);

const int      connectionFail    = 5000 ;
const int      MAXRETRY          = 120;
const int      sleepTime         = 600;

DS18B20  ds18b20(D2, true); //Sets Pin D2 for  Temp Sensor and 
                            // this is the only sensor on bus
char     szInfo[64];
double   celsius;
long     wakeTime;

void setup() {
  ds18b20.setResolution(12);
}

void loop() {
 Particle.connect();
 if (waitFor(Particle.connected, connectionFail)) {     // if connected to the cloud, process this cycle
    getTemp();                                          // take a measurement every interval, just within Mesh network
    
    if (!isnan(celsius))
    {
      sprintf(szInfo, "%2.1f", (float)((int)(millis()-wakeTime))/1000);
      
      auto result = Mesh.publish("WorkingTime", szInfo);
      if (result)
        System.sleep(D6, RISING, sleepTime);
      else
      {
          digitalWrite(D7, HIGH);
          delay (1000);
          digitalWrite(D7, LOW);
          System.sleep(D6, RISING, sleepTime);
      }
      wakeTime = millis();    
    }
    else
      delay(1000);
 }
 else
    System.sleep(D6, RISING, sleepTime);   // unable to connect to cloud, go to sleep and try again next time.
}

void getTemp(){
  float _temp;
  int   i = 0;

  do {
    _temp = ds18b20.getTemperature();
  } while (!ds18b20.crcCheck() && MAXRETRY > i++);

  if (i < MAXRETRY) {
    celsius = _temp;
  }
  else {
    celsius = NAN;
  }
  
  sprintf(szInfo, "%2.1f", celsius);
  Particle.publish("dsTmp", szInfo);
  Mesh.publish("dsTmp", szInfo);
}

Is there anything in my code that could be causing the device to stop working without reflashing? Or is there a bug in the deviceOS?

I don’t really need any mesh functionality for this project and can use all Argons since I can just do everything with cloud publish and subscribe, but the sensor nodes have to be battery powered, and given how much longer it takes an Argon to connect to the cloud compared to the Xenon, I won’t get enough battery life using Argons directly in my sensor nodes.

Thanks

@OracleJ, one thing I noticed is that you call Particle.connect() unconditionally at the start of loop(). Under the condition where isnan(celsius)) returns true, loop() will start over and Particle.connect() will be called again, even though the device is already connected. You may want to check Particle.connected() before calling Particle.connect().

Also, and this is mostly coding style, this piece of code:

      auto result = Mesh.publish("WorkingTime", szInfo);
      if (result)
        System.sleep(D6, RISING, sleepTime);
      else
      {
          digitalWrite(D7, HIGH);
          delay (1000);
          digitalWrite(D7, LOW);
          System.sleep(D6, RISING, sleepTime);
      }

could be simplified to:

      auto result = Mesh.publish("WorkingTime", szInfo);
      if (!result) {  // result = 0, Mesh.publish() succeeded
          digitalWrite(D7, HIGH);
          delay (1000);
          digitalWrite(D7, LOW);
      }
      System.sleep(D6, RISING, sleepTime);
1 Like

@peekay123 , so I replace the first line of my loop with this?

if (!Particle.connected()) Particle.connect();

Is it possible that was causing the problem I described? I can run another test if you think that change might help, but it usually works for a few days before failing.

Also, I wrote that if statement as a bit of debugging code a long time ago and haven’t thought about it. The Led does not ever blink on for a second, even though the Mesh.publish() succeeds (which I know because the Argon is simply republishing it to the cloud, and that is working).

@OracleJ, the only way to know for sure is to do the testing. However, a general rule is not to keep calling Particle.connect(), connected or not.

@peekay123 , all right, it’s running with those changes. I’ll post back in a few days to say if it’s still working.

Thank you for the help.

1 Like

On additional not about Particle.connect() - after calling it once it will take some time till Particle.connected() becomes true but you should not call Particle.connect() again during that periode. So you should also add some “timeout” (e.g. 60sec) before starting an other attempt.

2 Likes

@ScruffR , I never would have thought about that delay for Particle.connected().

But I can’t wait 60 seconds to try again, that will drain too much battery power. Right now, every 10 minutes the Xenon is awake for about 5 seconds average, and often takes a few tries through the loop to get a successful reading from the 18B20. If I’m up a couple of minutes on average, I’ll drop my battery life way over 90%.

I could put the Particle.connect() call at the end of setup, but then if it does fail to connect, I won’t get another try at it for that up cycle.

Or I could add a sleep for 1 minute to the end of the loop so I’ll effectively be doing your delay idea without wasting as much battery. But even then I will have a lot more wake cycles because there’s a lot of times I don’t get a reading the first try, and if the Mesh or WiFi is down, I will still be waking up every minute reducing my battery life 90% until the Mesh is available again.

I didn’t suggest you should wait 60 seconds for the connection but meant you shouldn’t call Particle.connect() again within that period as it would actually counteract an already ongoing connection attempt from a previous iteration of loop() and hence prolong your search for a connection.

In other words

  • you check whether you already have a connection or not
  • if not, check if you already initiated a Particle.connect() in a previous run no more than X seconds ago
  • if also not, call Particle.connect()
  • move on with your other tasks
  • loop round

Does this make more sense?

I understand what you meant, but since I do average multiple cycles through the loop, I’d end up waiting out the 60 seconds more often than not.

You’re right though, I should have been thinking to note the last time I attempted a connection and if not enough time has gone by, don’t run the connect again. I can try something like that if the current test run fails, but as it is, I give up and go back to sleep to save battery life in a lot less than 60 seconds if I don’t establish a connection, so maybe one attempt to connect in setup() is a better choice in this case.

The Xenon stopped working again yesterday. Rebooting it and leaving the battery disconnected for an hour didn’t help, but reflashing the firmware did again.

I made a few change to simplify the code and also make sure I’m only calling Particle.connect() once in setup().

Now my code is:

#include "DS18B20.h""

SYSTEM_MODE(SEMI_AUTOMATIC);
SYSTEM_THREAD(ENABLED);

const int      connectionFail    = 5000 ;
const int      MAXRETRY          = 120;
const int      sleepTime         = 600;

DS18B20  ds18b20(D2, true); //Sets Pin D2 for  Temp Sensor and 
                            // this is the only sensor on bus
char     szInfo[64];
double   celsius;
long     wakeTime;

void setup() {
  ds18b20.setResolution(12);
  Particle.connect();
}

void loop() {
 if (waitFor(Particle.connected, connectionFail)) {     // if connected to the cloud, process this cycle
    getTemp();                                          // take a measurement every interval, just within Mesh network
    
    if (!isnan(celsius))
        System.sleep(D6, RISING, sleepTime);
    else
        delay(1000);   // unable to get reading from temp sensor, try again in a second
 }
 else
    System.sleep(D6, RISING, sleepTime);   // unable to connect to cloud, go to sleep and try again next time.
}

void getTemp(){
  float _temp;
  int   i = 0;

  do {
    _temp = ds18b20.getTemperature();
  } while (!ds18b20.crcCheck() && MAXRETRY > i++);

  if (i < MAXRETRY) {
    celsius = _temp;
  }
  else {
    celsius = NAN;
  }
  
  sprintf(szInfo, "%2.1f", celsius);
  Particle.publish("dsTmp", szInfo);
  Mesh.publish("dsTmp", szInfo);
}