MQTT Client Library Encyclopedia – mqtt-elements

Guest post by Sandro Kock

<mqtt-elements>
Language Javascript
License MIT
Website https://github.com/mqttjs/mqtt-elements
API Style declarative

Description

`<mqtt-elements>` are Web Components build on top of `MQTT.js` to expose the mqtt functionality as a custom HTML-Element. Web Components enable a new way of web development where different parts of a Web-Application are encapsulated and re-usable. These custom elements are build using HTML and JavaScript to extend the functionality of HTML itself. All `<mqtt-elements>` are build using the Polymer 1.0 library that adds a lightweight sugaring layer to make the development of complex Web Components easier.

The first beta release of `<mqtt-elements>` was just about a month ago on 09/02/15, so it can be considered a relatively early stage project. But building on top of the highly tested `MQTT.js` library compatibility issues are unlikely.

`<mqtt-elements>` and the browserifyed version of `MQTT.js` are feature equivalent and everything that can be done with `MQTT.js` can be done with `<mqtt-elements>`. Currently the main focus of the project is to extend the test coverage of every custom element to make a production ready 1.0 release as soon as possible. Pull requests and feedback is highly welcome and should be made via the Github project page.

Features

MQTT 3.1 ok
MQTT 3.1.1 ok
LWT ok
SSL/TLS ok
Automatic Reconnect ok
QoS 0 ok
QoS 1 ok
QoS 2 ok
Authentication ok
Throttling Limited

Usage

Installation

You need `node.js` and bower installed to use the `<mqtt-elements>`.

To install bower use:

$ npm install –g bower 

To install and save `<mqtt-elements>`:

$ bower install –save mqtt-elements

This will create a folder in the current directory named `bower_components` in which all dependencies of `<mqtt-elements>` and `<mqtt-elements>` itself are saved in. Now create a HTML file e.g. “index.html” and paste the following markup into the file.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>mqtt-elements</title>
  <script type="text/javascript" src="bower_components/webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="bower_components/mqtt-elements/mqtt-elements.html">
</head>
<body unresolved class="fullbleed">

</body>
</html>

This will load `WebComponents.js` a polyfill shim for Custom Elements, HTML Imports and Shadow DOM, for browsers that don’t support these specs yet.

Connect

A custom HTML-Element is most likely declared in HTML and not created via code. To create a MQTT-Connection instance a connection is declared in HTML with:

<mqtt-connection url="ws://HOST:PORT"></mqtt-connection>

within the `<body>` Tag of the HTML file. The following example will create a MQTT-Connection as soon as possible and automatically connect to `iot.eclipse` on port »80« and use WebSockets as a transport layer.

<mqtt-connection url="ws://iot.eclipse.org:80/ws" auto></mqtt-connection>

To check if the connection is established use a private MQTT-Broker and verify in the log messages or paste the following command into the console in your browser:

document.querySelector("mqtt-connection").connected

The output should be `true` if a connection to the MQTT broker could be established.

Connect with MQTT 3.1 or MQTT 3.1.1

`<mqtt-elements>` connect with `MQTT 3.1.1 by default`. To connect with MQTT 3.1 supply the following parameter via the `mqtt-connection#options object`.

<mqtt-connection 
    url="ws://iot.eclipse.org:80/ws" 
    options='{"protocolId": "MQIsdp", "protocolVersion": 3}' 
    auto></mqtt-connection>

Please note the single and double quoting of the options property of the mqtt-connection element is needed so that Polymer is able to parse the String into a JSON-Object.

Connect with LWT

<mqtt-connection
    url="ws://iot.eclipse.org:80/ws"
    options='{"will": {"topic": "dead", "payload": "mypayload", "qos": 1,"retain": true}}' 
    auto>
</mqtt-connection>

The example above will create a connection to iot.eclipse.org and set the Will RETAIN, Will QoS and Will flag in the CONNECT packet that is send to the MQTT broker. To test if the LWT is set properly use a different MQTT client and subscribe to the LWT topic, in this example we used “dead”. If you refresh the browser with the `<mqtt-elements>` element and the LWT, you should see the message “myplayload” on the topic “dead”.

Connect with Username / Password

<mqtt-connection
    url="ws://iot.eclipse.org:80/ws"
    options='{"username": "USERNAME", "password": "PASSWORD"}'
    auto>
</mqtt-connection>

Like the LWT, username and password for a MQTT connection is supplied via the `option property` and send with the MQTT CONNECT packet to the MQTT broker.

Publish

<mqtt-connection
    url="ws://iot.eclipse.org:80/ws"
    auto>
  <mqtt-publish topic="foo/bar" payload="this is easy" auto></mqtt-publish>
</mqtt-connection>

Will publish the message »this is easy« on the topic »foo/bar« as soon as the mqtt-connection element establishes a connection to the »iot.eclipse« MQTT broker. While writing this post I tested my code and found a minor bug that is now documented at Github. This actually prevents the message from being send directly after the connection is established. Either alter the payload via `mqtt-publish#payload`

document.querySelector("mqtt-publish").payload="Not so easy"

to automatically publish to »foo/bar« or

document.querySelector("mqtt-publish").publish()

call `mqtt-publish#publish` manually. With the publication of this blogpost I believe the issue to be fixed.

To publish on multiple topics, any number of mqtt-publish elements can be added to the mqtt-connection element for e.g. see the example below to publish on the three topics »foo/bar«, »client/status« and »client/location«.

<mqtt-connection
    url="ws://iot.eclipse.org:80/ws"
    auto>
  <mqtt-publish topic="foo/bar" payload="this is easy" auto></mqtt-publish>
  <mqtt-publish topic="client/status" payload="online" auto></mqtt-publish>
  <mqtt-publish topic="client/location" payload="{'foo': 'bar'}" auto></mqtt-publish>
</mqtt-connection>

Changing the <mqtt-publish>#qos property to 1 or 2 will send the MQTT PUBLISH message with QoS level one or two.

<mqtt-connection
url="ws://iot.eclipse.org:80/ws"
auto>
<mqtt-publish topic="foo/bar" payload="this is easy" qos="1" auto></mqtt-publish>
</mqtt-connection>

Publish a retained message

To publish a retained MQTT message just add the » retained« flag to the mqtt-publish element and the message should be retained at the broker.

<mqtt-connection
    url="ws://iot.eclipse.org:80/ws"
    auto>
  <mqtt-publish topic="foo/bar" payload="this is easy" retained auto></mqtt-publish>
</mqtt-connection>

Any client that will subscribe to the topic »foo/bar« should then receive the last retained message to the topic.

Subscribe

<mqtt-connection
    url="ws://iot.eclipse.org:80/ws"
    auto>
  <mqtt-subscription topic="foo/bar"></mqtt-subscription>
</mqtt-connection>

This will add a subscription to the topic »foo/bar«. The last message to the topic will be saved in the mqtt-subscription#lastMessage property. To actually use of the message we can use the data binding feature provided by Polymer like this:

<template is="dom-bind">
  <mqtt-connection
      url="ws://iot.eclipse.org:80/ws"
      auto>
    <mqtt-publish topic="foo/bar" payload="lost"></mqtt-publish>
    <mqtt-subscription topic="foo/bar" last-message="{{message}}"></mqtt-subscription>
  </mqtt-connection>

  <div>{{message.topic}}</div>
  <div>{{message.message.dup}}</div>
  <div>{{message.message.retain}}</div>
  <div>{{message.message.qos}}</div>
  <div>{{message.parsedPayload}}</div>
</template>

To use Polymers data binding feature outside of a custom element, Polymer provides a custom element called »dom-bind« that extends the HTML »template« element. That allows the binding of properties to variables. Every time a new message is published on »foo/bar« the object in `mqtt-subscription#lastMessage` will be updated and the update will be reflected to the »{{message}}« variable. By default the payload of the MQTT message is expected to be a Unicode String and parsed with `String.fromCharCode` . The raw `Uint8Array` payload can be accessed via {{message.message.payload}} or overwrite the `mqtt-subscription#payloadParseFunction` with a function to parse the raw payload. The parsed payload will be stored in the mqtt-subscription#lastMessage.parsedPayload property. This allows the implementation to be easily extended to work with custom binary messages send via MQTT.

In addition by default each mqtt-subscription stores the last mqtt-message within the mqtt-subscription#messages array. To store the last n messages set the mqtt-subscription#numberOfMessages to n e.g. n=10 to store the last 10 messages.

The following example will store every/infinite message(s) received by the mqtt-subscription in the `mqtt-subscription#messages array`.

<mqtt-connection
    url="ws://iot.eclipse.org:80/ws"
    auto>
<mqtt-subscription topic="foo/bar" number-of-messages="Infinity"></mqtt-subscription>
</mqtt-connection>

Unsubscribe

To unsubscribe from a subscription just remove the mqtt-subscription element from the DOM and the mqtt-connection will automatically unsubscribe the topic at the MQTT broker.

document.querySelector("mqtt-subscription").remove()

Disconnect

To disconnect either call `mqtt-connection#disconnect` manually or just remove the element from the DOM.

document.querySelector("mqtt-connection").disconnect()

or

document.querySelector("mqtt-connection").remove()

Full example application

As a proof of concept – a fully working MQTT-client, build with `<mqtt-elements>`, is available at http://mqttjs.github.io/mqtt-elements/. The client allows the user to create one connection, subscribe to multiple topics and publish to those topics. The code is available in the `<mqtt-elements>` Github repository and is not even 300 lines of code/markup and some CSS. The following examples highlight some parts of the client to explain the usage of `<mqtt-elements>`.

<!--create mqtt-connection element-->
<mqtt-connection
        id="connection"
        url="[[url]]"
        connected="{{connected}}"
        client="{{client}}"
        subscriptions="{{subscriptions}}"
        options='{{options}}'
        on-mqtt-message="_handelMqttMessage">

<!--create a mqtt subscription for every item in topics-->
<template is="dom-repeat" items="{{topics}}" as="t">
<mqtt-subscription topic="[[t.topic]]"
                           number-of-messages="10"
                           qos="[[t.qos]]"></mqtt-subscription>
</template>

<!--create mqtt-publish element to publish mqtt messages to the broker -->
<mqtt-publish id="pub"
                    topic="[[topic]]"
                    payload="[[value]]"
                    auto$="[[pubAuto]]"
                    qos="[[pubQos]]"
                    retained="[[pubRetained]]"></mqtt-publish>
</mqtt-connection>

At first – one mqtt-connection element is declared to create the connection. Within the element a »dom-repeat« template element is used to iterate over all items in the »{{topics}}« array. For each item in the array one mqtt-subscription element is created, that subscribes to the topic of the item. Now to add one subscription it is only necessary to push an additional topic item to the `topics` array. Luckily the implementation of »dom-repeat« is smart enough to create DOM elements only once and not every time the array is altered. This makes it possible to just remove the topic item from the »topics« array to remove and unsubscribe one mqtt-subscription.

The mqtt-connection element exposes the property »subscriptions« via that a reference to every mqtt-subscription can be accessed. This array can be used to iterate over every subscription to render every MQTT message received by each MQTT subscription.
The following example iterates over every subscription stored in `mqtt-connection#subscriptions` and prints out the topic and the QoS. Within a second loop every message of that subscription rendered out, printing the topic, QoS and the parsed payload of the message.

<!--output every subscription-->
<template is="dom-repeat" items="[[subscriptions]]" as="sub" observe="messages.*">
  <span>[[sub.topic]]</span>
  <span>[[sub.qos]]</span>
  <template is="dom-repeat" items="{{sub.messages}}" as="message">
    <div>{{message.topic}}</div>
    <div>{{message.message.qos}}</div>
    <div>{{message.parsedPayload}}</div>
  </template>
</template>

One feature of `<mqtt-elements>` is that the MQTT.js `client` that is created to establish the MQTT connection, can be shared/ injected across multiple element instances. The following example demonstrated the injection of the `client` of the first mqtt-connection element into the second and third mqtt-connection element. Sharing the same WebSocket connection between elements saves resources and keeps the application maintainable.

<mqtt-connection
    auto
    url="ws://iot.eclipse.org:80/ws"
    client="{{client}}">
</mqtt-connection>

<mqtt-connection
    client="[[client]]">
  <mqtt-subscription topic="foo/bar"></mqtt-subscription>
</mqtt-connection>

<mqtt-connection
    client="[[client]]">
  <mqtt-subscription topic="other/topic"></mqtt-subscription>
</mqtt-connection>

Feedback and suggestions regarding `<mqtt-elements>` are highly welcome, pleas submit your experiences via email or Github.

Author Information

sandro_kock
Sandro Kock
Since 2014 Sandro Kock is a mobile developer at SSV Software Systems, responsible for developing mobile solutions, with a focus on IoT/M2M. Before that he wrote the MQTT client MQTTlens, which is based on Polymer.
  Website

Leave a Reply

Your email address will not be published. Required fields are marked *