Paired Devices & Sharing Events (on the same Particle Account)

Table of contents

  1. Code Template

The example below allows you to use the same code to control two or more identical devices on the same Particle user account.

Devices not the same account?

This template assumes that both of your devices are on the same Particle account. It will not work for two devices that are on separate accounts. Why? Particle’s event models are now private. This means that a published event will only be visible to other devices on the same user account group. They are not accessible by other devices. If you are interested in networking devices that are on different accounts, see the Webhooks section.

As Particle.subscribe allows you to partially match an event name we can take advantage of this here. We determine a short event name in this case diot/2019/paired/. Before sending the event we use a method System.deviceID() to look up the unique ID of the device and append that to the end of the shared event name, giving us: diot/2019/paired/12345678

So:

  • device 1 has an id of 1356AD342394810293 will trigger an event diot/2019/paired/1356AD342394810293
  • device 2 has an id of 324234AD324B2312AE will trigger an event diot/2019/paired/324234AD324B2312AE

We’ll set up a subscribe method (Particle.subscribe("diot/2019/paired/") ) that will catch events from all devices. This means we’ll receive events published from all other devices as well as the device that published it

We need a way to filter our the events from the current device. We do this by taking advantage of the information received by our handler void handleSharedEvent(const char *event, const char *data). Our handler gets both the event name and the data from the event. Using the event name (event), we can check to see if the event name contains the ID of our device and ignore any events that contain the ID of the current device

For example,

  • device 1 (1356AD342394810293) receives an event diot/2019/paired/1356AD342394810293 - we want to ignore it
  • device 2 (324234AD324B2312AE) receives an event diot/2019/paired/1356AD342394810293 - we want to respond to it
  • device 1 (1356AD342394810293) receives an event diot/2019/paired/324234AD324B2312AE - we want to respond to it
  • device 2 (324234AD324B2312AE) receives an event diot/2019/paired/324234AD324B2312AE - we want to ignore it

We do this by using a method in the String class called indexOf(). This allows us to search any string for the contents of another String. If it’s present it’ll return the position of the first instance of that string, and if not it’ll return -1

e.g.

String str = "particle"
str.indexOf("r") // returns 2
str.indexOf("t") // returns 4
str.indexOf("5") // returns -1
str.indexOf("34534") // returns -1

This is implemented in the sample code below.

Code Template


// This value will store the last time we published an event
long lastPublishedAt = 0;
// this is the time delay before we should publish a new event
// from this device
int publishAfter = 10000;

void setup()
{

  // We'll want to subscribe to an event thats fairly unique

  // From the Particle Docs
  // A subscription works like a prefix filter.
  // If you subscribe to "foo", you will receive any event
  // whose name begins with "foo", including "foo", "fool",
  // "foobar", and "food/indian/sweet-curry-beans".

  // Basically this will match any event that starts with 'db2018/paired/'
  // This is a feature we'll useto figure out if our event comes from
  // this device or another (see publishMyEvent below)

  Particle.subscribe(  "diot/2019/paired/" , handleSharedEvent );

}

void loop()
{
    // publish my event
    // you'll want some more complex stuff here
    publishMyEvent();

    // delay for a bit
    delay(100);
}


void publishMyEvent()
{
  // Remember that 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.
  // So we want to limit the amount of publish events that happen.

  // check that it's been 10 secondds since our last publish
  if( lastPublishedAt + publishAfter < millis() )
  {
      // Remember our subscribe is matching  "db2018/paired/"
      // We'll append the device id to get more specific
      // about where the event came from

      // System.deviceID() provides an easy way to extract the device
      // ID of your device. It returns a String object of the device ID,
      // which is used to identify your device.

      String eventName = "diot/2019/paired/" + System.deviceID();

      // now we have something like "diot/2019/paired/0123456789abcdef"
      // and that corresponds to this devices info

      // then we share it out
      Particle.publish( eventName, "data goes here" );

      // And this will get shared out to all devices using this code

      // we just pubished so capture this.
      lastPublishedAt = millis();
  }

}

// Our event handlde requires two bits of information
// This gives us:
// A character array that consists of the event name
// A character array that contains the data published in the event we're responding to.
void handleSharedEvent(const char *event, const char *data)
{
    // Now we're getting ALL events published using "db2018/paired/"
    // This includes events from this device.
    // So we need to ignore any events that we sent.

    // Let's check the event name
    String eventName = String( event ); // convert to a string object
    // This gives us access to a bunch of built in methods
    // Like indexOf()
    // Locates a character or String within another String.
    // By default, searches from the beginning of the String,
    // but can also start from a given index,
    // allowing for the locating of all instances of the character or String.
    // It Returns: The index of val within the String, or -1 if not found.

    // We can use this to check if our event name contains the
    // id of this device

    String deviceID = System.deviceID();

    // device id = 0123456789abcdef
    // event = "diot/2019/paired/0123456789abcdef"

    if( eventName.indexOf( deviceID ) != -1 ){
      // if we get anything other than -1
      // the event came from this device.
      // so stop doing stuff
      return;
    }

    // otherwise do your stuff to respond to
    // the paired device here

    //motorOn = true;

}