Introduction


Devices can send events and receive commands, either via HTTP or MQTT. This document will focus on events/commands communication via HTTP requests.

For details on device events/commands via MQTT, please see this article.

Beside events and commands, communication between devices and the MODE Cloud can be done via Device Data Proxy. For details, please see this article.

Sending Events


To send an event from a device, simply make a PUT request to the /devices/_DEVICE_ID_/event endpoint. For example:

$ curl -XPUT -i -N -H "Authorization: ModeCloud _YOUR_API_KEY_" -H "Content-Type: application/json" --data "{ \"eventType\": \"foo\",  \"eventData\": {} }"  https://api.tinkermode.com/devices/_DEVICE_ID_/event

The raw HTTP request is as follows:

PUT /devices/_DEVICE_ID_/event HTTP/1.1
Host: api.tinkermode.com
Authorization: ModeCloud _YOUR_API_KEY_
Content-Type: application/json

{ "eventType": "foo",  "eventData": {} }

Please make sure that you correctly replace _YOUR_API_KEY_ and _DEVICE_ID_ according to the device settings. You can expect the following response. Make sure the HTTP status code is 204.

HTTP/1.1 204 No Content
Access-Control-Allow-Credentials: false
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-Xsrf-Guard
Date: Tue, 25 Aug 2015 21:50:34 GMT

You can check to see if the event has been correctly delivered by using the app simulator. On the App Simulator, open the Incoming Events window to make sure the sent event is in fact delivered to the app. You can see something like the following in the event log:

{
  "homeId": 10,
  "timestamp": "2015-08-25T18:53:42.365519896Z",
  "eventType": "foo",
  "eventData": {},
  "originDeviceId": 8
}

The homeID, originDeviceId and timestamp properties of the returned JSON may vary depending on your configuration. If you cannot see the log, please make sure _YOUR_API_KEY_ or _DEVICE_ID_ are correct.

Receiving Commands via WebSocket


To receive commands, the device has to estable a WebSocket connection to the MODE cloud. To initiate the WebSocket connection, the device needs to make a GET request to the /devices/_DEVICE_ID_/command endpoint. Run the following command:

$ curl -i -N -H "Authorization: ModeCloud _YOUR_API_KEY_" -H "Upgrade: websocket" -H "Connection: Upgrade" -H "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==" -H "Sec-WebSocket-Version: 13" https://api.tinkermode.com/devices/_DEVICE_ID_/command

The raw HTTP request is as follows:

GET /devices/_DEVICE_ID_/command HTTP/1.1
Host: api.tinkermode.com
Authorization: ModeCloud _YOUR_API_KEY_
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13

You need to send the Upgrade, Connection, Sec-WebSocket-Key and Sec-WebSocket-Version headers in addition to the Authorization header to initiate a WebSocket connection. The Sec-WebSocket-Key header contains base64-encoded random bytes, and the server replies with a hash of the key in the Sec-WebSocket-Accept header. For more on WebSocket, see RFC6455.

If your request succeeds, you should see the following response. The connection is kept alive for the inbound data stream.

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

To make sure you are receiving commands, you can use the App Simulator to send some commands, as described here. If you send light as action, {"on":true} as parameters, then you will see the following output:

{
  "action": "light",
  "parameters": {
    "on": true
  }
}

You may see some strange characters before the JSON text. They are WebSocket frame headers. In the actual device software, you have to parse the headers. You can find lots of WebSocket libraries (e.g. ws, libwebsockets, etc.) in your favorite programming languages.

Some WebSocket libraries cannot accept any custom HTTP headers. In that case, you can use the authToken URL query parameter to pass the API key to the server:

$ curl -G -L -i -N -H "Upgrade: websocket" -H "Connection: Upgrade" -H "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==" -H "Sec-WebSocket-Version: 13" -d "authToken=_YOUR_API_KEY_"  "https://api.tinkermode.com/devices/__/command"

WebSocket Reconnection

Sometimes WebSocket connection could be shut down unexpectedly. For example, your Wi-Fi router could go down abruptly, the ISP and other upstream gateways could go down as well. If that happens, the device has to make the WebSocket connection again.

Normally, WebSocket libraries can detect that the connection is closed and handle errors. Whenever a device tries to reconnect, it should wait for some time before attempting the next reconnection.

The simple solution is to wait for a certain number of seconds (e.g. 10 seconds) after the first try failed. And it can keep trying to reconnect until the connection succeeds. However, this power-draining method may pose a problem to battery-powered devices.

A more sophisticated solution is to use Fibonacci numbers for the wait time. For example, after the first connection attempt failed, the device should try connecting again after 1 second. If it fails, it tries again after 2 seconds. After that, 3 seconds, 5 seconds, and so on. Obviously, the number would go to infinity, so you need to cap the number to say, 60 seconds.

WebSocket Ping Frames

The MODE cloud sends the ping control frames periodically through each WebSocket connection to prevent it from going stale. According to RFC6455 section 5.5.2, a WebSocket client has to return a pong frame back whenever a ping is received.

But even if a pong frame is not returned back to the MODE cloud, the WebSocket connection would not be shut down, because some WebSocket libraries cannot handle ping frames correctly. For example, most web browsers ignore pings and cannot send pongs back.