In the context of the Web of Things (WoT), a Binding Template is a blueprint that gives guidance on how to implement a specific IoT protocol, data format or IoT platform. The Core Binding Templates specification explains the overall mechanism and requirements for any binding to follow. This document gives implementation guidelines regarding the MQTT protocol, which is a lightweight, asynchronous, transport-independent, open protocol for publishing and subscribing to messages. It has been employed in many IoT platforms and IoT applications for its simplicity and scalability.

More specifically, this document defines a set of vocabulary terms that can be used inside a Thing Description document, and associated rules which allow to describe WoT operations using the MQTT protocol over the network. Additionally, relevant examples are provided to showcase different vocabulary terms and the associated behavior.

Introduction

The Message Queue Telemetry Transport (MQTT) protocol [[MQTT]] was born in 1999 to handle efficient machine to machine communication in the Internet of Things. The protocol is based on the publish subscribe model, where publishers publish messages to specific topics and subscribers receive notifications for filters that match one or more topics. The protocol is well-known for its simplicity and scalability and is used in many IoT platforms and applications.

In the context of the Internet of Things, many vendors expose MQTT publishers mixed with Web protocols like HTTP. This document explain how to describe MQTT endpoints and payloads with Thing Descriptions (TDs) the core building block of the Web of Things (WoT) [[WOT-ARCHITECTURE]].

This version of the document is designed around each affordance having its own MQTT topic. Usage of MQTT with an additional protocol on top that uses topics with specific payloads is possible, but it implies defining a payload structure in each affordance. Thus, this way of using MQTT is not supported out-of-the-box in this document.

Forms of a Thing Description instance with MQTT Binding complies with this specification if it follows the normative statements in and .

A JSON Schema [[?JSON-SCHEMA]] to validate Thing Description instances containing MQTT Binding is provided in the GitHub repository.

This document is a work in progress

URL format

There is no clear consensus on the correct URL format for MQTT protocol binding template

            {scheme}://{address}:{port}
        

Where:

Notice that the URL does not contain any information regarding [[[#topicname]]] or [[[#topicfilter]]]. These two parameters must be specified using their own parameter as described in [[[#form-terms]]]. This is necessary to avoid ambiguities regarding the starting / character and the usage of # which can be confused with the URL fragment character.

          mqtt://iot.platform.com:8088
        

MQTT Vocabulary

Form terms

Vocabulary term Description Assignment Type
mqv:retain If the RETAIN flag is set to 1 in a PUBLISH packet sent by a Client to a Server, the Server must replace any existing retained message for this topic and store the Application Message, so that it can be delivered to future subscribers whose subscriptions match its Topic Name. optional boolean
mqv:controlPacket In MQTT protocol clients sends control packets between each other using and intermediary called Server (or broker). This property describes the action of sending a ControlPacket in a NetworkConnection optional ControlPacket
mqv:qos This field indicates the level of assurance for delivery of an Application Message. optional QualityOfService
mqv:topic This field reports the TopicName of a packet optional TopicName
mqv:filter This field reports the list of TopicFilters of a packet optional TopicFilter Array of TopicFilter

Control Packet

In MQTT protocol messages are called Control Packets. An MQTT Control Packet consists of up to three parts: fixed header (present in all Control Packets), variable header, payload. The fixed header consists of a packet type and flags. The main packet types that can be uses in a Form are listed below. Although, it is possible to use different values of [[[#controlpacket]]] in forms, it is recommended to use the mapping defined in [[[#default-mappings]]].

Value Description
mqv:publish A PUBLISH packet is sent from a Client to a Server or from a Server to a Client to transport an Application Message.
mqv:subscribe The SUBSCRIBE packet is sent from the Client to the Server to create one or more Subscriptions. Each Subscription registers a Client’s interest in one or more Topics.
mqv:unsubscribe An UNSUBSCRIBE packet is sent by the Client to the Server, to unsubscribe from topics.

QualityOfService

MQTT delivers Application Messages according to the Quality of Service (QoS) levels defined in this ontology.

The Quality of Service (QoS) is a mechanism to ensure that messages are delivered to the subscriber in the order in which they were published. In the Web of Things the QoS reported in the TD when paired with writeproperty or invokeaction operation is used to determine the minimum QoS that the consumer must use to publish the message. On the other hand, when paired with subscribeevent, observeproperty, or readproperty, it indicates to the WebThing must send messages with that minium QoS. The QoS values are defined in the MQTT specification. The QoS values are:

Value Name Description
quality:0 atMostOnce The Server delivers the Application Message to the Client at most once
quality:1 atLeastOnce The message is delivered at least once.
quality:2 exactlyOnce The message is delivered exactly once.

TopicName

The label attached to an Application Message which is matched against the Subscriptions known to the Server. The Server sends a copy of the Application Message to each Client that has a matching Subscription. TopicName is used ony for publication to indicate a single topic, and thus MUST not contain any wildcards.

TopicFilter

An expression contained in a Subscription, to indicate an interest in one or more topics. A Topic Filter can include wildcard characters. TopicFilter is used for subscriptions to indicate a topic or a set of topics when a wildcard character is used.

Mappings

This section describes strategies and default values to employ protocol specific concepts within the WoT Interaction model.

Default mappings

op value Default Binding
readproperty "mqv:controlPacket": "mqv:subscribe"
writeproperty "mqv:controlPacket": "mqv:publish"
observeproperty "mqv:controlPacket": "mqv:subscribe"
unobserveproperty "mqv:controlPacket": "mqv:unsubscribe"
readallproperties "mqv:controlPacket": "mqv:subscribe"
readmultipleproperties "mqv:controlPacket": "mqv:subscribe"
writeallproperties "mqv:controlPacket": "mqv:publish"
writemultipleproperties "mqv:controlPacket": "mqv:publish"
invokeaction "mqv:controlPacket": "mqv:publish"
subscribeevent "mqv:controlPacket": "mqv:subscribe"
unsubscribeevent "mqv:controlPacket": "mqv:unsubscribe"

Possible mappings

For the MQTT protocol, if an MQTT client publishes a message to a topic with the retain flag set to true, the future subscribers of the topic will also get this message. Outside of this case, it is not possible to read a property but only possible to observe it. Additionally, in a Form element with MQTT protocol, if the op contains readproperty (meaning that retain flag is set to true), it SHOULD also contain observeproperty. On the other hand, if the MQTT publisher does not set the retain flag to true, the property will be only observable. In this case, the property in the exposed Thing Description SHOULD NOT have Form elements with MQTT protocol containing readproperty operation.

Examples

The following examples show how to use the MQTT protocol in a Thing Description. The [[[#example-simple-event]]] shows a simple form that indicates to compliant Consumers to subscribe or unsubscribe to the topic thing1/events/overheating in order to execute the subscribevent or unsubscribevent operation, respectively.

        {
            "href": "mqtt://broker.com:1883",
            "op": [
                "subscribeevent",
                "unsubscribeevent"
            ],
            "mqv:filter": "thing1/events/overheating" 
        }
      

[[[#example-simple-publish]]] shows how to use the mqv:publish packet when invoking a command. Remember that the invokeaction operation is mapped to mqv:publish control packet in [[[#default-mappings]]].

        {
            "href": "mqtt://broker.com:1883",
            "op": [
                "invokeaction"
            ], 
            "mqv:topic": "application/devices/thing1/program/commands/reset"
        }
      

Continuing with increasingly more complex examples, [[[#example-property]]] shows how to use the MQTT protocol when handling properties. mqv:retain is used to indicate the ability to read the property rather than just observe it.

        [{
            "href": "mqtt://broker.com:1883",
            "op": [
                "writeproperty"
            ], 
            "mqv:retain" : true,
            "mqv:topic": "application/devices/thing1/properties/test"
        },
        {
            "href": "mqtt://broker.com:1883",
            "op": [
                "readproperty",
                "observeproperty"
            ],
            "mqv:retain" : true,
            "mqv:filter": "application/devices/thing1/properties/test"
            }
        ]
      

If the implementer wants to give the ability to WoT clients to conveniently observe all properties in a single call, it is possible to use observeallproperties form in the root of a Thing Description. For example, in [[[#example-property-observeall]]] all the messages to topics under application/devices/thing1/properties/ will be delivered.

              {
                  "href": "mqtt://broker.com:1883",
                  "op": [
                      "observeallproperties"
                  ], 
                  "mqv:filter": "application/devices/thing1/properties/#"
              }
      

When the Web Thing wants to force a minimum level of [[[#qualityofservice]]] for a property, it can use the mqv:qos property in the Form element as shown in [[[#example-qos]]]. This will guarantee that consumers and exposers will get the message at the specified quality of service.

              [{
                  "href": "mqtt://broker.com:1883",
                  "op": [
                      "writeproperty"
                  ], 
                  "mqv:qos": "quality:1", 
                  "mqv:retain" : true,
                  "mqv:topic": "application/devices/thing1/properties/test"
              },
              {
                  "href": "mqtt://broker.com:1883",
                  "op": [
                      "readproperty",
                      "observeproperty"
                  ], 
                  "mqv:qos": "quality:1", 
                  "mqv:retain" : true,
                  "mqv:filter": "application/devices/thing1/properties/test"
              }]
     

Finally, [[[#example-full]]] reports a full Thing Description for a fictional commercial device. The broker address is only for demonstration purposes.

{
    "@context": "https://www.w3.org/2019/wot/td/v1",
    "title": "Gas Sensor",
    "id": "urn:dev:test",
    "description": "Gas sensor is a sensor that can measure combustible gas concentration and issue an alarm in the event of a gas leak.",
    "securityDefinitions": {
        "nosec_sc": {
            "scheme": "nosec"
        }
    },
    "security": "nosec_sc",
    "properties": {
        "status": {
            "title": "Sensor Status",
            "observable": true,
            "enum": [
                "unknown",
                "warmup",
                "normal",
                "fault"
            ],
            "type": "string",
            "forms": [
                {
                    "href": "mqtt://broker.com/",
                    "mqv:filter": "application/deviceid/sensor/operation",
                    "op": "observeproperty"
                }
            ]
        },
        "concentration": {
            "title": "Gas Concentration",
            "observable": true,
            "readOnly": false,
            "minimum": -1,
            "maximum": 65535,
            "type": "integer",
            "forms": [
                {
                    "href": "mqtt://broker.com",
                    "mqv:filter": "application/deviceid/sensor/concentration",
                    "op": "observeproperty"
                }
            ]
        },
        "gasAlarm": {
            "title": "Gas Alarm",
            "observable": true,
            "enum": [
                "unknown",
                "none",
                "mild",
                "heavy",
                "test"
            ],
            "type": "string",
            "forms": [
                {
                    "href": "mqtt://broker.com",
                    "mqv:filter": "application/deviceid/sensor/gas",
                    "op": "observeproperty"
                }
            ]
        },
        "valve": {
            "title": "Valve",
            "observable": true,
            "enum": [
                "unknown",
                "closed",
                "opened",
                "not_connected",
                "failure",
                "closing",
                "opening",
                "checking"
            ],
            "type": "string",
            "forms": [
                {
                    "href": "mqtt://broker.com/",
                    "mqv:filter": "application/deviceid/valve/0/state",
                    "op": "observeproperty"
                }
            ]
        }
    },
    "actions": {
        "mute": {
            "title": "Mute",
            "forms": [
                {
                    "href": "mqtt://broker.com/",
                    "mqv:topic": "application/deviceid/sensor/mute"
                }
            ]
        },
        "unmute": {
            "title": "Unmute",
            "forms": [
                {
                    "href": "mqtt://broker.com/",
                    "mqv:topic": "application/deviceid/sensor/unmute"
                }
            ]
        },
        "changeValveStatus": {
            "title": "Change Valve Status",
            "input": {
                "type": "string",
                "enum": [
                    "open",
                    "close"
                ]
            },
            "forms": [
                {
                    "href": "mqtt://broker.com/",
                    "mqv:topic": "application/deviceid/valve/0/command"
                }
            ]
        }
    }
}