Publishing not following sleep interval

Hi so i am using a boron device, it will be installed in the field to run on a battery, so i am trying to make use of the system.sleep function. using a interval of 10minutes
my issue is the length of the sleep isnt constistant some time i get multiple publish events within a few seconds of each other, other times its 4mins other times work no problem.
Here is my published data to the cloud.
image
my code

SYSTEM_MODE(SEMI_AUTOMATIC);
SystemSleepConfiguration config; 
MCP342X myADC;

int duration = 10*60*1000-3000; //default duration 10 minutes - 2 sec fo delay function in loop 

//created json object size number of inputs plus number or nested arrays by inputs
const int capacity = 255;
char output[capacity];//output string of same length

//ADC outputs
double ap0, ap1;

//mV per bit
const float mV = 0.0000625;

void setup() {
  //Cellular Setup
  Cellular.on(); //enable Cellular chip 
  Cellular.setActiveSim(INTERNAL_SIM); // set to internal or external simcard
  Cellular.connect(); // connect to network
  //Fetch Values on holding registers
  Particle.variable("Input1", ap0);
  Particle.variable("Input2", ap1);
  //Publish function to change duration
  Particle.function("Duration Minutes",assignduration);
  //configure i2c Bus and Devices
  Wire.begin(); // connect to i2c bus   
  myADC.configure(  MCP342X_MODE_ONESHOT | //low power mode
                    MCP342X_SIZE_16BIT |     //16bit resolution
                    MCP342X_GAIN_1X          //minimum gain to allow for 2.048V range
                  );
  Particle.connect();
}

void adc() {
  static int16_t adc0;
  static int16_t adc1; 

  //update variables
  // count out of 2.048V
  myADC.startConversion(MCP342X_CHANNEL_1);
  myADC.getResult(&adc0);
  myADC.startConversion(MCP342X_CHANNEL_2);
  myADC.getResult(&adc1);

  //convert viarbles into % of 4-20 ma range
  ap0 = ((((adc0 *mV)-.4)/1.6)*100);
  ap1 = ((((adc1 *mV)-.4)/1.6)*100);
}

void dataJson() {
  //create Json Data
  StaticJsonDocument<capacity> data;
  //Assign data in json characters
  data["input1"] = ap0;
  data["input2"] = ap1;
  serializeJson(data, output);
}

int assignduration(String command) {
  int temp1 = command.toInt();
  if (temp1 < 1){
    return 0;
  }
  duration = temp1*1000*60-3000;  //convert to milliseconds
  return duration;
}

void loop(void) {
  //update the ADC and generate JSON
  adc();
  dataJson();
  //publish data 
  Particle.publish("data", output,60, PRIVATE);
  //Particle.publishVitals();
  // needed 3 sec delay else sleep mode doesnt activate
  delay(3000);
  config.mode(SystemSleepMode::STOP)
        .network(NETWORK_INTERFACE_CELLULAR)
        .duration(duration);
  System.sleep(config);   
}

Can you check the wake reason after waking up?
Is your device even during your tests running on battery only or do you have other power sources connected too?

Instead of using delay(3000) you could also make use of SystemSleepFlag::WAIT_CLOUD to potentially save energy by going to sleep as soon the publish has been ACKed.

BTW, Cellular.setActiveSim() is a sticky setting so you’d not need to do that on each setup() and INTERNAL_SIM is the default anyhow.

And as a side note: Instead of having a fixed sleep duration I prefer to calculate the time needed in order to wake up at “cardinal times” (e.g. every full 10 minutes hh:00, hh:10, hh:20, …). That also makes it easier to catch an expected wake cycle as it won’t continually move through the day.

Im not sure how to check the reason after waking up.
I was using USB cable for power. seemed to be getting issues, but once i connected a battery wroked alot better.
i seem to be getting consistant sleep durations now, but upon commenting out delay(3000) and using .flag(systemsleepflag::wait_cloud)
im now geting upto a dozen publishes everytime it wakes up.it got so bad i had to impliment a 1 second wait after each publish.
see image

bool meterParticlePublish(void) 
{ 
  // Initialize and store value here
  static unsigned long lastPublish=0; 
  // Particle rate limits at 1 publish per second
  if(millis() - lastPublish >= 1000) {                                             
    lastPublish = millis();
    return 1;
  }
  else return 0;
}

void loop(void) 
{
    //update the ADC and generate JSON
  adc();
  dataJson();
  //publish data 
  Particle.publish("data", output,60, PRIVATE);
  //Particle.publishVitals();
  waitUntil(meterParticlePublish);
  //delay(3000);
  SystemSleepConfiguration config; 
  //SystemSleepResult result =System.sleepResult();
  config.mode(SystemSleepMode::STOP)
      .network(NETWORK_INTERFACE_CELLULAR)
      .flag(SystemSleepFlag::WAIT_CLOUD)
      .duration(duration); 
  SystemSleepResult result = System.sleep(config);   
}

This would suggest that SystemSleepFlag::WAIT_CLOUD does not work as expected. @rickkas7, can you help out here?

This might help :wink:
https://docs.particle.io/reference/device-os/firmware/boron/#wakeupreason-

Yeah I've seen that, in the examples.

if (result.wakeupReason() == SystemSleepWakeupReason::BY_GPIO) {
// Waken by pin
pin_t whichPin = result.wakeupPin();
}

Does this mean i essentially have to write a case statement and checking each possible wake up result

  • SystemSleepWakeupReason::UNKNOWN
  • SystemSleepWakeupReason::BY_GPIO (pin wakeup)
  • SystemSleepWakeupReason::BY_RTC (time wakeup)

That depends on whether you want your device to act differently according to the reason why it was woken up. If you don't care you won't need to.

But back in your original post you seemed to indicate your puzzlement as of why the device may be waking prematurely and hence my suggestion to investigate the wake reason :wink:

so I adding in the case statement like so. also i switched to ultra low power mode instead of stop

     SystemSleepConfiguration config; 
      config.mode(SystemSleepMode::ULTRA_LOW_POWER)
            .network(NETWORK_INTERFACE_CELLULAR)
            .flag(SystemSleepFlag::WAIT_CLOUD)
            .duration(interval);
      SystemSleepResult result = System.sleep(config);
      
      switch(result.wakeupReason()){
        case SystemSleepWakeupReason::BY_ADC:{
        Particle.publish("debug","woke by GPIO", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_BLE:{
        Particle.publish("debug","woke by BLE", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_CAN:{
        Particle.publish("debug","woke by CAN", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_DAC:{
        Particle.publish("debug","woke by DAC", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_GPIO:{
        Particle.publish("debug","woke by GPIO", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_I2C:{
        Particle.publish("debug","woke by I2C", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_LPCOMP:{
        Particle.publish("debug","woke by LPCOMP", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_NETWORK:{
        Particle.publish("debug","woke by network", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_NFC:{
        Particle.publish("debug","woke by NFC", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_RTC:{
        Particle.publish("debug","woke by RTC", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_SPI:{
        Particle.publish("debug","woke by SPI", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_TIMER:{
        Particle.publish("debug","woke by timer", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_USART:{
        Particle.publish("debug","woke by usart", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::BY_USB:{
        Particle.publish("debug","woke by usb", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }
        case SystemSleepWakeupReason::UNKNOWN:{
        Particle.publish("debug","woke by unknown", PRIVATE);
        waitUntil(meterParticlePublish);
        break;
        }

the device started up transmitted then went to sleep for 10 mins like i asked it to it then return woke by RTC as expected.
Then it kept spamming out new result at variasing intervals between 1min and 10 seconds
returning woke by network.
Sorry i have a picture but it wont upload

There is another thread dealing with this "issue" and a potential solution

Thanks using network(NETWORK_INTERFACE_CELLULAR, SystemSleepNetworkFlag::INACTIVE_STANDBY fixed the issue now reports every 10 minutes like i asked.
a few cavoites with it though particle function and particle variables dont work most of the time cause the network is on standby.
get a spark/Status offline
then spark/Status online
at the start of every interval.

context on how i call the network flag

      SystemSleepConfiguration config; 
      config.mode(SystemSleepMode::ULTRA_LOW_POWER)
            .network(NETWORK_INTERFACE_CELLULAR, SystemSleepNetworkFlag::INACTIVE_STANDBY)
            .flag(SystemSleepFlag::WAIT_CLOUD)
            .duration(interval);
      SystemSleepResult result = System.sleep(config);  

That's true but no way around it. You either can have your device react to remote requests and wake up to service them or stay asleep and ignore them.

You cannot have the cake and eat it too :wink:

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.