Particle publish with WITH_ACK not working properly?

hello,

to save battery we want the photon to deep sleep as much as possible. the 0.6.1 Particle.publish option WITH_ACK should finish the publish before returning according the documentation. but the code below does not publish anything (most of the time, on occasion it will publish). only when i add back the 3 seconds delay it will consistently publish the event.

we do see the publish taking much longer (> 100 ms) with the WITH_ACK compared to without (< 10 ms).

are we doing something wrong? what more do we need to “flush” the publish?

thanks,
frank

void setup() {

   pinMode(D7, OUTPUT);

   digitalWrite(D7, HIGH);

   Particle.publish("myEvent","myValue",WITH_ACK);

   // delay(3000);

   digitalWrite(D7, LOW);

   System.sleep(SLEEP_MODE_DEEP, 60);

}

void loop() {
    
}
1 Like

This is the respective GitHub issue for that which is currently slated for 0.7.0

hi scruffr,

i saw that thread but it was not very clear to me what issue would be resolved in 0.7.0

the documentation says:

_WITH_ACK flag_

Since 0.6.1

This flag causes Particle.publish() to return only after receiving an acknowledgement that the published event has been received by the Cloud.

and that clearly does not work

so is a 3 sec delay really the only way to make sure all events are published?

thanks
frank

Currently that’s the easiest workaround.

okay, thanks!

Is there still no fix for this issue? WITH_ACK seems to have no effect whatever on my Photon. I still have to wait 5 seconds after everything is done before going to sleep. Which is absurd.

What device os version?

Photon 1.1.0

I just had a similar experience with Mesh devices (running 1.1.0 and 1.2.1-rc.2)

Hence I would renew my assessment given back in May 2018 that the issue was closed prematurely.
@BDub, although tagged back then there was no further comment from Particle’s side in the issue linked above (#1165).

1 Like

Particle.publish returns a “future” bool and doesn’t actually block until the return value is accessed. Something like the following will result in expected blocking behavior without requiring explicit/arbitrary delays.

bool rval = Particle.publish(...);
if(!rval)
{
  Log.info("an error!");
}

Documentation could definitely be updated for clarity…

Is that also the case for WITH_ACK.

Then it would also be good to get a cross-reference to any of the functions that could potentially "harm" the functionality (e.g. WiFi.off(), Mesh.off(), System.sleep(), ...) and samples how to deal with them.

See this discussion

I also tried WITH_ACK (instead of delay()) to prevent Mesh.off() from cutting the connection before the event was sent, but that didn't help.
How would one go about this?

When saving result to a bool the block happens immediately on the publish (before checking result) as an effect of finalizing the future into the bool variable.

When saving the publish result as a future the block doesn’t happen until the result is explicitly extracted.

When dropping the publish result (not saving anywhere) it does not block at all.

I didn’t test on behavior if saved to a bool variable but not used so could be optimized away.

Cases that didn’t immediately block on response still took ~150ms to begin the publish on system thread and return back.

#include "Particle.h"

SerialLogHandler logHandler(Serial, LOG_LEVEL_TRACE);

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

void setup() {
  waitUntil(Serial.isConnected);
  Particle.connect();
  waitUntil(Particle.connected);
  Log.info("connected!");
  // cloud might still be dealing with describe so wait a little
  delay(5000);
}

void loop() {
  static bool run_once = true;

  if(run_once)
  {
    run_once = false;
    
    Log.info("WITH_ACK save bool begin");
    bool bool_result = Particle.publish("test_event", "test_data", PRIVATE, WITH_ACK);
    Log.info("WITH_ACK save bool after");
    if(bool_result)
    {
      Log.info("WITH_ACK check result success");
    }
    else
    {
      Log.info("WITH_ACK check result error");
    }

    Log.info("WITH_ACK save future begin");
    auto future_result = Particle.publish("test_event", "test_data", PRIVATE, WITH_ACK);
    Log.info("WITH_ACK save future after");
    if(future_result.result())
    {
      Log.info("WITH_ACK check result success");
    }
    else
    {
      Log.info("WITH_ACK check result error");
    }

    Log.info("WITH_ACK no bool begin");
    Particle.publish("test_event", "test_data", PRIVATE, WITH_ACK);
    Log.info("WITH_ACK no bool after");
  }
}
3 Likes

I have a couple questions:

  1. Since this issue affects Mesh endpoints ability to publish, wouldn't it be wise for @will to add it to the list of Gen 3 known issues? Maybe we can get a top-down approach addressing the problem (or at least documenting it).

  2. Would using waitUntil or waitFor along with a bool test successfully block until the publish is complete?

I'm just not clear on how I can check the truthiness of Particle.publish if it returns a future bool and I want to have code that runs contingent on the outcome of its success (such as turning off the radio).

Do I need to save the bool first, then run something like a waitUntil? From what @joel is describing, if Particle.publish is not immediately checked it will not block, and waitUntil may not return until the future event has complete and thus is unable to block if used alone. So something like this:

Mesh.connect();  
bool rval = Particle.publish("test_event", "test_data", PRIVATE, WITH_ACK);
if(!rval) {
 waitUntil(rval);
}
Mesh.off();  

If you write the result into a (classic) bool the assignment causes the blocking and the following if statement is executed after the fact.

If you use a “future bool” by using auto instead of bool you can execute some code between the assignment and the value check. If the value is already present by the time your “in-between code” was executed not further blocking will occure, but if the “in-between” was faster the blocking will occure at the check, till the value materialises.

BTW, waitUntil() does not take a boolean as input parameter but a function pointer to a function that returns a bool and takes no parameters.
e.g taking waitUntil(Particle.connected) means to “repeatedly” execute the function and wait for it to change from known false to known true.
But with Particle.publish() it’s a different situation - there you start of with “not yet known” to true or false respectively - waitUntil()/waitFor() are not meant for such a scenario.

Well said.

The Future has its own API that can be explicitly called to check the status in a non-blocking fashion. You also don’t need to use auto, just more convenient than explicitly naming the return type.

particle::Future<bool> rval = Particle.publish(...);
while(!rval.isDone())
{
  // do some things...
}
if(rval.isSucceeded())
{
  Log.info("success!");
}

So something like waitFor(rval.isDone) would work though not sure where it might be useful.

One caveat, the implicit blocking behaviors only work from main application thread. Publishing from another thread requires use of the future API directly. @rickkas7 has an example in his async publish library https://github.com/rickkas7/PublishQueueAsyncRK/blob/5fd90b92255c833d91e7be72821a7cbb9dae535d/src/PublishQueueAsyncRK.cpp#L249.

2 Likes

I see what you mean.
I’m still not sure how (or if) I can use WITH_ACK to verify a publish has successfully completed prior to calling Mesh.off(), and thus avoiding a premature disconnect.

You just have to check the return value coming out of the Particle.publish in some fashion. You can do so in a blocking fashion (by accessing it as a standard bool) or in a non-blocking fashion (by accessing it via the underlying Future).

See code snippets already posted in this thread for examples of both methods. Choose one and adapt as necessary to your code.

2 Likes