Particle.connect() blocking main loop permanently, even with SYSTEM_THREAD(ENABLED)

This document does not hint at the behavior that @ScruffR has described about WiFI.connect():

connect()

Attempts to connect to the Wi-Fi network. If there are no credentials stored, this will enter listening mode (see below for how to avoid this.). If there are credentials stored, this will try the available credentials until connection is successful. When this function returns, the device may not have an IP address on the LAN; use WiFi.ready() to determine the connection status.

// SYNTAX
WiFi.connect();

Since 0.4.5 It's possible to call WiFi.connect() without entering listening mode in the case where no credentials are stored:

// SYNTAX
WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);

If there are no credentials then the call does nothing other than turn on the Wi-Fi module.

This document never says explicitly that Particle.connect() does not block while in MANUAL mode:

Particle.connect()

Particle.connect() connects the device to the Cloud. This will automatically activate the Wi-Fi connection and attempt to connect to the Particle cloud if the device is not already connected to the cloud.

void setup() {}

void loop() {
if (Particle.connected() == false) {
Particle.connect();
}
}

After you call Particle.connect(), your loop will not be called again until the device finishes connecting to the Cloud. Typically, you can expect a delay of approximately one second.

In most cases, you do not need to call Particle.connect(); it is called automatically when the device turns on. Typically you only need to call Particle.connect() after disconnecting with Particle.disconnect() or when you change the system mode.

Manual mode

The "manual" mode puts the device's connectivity completely in the user's control. This means that the user is responsible for both establishing a connection to the Particle Cloud and handling communications with the Cloud by calling Particle.process() on a regular basis.

SYSTEM_MODE(MANUAL);

void setup() {
// This will run automatically
}

void loop() {
if (buttonIsPressed()) {
Particle.connect();
}
if (Particle.connected()) {
Particle.process();
doOtherStuff();
}
}

When using manual mode:

  • The user code will run immediately when the device is powered on.
  • Once the user calls Particle.connect(), the device will attempt to begin the connection process.
  • Once the device is connected to the Cloud (Particle.connected() == true), the user must call Particle.process() regularly to handle incoming messages and keep the connection alive. The more frequently Particle.process() is called, the more responsive the device will be to incoming messages.
  • If Particle.process() is called less frequently than every 20 seconds, the connection with the Cloud will die. It may take a couple of additional calls of Particle.process() for the device to recognize that the connection has been lost.

This is heavily misleading:

Under System Threading Behavior,

System modes SEMI_AUTOMATIC and MANUAL behave identically

which is not true, except in this narrow aspect:

both of these modes do not not start the Networking or a Cloud connection automatically

There is nothing that brings the material together and presents it in a cohesive way. There are bits and pieces of information scattered throughout the API reference, but even if you collect all the information in there together, there are enough gaps that you will be led astray even if you're reading carefully.

This is an API reference, but the "Reference Manual" is missing. There is no Theory of Operation discussion or examples showing recommended ways to handle common scenarios-- leaving new users (including experienced engineers) to trial-and-error their way through building an application.