Skip to end of metadata
Go to start of metadata

Learning Objectives

After completing this lesson, you will be able to do the following:

  • Explain what a pico subscription is
  • Understand pico-to-pico relationships based on subscriptions
  • Use the developer tools to manage pico subscriptions
  • Programmatically link picos using a subscription and have them interact. 

Prerequisites 

You should have already completed the following lessons:

Contents

Subscriptions

Subscriptions play an important role in building systems of picos. In Pico-Based Systems Lesson, you created child picos. If the parent-child relationship were the only one that existed, we could create hierarchies of picos, but not peer-to-peer systems of picos. Subscriptions allow us to establish relationships between any two picos. 

A subscription represents a relationship between two picos. It has a name and two channels, one from each pico participating in the subscription to the other. Each side in the subscription can be given a role to further identify the purpose of the subscription. 

Managing Subscriptions Programmatically

Wrangler provides functions, actions, and rules for managing subscriptions from within your KRL code.

In this section, we'll use a simple example. Here the owner pico has three child picos, as shown by the familiar black parent-child edges. However, let's say the "Mischief Pico" needs to communicate with the other two picos.

The subscriptions which we will create to enable this pico to pico communication are shown as dashed magenta lines. (This diagram is available at localhost:8080/?subscr )

Engine Compatibility

Very soon, the ability to manage subscriptions will be built-in to every pico. Right now, you will need to install the ruleset with RID "Subscriptions" into the three picos which will participate in subscriptions. This can be done in the Rulesets tab of each pico, by clicking on the "install ruleset" button beside the dropdown when it shows "Subscriptions".

The "Subscriptions" ruleset is automatically registered in the pico engine during start-up, because it exists (in a file named "io.picolabs.subscriptions.krl") in the folder name "krl". However, it is not automatically installed in any pico. Soon, it will be.

Since most of the heavy lifting is done by the Subscriptions ruleset, it is easy to initiate, approve, and use subscriptions inside of your own rulesets.

Prepare for this section by manually creating three child picos of your owner pico.

  1. Install this ruleset into your owner pico: https://raw.githubusercontent.com/Picolab/pico_lessons/master/subscriptions/mischief.owner.krl
  2. Install this ruleset into your Mischief pico: https://raw.githubusercontent.com/Picolab/pico_lessons/master/subscriptions/mischief.krl, and 
  3. Finally, install this ruleset into each of your thing picos: https://raw.githubusercontent.com/Picolab/pico_lessons/master/subscriptions/mischief.thing.krl

Initiating subscriptions by introduction

It is possible to initiate a subscription with a rule running in a pico which already has in its possession the ECI's of the two picos which need to be related by the subscription. Once you have set up the three child picos, Mischief, Thing1, and Thing2, and installed their respective rulesets, study the code and prepare for the introductions.

The owner pico already has all three of the other ECI's in its array of children (maintained by the io.picolabs.pico aka Wrangler ruleset), but it doesn't know which is which. So we added this rule to allow it to distinguish between the Mischief pico (which identifies itself by ECI) and the Thing1 and Thing2 picos.

  rule mischief_who {
    select when mischief who
    pre {
      mischief = event:attr("eci")
      things = wrangler:children().map(function(v){v.eci})
                                  .filter(function(v){v != mischief})
    }
    always {
      ent:mischief := mischief;
      ent:things := things
    }
  }

The ruleset for the Mischief pico sets up a button "mischief/identity" in that pico's Testing tab which will send this event to the owner pico. Navigate to the Testing tab of the Mischief pico and click the button. Doing so will send the event mischief:who to the owner pico, and that event will trigger the rule shown above. You can check the result of this calculation by looking at the entity variables held by the mischief.owner ruleset in the Rulesets tab of the Owner Pico.

Once the owner pico has all of the ECI's, the code to introduce the Mischief pico to each of the thing picos is straight-forward.

  rule mischief_subscriptions {
    select when mischief subscriptions
    pre {
      mischief = ent:mischief
      thing1 = ent:things[0]
      thing2 = ent:things[1]
    }
    if mischief && thing1 && thing2 then every {
      event:send(
        { "eci": mischief, "eid": "subscription",
          "domain": "wrangler", "type": "subscription",
          "attrs": { "name": "thing1",
                     "name_space": "mischief",
                     "my_role": "controller",
                     "subscriber_role": "thing",
                     "channel_type": "subscription",
                     "subscriber_eci": thing1 } } )
      event:send(
        { "eci": mischief, "eid": "subscription",
          "domain": "wrangler", "type": "subscription",
          "attrs": { "name": "thing2",
                     "name_space": "mischief",
                     "my_role": "controller",
                     "subscriber_role": "thing",
                     "channel_type": "subscription",
                     "subscriber_eci": thing2 } } )
    }
  }

The ruleset also sets up a button in the owner pico's Testing tab, "mischief/subscriptions" to send the event that causes this rule to evaluate. Navigate to the Testing tab for the Owner Pico to click on this button.

The final step is that a rule selecting on wrangler/inbound_pending_subscription_added is in each of the thing picos (the ruleset mischief.thing), and this will complete the subscription process. You can see the results by refreshing the UI and navigating to the Subscriptions tab for any of the picos involved in one of the two subscriptions.

Initiating subscriptions by direct request

A pico can directly initiate a subscription. The subscription is initiated by a rule installed in the pico raising the wrangler:subscription event in the postlude block of one of its rules.

      raise wrangler event "subscription"
          with name = "thing1"
               name_space = "mischief"
               my_role = "controller"
               subscriber_role = "thing"
               channel_type = "subscription"
               subscriber_eci = thing1

As in the case of introductions, the target pico must have a rule selecting on wrangler/inbound_pending_subscription_added which will complete the subscription process by raising the wrangler/pending_subscription_approval event.

Writing rules that use subscriptions

Suppose that we wanted the Mischief pico to respond to a mischief/hat_lifted event and send the same event to all of the thing picos that it controls. Assuming that you have arranged to use Subscriptions as a module in the meta block, as in

  use module Subscriptions

a rule like this one would accomplish this:

  rule mischief_hat_lifted {
    select when mischief hat_lifted
    foreach Subscriptions:getSubscriptions() setting (subscription)
      pre {
        subs_attrs = subscription{"attributes"}
      }
      if subs_attrs{"subscriber_role"} == "thing" then
        event:send(
          { "eci": subs_attrs{"outbound_eci"}, "eid": "hat-lifted",
            "domain": "mischief", "type": "hat_lifted" }
        )
  }

Notice that the rule evaluates for each of the subscriptions. It only acts for those subscriptions with a subscriber_role of "thing", and is able to reach that pico through the outbound_eci which was established when the subscription was accepted.

Deleting subscriptions


Engine Compatibility

Very soon, Wrangler will fully integrate subscriptions, so that when you delete a child pico any subscriptions it participates in will also be deleted. In the meantime, you may wish to programmatically delete such subscriptions before requesting the deletion of the child pico.

To delete a subscription, either of the picos which participate in the subscription would raise the event wrangler/subscription_cancellation including an attribute named "subscription_name" whose value is the subscription name_space concatenated with a colon and the subscription name. For example, if the Thing2 pico wanted to cancel its subscription, it might include this code in the postlude of one of its rules.

    raise wrangler event "subscription_cancellation"
      with subscription_name = "mischief:thing2"

The raised event triggers a rule in the Subscriptions ruleset. This rule takes care of deleting both sides of the subscription.

Managing Subscriptions Manually

We showed above how to write KRL code to initiate a subscription. Here, we will create a subscription manually (using a RESTful interface such as the Postman REST client, or curl, or the browser–in this example we'll use the browser).

Prepare a URL like this one in your browser (the line breaks shown here are for readability–your URL will not contain line breaks):

http://localhost:8080/sky/event/cj0dea39q0001khpqy4su0ru3/subscr/wrangler/subscription?
name=thing1&
name_space=mischief&
my_role=controller&
subscriber_role=thing&
channel_type=subscription&
attrs=&
subscriber_eci=cj0dea81g0003khpqy7j9knqz

Your URL will be different because the ECI to which the event is sent (in the example, cj0dea39q0001khpqy4su0ru3) needs to be replaced by the main ECI of your Mischief Pico, and the subscriber_eci parameter needs to indicate the ECI of your Thing1 Pico.

A subscription has a name within a name_space, and we indicate the role that the picos involved in the subscription will each play (my_role and subscriber_role).

When you visit this URL, the wrangler/subscription event will be sent to the Mischief Pico and the subscription will be created. This will result in each of the two picos involved having a subscription. Each of them will also have a new channel, especially created for use with the subscription. Here is the new channel created for the Thing1 pico:

Repeat the process for the Thing2 pico.

Listing Subscriptions

If we were now to query the Mischief Pico to see its subscriptions, using a URL like

http://localhost:8080/sky/cloud/cj0dea39q0001khpqy4su0ru3/Subscriptions/getSubscriptions

we would see that it participates in two subscriptions:

{
  "mischief:thing1": {
    "eci": "cj0deky300006khpqn7ucdvhj",
    "name": "mischief:thing1",
    "type": "subscription",
    "attributes": {
      "subscription_name": "thing1",
      "name_space": "mischief",
      "relationship": "controller<->thing",
      "my_role": "controller",
      "subscriber_role": "thing",
      "subscriber_eci": "cj0dea81g0003khpqy7j9knqz",
      "status": "outbound",
      "attributes": ""
    }
  },
  "mischief:thing2": {
    "eci": "cj0devoqc0008khpqenjg11xc",
    "name": "mischief:thing2",
    "type": "subscription",
    "attributes": {
      "subscription_name": "thing2",
      "name_space": "mischief",
      "relationship": "controller<->thing",
      "my_role": "controller",
      "subscriber_role": "thing",
      "subscriber_eci": "cj0deacyn0005khpq8q0qk080",
      "status": "outbound",
      "attributes": ""
    }
  }
}

Similarly, the Thing1 Pico participates in just one subscription. Doing the same sky/cloud query to its ECI will show something like this:

{
  "mischief:thing1": {
    "eci": "cj0deky3l0007khpqdmo4037y",
    "name": "mischief:thing1",
    "type": "subscription",
    "attributes": {
      "subscription_name": "thing1",
      "name_space": "mischief",
      "relationship": "thing<->controller",
      "my_role": "thing",
      "subscriber_role": "controller",
      "outbound_eci": "cj0deky300006khpqn7ucdvhj",
      "status": "inbound",
      "attributes": ""
    }
  }
}

Accepting Subscriptions

There is one step remaining in the subscription process. Just because one pico offers a subscription to another pico doesn't mean that target pico is forced to accept it. This is manifest by the "status" of the subscriptions. For the originating pico, the status is "outbound" (short for outbound, pending), and for the other pico, the status is "inbound" (i.e. inbound, pending).

In fact, after the pending subscriptions were created, the Subscriptions rule for wrangler/subscription raises the wrangler event "inbound_pending_subscription_added" passing along all of the attributes. It is up to your pico to react by either accepting or rejecting. This cookbook example shows how to write a rule that auto-approves subscriptions.

This shows the event attributes associated with the event wrangler:inbound_pending_subscription_added:

{ name_space: 'mischief',
  relationship: 'thing<->controller',
  my_role: 'thing', 
  subscriber_role: 'controller',
  outbound_eci: 'cj0lk0my70009widdmk6bbnsk',
  status: 'inbound',
  channel_type: 'subscription',
  channel_name: 'mischief:thing2',
  attributes: 'status',  
  name: thing2 }

Generally, promiscuously approving pending subscriptions is a security risk, so most auto-approvals take place where something about the subscription requestor can be verified. For example, a child might be programmed to automatically approve subscription requests from its parent, after checking that the invitation came in on a channel that can be verified as being from the parent.

For now, to complete the manual process, we will send this event to the Thing1 pico (line break added for readability–your URL will be all in one line):

http://localhost:8080/sky/event/cj0deky3l0007khpqdmo4037y/approve/wrangler/pending_subscription_approval?
subscription_name=mischief:thing1

Checking the Thing1 pico again, you will see that its one subscription now has the the status of "subscribed". At the same time, that subscription in the Mischief pico also now has the status of "subscribed".

Deleting Subscriptions

You can cancel a subscription manually by sending an event to either of the picos involved in the subscription, in this example, the Thing1 pico.

http://localhost:8080/sky/event/cj0deky3l0007khpqdmo4037y/del/wrangler/subscription_cancellation?
subscription_name=mischief:thing1



Endnotes

This page is inspired by (and often copied verbatim from) the original fourth lesson, (Classic) Lesson: Pico to Pico Subscriptions.


  • No labels