Calling Particle.disconnect() after a failed Particle.connect() does not stop LED from blinking green

I am trying to enable/disable the cloud connection and WIFI to improve battery life. I have SYSTEM_THREAD(ENABLED) and SYSTEM_MODE(AUTOMATIC) in my code.

I use the following functions to connect/disconnect from the cloud and enable/disable WIFI:

long _startedConnecting = 0;
#define CLOUD_CONNECTION_TIMEOUT 60000

bool ParticleCloud::connect()
{
    if(0 == _startedConnecting) //Not already connecting
    {
        _logger.logMessage(INFO_LOG, "Connecting");
        Particle.connect();//Enable wifi and connect to cloud - non blocking with SYSTEM_THREAD(ENABLED)
        _startedConnecting = millis();
        return true;
    }
    else if((millis() - _startedConnecting) >= CLOUD_CONNECTION_TIMEOUT) //Already connecting - check for time out
    {
        _logger.logMessage(WARN_LOG, "Connecting timed out");
        disconnect();
        return false;
    }
    else return true;
}

void ParticleCloud::disconnect()
{
    _logger.logMessage(INFO_LOG, "Disconnecting");
    Particle.disconnect(); //Disconnects from cloud - non blocking
    WiFi.off(); //Disables wifi - non blocking
    _startedConnecting = 0;
}

I then call connect() in a loop until either:

  • connect() returns false denoting a time out
  • Particle.connected() returns true denoting a successful connection

I have a couple of problems:

  • Lots of the time connect() times out (60 seconds), but when the Photon is first connected to power it connects within 10 seconds.
  • When connect() times out disconnect() is called but the Photon stays flashing green. This runs my battery down and the Photon will not reconnect after this.

The log messages are below:

INFO LOG - Wed Feb  3 14:29:03 2016 - Disconnecting //LED is breathing white
INFO LOG - Wed Feb  3 14:30:03 2016 - Connecting //LED is flashing green
WARN LOG - Wed Feb  3 14:31:03 2016 - Connecting timed out //LED is flashing green
INFO LOG - Wed Feb  3 14:31:03 2016 - Disconnecting //LED is flashing green -> should be breathing white

Any ideas or workarounds I can try to fix this? I really need connecting/disconnecting to be as reliable as possible.

Cheers

EDIT:
Has anyone got a “gold standard” non-blocking way of connecting/disconnecting they would be willing to share?

@joe4465, you should be using MANUAL or SEMI_AUTOMATIC modes. You could also use the [waitFor()][1] macro to help with the connect/disconnect steps. Your code checks for a connect() timeout but doesn’t check the connection is complete with Particle.connected().

Also, with WiFi.off(), it may not be necessary to do a Particle.disconnect() though I have to check on that.

Hi,

My understanding is that the waitFor() macro is blocking. I do use this in other projects where I don't need to do anything whilst waiting for a connection.

In my loop I call connect() followed by an if statement that checks for Particle.connected() thus I break out my loop and do something when either:

  • connect() returns false denoting a time out
  • Particle.connected() returns true denoting a successful connection

I use both Particle.disconnect() and WiFi.off() as the docs state that Particle.disconnect() does not disable the WIFI module.

I was using AUTOMATIC mode as the docs state:

In automatic mode, the user can still call Particle.disconnect() to disconnect from the Cloud, but is then responsible for re-connecting to the Cloud by calling Particle.connect().

I will try SEMI_AUTOMATIC mode now and report back.

Thanks

1 Like

I get the same behavior in SEMI_AUTOMATIC mode.

When the Photon fails to connect within 60 seconds I call disconnect() but the Photon stays flashing green.

When the Photon connects within 60 seconds I do some stuff and then call disconnect() and the Photon goes to breathing white.

EDIT:
I will do a test case now

@joe4465, can you create minimal test code I could run?

1 Like

Test case:

#include "application.h"

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

#define CLOUD_CONNECTION_TIMEOUT 30000
#define CLOUD_CONNECTION_INTERVAL 60000

long _startedConnecting = 0;
long _lastConnectionTime = -CLOUD_CONNECTION_INTERVAL; //Causes code to run on startup, otherwise we would need to wait 60 secs before a connection

void setup()
{
    Serial.begin(115200);
}

void loop()
{
    if(abs(millis() - _lastConnectionTime) > CLOUD_CONNECTION_INTERVAL)
    {
        bool timedOut = connect();

        if(timedOut == false)
        {
            Serial.printf("Connecting FAILED\r\n");
            _lastConnectionTime = millis();
            
            //Do some offline stuff i.e. save data I was trying to send to EEPROM
        }

        if(Particle.connected())
        {
            Serial.printf("Connecting SUCCESS\r\n");
            _lastConnectionTime = millis();
            
            //Do some online stuff i.e. send data
            
            disconnect();
        }
    }
    
    //Do lots of other stuff that cannot be blocked whilst connecting/disconnecting
}

bool connect()
{
    if(0 == _startedConnecting) //Not already connecting
    {
        Serial.printf("Connecting\r\n");
        Particle.connect();//Enable wifi and connect to cloud - non blocking with SYSTEM_THREAD(ENABLED)
        _startedConnecting = millis();
        return true;
    }
    else if((millis() - _startedConnecting) >= CLOUD_CONNECTION_TIMEOUT) //Already connecting - check for time out
    {
        Serial.printf("Connecting timed out\r\n");
        disconnect();
        return false;
    }
    else return true;
}

void disconnect()
{
    Serial.printf("Disconnecting\r\n");
    Particle.disconnect(); //Disconnects from cloud - non blocking
    WiFi.off(); //Disables wifi - non blocking
    while(Particle.connected()) delay(100); //Delay in here so that I can print the "disconnecting SUCCESS" message. This would be removed in my actual code as it is blocking
    Serial.printf("Disconnecting SUCCESS\r\n");
    _startedConnecting = 0;
}

Output when WIFI hot spot is on:

Connecting -> LED transitions from breathing white to flashing green
Connecting SUCCESS -> LED transitions from flashing green to breathing blue
Disconnecting -> LED transitions from breathing blue to breathing white
Disconnecting SUCCESS

Output when WIFI hot spot is off:

Connecting  -> LED transitions from breathing white to flashing green
//one minute passes.....
Connecting timed out -> LED still flashing green (incorrectly)
Disconnecting -> LED still flashing green (incorrectly)
Disconnecting SUCCESS -> LED still flashing green (incorrectly)
Connecting FAILED -> LED still flashing green (incorrectly)
//one minute passes.....
Connecting  -> LED transitions from flashing green to breathing white. Stays breathing white forever. This should transition from breathing white to flashing green.

Thanks for your help @peekay123

Hey @mdma and @Dave,

I have a problem where calling Particle.disconnect() without a wifi network present gets the photon stuck flashing green, after this no more connection attempts succeed even when I have enabled my wifi network.

Would you mind trying out the code in the last post to see if you get the same behaviour?
Am I misreading the docs or doing something stupid?

Any help or pointers is much apppreciated as I know your very busy.

Thanks

1 Like

In the next release. you will be able to call WiFi.disconnect() to forcibly terminate any attempts at wifi connection. The branch release/v5.0-beta contains this change already.

Calling Particle.disconnect() won’t do this since that’s a request to disconnect from the cloud, not to disconnect WiFi.

2 Likes

@mdma, I follow Particle.disconnect() with WiFi.off() but the LED stays blinking green.
I need to disable the WIFI module to save battery life.

What is the proper (safe) way to disable the WIFI module and not break future connection attempts? Preferably without using WiFi.disconnect() as I cannot flash devices in the field with new Particle firmware.

Thanks

I must be misunderstanding - this seems like a contradiction - you want to turn off WiFi (to stop it blinking green) but also keep it available for flashing new firmware. You can’t have your cake and eat it! :smile:

Sorry, let me try to explain what I need, what I am doing currently and the issues with that.

I need to be able to turn on the WIFI module and connect to the Particle cloud once per hour to send data. Once the data has been sent I need to disconnect from the Particle cloud and disable the WIFI module.

  • The connection/disconnection needs to be non blocking as I have a sensor I need to read from every 100ms.
  • The connection needs to timeout and disable the WIFI module is no connection if found for 1 min (wifi network is down etc.)

At the moment I call Particle.connect() to enable WIFI and try to connect to the Particle cloud. I then check for connectivity using Particle.connected() until either it returns true and I am connected OR 1 minute is up and the connection has timed out. If the connection was successful I send some data, if the connection timed out I save some data. I then disconnect from the Particle cloud using Particle.disconnect() and disable the WIFI module using WiFi.off()

The main issue I have found with this is that when no WIFI network is present my code times out after 1 min and calls Particle.disconnect() followed by WiFi.off() BUT the LED stays flashing green which means it is still trying to connect and at the next connection attempt it fails to connect even though a WIFI network is present. (my test case code and output above demonstrates this).

So I think what I need is a reliable way to disable the WIFI module independent of the connection state. I have read through the docs quite a lot and I am pretty sure the way I do this in my test case code above is correct.

I think I confused you with this:

Preferably without using WiFi.disconnect() as I cannot flash devices in the field with new Particle firmware.

I just meant that I cannot easily flash devices in the field with release/v5.0-beta so I would rather not use features present in that release.

Thanks for your help

1 Like

OK so given that I have posted a test case which demonstrates the issue and no one has said the code is incorrect I am starting to think this is a known issue. Is this the case? and if so is the only fix to use WiFi.disconnect() in the next release?

I would love it if someone else could run the test case code and confirm whether they see the same behavior on their device and network. I would love it even more if anyone has any suggestions or ideas of other things I could try… maybe I am just being impatient but I have spent far too much time now on a seemingly simple issue. Enabling and disabling the WIFI connection should not be this hard or unreliable on an IoT platform.

Please tell me I am being an idiot :wink: and that there is an easy way to achieve what I need.

Thanks

Firstly let me say thanks for raising this issue - it's a known problem and on our radar.

Two points here:

  1. The device does eventually transition out of flashing green so the title of the thread is a bit misleading. Of course we would like this to be much quicker. I've already mentioned that the next release will make this process quicker.

  2. The device does not resume flashing green because you've called WiFi.off(). The system will not turn on wifi for you in SEMI_AUTOMATIC mode.

This seemingly simple issue is far from that - it's a complex interaction of many different pieces of software, made only more complex with multithreading.

2 Likes

Hi @mdma,

Thanks for replying, I really do appreciate it.

The LED does take at least 1 min to stop flashing green after calling Particle.disconnect() and WiFi.off(). This is not too big of an issue although the faster this happens the lower my power consumption. I’m happy this will become quicker in the next release :smile:

The docs state that calling Particle.connect() will activate the WiFi module if it is not already activated so I was not aware I needed to call WiFi.on() first when in SEMI_AUTOMATIC mode. Perhaps the docs could be made clearer in this respect. I will test this today and see if allows me to reliably enable and disable the cloud connection.

I totally understand that all this stuff is super complex and takes time to get right - I think that maybe I overestimated how far along Particle was with everything and therefore expected everything to “just work”. Having said that you guys are always very helpful and this forum is one of the best community’s I have come across - every forum should have Elites!

Thanks

2 Likes

This has been solved by adding WiFi.on() and a check to ensure Particle.connect() is only called once when the Wifi is ready.This has been tested for about 3 days.

#include "application.h"

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

#define CLOUD_CONNECTION_TIMEOUT 30000
#define CLOUD_CONNECTION_INTERVAL 60000

long _startedConnecting = 0;
bool _particleConnecting = false;
long _lastConnectionTime = -CLOUD_CONNECTION_INTERVAL; //Causes code to run on startup, otherwise we would need to wait 60 secs before a connection

void setup()
{
    Serial.begin(115200);
}

void loop()
{
    if(abs(millis() - _lastConnectionTime) > CLOUD_CONNECTION_INTERVAL)
    {
        bool timedOut = connect();

        if(timedOut == false)
        {
            Serial.printf("Connecting FAILED\r\n");
            _lastConnectionTime = millis();
            
            //Do some offline stuff i.e. save data I was trying to send to EEPROM
        }

        if(Particle.connected())
        {
            Serial.printf("Connecting SUCCESS\r\n");
            _lastConnectionTime = millis();
            
            //Do some online stuff i.e. send data
            
            disconnect();
        }
    }
    
    //Do lots of other stuff that cannot be blocked whilst connecting/disconnecting
}

bool connect()
{
    if(_startedConnecting == 0) //Not already connecting
    {
        Serial.printf("Enabling WIFI\r\n");
        WiFi.on();
        WiFi.connect();
        _startedConnecting = millis();
        return true;
    }
    else if(WiFi.ready() && !_particleConnecting)
    {
        Serial.printf("Connecting to Particle cloud\r\n");
        Particle.connect();
        _particleConnecting = true;
    }
    else if((millis() - _startedConnecting) >= CLOUD_CONNECTION_TIMEOUT) //Already connecting - check for time out
    {
        Serial.printf("Connecting timed out\r\n");
        disconnect();
        return false;
    }
    else return true;
}

void disconnect()
{
    Serial.printf("Disconnecting\r\n");
    Particle.disconnect();
    WiFi.disconnect();
    WiFi.off();
    _startedConnecting = 0;
    _particleConnecting = false;
}