Filter results by

Send Actions to Remote Devices

Most of our posts so far have talked about storing and reading messages in ARTIK Cloud. Today I’d like to give you an introduction to what we call “Actions”, a way that a device can send a command to another device.

Defining which Actions a device supports

The first step is to update your Advanced Manifest and define which Actions your device type supports. The simplest example is for a smart light to support being turned on and off.

We start by implementing the “Actionable” interface in our Manifest like this:

public class MySmartLightManifest implements Manifest, Actionable {

Next we want to define all the Actions supported. I usually add this at the bottom of my Manifest:

1 @Override
2 List<Action> getActions() {
3   return [
4     new Action("setOn", "Sets the light state to On"),
5     new Action("setOff", "Sets the light state to Off"),
6     new Action("setIntensity", "Changes the intensity of the light (value in percent)",
7         INTENSITY)
8 	]
9 }

Notice how the first two Actions only have two parameters while the third has three. The first parameter is the name of the Action; the second is a description. Any further parameter is passed to the destination device. In my case I want to set the INTENSITY of the light as a number from 1 to 100. I could also pass the color or any other parameter I define. This gives you either the simplicity of a command that has only one possible execution (turning the light on) or the flexibility of parameters.

Our documentation has more information on how to define Actions in Manifests.

Sending an Action

Devices and applications can start sending Actions as soon as the new Manifest is approved. Sending an Action is as simple as sending a message to ARTIK Cloud with a couple more parameters.

When you are sending a regular message to ARTIK Cloud, your request will look something like this:

{
  "sdid": "HIuh2378jh",
  "ts": 1388179812427,
  "type": "message",
  "data": [payload]
}

With Actions it’s not different. What we want to do is specify a destination device ID (parameter ddid) and the Action. We will also change the type to “action”. An Action to turn my light on will look like this:

{
  "ddid": "9f06411ad3174a4f98444a374447fe10",
  "ts": 1388179812427,
  "type": "action",
  "data": {
    "actions": [
      {
        "name": "setOn",
        "parameters": {}
      }
    ]
  }
}

Since the “setOn” Action doesn’t expect any parameter we will define parameters as an empty object.

We can send multiple Actions in a single message as follows:

"actions": [
  {
    "name": "setOn",
    "parameters": {}
  },
  {
    "name": "setColorAsRGB",
    "parameters": {
      "colorRGB": {
        "r": 192,
        "g": 180,
        "b": 45
      },
      "intensity": 55
    }
  }
]

We briefly covered how to send Actions to a device from an Android app in Making the Perfect Remote Control in Five Steps.

And if you feel thorough you can read our documentation on Posting a message with Actions.

Discovering Actions

Remember how each Action in my Manifest also had a description? I suggest that when you create your Manifest you think this through, because it’s going to be handy to many people if you publish your device type. At any time you can query the ARTIK Cloud API to get the latest Manifest properties and return a full list of supported Actions. FWIW you can query for any Manifest version, but I like to work on the latest and greatest (more on this in our API spec).

If you want to look at a device type that we created and that supports Actions, I suggest you try the “SAMI Example Smart Light”. You can go to My ARTIK Cloud, create a device of this type for your user and start sending Actions to it.

Anyway, execute this GET:

https://api.artik.cloud/v1.1/devicetypes/dt71c282d4fad94a69b22fa6d1e449fbbb/manifests/latest/properties

And here is a shortened version of the response:

 1 {
 2   "data": {
 3     "properties": {
 4       "fields": {
 5         "colorRGB": {
 6           "b": {
 7             "type": "Integer",
 8             "unit": "",
 9             "isCollection": false,
10             "description": "blue component"
11           },
12           "g": {
13             "type": "Integer",
14             "unit": "",
15             "isCollection": false,
16             "description": "green component"
17           },
18           "r": {
19             "type": "Integer",
20             "unit": "",
21             "isCollection": false,
22             "description": "red component"
23           }
24         }
25       }
26     },
27     "actions": {
28       "setColorAsRGB": {
29         "description": "Changes the light color with RGB values and set the intensity (value in percent)",
30         "parameters": {
31           "colorRGB": {
32             "b": {
33               "type": "Integer",
34               "unit": "",
35               "isCollection": false,
36               "description": "blue component"
37             },
38             "g": {
39               "type": "Integer",
40               "unit": "",
41               "isCollection": false,
42               "description": "green component"
43             },
44             "r": {
45               "type": "Integer",
46               "unit": "",
47               "isCollection": false,
48               "description": "red component"
49             }
50           }
51         }
52       }
53     }
54   }
55 }

If you are building an application like our remote control, this is how you can programmatically explore the device types that the user has and what each is capable of.

Receiving Actions

Actions are meant as a command that a device sends to another device for execution in near-real-time. My recommendation is that for any device type that you created that can receive Actions, you keep it connected to ARTIK Cloud using WebSockets. When ARTIK Cloud receives a new Action it tries to deliver it immediately to the destination device via WebSocket; if it fails it will NOT retry. ARTIK Cloud provides two endpoints for WebSockets; for Actions you should use the device channel WebSocket. Once your device is connected to /websocket it will receive the Action as soon as ARTIK Cloud processes it.

Also note that when a device sends an Action to ARTIK Cloud, ARTIK Cloud will confirm receipt of the Action, but it will not confirm delivery to the destination device. This is something left to you to implement.

Confirming that a device received an Action

Since ARTIK Cloud does not automatically confirm to the source device that an Action was delivered, you should implement the proper functionality in both your device and Manifest to provide a meaningful way to confirm you received and executed on the Action.

In my example, I created a smart light that can receive a few commands including turning it on and off. It is good practice that you define your Manifest so that it has a way to keep track of the current status. In my case, because of lack of creativity, I am calling it state. Since I have the device-channel WebSocket open it’s very easy to set a new status right away. It will be the responsibility of the device that originated the Action to check the updated status and act consequently.

My Manifest that supports Actions, state, intensity and color looks like this:

 1 import com.samsung.sami.manifest.Manifest
 2 import com.samsung.sami.manifest.actions.*
 3 import com.samsung.sami.manifest.fields.*
 4 import groovy.json.JsonSlurper
 5 import javax.measure.unit.SI
 6  
 7 public class PhillipsHueManifest implements Manifest, Actionable {
 8     public final static FieldDescriptor STATE = new FieldDescriptor("state", String.class);
 9     public final static FieldDescriptor INTENSITY = new FieldDescriptor("intensity", Integer.class);
10     public final static FieldDescriptor COLOR_AS_RGB = new FieldDescriptor("colorRGB",
11         COLOR_RED_COMPONENT, COLOR_GREEN_COMPONENT, COLOR_BLUE_COMPONENT);
12  
13     @Override
14     List<Field> normalize(String input) {
15         def slurper = new JsonSlurper()
16         def json = slurper.parseText(input)
17         return [
18             new Field(STATE, json.status.state.on ? "on" : "off")
19             // ... more parsing can be done here to return color and intensity states
20         ]
21     }
22     @Override
23     List<FieldDescriptor> getFieldDescriptors() {
24         return [STATE, COLOR_AS_RGB, INTENSITY]
25     }
26     @Override
27     List<Action> getActions() {
28         return [
29             new Action("setOn", "Sets the light state to On"),
30             new Action("setOff", "Sets the light state to Off"),
31             new Action("toggle", "Toggle between On and Off states"),
32             new Action("setIntensity", "Changes the intensity of the hue light (value in percent)",
33                     INTENSITY),
34             new Action("setColorAsRGB", "Changes the light color with RGB values and set the intensity (value in percent)",
35                     COLOR_AS_RGB, INTENSITY)
36         ]
37     }
38 }