How long after WiFi connect can Particle.publish() be reliable?

I am working on power conservation with Photon and have a reliability issue using Particle.publish as well as MQTT. It seems there needs to be a delay between turning on WiFi and making any network calls to have a reliable connection. My testing shows there needs to be a delay of ~5 sec from Particle.connect = true to publishing anything. Is this what others are seeing or is this something that is limited to my units? Test code included below.


SYSTEM_MODE(MANUAL);

void setup ()
  {
    Serial.begin(9600);
    pinMode(D7, OUTPUT);
  }

void loop ()
  {
    Serial.println("connect()");
    connect();
    Particle.process();

    Serial.println("LED On");
    delay(5000);
    Particle.process();
    
    Particle.publish("led", "on", 60, PRIVATE);
    Particle.process();

    digitalWrite(D7, HIGH);
    Particle.process();

    delay(1000);
    Serial.println("LED Off");
    Particle.publish("led", "off", 60, PRIVATE);
    Particle.process();

    digitalWrite(D7, LOW);
    delay(1000);
    Particle.process();

    Serial.println("WiFi.off()");
    WiFi.off();
    delay(10000);
    Particle.process();
  }

void connect() {
  WiFi.on();
  Particle.process();
  WiFi.connect();
  Particle.process();

  if (WiFi.ready() == false)
    {
      delay(100);
      Particle.process();
    }
  if (Particle.connected() == false)
    {
    Particle.connect();
    Particle.process();
    delay(100);
    }
  }

Have you tried waiting for ‘particle.connected’ to return true before continuing?

I believe that is what this part of my connect() function is doing. Is that not the case?

It looks like moving the Particle.connect command prior to the connected check solves the problem. See working code below.

Particle.connect();
Particle.process();

  if (Particle.connected() == false)
    {
    Particle.process();
    delay(100);
    }

To make it wait until it’s connected, you could use a while loop, since the if will trigger only once and move on.
You should be able to use this as well: https://docs.particle.io/reference/firmware/photon/#waiting-for-the-system

1 Like

There might be a misconception.
Particle.connect() starts to establish a connection, but will return before theconnection stands.
Particle.connected() on the other hand only checks if a cloud connection is already established.

Neither of both waits for a connection to be established.

So, no, your connect() function doesn't do what you expected.

You can use @Moors7's linked functions or by use of the above functions you'd need to do something like this

  if (!Particle.connected())
    Particle.connect();

  while(!Particle.connected()) Particle.process;

BTW, Particle.connect() does all the required WiFi.xxx() stuff (apart from WiFi.on()) implicitly, so no need to do all that yourself.

1 Like

Thanks for the clarification. I have implemented the following code:

void connect() {

  int elapsed;

  elapsed = millis();
  Serial.println("WiFi.on()");
  WiFi.on();
  Particle.process();

  if (WiFi.ready()) {
      Serial.println("WiFi Connected!");
    }
  else
    {
      Particle.process();
    }

  Serial.print("Elapsed time = ");
  Serial.println(millis() - elapsed);
  Particle.process();

  Serial.println("Particle.connect()");
  Particle.connect();
  Particle.process();

  Serial.println("Waiting for connection");
  waitUntil(Particle.connected);
  Particle.process();

  Serial.print("Elapsed time = ");
  Serial.println(millis() - elapsed);

  delay(500);
  Particle.process();
  }

What I have found is that anything less than a delay of 500 milliseconds leads to missing events in the cloud log. If I decrease to 450 I lose maybe 10% at 250 I lose 100%. I see that by default Particle.publish is a reliable connection with up to three retries. Is there a way to get an ack that it was not successful so that I can retry? I guess I could subscribe to the event and retry if I don’t receive the subscription, but that seems a little wonky.

Thanks for the help.

At the moment I’ve no way of doing that test myself (vacation :wink: ), but just a few more notes.

  WiFi.on();
  Particle.process();

  if (WiFi.ready()) {
      Serial.println("WiFi Connected!");
    }
  else
    {
      Particle.process();
    }

Similar to Particle.connected() WiFi.ready() is non-blocking and WiFi.on() doesn’t establish a WiFi connection, hence that part does not make a lot of sense.
If you want to set up a connection step-by-step, you’d do something like that

  if (!WiFi.ready())
  {
    WiFi.on();
    WiFi.connect();
    while(!WiFi.ready())  Particle.process();  // you could add a timeout and bail out or use waitFor()
    // one extra for internal processes
    Particle.process();
  }
  // now you should have an established connection and WiFi.localIP() should be valid

After that follows the cloud part as mentioned above.

As for the acknowledge of publishes, that’s a feature to come. But for the time being, self-subscribing is the only way to ensure the delivery of a publish.

BTW, how were you checking whether your event got published or not?

Strange. It was a few months ago, but when I did the tests for using an accelerometer to wake a Photon from sleep when shaken, I didn't wait at all before publishing and I'm pretty sure all of the publishes went through as I was actually looking for that as part of the testing.

As you can see as soon as Particle.connected() returns true, I did the publish. Now I did wait 4 seconds after that before disconnecting and sleeping; that may or may not be significant.

	case PUBLISH_STATE:
		if (Particle.connected()) {
			// The publish data contains 3 comma-separated values:
			// whether movement was detected (1) or not (0) The not detected publish is used for battery status updates
			// cell voltage (decimal)
			// state of charge (decimal)
			char data[32];
			float cellVoltage = batteryMonitor.getVCell();
			float stateOfCharge = batteryMonitor.getSoC();
			snprintf(data, sizeof(data), "%d,%.02f,%.02f", awake, cellVoltage, stateOfCharge);

			Particle.publish(eventName, data, 60, PRIVATE);

			// Wait for the publish to go out
			stateTime = millis();
			state = SLEEP_WAIT_STATE;
		}
		else {
			// Haven't come online yet
			if (millis() - stateTime >= MAX_TIME_TO_PUBLISH_MS) {
				// Took too long to publish, just go to sleep
				state = SLEEP_STATE;
			}
		}
		break;

Full code here:

Good point, I missed that WiFi.off() at the end of loop() that definetly impacts the publishes.
There are multiple threads that discuss that matter, that you have to allow for the publish to go through completely (without any real way of knowing how long that’ll take - aprox. avg. 4~5sec) before cutting the umbillical.

The delay(1000) after the last publish is definetly too short to get reliable publishes.

So it might rather be the premature disconnect than the actual connect that causes the confusion.

BTW, how were you checking whether your event got published or not?

I am watching the serial output on one screen and the cloud log on another.

Now I did wait 4 seconds after that before disconnecting and sleeping; that may or may not be significant.

That looks like my problem. I got rid of the delay before the publish and added a 5 second delay after and it seems to be stable and reliable.

As for the acknowledge of publishes, that's a feature to come.

I will look forward to that then!

Thanks for the help.

1 Like

Good to know you got it working now.

About the how you observe the publish

didn't realy answer what I wanted to know :wink: I actually meant if you looked at the Particle Dashboard/Console or the event stream direct via the API endpoint.
The former does happen to miss the odd event but the evenstream should show all.