Xenon Mesh Connection Only Issues


#1

I’ve got some simple code that I’m using for a remote temp sensor; the gist of the code is that it reads the temp and battery, mesh publishes it and then goes to sleep (I have it set for 60 seconds right now for testing, will be more like 15-60 minutes in the final version). I got it working just fine when having it fully connect to the Particle cloud, however I noticed that it tends to take a while (5-10 seconds) and obviously this all requires that my Argon has internet connectivity. While not strictly necessary, it would be nice to just have it mesh connect since it doesn’t need internet (and I’d like to know how, for other projects where internet might be more intermittent).

Been trying to use Semi-Automatic mode to have it only connect to the mesh network when it’s running on battery but still connect to the cloud when it’s powered via USB. I definitely cuts down on the time that’s it’s powered on each cycle, but I’ve been getting weird behavior.

For one it seems to wake up at somewhat random times (it tended to alternate between the coded 60 seconds and about 30 seconds). And then at some point it’s always gotten stuck flashing green until I reset it (or it kills the battery). It’s taken anywhere from ~15 minutes to over a day, but it’s always gotten stuck flashing green.

Kind of at a loss… I’m guessing there’s something simple/obvious I’m missing? Code below:

#include "Particle.h"
#include <math.h>

#define Power_Pin A1
#define Temp_Pin A0

int Temp_Reading;
float TempC;
float TempF;
int Temp;
String Temp_String;
double Battery_V;
int Battery_Percent;
String Battery_String;
String Status = "Startup";
int USB_Status;
int CHG_Status;
bool Startup_Complete;

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

void setup() {
    
    pinMode(Power_Pin, OUTPUT);
    pinMode(Temp_Pin, INPUT);
    pinMode(PWR, INPUT);
	pinMode(CHG, INPUT);
	
	//Particle.variable("Status", Status);
	//Particle.variable("Battery_Percent", Battery_Percent);
	//Particle.variable("Temp", Temp);
	
	if (Startup_Complete != true) {
	    Particle.variable("Status", Status);
        Particle.variable("Battery_Percent", Battery_Percent);
        Particle.variable("Temp", Temp);
        Particle.connect();
        waitUntil(Particle.connected); 
        Startup_Complete = true;
	}
    else {
        Mesh.connect();
    }
    
	Time.zone(-5);
}

void loop() {
    
    digitalWrite(Power_Pin, HIGH);
    delay(250); //Delay to give the temp sensor time to 'warm-up'. Occassionally worked with 100, worked with 500 and 300
    Temp_Reading = analogRead(Temp_Pin);
    digitalWrite(Power_Pin, LOW);
    TempC=((100*((float)Temp_Reading/4095)*3.3)-50);
    TempF=((TempC*9/5)+32);
    Temp=TempF; //Select TempF or TempC
    Temp_String = String(Temp);
    
    Battery_V = analogRead(BATT) * 0.0011224;
    USB_Status = digitalRead(PWR); // PWR: 0=no USB power, 1=USB powered
    CHG_Status = digitalRead(CHG); // CHG: 0=charging, 1=not charging
    
    if (USB_Status == 0) {
        Status = "Running on Battery";
        Battery_Percent = 157.58*Battery_V - 525.82;
        Battery_String = String(Battery_Percent);
        
        waitUntil(Mesh.ready);
        Mesh.publish("Fireplace_Temp", Temp_String);
        Mesh.publish("Fireplace_Battery", Battery_String);
        System.sleep(PWR,CHANGE,60); //Sleeps for 60 seconds. {} can be used if no wakeup pins are wanted
    }
    else if (USB_Status == 1 and CHG_Status == 0) {
        Status = "Battery Charging";
        Battery_Percent = 127.56*pow(Battery_V,2) - 846.99*Battery_V + 1405.8;
        Battery_String = String(Battery_Percent);
    }
    else if (USB_Status == 1 and CHG_Status == 1) {
        Status = "Battery Charged/Running on USB Power";
        Battery_Percent = 100;
        Battery_String = String(Battery_Percent);
    }
    
    if (USB_Status == 1 and Particle.connected() == false) {
        //Not sure if the variables need to be re-defined since they were during the first startup
        //Particle.variable("Status", Status);
        //Particle.variable("Battery_Percent", Battery_Percent);
        //Particle.variable("Temp", Temp);
        Particle.connect();
        //waitUntil(Particle.connected); //Not sure if this is needed either, but it seems like it would be best?
    }
}

#2

How would your Startup_Complete != true check in setup() ever be able to enter the else branch?
It’s always initialised false and nothing in setup() would turn it true ever.

If this only was a “compile” switch making it const bool and explicitly initialising it (and a respective comment) or real compiler directives (#define, #if ... #else ... #endif) would make things a bit clearer :wink:

However, since your code initially activates the cloud connection in setup() any subsequent wake from Stop Mode Sleep will reestablish the connection status that was active at the time of going to sleep.
If you don’t want a cloud connection to be reestablished after wake, you need to disconnect (with enough lead time) from the cloud before going to sleep.


#3

My understanding of the sleep function I’m calling is that it keeps variable values and reruns the code from setup. My intent for that if/else statement in setup is to register the particle variables and force a cloud connection on the first run of the code, but only connect to the mesh network on subsequent wakeups. Am I misunderstanding how the sleep function works?

I wasn’t aware that it resumes the connection status at sleep when it wakes up versus essentially starting from scratch and only running the code. Would you suggest I basically just add a disconnect followed by a delay before sleeping?

Thanks for the help!


#4

Nope, that’s not how this kind of sleep mode (Stop Mode) works.
As the name suggests, it just stops execution there and then and continues from there when it wakes up with all variables as they were prior to sleep.

On the other hand there is Deep Sleep (aka Standby Sleep).
That would cause the device to reset on wake and start (almost) as if you hit the RESET button but all variables that are not explicitly declared retained would be reset too.
And on mesh devices this sleep mode also has no internal option for a timed wake.


#5

Thanks for the clarification!

I updated my code with that in mind and still got similar behavior: when it started it’s sleep cycles, it only woke/published/slept a few times before getting stuck blinking green (Reset it once and got the same thing, although it ran a little longer). Additionally, for a few of the times when it woke and went back to sleep it didn’t seem to publish.

#include "Particle.h"
#include <math.h>

#define Power_Pin A1
#define Temp_Pin A0

int Temp_Reading;
float TempC;
float TempF;
int Temp;
String Temp_String;
double Battery_V;
int Battery_Percent;
String Battery_String;
String Status = "Startup";
int USB_Status;
int CHG_Status;
//bool Startup_Complete;

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

void setup() {
    
    pinMode(Power_Pin, OUTPUT);
    pinMode(Temp_Pin, INPUT);
    pinMode(PWR, INPUT);
	pinMode(CHG, INPUT);
	
	Particle.variable("Status", Status);
	Particle.variable("Battery_Percent", Battery_Percent);
	Particle.variable("Temp", Temp);
	Particle.connect();
	waitUntil(Particle.connected); //Not strictly necessary, but makes sure the particle variables get registered if battery-powered
     
	/*
	if (Startup_Complete != true) {
	    Particle.variable("Status", Status);
        Particle.variable("Battery_Percent", Battery_Percent);
        Particle.variable("Temp", Temp);
        Particle.connect();
        waitUntil(Particle.connected); 
        Startup_Complete = true;
	}
    else {
        Mesh.connect();
    }
    */
    
	Time.zone(-5);
}

void loop() {
    
    digitalWrite(Power_Pin, HIGH);
    delay(250); //Delay to give the temp sensor time to 'warm-up'. Occassionally worked with 100, worked with 500 and 300
    Temp_Reading = analogRead(Temp_Pin);
    digitalWrite(Power_Pin, LOW);
    TempC=((100*((float)Temp_Reading/4095)*3.3)-50);
    TempF=((TempC*9/5)+32);
    Temp=TempF; //Select TempF or TempC
    Temp_String = String(Temp);
    
    Battery_V = analogRead(BATT) * 0.0011224;
    USB_Status = digitalRead(PWR); // PWR: 0=no USB power, 1=USB powered
    CHG_Status = digitalRead(CHG); // CHG: 0=charging, 1=not charging
    
    if (USB_Status == 1 and Particle.connected() == false) {
        Particle.connect();
    }
    else if (USB_Status == 0 and Particle.connected() == true) {
        Particle.disconnect();
    }
    
    if (Mesh.ready() == false) {
        Mesh.connect();
    }
    
    if (USB_Status == 0) {
        Status = "Running on Battery";
        Battery_Percent = 157.58*Battery_V - 525.82;
        Battery_String = String(Battery_Percent);
        
        waitUntil(Mesh.ready);
        Mesh.publish("Fireplace_Temp", Temp_String);
        Mesh.publish("Fireplace_Battery", Battery_String);
        System.sleep(PWR,CHANGE,60); //Sleeps for 60 seconds. {} can be used if no wakeup pins are wanted
    }
    else if (USB_Status == 1 and CHG_Status == 0) {
        Status = "Battery Charging";
        Battery_Percent = 127.56*pow(Battery_V,2) - 846.99*Battery_V + 1405.8;
        Battery_String = String(Battery_Percent);
    }
    else if (USB_Status == 1 and CHG_Status == 1) {
        Status = "Battery Charged/Running on USB Power";
        Battery_Percent = 100;
        Battery_String = String(Battery_Percent);
    }
}

#6

This order seems wrong.
On a Xenon without Mesh.ready() Particle.connected() can never be true and you may want to add a waitUntil(Mesh.ready) after connecting.

Another thing we keep recommending is to stay away from String wherever possible and use C strings (aka char array) to reduce the risk of heap fragmentation.


#7

Changed the order of the if statements and added a waitUntil as you recommended but still much the same behavior (although as of now it hasn’t gotten stuck blinking green yet). I’ll leave it running to see if this happens again though (it historically has been able to run for over a day before happening).

The majority of the time I observe it to sleep for 60 seconds but when it wakes it only briefly blinks green and then goes back to sleep without publishing data. A minority of the time (seemingly random) it wakes up after only ~30 seconds but stays on longer, the LED blinks as it would normally, and it publishes data successfully.


#8

It ultimately got stuck blinking green again within a few hours of flashing the code. Any other ideas? Does anyone have some similarish code that works fine that I could try? Seems like using a Xenon to make periodic readings, mesh publish the data and then go back to sleep would be a common use-case.