Blocking Particle.connect() and publish()

I was curious if you (or anyone else) could explain to me if there’s any difference between these two pieces of code? With my original code, I would still have the occasional blocking Electron that required a manual reset to be done.

Original code:

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);

void loop() {
....
    if (!connecting) {
        Particle.connect();
        connecting = true;
        }
    if (Particle.connected()) {
        Particle.publish(publish, data, PRIVATE);
        ...    
        }
    else if (millis() - stateTime >= 180000) {
        Cellular.off();
        delay(2000);
        trueReset();
        break;
        }
...

Revised code:

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);

void loop() {
....
    if (!connecting) {
        Particle.connect();
        connecting = true;
        }
     if (waitFor(Particle.connected, 180000)) {
        Particle.publish(publish, data, PRIVATE);
        ...    
        }
    else {
        Cellular.off();
        delay(2000);
        trueReset();
        break;
        }
...

The waitFor will timeout and move to else after 3 minutes

1 Like

So when Particle.connect() ends up blocking, it still wouldn’t time out after 3 minutes would it? Seems like both pieces of code effectively do the same thing. I’ve had devices block with my Original code (System Threading + Manual) so I’m guessing FW-side there isn’t much else to do here to reduce the issue?

I used to just have the Electron go back to sleep until the next publish event when the connection timed out.

I was sending data every 5 mins so the wake up would not take to long.

1 Like

I’m probably missing something here, but I would think your “Revised” Code should work.
If a Publish was missed using the Revised Code, maybe it was just that the Electron couldn’t connect to the cellular network during the 3 minutes (poor signal, etc) ?

I would guess you would rather go to sleep in that case verses Reset.
It was suggested to me in another Thread to skip the “else” and go to sleep after the waitFor, since it either Published or Not (didn’t really matter). Again, I’m not sure if this helps in your Project.

When the connection attempt fails, I reset the device up to 3 times, before I put it back into Sleep mode. I did this, because my devices don’t publish much but when they do it’s pretty important they do so successfully.

Anyway, publishes being missed isn’t the real issue here to me, as that’s simply related to overall product constraints. The real problem I have is that after I call particle.connect() in my Original Code, the device occasionally blinks green endlessly for hours, sometimes until the battery goes dead alltogether. Usually the 3-minute timer described in my code kicks in correctly and prevents this, but not always.

As far as I understand, since particle.connect() is blocking, timers aren’t failproof and there isn’t a good way (?) to mitigate the issue FW side. Hence why I’m already adding in the HW Watchdog in my next version.

Note: trueReset() in my code puts the device into Deep Sleep for 30 seconds before waking it up. Any connection failures are therefore always followed by Deep Sleep.

Check the battery and voltage converter voltages during this constant flashing green connection issue because I saw that happen when the battery voltage was low and not when it was higher.

Plus it’s a cold time of year so colder temps usually cause battery voltages to drop vs warmer temps. Cellular RSSI will help determine if your the device has weak cellular signal as weather can affect signal strength also.

It’s definitely an RSSI issue. I have my devices deployed in a few locations. At our main site I’m getting RSSI values of -50 to -65 and things are going great; the couple of sites I’m having issues at show values of -80 to -95.

I’d rule out cold temperature as I had a few of them in a freezer (-18C) for months, and the voltage output remained satisfactory. In the field we usually don’t see the temperature drop below -5C.

The RSSI is one of the reasons I decided to go with Bell SIMs over the Particle ones. Can’t wait to test those and see whether it improves the situation.

Sounds like a RSSI issue then.

I would save the date and time of the data you are trying to send in retainer memory and only clear it after a successful publish. That way you can just go back to sleep if it does not connect and know the data will eventually make it on the next successful connection.

Sounds like you have ruled out cold weather as the issue which is good.

1 Like

I already save my data for the next publish :wink:

The issue really is when the Electron sits there for 1h+ blinking green before finally (a) deciding to go to Sleep (b) running out of battery juicd.

@Vitesze, have you experienced an Electron doing this when using
if (waitFor(Particle.connected, 180000)) in Threaded + Manual Modes?

I'm asking because I have Electrons deployed in a similar situation (very sensitive to wasting battery power) and haven't noticed this. But as I said before, I don't have near as many deployed as you do.

I step through the modem connect/disconnect process with "safe" delays (seen here), but I've also read where that shouldn't be necessary.
Maybe you need the "safe" delays with the Particle.process() calls?
1 Sec Delay after each action => for (uint32_t ms = millis(); millis() - ms < 1000; Particle.process());

Here's my Generic Flow for 1-shot Manual Mode:

 Cellular.on / 1 Sec / Particle.connect / 10 Sec /
      / waitFor Timeout / Publish / 5 Sec /
 Particle.disconnect / 1 Sec /  Cellular.off / 1 Sec /  Deep Sleep

I even tried disconnecting the Cellular antenna during the connection process many times and could never get the Electron to hang-up and not go to sleep.
This Code Flow "should" mitigate your RSSI issues at the problem sites (similar to no antenna).

2 Likes

It’s too early to say yet if I have any blocking code with if (waitFor(Particle.connected, 180000)). I’ll need to wait a bit longer for that.

Thanks for your tips! I now have something like this:

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);

void loop() {
....
    Cellular.on();
    for (uint32_t ms = millis(); millis() - ms < 1000; Particle.process());
    Particle.connect();
    for (uint32_t ms = millis(); millis() - ms < 10000; Particle.process());
     if (waitFor(Particle.connected, 180000)) {
        Particle.publish(publish, data, PRIVATE);
        for (uint32_t ms = millis(); millis() - ms < 5000; Particle.process());
        ...
        }
    else {
        Particle.disconnect();
	for (uint32_t ms = millis(); millis() - ms < 1000; Particle.process());
        Cellular.off();
        for (uint32_t ms = millis(); millis() - ms < 2000; Particle.process());
        trueReset();
        break;
        }
...

The delays I had previously very well could’ve impacted my code before too.

With the code above, I still appear to have some blocking issues (i.e. blinking green way beyond 180s). Additionally, shutting off the cellular also seems to take quite some time (i.e. breathing blue for 1-2m).

I observed this behaviour in multiple Electrons across my product in the past 10 days.

I will be able to test my new HW Watchdog feature soon, which should fix it partially (at least limiting the blocks to x minutes).However, it’s still concerning that this issue can be so prominent.

Blinking green does not indicate a blocking issue with Particle.connect() per se. Your device is searching for a cellular network, which can in fact take several minutes. Particle.connect() relies on there being a cellular connection. Thus, if you have no cellular connection, Particle.connected() will never return true.

Breathing blue means that you are in listening mode, which is a state of Cellular disconnection. For me Cellular.off() is pretty quick. Here is the code I use to perform a reset that includes the modem reset:

if (resetNow)
        {
            delay(1000);
            SINGLE_THREADED_BLOCK()
            {
                // A reset was triggered somewhere, handling after operations complete
                if (alsoResetModem)
                {
                    // The reset is related to cellular connectivity, so also resetting modem first
                    log(LOG_LVL_INFO, LOG_GRP_WD,"Disconnecting from Particle cloud before resetting modem...");
                    Particle.disconnect();
                    delay(100);
                    log(LOG_LVL_INFO, LOG_GRP_WD,"Resetting Modem...");
                    #if Wiring_Cellular
                        // 16:MT silent reset (with detach from network and saving of NVM parameters), with reset of the SIM card
                        Cellular.command(30000, "AT+CFUN=16\r\n");
                        delay(100);
                        Cellular.off();
                    #elif Wiring_WiFi
                        WiFi.off();
                    #endif
                    delay(200);
                }
                // Now let's reset the electron
                log(LOG_LVL_INFO, LOG_GRP_WD,"Resetting Device...");
                reset_handler();
                System.reset(reset_reason_code);
            }
        }

Regardless, if your observed problem is that a device is blinking green for a long, long time, the waitFor code you have above will technically work (though I’d add the Cellular command to fully reset too), but I recommend increasing your timeout beyond 180sec to maybe 240sec, which is where I’ve successfully had it. Keep in mind that if your location just doesn’t have Cell service, no firmware change can fix that.

Actually not Listening Mode but "Cellular module not connected"
Listening Mode would be blinking blue.

In this code example, how could this occur though? I would expect the Electron here to attempt a connection for 3 minutes. If after 3 minutes no connection has been established, it should turn off the cellular and reset within a few seconds. The LED pattern I expect is:

Blinking Green - (Rapid-blinking Cyan) - Breathing Blue - Reset

I would expect the Breathing Blue phase to only last 1-3 seconds (based on how long it takes to actually turn off the cellular) but I noticed a few cases where it took as long as a few minutes.

     if (waitFor(Particle.connected, 180000)) {
        Particle.publish(publish, data, PRIVATE);
        for (uint32_t ms = millis(); millis() - ms < 5000; Particle.process());
        ...
        }
    else {
        Particle.disconnect();
	for (uint32_t ms = millis(); millis() - ms < 1000; Particle.process());
        Cellular.off();
        for (uint32_t ms = millis(); millis() - ms < 2000; Particle.process());
        trueReset();
        }

This is also in response to @justicefreed_amper , as I understand cell service may be poor and Particle.connected() won't return true, but this should still mean the device resets after exactly 3 minutes. I've seen it exceeding this amount by a few minutes a few times.

Probably no way, but I guess there is some more code which we can't see but may well cause that.
This state can be reached two ways

  1. after the cellular modem was powered on but no call for Cellular.connect() nor Particle.connect() had been executed, or
  2. after the device was connected to the cell network any you call Cellular.disconnect()

However, some timeout condition may also cause the system thread to get the cell modem to that state.

For reference, here's my code: Particle Web IDE

I don't believe (1) should ever happen, as Cellular.on() in my code is always followed by Particle.connect(). Would (2) be achieveable by calling Cellular.off() as well? Right after connecting, I publish my data and then immediately call Particle.disconnect() + Cellular.off()

I'm not aware of anything else in my firmware that could cause issues like this but I'm probably overlooking things. Connectivity is still a huge culprit with my devices for some reason.

That's possible, but that phase should be too short to actually see it breathe

Yeah it is, it usually only breathes for a second or so :thinking: