Missed Scheduled Events

Ive got a a particle photon that I need reliable local scheduling and control as it controls pumps valves and chemical injections. I want the cloud to be as an enhancement not something that gets in the way of normal function. I’ve created a function that I check the time of day and do stuff at scheduled times. I’m checking the hour and minute to see if they match my time and running if the minute changed from the last minute so it only runs once when the time matches that hour and minute. Problem is the photon is randomly missing some of these events and its important that it doesn’t. The only thing I can think of is internet connectivity issues occasionally causing blocking code that keeps my loop from even running. I’ve tried several things from semi automatic mode to now my most recent code which I think in manual mode should keep any cloud or mqtt call from blocking longer than 15 serconds. With this code I’m expecting It should never miss an entire minute?! It shouldn’t be hard to get a one minute resolution with this. Ill post the relevant code and hopefully you guys can see why I may be missing any events… I missed one this morning and when I went to investigate the photon is connected behaving normally and shows perfect device health and a round trip time of a few milliseconds…

STARTUP(WiFi.selectAntenna(ANT_EXTERNAL)); // Use external antenna
SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);    // enable so loop and setup run immediately as well as allows wait for to work properly for the timeout of wifi
// This #include statement was automatically added by the Particle IDE.
#include <MQTT.h>

// Time Variables for scheduling
int month;
int hour;
int minute;
int day;
int daylasttimesync;
int previousminute;
bool minutechange = false;
int rssi = 0;

void handlecloud(){
  if (WiFi.ready()){
     if (client.isConnected()){
        client.loop();
     }
     else{
        mqttconnect();
     }
     if (Particle.connected()){
        Particle.process();
     }
     else{
        Particle.connect();    // attempt to connect to the cloud
        waitFor(Particle.connected, 15000); // allow 15 seconds to conncect
        if (Particle.connected()){
           Particle.process();
        }
        else{
            Particle.disconnect();
        }  
     }
  }
  else{
       WiFi.connect();   //attempt to connect to wifi
       if (!waitFor(WiFi.ready, 15000)){
          WiFi.disconnect();
       }
      if (WiFi.ready()){
        if (client.isConnected()){
            client.loop();
        }
        else {
             mqttconnect();
        } 
        Particle.connect();    // attempt to connect to the cloud
        waitFor(Particle.connected, 15000); // allow 15 seconds to conncect
      
        if (Particle.connected()){
            Particle.process();
        }
        else{
            Particle.disconnect();
        }
      }
  }
}

void mqttconnect(){
  
  if (WiFi.ready()){
  //** Mqtt connect
  // connect to the mqtt server with your username and password here
    client.connect("clientname", "username", "password");
    int i = 0;
    while(!client.isConnected() && i < 20) {
          delay(100);
          i++;
    }
    // subscribe to mqtt events that you wish
    if (client.isConnected()) {
      client.subscribe("subscriptiontopics");
    }
  }
}
// Runs when called upon in loop to check for a regularly scheduled event such as pump speed changes valve changes and chemical pump changes at set times of the day
void checktime() {
  hour = Time.hour();
  minute = Time.minute();
  month = Time.month();
  day = Time.weekday();
  //check if the minute changed so stuff runs once
  if (minute != previousminute){
      minutechange = true;
      previousminute = minute;
  }
  else {
      minutechange = false;
  }

  int cursec = Time.local() % 86400;

  if (hour == 6 && minute == 30 && minutechange == true){
      //doesstuff its these scheduled events that its occaionally missing
  }

  // 8 am 1500 rpm main returns setting 3

  if (hour == 8 && minute == 0 && minutechange == true){
      // does more stuff yada yada yada more like this occasionally missing to fire
  }
}

void setup(){
  WiFi.connect();   //attempt to connect to wifi
  if (!waitFor(WiFi.ready, 15000)){
     System.reset(); 
  }
  if (WiFi.ready()){
     mqttconnect();
     Particle.connect();    // attempt to connect to the cloud
     waitFor(Particle.connected, 15000); // allow 15 seconds to conncect
  }
  if (Particle.connected()){
     Particle.process();
  }
  
//set timezone  
  Time.zone(-7);
}

void loop() {
  handlecloud();
  rssi = WiFi.RSSI();
  // check time for schedule based functions
  checktime();
}

I’d avoid using checks against the hour and minute but rather check the current second of the day and range check rather then specific timestamps.

You are calculating cursec but not using it in the code you posted above.

Also instead of

        waitFor(Particle.connected, 15000); // allow 15 seconds to conncect
        if (Particle.connected()){
           Particle.process();
        }
        else{
            Particle.disconnect();
        }  

you could just write

        if (!waitFor(Particle.connected, 15000)) // allow 15 seconds to conncect
           Particle.disconnect();

With SYSTEM_THREAD(ENABLED) you won’t need to call Particle.process() yourself anywhere in your code.

Your handlecloud() is overly elaborate IMHO too. There are multiple parallel cases and other impossible cases. Plus you are doing some of the same work in setup() too while you could just call that function there as well.

Okay thanks for the feedback Ill look at consolidating the handlecloud funtion and as far as calling Particle.process I don’t have to do it even in manual mode? Yeah for some reason I was using the cursec for something else further down that same funtion. I’m still at a loss for why the specific time stamp thing doesn’t work though? It literally has 60 seconds to catch that condition being true in a loop that completes in a few milliseconds ideally… Even if its more preferred to use cur sec and a range how big of a range should I expect to have to put since one minute seems too long for the other to work? Obviously id need a flag variable to set so it doesnt trigger multiple times in that range as well…

Perhaps this “rssi” value is updated much too frequently (every time thru loop()). Try commenting this line out or throttle it down so it updates only when you need the info.

i used to have that in there every ten minutes but I still remember having this similair problem

Just moved the Rssi cal to only call once a day and on setup just in case you are right.

Sorry, I did not mean to distract. I do not think changing the “rssi” code will “fix” things. Just pointing out to eliminate unnecessary code, wherever it may be. Once a solution is found, you can put the code back in, if you wish.

So, back to “calculating the current second” and changing “handlecloud()”.

I have been using checks against the hour and minute, similar to what you are doing. Maybe my code is failing in this regard and I just don’t know it. :wink: So, I thought it was high time I learned what you and @ScruffR know about calculating cursec. I took a look in the forum and found this thread:

https://community.particle.io/t/doing-something-at-a-certain-time/40245/5

In an example, there is a variable called oneShotGuard you might be interested in.

Moving on to Particle cloud connection (will leave MQTT to you). I would recommend using PublishQueueAsyncRK library to publish messages asynchronously. This library is a handy tool allowing status messages you might publish get through to your console without blocking even if there is a seconds to minutes disconnect occurring. This might help in monitoring your pump commands while finding a solution.
https://community.particle.io/t/publishqueueasyncrk-and-large-datasets/52733/20

2 Likes