MQTT, STOMP and WebSockets

Messaging, stream subscriptions and alternative transports.

These examples document the original platform. Use your own deployment; this website does not provide the former hosted API or account service.

Introduction

servIoTicy allows for the interaction with the platform through protocols that are not HTTP/REST. Support for MQTT, STOMP-over-TCP and STOMP-over-WS is provided. This page describes how to leverage this protocols for easy interaction with the platform.

They can be used in three different forms:

  • For cient/server interaction with servIoTicy, emulating the behaviour of the REST API
  • For data streams subscriptions: A client can subscribe to a data stream and receive all the updates being send to a SO stream. Note that given that the platform provides eventual consistency, this is a good way to get most recent updates for a SO stram asynchronously and in real-time. Polling is not recommended.
  • For actuations: This is described in a separate document here. Some information contained in this page is still relevant.

Information for communicating with the platform using MQTT/WS/TCP:

  • MQTT Endpoint: api.servioticy.com:1883
  • STOMP/TCP Endpoint: api.servioticy.com:1883
  • STOMP/WS Endpoint: api.servioticy.com:61623
  • User: compose
  • Password: shines

Topics:

  •  Sending data from the Web Object: “<API_TOKEN>/from” (MQTT) – “/topic/<API_TOKEN>.from” (STOMP)
  •  Sending data to the Web Object (HTTP responses): “<API_TOKEN>/to” (MQTT) – “/topic/<API_TOKEN>.to” (STOMP)
  • Updates produced by subscriptions: “<API_TOKEN>/<SO_Id>/streams/<streamId>/updates” (MQTT) – “/topic/<API_TOKEN>.<SO_Id>.streams.<streamId>.updates” (STOMP)

Important: Notice that the topics used in MQTT and STOM follow a different format. More information found here (MQTT) and here (STOMP)

Subscribing to data streams:

We would POST the following JSON document to the URL:

http://api.servioticy.com/SOid/streams/streamID/subscriptions

Note that the filed “destination” is here the API_TOKEN of the subscriber.
Example topic:
“M2JhMmRkMDEtZTAwZi00ODM5LThmYTktOGU4NjNjYmJmMjc5N2UzNzYwNWItNTc2ZS00MGVlLTgyNTMtNTgzMmJhZjA0ZmIy/1396461657731411aa73c28444ecf9a8c803e62312fd1/streams/location/updates”

creating a MQTT subscription
{
  "callback": "pubsub",
  "destination": "M2JhMmRkMDEtZTAwZi00ODM5LThmYTktOGU4NjNjYmJmMjc5N2UzNzYwNWItNTc2ZS00MGVlLTgyNTMtNTgzMmJhZjA0ZmIy",
}

Client-Server interaction:

REST API is mapped on top of a topic using the following structure (note the use of an optional “messageId” field to match queries and responses):

Document structure
{
   "meta": {
     "authorization": "API_TOKEN HERE",
     "method": "PUT/GET/POST",
     "url": "/full/path/to/destination"
     "messageId": "random string to match requests and responses"
   },
   "body": {
     <STRUCTURE OF THE JSON DOCUMENT YOU SHOULD SEND TO THE REST API>
   }
}

An example of how to to list all the SOs belonging to a user:

list all SOs
{
   "meta": {
     "authorization": "API_TOKEN HERE",
     "method": "GET",
     "url": "/",
     "messageId": 123456
   }
}

An example of how to push data to the platform:

PUT data
{
   "meta": {
     "authorization": "API_TOKEN HERE",
     "method": "PUT",
     "url": "/13944639303973f5530eab507412d88bef305089a7720/streams/weather",
     "messageId": 123456
   },
   "body": {
     "lastUpdate": 1199192932,
     "channels": {
       "location": {
         "current-value": "40.12,-71.34",
         "unit": "degrees"
       },
       "temperature": {
         "current-value": 33,
         "unit": "degrees"
       }
     }
   }
}

Code samples

A sample python code for pushing data to the platform (based on Paho):

Simple tester
import paho.mqtt.publish as publish
import paho.mqtt.client as mqtt

putData = """
{
   "meta": {
     "authorization": "API_TOKEN HERE",
     "method": "PUT",
     "url": "/13944639303973f5530eab507412d88bef305089a7720/streams/weather"
   },
   "body": {
     "lastUpdate": 1199192932,
     "channels": {
       "location": {
         "current-value": "40.12,-71.34",
         "unit": "degrees"
       },
       "temperature": {
         "current-value": 33,
         "unit": "degrees"
       }
     }
   }
}
"""

getAllSO = """
{
   "meta": {
     "authorization": "API_TOKEN HERE",
     "method": "GET",
     "url": "/"
   }
}
"""


def on_connect(mqttc, obj, rc):
    mqttc.publish("API_TOKEN HERE/from", getAllSO)
    mqttc.publish("API_TOKEN HERE/from", putData)

def on_message(mqttc, obj, msg):
    print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload))

def on_log(mqttc, obj, level, string):
    print(string)


mqttc = mqtt.Client()
mqttc.on_connect = on_connect
# Uncomment to enable debug messages
#mqttc.on_log = on_log
mqttc.username_pw_set("compose","shines")
mqttc.connect("api.servioticy.com", 1883, 60)

mqttc.loop_forever()

The actual Node.js multi-protocol bridge between the broker and the platform:

Note that it uses STOMP+TCP, and therefore uses a topic notation that is: “/topic/field1.field2.field3….”

Simple Bridge (NodeJS)
var Stomp = require('stompjs');
var api = require('restler');

// Use raw TCP sockets
var client = Stomp.overTCP('api.servioticy.com', 1883);
// uncomment to print out the STOMP frames
//client.debug = console.log;

client.connect('compose', 'shines', function(frame) {
client.subscribe('/topic/*.from', function(message) {

        var request = JSON.parse(message.body);
        console.log("Going for a "+request.meta.method)
        console.log("Posted data "+JSON.stringify(request.body))
        api.json("http://api.servioticy.com"+request.meta.url,
                 request.body,
                 {headers: {'Content-Type': 'application/json', 'Authorization':request.meta.authorization}},
                 request.meta.method
        ).on('complete', function(data, response) {
                data.messageId = request.meta.messageUd || null;
                client.send('/topic/'+request.meta.authorization+".to",{},JSON.stringify(data))
                console.log("result: "+JSON.stringify(data))
        });
  });
});