Non-blocking Clock-Aware Functionality Inside Main Loop

I have a boron pulling serial data from a solar charge controller and publishing those values using Particle.publish(). I want to replicate Campbell Scientific datalogger behavior with the boron. With CSci, the main loop scans with the system clock and tables are written/aggregated with the clock as well. For example, scans set to every 3 seconds and tables written every 1 minute would result in values taken at 12:00:03, 12:00:06, 12:00:09, etc. with the table written at 12:01:00, 12:02:00 etc.

Here’s a basic working example of how I’m implementing this currently:

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

const unsigned long scanInterval = 10000; // 10 seconds
const unsigned long publishInterval = 3000000; // 5 minutes
long int timestamp;
unsigned long previous_scan_millis = millis();
uint8_t pollmessage[6] = {0xAA, 0x55, 0x00, 0x00, 0x00, 0x55};
byte rawdata[20];
Statistic Stats[1];

SYSTEM_THREAD(ENABLED);

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {
  
  if (millis() - previous_scan_millis >= scanInterval && (Time.now() % (scanInterval/1000) == 0)) {
        timestamp = Time.now();
        Serial1.write(pollmessage, sizeof(pollmessage));
        //300ms delay as device responds
        Serial1.readBytes((char *)rawdata, 20);
        Stats[0].add((rawdata[3] << 8 | rawdata[2])/10.0);
        previous_scan_millis = millis();
    //Publish
    if (timestamp % (publishInterval/1000) == 0) {
            Particle.publish("battvolts",String::format("%.2f",Stats[0].average()));
            Stats[0].clear();
        }
  }
}

This generally works okay, but I have a few missed publishes per day. I’m not 100% sure if it’s because of my time logic (please let me know if there’s a better way to do this) or because of a blocking issue with Particle.publish() and cell connectivity. What are some good tips for doing this kind of behavior and avoiding skipped Publishes?

Thanks for the help!

Particle.publish can block for 20 seconds, sometimes up to 10 minutes.

One solution is moving publishing to a separate thread, such as by using PublishQueueAsyncRK

If you do not do this, you should always check Particle.connected() before publishing, as that almost always leads to a lengthy blocking call if not connected to the cloud yet.

The other option is to move your serial code to a separate thread. This is a good option if you plan to add other things to your loop.

You can also do both.

Ok, I’ll implement PublishQueueAsyncRK. No real reason not to. I’m not worried about serial too much. On all my testing that 300ms response time doesn’t change.

I think I may also have an issue with my main conditional in the loop. The scanInterval parameter is in both comparisons and depending on how long that Publish and Serial instruction takes, could result in missing scans as well. I think changing the first scanInterval to something above 1000 and below the desired interval would clean that up.

Thanks!