W3C Web of Things enables applications to interact with and orchestrate connected Things at the Web scale. The standardized abstract interaction model exposed by the WoT Thing Description enables applications to scale and evolve independently of the individual Things.
Many network-level protocols, standards and platforms for connected Things have already been developed, and have millions of devices deployed in the field today. These standards are converging on a common set of transport protocols and transfer layers, but each has peculiar content formats, payload schemas, and data types.
Despite using unique formats and data models, the high-level interactions exposed by most connected things can be modeled using the Property, Action, and Event interaction affordances of the WoT Thing Description.
Binding Templates enable a Thing Description to be adapted to a specific protocol, data payload formats or platforms that combine both in specific ways. This is done through additional descriptive vocabularies, Thing Models and examples that aim to guide the implementors of Things and Consumers alike.
This document acts as the base and explains how other binding templates should be designed. Concrete binding templates are then provided in their respective documents that are linked to from this document.
Please contribute to this draft using the GitHub Issue feature of the WoT Binding Templates repository. For feedback on security and privacy considerations, please use the WoT Security and Privacy Issues, as they are cross-cutting over all our documents.
Binding Templates consist of multiple specifications, referred to as a subspecification in this document, that enable an application client (a Consumer) to interact, using WoT Thing Description[[WOT-THING-DESCRIPTION] (TD), with Things that exhibit diverse protocols, payload formats and their usage. These subspecifications are categorized into three:
Each subspecification is an independent document that has separate list of authors and publication dates. This document explains what each subspecification should contain given their respective category and also links to the respective specification.
The fundamental WoT terminology such as Thing, Consumer, Thing Description (TD), Interaction Model, Interaction Affordance, Property, Action, Event, Protocol Binding, Servient, Vocabulary, WoT Interface, WoT Runtime, etc. is defined in Section 3 of the WoT Architecture specification [[WOT-ARCHITECTURE]].
This section describes the mechanisms of binding templates for protocols, payload formats and platforms. Each subsection lists the idea behind the category of the binding, the currently existing bindings and requirements for new bindings.
Most protocols have a relatively small set of methods that define the message type, the semantic intention of the message. REST and PubSub architecture patterns result in different protocols with different methods. Common methods found in these protocols are GET, PUT, POST, DELETE, PUBLISH, and SUBSCRIBE. Binding Templates describe how these existing methods and vocabularies can be described in a Thing Description.
This is done by defining the URI scheme of the protocol and mapping the protocol
methods to the abstract WoT operations such as readproperty
, invokeaction
and
subscribeevent
.
The table below summarizes the currently specified protocols in their respective subspecification.
Abbreviation | Name | Link |
---|---|---|
HTTP | Hypertext Transfer Protocol | Link |
CoAP | Constrained Application Protocol | Link |
MQTT | Message Queuing Telemetry Transport | Link |
Modbus | Modbus | Link |
When creating a new protocol binding subspecification, e.g. based on a new communication protocol, the proposed document should enable implementations of this binding in an interoperable way for Consumer and Producer implementations. More specifically, each binding MUST specify the following:
base
or in the href
term of the forms
container. These can be officially registered ones at IANA [[iana-uri-schemes]] (e.g.
"https://"
, "coap://"
) or they can be declared in the protocol
subspecification (e.g. "mqtt://"
, "modbus+tcp://"
). How the full URI
can be constructed for different affordances (or resources) MUST be specified as well.
readproperty
,
invokeaction
, etc.) to concrete protocol message types or methods. When specifying
the mapping, the mapping SHOULD be bidirectional, i.e. it should be clear how to
do a readproperty
operation with the given protocol and how an existing
implementation's endpoints can be mapped to a WoT operation should be also clear.
A vocabulary detailing the operations methods SHOULD be provided to allow semantic annotations
of the operations with protocol specific information.
A template is also provided for new protocol binding specifications at the GitHub Repository.
The rest of this chapter (4.1.2) is not restructured yet
contentType
in the Forms of a TD, which is mandatory for
each Interaction Affordance.
In some cases such as images, videos or any unstructured data, they are enough to describe the
payload.
Correct indication of Media Types enables proper processing of the serialized documents.
This way, the documents can be exchanged in any format and allow the upper layers of an application
to adapt to different formats.
Abbreviation | Name | Media Type | Link |
---|---|---|---|
JSON | JavaScript Object Notation | application/json |
TODO |
XML | eXtensible Markup Language | application/xml |
Link |
text | text | text/plain |
TODO |
Unstructured Data | Unstructured Data | various | TODO |
Each payload format binding document, SHOULD contain the respective media type.
Ideally this media type has been registered at the IANA registry [[IANA-MEDIA-TYPES]] with a
corresponding mime type (e.g. application/json
).
If it is not registered, the binding document can propose a mime type. Additionally, how that media
type is represented
in a Data Schema SHOULD be demonstrated with examples.
In all cases, the following information SHOULD be provided:
There are already various IoT platforms on the market that allows exposing physical and virtual Things to the Internet. These platforms generally propose a certain API specification over a protocol and media type. Thus, they can be seen as a combination of the and . Platform subspecifications provide Thing Models and examples of TDs on how to integrate these platforms in to the W3C Web of Things.
The table below summarizes the currently specified platforms.
Name | Link |
---|---|
Philips Hue | TODO |
ECHONET | TODO |
OPC-UA | TODO |
Depending on the platform and the variety of devices it proposes, each binding specification will be structured differently. When the platforms offer a reasonable set of device types, a Thing Model for each device type SHOULD be provided. In other cases, possible devices SHOULD be generalized by providing a set of example Thing Models or TDs. In all cases, the following information SHOULD be provided:
The following TD examples uses CoAP and MQTT Protocol Bindings.
These TD Context Extensions assume that there is a CoAP and MQTT in RDF vocabulary similar to
[[?HTTP-in-RDF10]] that is accessible via the namespace http://www.example.org/coap-binding#
and http://www.example.org/mqtt-binding#
, respectively.
The supplemented cov:methodName
member instructs the Consumer which CoAP method has to be
applied (e.g., GET
for the CoAP Method Code 0.01, POST
for the CoAP Method Code
0.02, or iPATCH
for CoAP Method Code 0.07).
The supplemented "mqv:controlPacketValue"
member instructs the Consumer which MQTT command has
to be applied (e.g., 8
for the subscribing and 10
for unsubscribing).
A TD with simple payload format and protocols can be seen below. Here each interaction affordance has one form with one protocol.
{ "@context": [ "https://www.w3.org/2019/wot/td/v1", { "iot": "http://iotschema.org/", "cov": "http://www.example.org/coap-binding#", "mqv": "http://www.example.org/mqtt-binding#" } ], "@type": [ "Thing", "iot:Light", "iot:LevelCapability", "iot:BinarySwitchCapability" ], "base": "http://example.com", "title": "Lamp", "id": "urn:dev:ops:32473-WoTLamp-1234", "securityDefinitions": {"basic_sc": { "scheme": "basic", "in": "header" }}, "security": ["basic_sc"], "properties": { "switchState": { "@type": ["iot:SwitchStatus", "iot:SwitchData"], "type": "boolean", "writeOnly": false, "readOnly": false, "observable": false, "forms": [ { "href": "/example/light/currentswitch", "op": ["readproperty", "writeproperty"], "contentType": "application/json" } ] }, "brightness": { "@type": ["iot:CurrentLevel", "iot:LevelData"], "type": "number", "writeOnly": false, "readOnly": false, "observable": false, "forms": [ { "href": "coap://example.com/example/light/currentdimmer", "op": ["readproperty", "writeproperty"], "contentType": "application/json" } ] } }, "actions": { "switchOn": { "@type": ["iot:SwitchOnAction"], "input": { "type": "boolean", "const": true }, "forms": [ { "href": "/example/light/currentswitch", "op": ["invokeaction"], "contentType": "application/json" } ] }, "switchOff": { "@type": ["iot:SwitchOff"], "input": { "type": "boolean", "const": false }, "forms": [ { "href": "/example/light/currentswitch", "op": ["invokeaction"], "contentType": "application/json" } ] }, "setBrightness": { "@type": ["iot:SetLevelAction"], "input": { "@type": ["iot:LevelData"], "type": "number" }, "forms": [ { "href": "/example/light/currentdimmer", "op": ["invokeaction"], "contentType": "application/json" } ] } } }
Another version of the previous TD with complex payload and multiple protocol options is shown below.
Notably, the brightness
property can be read via HTTP, written to via CoAP and observed via
MQTT.
{ "@context": [ "https://www.w3.org/2019/wot/td/v1", { "iot": "http://iotschema.org/", "cov": "http://www.example.org/coap-binding#", "mqv": "http://www.example.org/mqtt-binding#" } ], "base": "http://example.com/", "@type": [ "Thing", "iot:Light", "iot:LevelCapability", "iot:BinarySwitch" ], "title": "Lamp", "id": "urn:dev:ops:32473-WoTLamp-1234", "securityDefinitions": {"basic_sc": { "scheme": "basic", "in": "header" }}, "security": ["basic_sc"], "properties": { "switchState": { "@type": ["iot:SwitchStatus"], "type": "object", "properties": { "switch": { "@type": ["iot:SwitchData"], "type": "boolean" } }, "writeOnly": false, "readOnly": false, "observable": true, "forms": [ { "href": "/example/light/currentswitch", "contentType": "application/json", "op": ["readproperty"], "htv:methodName": "GET" }, { "href": "/example/light/currentswitch", "contentType": "application/json", "op": ["writeproperty"], "htv:methodName": "POST" }, { "href": "mqtt://example.com/example/light/currentswitch", "op": ["observeproperty"], "mqv:controlPacketValue": "SUBSCRIBE" } ] }, "brightness": { "@type": ["iot:CurrentLevel"], "type": "object", "properties": { "brightness": { "@type": ["iot:LevelData" ], "type": "integer", "minimum": 0, "maximum": 255 } }, "writeOnly": false, "readOnly": false, "observable": true, "forms": [ { "href": "coap://example.com/example/light/currentdimmer", "contentType": "application/json", "op": ["readproperty"], "cov:methodName": "GET" }, { "href": "/example/light/currentdimmer", "contentType": "application/json", "op": ["writeproperty"], "htv:methodName": "POST" }, { "href": "mqtt://example.com/example/light/currentdimmer", "op": ["observeproperty"], "mqv:controlPacketValue": "SUBSCRIBE" } ] }, "transitionTime": { "@type": ["iot:TransitionTime"], "type": "object", "properties": { "transitionTime": { "@type": ["iot:TransitionTimeData" ], "type": "integer", "minimum": 0, "maximum": 255 } }, "writeOnly": false, "readOnly": false, "observable": false, "forms": [ { "href": "/example/light/transitiontime", "contentType": "application/json", "op": ["readproperty"], "htv:methodName": "GET" }, { "href": "/example/light/transitiontime", "contentType": "application/json", "op": ["writeproperty"], "htv:methodName": "POST" } ] } }, "actions": { "switchOn": { "@type": ["iot:SwitchOnAction"], "input": { "type": "boolean", "const": true }, "forms": [ { "href": "/example/light/currentswitch", "contentType": "application/json", "op": ["invokeaction"], "htv:methodName": "POST" } ] }, "switchOff": { "@type": ["iot:SwitchOffAction"], "input": { "type": "boolean", "const": false }, "forms": [ { "href": "/example/light/currentswitch", "contentType": "application/json", "op": ["invokeaction"], "htv:methodName": "POST" } ] }, "setBrightness": { "title": "Set Brightness Level", "@type": ["iot:SetLevelAction"], "input": { "type": "object", "properties": { "brightness": { "@type": ["iot:LevelData"], "type": "integer", "minimum": 0, "maximum": 255 } }, "transitionTime": { "@type": ["iot:TransitionTimeData"], "type": "integer", "minimum": 0, "maximum": 65535 } }, "forms": [ { "href": "/example/light/", "contentType": "application/json", "op": ["invokeaction"], "htv:methodName": "POST" } ] } } }
Security and privacy considerations are still under discussion and development; the content below should be considered preliminary. Due to the complexity of the subject we are considering producing a separate document containing a detailed security and privacy considerations discussion including a risk analysis, threat model, recommended mitigations, and appropriate references to best practices. A summary will be included here. Work in progress is located in the WoT Security and Privacy repository. Please file any security or privacy considerations and/or concerns using the GitHub Issue feature.
Security is a cross-cutting issue that needs to be taken into account in all WoT building blocks. The W3C WoT does not define any new security mechanisms, but provides guidelines to apply the best practices from Web security, IoT security, and information security for general software and hardware considerations.
The WoT Thing Description must be used together with integrity protection mechanisms and access control policies. Users must ensure that no sensitive information is included in the TDs themselves.
The WoT Binding Templates must correctly cover the security mechanisms employed by the underlying IoT platform. Due to the automation of network interactions necessary in the IoT, operators need to ensure that Things are exposed and consumed in a way that is compliant with their security policies.
The WoT Runtime implementation for the WoT Scripting API must have mechanisms to prevent malicious access to the system and isolate scripts in multi-tenant Servients.
Special thanks to all active participants of the W3C Web of Things Interest Group and Working Group for their technical input and suggestions that led to improvements to this document.
The below chapters are copied from other places in this document. They require discussion on where to place them, i.e. either here or another document of the working group, or to be completely removed.
The form elements contain the URI [[RFC3986]] pointing to an instance of the interaction and descriptions of the protocol settings and options expected to be used when between the Consumer and the Thing for the interaction.
Form Operation Types describe the intended semantics of performing the operation described by the form.
For example, the Property interaction allows read and write operations. The
protocol binding may contain a form for the read operation and a different
form for the write operation. The value of the op
attribute of the form
indicates which form is which and allows the Consumer to select the correct
form for the operation required.
"op": "readproperty" "op": "writeproperty"
The vocabulary in section 4 lists the recommended set of form operations, and the full TD examples in section 5 contain example uses of form operations types.
Content Types define the serialization details and other rules for processing the payloads. The content type is used to select a serializer/deserializer and to select an additional set of rules and constraints for the protocol driver. Content type includes the media type and potential parameters for the media type.
For example, the media type application/ocf+cbor
indicates that CBOR
serialization is used, but also that OCF rules and namespaces
apply to the processing of the representations.
Some special protocol drivers may be invoked by using a non-registered
media type (e.g., x-
) along with a custom URI Scheme [[RFC3986]] and its
own set of protocol methods and options defined for that URI Scheme.
When the media type is application/xml
(or its binary representation
application/exi
) and there is a Data Schema provided for the payload, the payloads are
constrained by a XML Schema derived from the Data Schema.
See XML Binding
for how to derive a XML Schema from a Data Schema definition.
Each target protocol may specify different method names for similar operations, and there may be semantic differences between similar method names of different protocols. Additionally, platforms may use different methods for realizing a particular WoT Interaction Affordance. For example, POST may be used for writing a Property value in one platform, while PUT may be used in another. For these reasons, we require the ability to specify which method to use for a particular Interaction. We also will provide vocabulary to differentiate between methods of different protocols.
The W3C RDF vocabulary for HTTP [[HTTP-in-RDF10]] is used to identify the methods and options specified in the HTTP protocol bindings.
For the sake of consistency, we will use the same ontology design pattern to derive a vocabulary for each target protocol, e.g. CoAP, MQTT.
The example below shows some method definitions for various protocols.
"htv:methodName": "GET" "mqv:controlPacketValue": "SUBSCRIBE" "cov:methodName": "GET"
Header options in HTTP, CoAP, MQTT sometimes must be included in a protocol binding in order to successfully interact with the underlying protocol. The example below shows the structure of the definition for HTTP header options, according to the W3C HTTP Vocabulary in RDF.
"htv:headers": [ { "htv:fieldName": "Accept", "htv:fieldValue": "application/json" }, { "htv:fieldName": "Transfer-Encoding", "htv:fieldValue": "chunked" } ]
Note: different forms in a binding may need different header constructions,
therefore the htv:headers
construct is an extension of the TD "form" element.
Protocols may have defined sub-protocols that can be used for some interaction
types. For example, to receive asynchronous notifications using HTTP, some
servers may support long polling (longpoll
), WebSub [[WebSub]]
(websub
) and Server-Sent Events [[eventsource]] (sse
).
The subprotocol
item may be defined in a form instance to indicate the
use of one of these protocols, for example long polling with its special use of HTTP:
{ "op": "subscribeevent", "href": "https://mylamp.example.com/overheating", "subprotocol": "longpoll" }
subprotocol
Vocabulary
The subprotocol
field is defined in [[!WOT-THING-DESCRIPTION]].
Currently, the supported values are longpoll
, websub
and sse
defined for HTTP. Subprotocols can be used for asynchronous event delivery or observing Properties.
For WebSockets, the IANA-registered Websocket Subprotocols [[iana-web-socket-registry]] may be used.
For CoAP, "subprotocol":"cov:observe"
can be used to describe asynchronous observation
operations as defined by [[RFC6741]]
This section describes unique aspects of protocol bindings for the three WoT Interaction Affordances.
This section describes unique aspects of protocol bindings for WoT Property interactions.
The abstract operations exposed for the Property Interaction are readproperty
,
writeproperty
, observeproperty
and unobserveproperty
.
These are mapped by using form operations that describe how the abstract operation is performed,
resulting in a semantic interpretation similar to HTML form submission.
Additionally, the abstract operations exposed for multiple Property Interactions are
readallproperties
, writeallproperties
,
readmultipleproperties
and writemultipleproperties
.
{ "op": "writeproperty", "href": "/example/level", "htv:methodName": "POST" }
The form element in the example above conveys the statement:
"To do a writeproperty
of the subject Property (context of the form), perform
an HTTP POST
on the resource at the target URI /example/level
."
Properties may be observable, defined by the TD keyword "observable".
If there is an observe form and a retrieve form, the observe form may be
indicated by including op=observeproperty
in the form. The observe form may
also specify header options to use, as specified in Observing in CoAP[[?RFC7641]]for example
setting the CoAP Observe option to 0
in the header, starts observation.
This section describes unique aspects of protocol bindings for Actions.
The abstract operation on Actions is invokeaction
.
In the same way that the abstract operations on Properties are mapped using form operation
types, the abstract operation of Actions is also mapped.
{ "op": "invokeaction", "href": "/example/levelaction", "http:methodName": "POST" }
The form element in the example above conveys the statement: "To do an
invokeaction
of the subject Action (context of the form), perform a
POST
on the resource at the target URI /example/levelaction
."
This section describes unique aspects of protocol bindings for WoT Event Interaction Affordances.
The abstract operations on Events are subscribeevent
and
unsubscribeevent
.
The subscribeevent
operation may directly enable event instance delivery
from the pre-defined URI to observable resources or pubsub topics encoded in URIs.
Alternatively, it may return a location or resource URI from which event instance may be
obtained, either by observation or some other mechanism, depending on the transfer protocol.
Usually, the unsubscribeevent
only occurs when the transfer protocol has no
implicit unsubscribe operation such as closing the connection. Examples are Webhooks that require
particular unsubscribe requests.
If the binding offers an observable Event resource from which events are obtained, there will be a form which describes the required transfer layer operation, for example CoAP Observe or HTTP Long Polling.
{ "op": "subscribeevent", "href": "mqtt://wot.example.com/levelevent", "mqv:controlPacketValue": "SUBSCRIBE" }
The form element in the example above conveys the statement: "To do an
subscribeevent
of the subject Event (context of the form), perform an
MQTT SUBSCRIBE
on the topic /levelevent
on the broker at
wot.example.com
using the default MQTT port."
A data schema describes the payload structure and included data items that are passed between the Consumer and the Thing during interactions.
Payload Structure is determined by DataSchema
elements of a Thing Description.
DataSchema elements should be used by an instance of a PropertyAffordance
,
input
/output
of ActionAffordance
,
data
/subscription
/cancellation
of an
EventAffordance
or by
a uriVariable
of the InteractionAffordance
.
As indicated in the [[WOT-THING-DESCRIPTION]], DataSchema
Vocabulary is a subset of
JSON Schema [[json-schema]]
In the case of Action Affordances, the additional keywords input
and
output
are used to provide two different schemas when data
might be exchanged in both directions, such as in the case of invoking an Action Affordance
with input parameters and receiving status information.
In the case of Event Affordances, the additional keywords data
,
subscription
and cancellation
are used to describe the payload when the event data
is delivered by the
Exposed Thing, the payload needed to subscribe to the event and the payload needed to cancel receiving event
data
from the Exposed Thing, respectively.
In addition to the example pattern in [[WOT-THING-DESCRIPTION]] of an object with name/value constructs or simple arrays, Protocol Bindings for existing standards may require nested arrays and objects, and some constant values to be specified.
Below are examples of different payloads and their corresponding DataSchema
.
For example, a simple payload structure may use a map:
{ "level": 50, "time": 10 } |
{ "type": "object", "properties": { "level": { "@type": ["iot:LevelData"], "type": "integer", "minimum": 0, "maximum": 255 }, "time": { "@type": ["iot:TransitionTimeData"], "type": "integer", "minimum": 0, "maximum": 65535 } } } |
SenML [[RFC8428]] might use the following construct:
[ { "bn": "/example/light/" }, { "n": "level", "v": 50 }, { "n": "time", "v": 10 } ] |
{ "type": "array", "items": [ { "type": "object", "properties": { "bn": { "type": "string", "const": "example/light" } } }, { "type": "object", "properties": { "n": { "type": "string", "const": "level" }, "v": { "@type": ["iot:LevelData"], "type": "integer", "minimum": 0, "maximum": 255 } } }, { "type": "object", "properties": { "n": { "type": "string", "const": "time" }, "v": { "@type": ["iot:TransitionTimeData"], "type": "integer", "minimum": 0, "maximum": 65535 } } } ] } |
A Batch Collection according to OCF[[OCF]] may be structured like this:
[ { "href": "/example/light/level", "rep": { "dimmingSetting": 50 } }, { "href": "/example/light/time", "rep": { "rampTime": 10 } } ] |
{ "type": "array", "items": [ { "type": "object", "properties": { "href": { "type": "string", "const": "/example/light/level" }, "rep": { "type": "object", "properties": { "dimmingSetting": { "@type": ["iot:LevelData"], "type": "integer", "minimum": 0, "maximum": 255 } } } } }, { "type": "object", "properties": { "href": { "type": "string", "const": "/example/light/time" }, "rep": { "type": "object", "properties": { "rampTime": { "@type": ["iot:TransitionTimeData"], "type":"integer", "minimum": 0, "maximum": 65535 } } } } } ] } |
And an IPSO Smart Object on LWM2M [[LWM2M]] might look like the following:
{ "bn": "/3001/0/", "e": [ { "n": "5044", "v": 0.5 }, { "n": "5002", "v": 10.0 } ] } |
{ "type": "object", "properties": { "bn": { "type": "string", "const": "/3001/0/" }, "e": { "type": "array", "items": [ { "type": "object", "properties": { "n": { "type": "string", "const": "5044" }, "v": { "@type": ["iot:LevelData"], "type": "number", "minimum": 0.0, "maximum": 1.0 } } }, { "type": "object", "Properties": { "n": { "type": "string", "const": "5002" }, "v": { "@type": ["iot:TransitionTimeData"], "type": "number", "minimum": 0.0, "maximum": 6553.5 } } } ] } } } |
Note that in Example 7 above, the values are floating point (double
) while the other
examples have integer values.
In general, Consumers should follow the data schemas strictly, not generating anything not given in
the WoT Thing Description, but should accept additional data from the Thing not given explicitly in
the WoT Thing Description.
This means that a Consumer sending the payload of the Example 7 should use floating points in the
payload.