Problems with calling Spark.connect within setup()

I’m trying to manage the core’s WiFi and Cloud connections manually. I’m using SYSTEM_MODE(MANUAL) and able to successfully manage starting up and tearing down the WiFi connection. I can successfully send data to a remote server after the WiFi connection is up. I was trying to add support for enabling the Spark Cloud however I am running into some problems.

If I call Spark.connect() after I have an established WiFi connection it will connect to the cloud (breathing cyan) and pass the Spark.connected() test but my subsequent TCP Client connect call fails everytime. I try 10 times and it will pause for the first call and then immediately fail on the 9 subsequent calls. I have verified that I have an IP address and a valid DNS address

In troubleshooting this I tried to connect to the cloud in my setup routine, however in that case calling Spark.connect() from within the setup routine hangs the spark.

  1. Does anyone know why my TCP client connect calls fail after I have manually established the WiFi and Spark connections?
  2. Why does calling Spark.connect() from setup cause the core to hang?

Are you calling Spark.process() regularly enough?

@ScruffR I think so. I call Spark.process() in my main loop and in setup while I am trying to establish the cloud connection.

As I understand Spark.connect() it blocks user code until it completes. That is the behavior I am seeing.

Here is my function that establishes my network connection -

int startWiFi() {

	// startup wifi
	switch (_wifistate) {
	    case WIFI_OFF:
                D(_start_net_connect = millis(); _j = 0;)
           	D(Serial.print("Starting WiFi\n\r");)
                WiFi.on();            // Turn on the WiFi radio
                WiFi.connect();       // Start WiFi connection
                _wifistate = WIFI_CONNECTING;
                D(Serial.print("Enabling WiFi");)
                break;
	    case WIFI_CONNECTING:
                // Wait for WiFi DHCP to get setup
                D(if (!(++_j % 5000)) Serial.print(".");)
                if (!WiFi.connecting() && WiFi.ready())
#if defined(ENABLE_SPARK_CLOUD)
            	_wifistate = WIFI_ON;
#else
		_wifistate = WIFI_READY;
#endif
                break;
	    case WIFI_ON:
                // Start the connection with the Spark Cloud
		D(Serial.print("\n\rConnecting to Cloud\n\r");)
		_wifistate = WIFI_CLOUD_CONNECTING;
                Spark.connect();
                break;
	    case WIFI_CLOUD_CONNECTING:
                // Wait for WiFi DHCP to get setup
                D(if (!(++_j % 5000)) Serial.print(".");)
                if (Spark.connected())
                    _wifistate = WIFI_READY;
                break;
	    default:
		D(Serial.println("Invalid WiFi state");)
		break;
	}

	if (_wifistate == WIFI_READY) {
            // We have working WiFi connection
            D(Serial.print("WiFi connected: time to connect = ");)
            D(float _t = (millis() - _start_net_connect) / 1000;)
            _totalConnectTime += _t;
            D(Serial.print(_t, 2);)
            D(Serial.print("s.\n\r");)
	}

	return _wifistate;
}

My main loop basically calls this function once each time thru the loop. It also calls Spark.process() everytime.

Only after startWiFi rturns WIFI_READY do I try and connect to my remote server.

This works reliably when I don’t try and establish a Cloud connection. (I can even call it from my setup function)

But when I add #define ENABLE_SPARK_CLOUD it all goes wrong.

UPDATE:: Turns out Spark.connected() is not really accurate. I added 50 loop iterations with calls to Spark.process() and now the network TCP client connections work.

I still don’t know why calling Spark.connect() from within the setup function hangs. I guess I will add my Spark.function calls in my loop.

Good to hear that it works now - I was just about to send you a list of checks, that are obsolete now :+1:

The thing with Spark.connect() hanging in setup seems odd to me.
Could you try a sole Spark.connect() in your setup(), without any other stuff happening - as Spark.connect() should implicitly do all the WiFi establishing work anyhow.
Does it then definetly hang within setup() - how does this hanging look like (checkpoints)?

1 Like

@ScruffR Thanks for the suggestion. I was able to get the Cloud up in Setup by JUST calling Spark.connect(); Not sure why my own management function did not work, but anyway it was able to connect.

Unfortunately, it looks like in order for you to be able to use Cloud functions the connection needs to be alive and running continuously. I had it connect and register a function but when I check the Cloud is tells me the core is down.

I don’t know enough about the cloud - core interaction to know what’s needed to make the cloud think the core is alive.

The functionality I’m looking for is to send a message to the cloud that is picked up by the core the next time it checks in.

Specifically I want to be able to tell the core to change it’s WiFi intermittent behavior to continuous WiFi so I can send it firmware updates.

I figured the cloud would be the logical place for that type of communications. Maybe I’ll start another thread, or study the local Cloud software.

If you use just Spark.connect() in setup everything is OK, If you bring up the WiFi manually and then try and call Spark.connect() from within setup it never returns and the RGB light stays solid green.

If you do this within the main loop everything is happy. So something is different when calling Spark.connect() from setup when you already have a WiFi connection.

Spark.connect() by itself works in setup, so I will just use that for now.

1 Like

@mtnscott, whenever I couldn’t quite figure out, why things on the Core didn’t quite behave as I assumed they should, I found it most enlightning to have a look at the Open Source sections



To see what’s actually happening behind the scenes.

I found the best way to get to the root of things is to download all three repo zips unpack them into one folder and then do a grep or other contents search for the desired keywords (e.g. SparkClass::conect, WiFiClass::connect and wlan_start).
It is a bit of detective work, but you learn loads about the Core and cloud!

@ScruffR Yep, I already had them and was looking - so Spark.connect() calls WiFi.connect() and then sets SPARK_CLOUD_CONNECT = 1. WiFi.connect() in my case just returns as I have already started the WiFi. (it tests WiFi.ready() and returns if true)

One difference is that when I do this from main loop I return from the loop every transition of my state machine - after WiFi.connect() and before Cloud.connect(), in setup I don’t return between these two which does not allow this code segment to execute (from main.cpp)

if(SPARK_WLAN_SETUP)
{
  DECLARE_SYS_HEALTH(ENTERED_WLAN_Loop);
  SPARK_WLAN_Loop();
}

I think at this point since the having the cloud connection up briefly does not accomplish what I need thee is no point to debugging this further.

Thanks for your help

Maybe sometime later I will look deeper into WiFi.connect() to understand why Cloud.connect() hangs if WiFi.ready() is already true in setup when I call Cloud.connect()

Just to get to the bottom of things, could you try to wait till your Core has received a valid IP address before you attempt to Spark.connect?

Maybe this is a thing Spark.connect does when WiFi is not ready at call time, but misses if WiFi.ready is already true at call time.

1 Like

@mtnscott and @ScruffR
I am kinda being lazy (thanks in advance if you respond) here by not digging into the source myself, but as a quick sanity check (if you don’t mind) tell me if this makes sense.

running in semi-automatic.

was… called every loop. This seemed to work, until I tested on my older netgear

    if(current_mode != listen_mode && !Spark.connected())
      {
          Spark.connect();
      }

changed to (below)… works on my netgear… does it make since that calling spark.connect() too often will prevent a connection if you router is “slow”?

if(current_mode != listen_mode && !Spark.connected())
  {
    if(!sparkconn_once)
    {
      sparkconn_once = true;
      Spark.connect();
    }
  }
  else
  {
    sparkconn_once = false;
  }

@jerome Here is what I used in my DNS tool for creating a connection to the Spark Cloud.

#define MAX_WIFI_RETRY 100
Serial.print("connecting +");
Spark.connect();
_timeout = 0;
while (_timeout < MAX_WIFI_RETRY && !Spark.connected()) {
    Serial.print("+"); _timeout++; delay(100);
}

if (_timeout == MAX_WIFI_RETRY) {
    Serial.println("Failed to connect to Spark Cloud.");
}
else {
    Serial.println();
    bWiFiEnable = true;
    bWiFiConnect = WiFi.ready();
}

The basic idea is that Spark.connect(); returns immediately and there is no need to call it again unless you fail to connect after some timeout period. It’s only later after the call that the connection completes. In my example the call to Spark.connected(); allows (I think) the Spark WiFi loop to continue and establish the connection.

Maybe the Netgear is slower to establish the WiFi connection and calling Spark.connect(); over and over again may reset the previous attempt?

3 Likes