Loop not getting called when using SYSTEM_THREAD(ENABLED)

I have a question about SYSTEM_THREAD(ENABLED). In the documentation it states that user application code should still run even when there is no connection to the cloud. However in my experience, if my device boots without ever connecting to the cloud (it just blinks green), my user code is never run and seems to be blocked. Is this intended behaviour?

Quoted from reference documentation:
“after setup() is called, loop() is called repeatedly, independent from the current state of the network or cloud connection. The system does not block loop() waiting for the network or cloud to be available, nor while connecting to Wi-Fi.”

Are you calling Particle.connect() (or similar WiFi/cloud connected functions) in your code?
If so, you may be pulling the actuall task into the application thread which might be blocking it.

What SYSTEM_MODE() are you using?

Im using SYSTEM_MODE(AUTOMATIC).

I do call Particle.variable/Particle.function and Particle.publish in my setup function. Could that be the reason? Is there a way to do it such that it doesn’t block?

Remove all code from loop() except led blink and test again

What system version are you running?
And while Particle.variable() and Particle.function() (as well as Particle.subscribe()) don’t require an active connection, Particle.publish() does and hence you should guard against a call without connection like this

  if (Particle.connected())
    Particle.publish(...., PRIVATE); // I explicitly state PRIVATE to stress better practice than just using the default PUBLIC ;-)

If you need your publish to happen during setup() you should do this

  waitUntil(Particle.connected);  
  Particle.publish(..., PRIVATE);

If you’d only prefer to have the publish but could worst case have it otherwise you can opt for this

  if (waitFor(Particle.connected, 60000)) // wait max. 60sec
    Particle.publish(..., PRIVATE);
  else
    Serial.println("No connection, need to find other ways");

But showing your actual code (or some stripped down test code that exerts the same behaviour) would rid us from the need to guess away.

4 Likes

Apologies for such a delayed response.

I wanted to give an update to the situation. Everything ScruffR said makes alot of sense and was very helpful. I found out that Particle.variable and Particle.function did indeed block (whether or not this is intended behaviour I’m not sure). In the end I guarded against these calls using if(Particle.connected()) statements. BUT that also meant that my variables/functions would never be exposed to the cloud if there is no wifi connection when my device boots up or resets (which is basically 100% of the time because a particle connection won’t happen on startup). Therefore in my loop I have functions that setup my functions and particle based on a flag.

void Particle_Functions(){
   Particle.function("function1", function1);
   Particle.function("function2", function2);
   ...
}

void Particle_Variables(){
   Particle.variable("variable1", variable1);
   Particle.variable("variable2", variable2);
   ...
}

void loop{
   ...
   if(Particle.connected() && !flag){
      Particle.variable();
      Particle.function();
      flag = true;
   }
   ...
}

I’m not too sure if having these checks in the loop will bog down the cpu but I am open to any suggestions. Thanks alot!

You should not do that. You should make calls to Particle.variable and Particle.function at the very top of your setup, before you do anything else. This can (and should) be done before connecting to the cloud.

Functions and variables are only uploaded once per connection to the cloud, and if you wait until connected, you can easily miss the window of opportunity and they will not be set.

1 Like

I'm pretty sure that's not the case and is definetly not the intended behaviour (unless my understanding of a blocking call differs greatly from yours).

Hence I repeat my question from above

And have you - as the topic title suggests - actually tried this with SYSTEM_THREAD(ENABLED)?
Can you also try a non-AUTOMATIC SYSTEM_MODE()?

I am running 0.7.0. And yes I am testing this with SYSTEM_THREAD(ENABLED).

What I mean by blocking is that it is preventing the rest of my user firmware from running. I originally wanted my user firmware to run on start up even if there is no cloud connection. I have a button that changes the state of a relay and the colour of an LED. If I have the Particle.function/Particle.variable function in the setup function, I am not able to control the relay using the button. However once I comment those out, the button works as soon as I power on the device. Here is a cut down version of the code.

void setup(){
   //particle variable setup
   Particle.variable("variable1", variable1);
   Particle.variable("variable2", variable2);
   Particle.variable("variable3", variable3);

   //particle function setup
   Particle.function("function1", function1);
   Particle.function("function2", function2);
   Particle.function("function3", function3);
   
   //pin mode setup
   pinMode(relayPin, OUTPUT);
   pinMode(LEDPIN, OUTPUT);
   pinMode(buttonPin, INPUT);

   //interrupt for button to change relay state
   attachInterrupt(buttonPin, interrupt_function, RISING);
}

There are no publish/subscribes. If I comment out all the Particle.function/variable calls, the device will work as intended. If I leave them there, it'll wait for cloud connection before my button will work.

I also JUST noticed the documentation was updated to actually address this particular issue. https://docs.particle.io/reference/firmware/photon/#system-functions

Synchronous system functions always block the caller until the system has performed the requested operation. These are the synchronous system functions:

  • WiFi.hasCredentials(), WiFi.setCredentials(), WiFi.clearCredentials()
  • Particle.function()
  • Particle.variable()
  • Particle.subscribe()
  • Particle.publish()

For example, when the system is busy connecting to Wi-Fi or establishing the cloud connection and the application calls Particle.variable() then the application will be blocked until the system finished connecting to the cloud (or gives up) so that it is free to service the Particle.variable() function call.

This presents itself typically in automatic mode and where setup() registers functions, variables or subscriptions. Even though the application thread is running setup() independently of the system thread, calling synchronous functions will cause the application to block until the system thread has finished connecting to the cloud. This can be avoided by delaying the cloud connection until after the synchronous functions have been called.

Does that mean I should be using semi-automatic/manual mode? If so, I'm assuming I'll have to constantly call Particle.process as well as Particle.connect when it loses cloud connection?

Yes, you should use an alternative SYSTEM_MODE, but no, when using SEMI_AUTOMATIC mode, you won't need to constantly call Particle.process() or Particle.connect() (especially when it's called on the system thread).

This was happening to me too.
The way I fixed it was to enable system thread and change system mode to semi-automatic. (when I did my testing, I found that thread does not work with automatic mode).

Note you need to call Particle.connect() when using semi-automatic mode.

If you put the particle.function and particle.variables at the start of the setup function and particle.connect at the end it should resolve it. (it did for me).

I have done my own tests and could not find any unexpected behaviour.
Could you post your test code and also state what you’d expect to happen vs. what actually happens to either see the erronous behaviour or clear some misconceptions how things should behave.

Some time ago now I detailed my trouble with an Electron exhibiting this behavior, at the time I stated the firmware worked fine on the Photon, turns out that wasn’t actually true. For my photon devices there was always an excellent WiFi signal present so there was only an imperceptible delay while the device connected. As I had already moved on from checking the device ran with no signal in previous updates of my code, I neglected to check it in more detail. Other N issues I didn’t see because I have an Asus router with “b/g protection” & 20Mhz only enabled which I think makes it work with devices like this better.

If I recompile my software for Firmware 0.6.3(photon) or 0.6.4(electron) I’m back to having fully working devices that run loop() without a connection. So I don’t think this is a Wireless-N issue, I think its a v0.7+ issue and it kicks in when a program reaches a certain level of complexity or size. A test program that just cycles inputs and displays readings on a display works just fine on 0.7.0 in threaded mode.

2 Likes