Cloud functions

Particle.publish()

Particle.publish, publish

Publish an event through the Particle Device Cloud that will be forwarded to all registered listeners, such as callbacks, subscribed streams of Server-Sent Events, and other devices listening via Particle.subscribe().

This feature allows the device to generate an event based on a condition. For example, you could connect a motion sensor to the device and have the device generate an event whenever motion is detected.

Particle.publish pushes the value out of the device at a time controlled by the device firmware. Particle.variable allows the value to be pulled from the device when requested from the cloud side.

Cloud events have the following properties:

  • name (1–64 ASCII characters)

Note: Only use letters, numbers, underscores, dashes and slashes in event names. Spaces and special characters may be escaped by different tools and libraries causing unexpected results.

  • optional data. The data has a maximum size of 255 to 1024 bytes of UTF-8 characters; see API Field Limits as the limit varies depending on Device OS version and sometimes the device.

A device may not publish events beginning with a case-insensitive match for "spark". Such events are reserved for officially curated data originating from the Cloud.

Calling Particle.publish() when the cloud connection has been turned off will not publish an event. This is indicated by the return success code of false.

If the cloud connection is turned on and trying to connect to the cloud unsuccessfully, Particle.publish() may block for up to 20 seconds (normal conditions) to 10 minutes (unusual conditions). Checking Particle.connected() can before calling Particle.publish() can help prevent this.

String variables must be UTF-8 encoded. You cannot send arbitrary binary data or other character sets like ISO-8859-1. If you need to send binary data you can use a text-based encoding like Base64.

NOTE 1: Currently, a device can publish at rate of about 1 event/sec, with bursts of up to 4 allowed in 1 second. Back to back burst of 4 messages will take 4 seconds to recover.

NOTE 2: Particle.publish() and the Particle.subscribe() handler(s) share the same buffer. As such, calling Particle.publish() within a Particle.subscribe() handler will overwrite the subscribe buffer, corrupting the data! In these cases, copying the subscribe buffer's content to a separate char buffer prior to calling Particle.publish() is recommended.

NOTE 3: Public events are not supported by the cloud as of August 2020. Specifying PUBLIC or leaving out the publish scope essentially results in a private event.

For non-product devices, events published by a device can be subscribed to:

  • By other devices claimed to the same account
  • By webhooks for the user the device is claimed to
  • By the SSE event stream for the user the device is claimed to

For product devices, events published by a device can be subscribed to:

  • By other devices claimed to the same account, if the device is claimed
  • By webhooks for the user the device is claimed to, if the device is claimed
  • By the SSE event stream for the user the device is claimed to, if the device is claimed
  • By product webhooks for the product the device is associated with, whether or not the device is claimed
  • By the SSE event stream for the product the device is associated with, whether or not the device is claimed

Public events could previously be received by anyone on the Internet, and anyone could generate events to send to your devices. This did not turn out to a common use-case, and the ease at which you could accidentally use this mode, creating a security hole, caused it to be removed.

Each publish uses one Data Operation from your monthly or yearly quota. This is true for both WITH_ACK and NO_ACK modes.

  • Publishes are not end-to-end confirmed. Even if the Particle.publish returns true, there is no guarantee that any recipient (another device, webhook, or SSE) will receive it.
  • It is possible to receive an event more than once. The most common reason is a lost ACK, which will cause the device to send the event again. Storing a unique identifier in the event payload may help code defensively for this possibility.
  • It is possible that events will arrive out-of-order. The most common cause is retransmission, but it can also occur because events can flow through different redundant servers, each with slightly difference latency, so it's possible that two event sent rapidly will arrive out-of-order as well. This is common for multi-part webhook responses.
  • It is possible that even if Particle.publish returns false, the event will still be received by the cloud later. This occurs because the 20-second timeout is reached, so false is returned, but the event is still buffered in Device OS and will be retransmitted if the reconnection to the cloud succeeds.

Publish an event with the given name and no data.

// SYNTAX
Particle.publish(const char *eventName, PublishFlags flags);
Particle.publish(String eventName, PublishFlags flags);

Returns: A bool indicating success: (true or false)

// EXAMPLE USAGE
bool success;
success = Particle.publish("motion-detected");
if (!success) {
  // get here if event publish did not work
}

// EXAMPLE USAGE - This format is no longer necessary
// PRIVATE is the default and only option now
bool success;
success = Particle.publish("motion-detected", PRIVATE);
if (!success) {
  // get here if event publish did not work
}

// PROTOTYPES
particle::Future<bool> publish(const char* name);
particle::Future<bool> publish(const char* name, const char* data);

// EXAMPLE USAGE 1
Particle.publish("temperature", "19");

// EXAMPLE USAGE 2
int temp = 19;
Particle.publish("temperature", String(temp));

// EXAMPLE USAGE 3
float temp = 19.5;
Particle.publish("temperature", String::format("%.1f", temp);

Publish an event with the given name and data.

The data must be a string in the ASCII or UTF-8 character set. If you have an integer or floating point value, you'll need to convert it to a string first.

You cannot publish binary data with Particle.publish. To send binary data, convert it to a string using hex or Base 64 encoding.

While Base85 (Ascii85) provides a more dense encoding than Base64, it is not recommended if you are publishing data to be sent to an external server by a webhook. The Base85 alphabet includes the left curly bracket, and the {{ sequence is recognized as a mustache template delimiter during webhook processing, causing the data to be corrupted. The backslash can also cause unexpected data transformation.


// EXAMPLE - Check if event was queued for publishing successfully
float temp = 19.5;
bool success = Particle.publish("temperature", String::format("%.1f", temp);

// EXAMPLE - Check if event was queued for publishing successfully
float temp = 19.5;
bool success = Particle.publish("temperature", String::format("%.1f", temp);

Normally, you store or test the result of Particle.publish in a bool variable that indicates that the event was queued for publishing successfully, or reached the cloud, when used with WITH_ACK.

But what is the particle::Future<bool> in the prototype above? See the application note AN009 Firmware Examples for how to use a Future to make the otherwise synchronous Particle.publish() call asynchronous.


COMPLEMENTARY API CALL
GET /v1/events/{EVENT_NAME}

# EXAMPLE REQUEST
curl -H "Authorization: Bearer {ACCESS_TOKEN_GOES_HERE}" \
    https://api.particle.io/v1/events/motion-detected

# Will return a stream that echoes text when your event is published
event: motion-detected
data: {"data":"23:23:44","ttl":"60","published_at":"2014-05-28T19:20:34.638Z","deviceid":"0123456789abcdef"}

Cellular Devices (B-Series SoM, Tracker SoM, Tracker One, Boron, E404X, E-Series, and Electron):

// PROTOTYPES
particle::Future<bool> publish(const char* name, PublishFlags flags1, PublishFlags flags2 = PublishFlags());
particle::Future<bool> publish(const char* name, const char* data, PublishFlags flags1, PublishFlags flags2 = PublishFlags());

// SYNTAX

float temperature = sensor.readTemperature();  // by way of example, not part of the API
Particle.publish("t", String::format("%.2f",temperature), NO_ACK);  // make sure to convert to const char * or String

On Gen 2 cellular devices (Electron, E-Series) and all Gen 3 devices (Argon, Boron, B-Series SoM, Tracker SoM, E404X):

NO_ACK flag

Unless specified otherwise, events sent to the cloud are sent as a reliable message. The device waits for acknowledgement from the cloud that the event has been received, resending the event in the background up to 3 times before giving up.

The NO_ACK flag disables this acknowledge/retry behavior and sends the event only once. This reduces data consumption per event, with the possibility that the event may not reach the cloud.

For example, the NO_ACK flag could be useful when many events are sent (such as sensor readings) and the occasional lost event can be tolerated.


// SYNTAX
bool success = Particle.publish("motion-detected", NULL, WITH_ACK);

// No longer necessary, PRIVATE is always used even when not specified
bool success = Particle.publish("motion-detected", NULL, PRIVATE, WITH_ACK);

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.

If you do not use WITH_ACK then the request is still acknowledged internally, and retransmission attempted up to 3 times, but Particle.publish() will return more quickly.


Since 0.7.0:

// EXAMPLE - combining Particle.publish() flags
// No longer necessary, PRIVATE is always used even when not specified
Particle.publish("motion-detected", PRIVATE | WITH_ACK);

Particle.publish() flags can be combined using a regular syntax with OR operator (|).


For products, it's possible receive product events sent by devices using webhooks or the Server-Sent-Events (SSE) data stream.


// SYNTAX - DEPRECATED
Particle.publish(const char *eventName, const char *data, int ttl, PublishFlags flags);
Particle.publish(String eventName, String data, int ttl, PublishFlags flags);

Previously, there were overloads with a ttl (time-to-live) value. These have been deprecated as the ttl has never been supported by the Particle cloud. All events expire immediately if not subscribed to or exported from the Particle cloud using a webhook, integration like Google cloud, or the server-sent-events (SSE) stream.

Even if you use NO_ACK mode and do not check the result code from Particle.publish() it is possible that the call will still block for an indeterminate amount of time, possibly for as long as 10 minutes. This can occur if you publish while in the process of attempting to reconnect to the network. At a minimum, you should make sure that Particle.connected() returns true before publishing. Doing publish operations from a separate worker thread is another option.