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.
This document is a work in progress
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.
There is no clear consensus on the correct URL format for MQTT protocol binding template
{scheme}://{address}:{port}
Where:
{scheme}
is the protocol scheme, either mqtt
or mqtts
{address}
is the IP address of the MQTT broker{port}
is the port of the MQTT broker/
character and the usage of #
which can be confused with the URL
fragment character.
mqtt://iot.platform.com:8088
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 |
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 |
---|---|
publish |
A PUBLISH packet is sent from a Client to a Server or from a Server to a Client to transport an Application Message. |
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. |
unsubscribe |
An UNSUBSCRIBE packet is sent by the Client to the Server, to unsubscribe from topics. |
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 |
---|---|---|
0 |
atMostOnce | The Server delivers the Application Message to the Client at most once |
1 |
atLeastOnce | The message is delivered at least once. |
2 |
exactlyOnce | The message is delivered exactly once. |
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.
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.
This section describes strategies and default values to employ protocol specific concepts within the WoT Interaction model.
op value |
Default Binding |
---|---|
readproperty |
"mqv:controlPacket": "subscribe" |
writeproperty |
"mqv:controlPacket": "publish" |
observeproperty |
"mqv:controlPacket": "subscribe" |
unobserveproperty |
"mqv:controlPacket": "unsubscribe" |
readallproperties |
"mqv:controlPacket": "subscribe" |
readmultipleproperties |
"mqv:controlPacket": "subscribe" |
writeallproperties |
"mqv:controlPacket": "publish" |
writemultipleproperties |
"mqv:controlPacket": "publish" |
invokeaction |
"mqv:controlPacket": "publish" |
subscribeevent |
"mqv:controlPacket": "subscribe" |
unsubscribeevent |
"mqv:controlPacket": "unsubscribe" |
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.
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": "1", "mqv:retain" : true, "mqv:topic": "application/devices/thing1/properties/test" }, { "href": "mqtt://broker.com:1883", "op": [ "readproperty", "observeproperty" ], "mqv:qos": "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" } ] } } }