This document describes a formal model and a common representation for a Web of Things (WoT) Thing Description. A Thing Description describes the metadata and interfaces of Things, where a Thing is an abstraction of a physical or virtual entity that provides interactions to and participates in the Web of Things. Thing Descriptions provide a set of interactions based on a small vocabulary that makes it possible both to integrate diverse devices and to allow diverse applications to interoperate. Thing Descriptions, by default, are encoded in a JSON format that also allows JSON-LD processing. The latter provides a powerful foundation to represent knowledge about Things in a machine-understandable way. A Thing Description instance can be hosted by the Thing itself or hosted externally when a Thing has resource restrictions (e.g., limited memory space) or when a Web of Things-compatible legacy device is retrofitted with a Thing Description.

Implementers need to be aware that this specification is considered unstable. Vendors interested in implementing this specification before it eventually reaches the Candidate Recommendation phase should subscribe to the repository and take part in the discussions.

Text and table entries highlighted with a yellow background indicates a feature associated with an at-risk assertion for which insufficient implementation experience exists. When an entire section is at-risk the words "This section is at risk." will be placed at the start of the section and highlighted with a yellow background.

Introduction

The Thing Description (TD) model is a central building block in the W3C Web of Things (WoT) and can be considered as the entry point of a Thing (much like the index.html of a Web site). A TD instance has four main components: textual metadata about the Thing itself, a collection of affordances to interact with the Thing on the basis of WoT's high-level interaction paradigm (involving the classes PropertyAffordance, ActionAffordance and EventAffordance), schemas for the information exchanged with the Thing for machine-understandability, and, finally, Web links to express any formal or informal relation to other Things.

Property affordances (PropertyAffordance class) can be used for sensing and controlling parameters, such as getting the current value or setting an operation state. Action affordances (ActionAffordance class) model invocation of physical (and hence time-consuming) processes, but can also be used to abstract RPC-like calls of existing platforms. Event affordances (EventAffordance class) are used for the push model of communication where notifications, discrete events, or streams of values are sent asynchronously to the receiver. In general, the TD provides metadata for different communication bindings identified by URI schemes [[iana-uri-schemes]] (e.g., http, coap, etc.), content types based on media types (e.g., application/json, application/xml, application/cbor, application/exi etc.) [[iana-media-types]], and security mechanisms (for authentication, authorization, confidentiality, etc.). Serialization of TD instances is based on JSON [[rfc8259]], where JSON keys refers to terms of the TD core vocabulary, as defined in this specification document. In addition the JSON serialization of TDs follows the syntax of JSON-LD 1.1 [[json-ld11]] to enable context extension and RDF processing.

Example 1 shows a TD instance and illustrates the TD model's PropertyAffordance, ActionAffordance and EventAffordance classes by describing a lamp Thing with the name MyLampThing.

From this TD example, we know there exists one property affordance with the name status. In addition, information is provided to indicate that this Property is accessible via (the secure form of) the HTTP protocol with a GET method at the URI https://mylamp.example.com/status (announced within the forms structure by the href name), and will return a string-based status value. The use of the GET method is not stated explicitly, but is one of the default assumptions defined by this document and explained in [[WoT-Binding-Templates]].

In a similar manner, an action affordance is specified to toggle the switch status using the POST method applied to the https://mylamp.example.com/toggle resource, where POST is again a default assumption for invoking Actions.

The event affordance enables a mechanism for asynchronous messages to be sent by a Thing. Here, a subscription to be notified upon a possible overheating event of the lamp can be obtained by using the HTTP with its long polling sub-protocol at https://mylamp.example.com/oh.

This example also specifies the basic security scheme, requiring a username and password for access. Note that a security scheme is first given a name in a securityDefinition and then activated by specifying that name in a security section. In combination with the use of the HTTP protocol this example demonstrates the use of HTTP Basic Authentication. Specification of at least one security scheme at the top level is mandatory, and gives the default access requirements for every resource. However, security schemes can also be specified per-form, with configurations given at the form level overriding configurations given at the Thing level, allowing for the specification of fine-grained access control. It is also possible to use a special nosec security scheme to indicate that no access control mechanisms are used. Additional examples will be provided later.

The Thing Description offers the possibility to add contextual definitions in some namespace. This mechanism can be used to integrate additional semantics to the content of the Thing Description instance, provided that formal knowledge, e.g. logic rules for a specific domain of application, can be found under the given namespace. Contextual information can also help specify some configurations and behavior of the underlying communication protocols declared in the forms field. Example 2 extends the TD sample from Example 1 by introducing a second defintion in the @context to declare the prefix saref as referring to the SAREF vocabulary namespace [[!smartM2M]]. The SAREF vocabulary includes terms to describe lighting devices and other home automation devices that one can embed in a TD as semantic labels as values for the @type property. In the present example, the Thing is labelled with saref:LightingDevice, the status property affordance is labelled with saref:OnOffState and the toggle action affordance with saref:ToggleCommand.

The declaration mechanism inside some @context is specified by JSON-LD. A TD instance complies to version 1.1 of this specification [[json-ld11]]. The TD instance can be also processed as an RDF document (details are given in ).

Terminology

The generic WoT terminology is defined in [[WOT-ARCHITECTURE]]: Thing, Thing Description (in short TD), Web of Things (in short WoT), WoT Interface etc.

In addition, this document introduces the following definitions:

TD Information Model
Set of constraints and equivalence relations applying to pre-defined vocabularies (i.e., a core vocabulary with extension like JSON Schema, Web Linking and WoT Security), thus defining the semantics of these vocabularies. Constraints and equivalence relations are typically expressed in terms of class membership and property value assignment on arbitrary object-oriented data structures.
TD Processor
A system that can serialize some internal representation of a TD (an arbitrary data structure) in a given format and deserialize it from that format. If two TDs have different serializations but are semantically equivalent, their internal representation by a TD processor must be strictly identical. For instance, a TD in which default values were omitted is equivalent to a TD that would include default values. Moreover, a TD processor must also detect semantically inconsistent TDs, for which no representation should exist. A TD processor is typically a sub-system of a WoT runtime. The reference serialization format for TDs is JSON.
Vocabulary
A collection of vocabulary terms, identified by a namespace IRI.
Vocabulary Term
A class name (like Thing), a property name (like forms) or a property value (like readproperty).

Namespaces

The namespace for the W3C Thing Description vocabulary as defined in this document is

https://www.w3.org/2019/wot/td#

Using content negotiation, this namespace serves either the TD ontology file (Turtle) or an HTML documentation for the ontology. The JSON-LD context file for TD documents is available under

https://www.w3.org/2019/wot/td/v1

A Thing Description instance complies with this specification if it follows the normative statements in Section and Section regarding Thing Description serialization.

A JSON Schema [[?JSON-SCHEMA-VALIDATION]] is provided in Annex to validate Thing Description instances based on JSON serialization.

In the future some information about RDF validation will be provided.

Information Model

This section introduces the Thing Description information model. The Thing Description Information model serves as the conceptual basis for the serialization and processing of Thing Description described in later sections in this document.

Overview

The W3C Thing Description provides a set of vocabulary for describing physical and virtual Things. In general, the Thing Description vocabulary set is grouped in three modules:

An overview of this vocabulary with its class context and class relation is given by the following three figures. Vocabulary terms identify members within the TD information model. Both the terms shown on the left side of " : " (i.e. colon) in the boxes representing classes and the terms labelling the arrows constitute the vocabulary terms of Thing Description information model. Please note that the figures reflect the vocabulary terms and structure as they would be used in a Thing Description instance (see Section ).

The following diagrams are automatically generated from the ontology files. The layout will be improved in one of the next TD updates.

TD core model figure
TD core model (Click SVG file)
TD data schema model figure
JSON schema model (Click SVG file)
TD security model figure
WoT security model (Click SVG file)
Web linking model figure
Web linking model (Click SVG file)

A detailed description of the vocabulary of the TD core model, TD data schema model and TD security model is given in the following sub-sections.

All equivalence relations expressed in Tables in Section MUST be followed by a TD processor. These equivalences are implicitely defined as default value assignments for certain vocabulary terms.

All vocabulary constraints noted in tables in Section , , , and MUST be followed by a TD processor.

The constraints noted in all tables are the following:

The section explains how to serialize these vocabulary terms to a Thing Description instance using a JSON-based representation. It also defines default values for some mandatory vocabulary and explains the options how they can be serialized.

Default Values for Vocabulary Terms

The follow table gives default value assignments when a TD does not assign certain property to any value.

Vocabulary term Default value Context
contentType application/json
safe false
idempotent false
op Array of strings with values readproperty followed by writeproperty PropertyAffordance
op invokeaction ActionAffordance
op subscribeevent EventAffordance
in header BasicSecurityScheme
DigestSecurityScheme
BearerSecurityScheme
PoPSecurityScheme
in query APIKeySecurityScheme
qop auth DigestSecurityScheme
alg ES256 BearerSecurityScheme
PoPSecurityScheme
format jwt BearerSecurityScheme
PoPSecurityScheme
flow implicit OAuth2SecurityScheme

Core Vocabulary Definition

In the following tables, a type given as "map of X" should be interpreted as defining an unordered collection of name-value pairs associating unique names with values of type X. Likewise a type given as "array of X" should be interpreted as defining an ordered collection of instances of type X.

Note that for now securityDefinitions are mandatory at the top level of a Thing since there needs to be at least one definition available for use in the top-level mandatory security block. However, a future extension may allow in-place anonymous definitions within security blocks in which case this requirement may be relaxed.

Thing

An abstraction of a physical or a virtual entity whose metadata and interfaces are described by a WoT Thing Description, whereas a virtual entity is the composition of one or more Things.

Vocabulary termDescriptionAssignmentType
@contextKnown from JSON-LD [[json-ld11]], @context is used to define short-hand names called terms that are used throughout a TD document.mandatorystring or array
@typeKnown from JSON-LD [[json-ld11]], @type is used to state that a thing is an instance of a class.

Each string in the value array represents a class.
optionalstring or array of string
idunique identifier of the Thing (URI, e.g. custom URN).mandatoryanyURI
nameName of the Thing.mandatorystring
descriptionProvides additional (human-readable) information based on a default language.optionalstring
descriptionsCan be used to support (human-readable) information in different languages.optionalMultiLanguage
versionProvides version information.optionalVersionInfo
createdProvides information when the TD instance was created.optionaldateTime
lastModifiedProvides information when the TD instance was last modified.optionaldateTime
supportProvides information about the TD maintainer (e.g., author, link or telephone number to get support, etc).optionalstring
baseDefine the base URI that is used for all relative URI references throughout a TD document. In TD instances, all relative URIs are resolved relative to the base URI using the algorithm defined in [[RFC3986]].

base does not affect the URIs used in @context and the IRIs [[?RFC3987]] used within Linked Data [[?LINKED-DATA]] graphs that are relevant when semantic processing is applied to TD instances.
optionalanyURI
propertiesAll Property-based interaction affordance of the Thing.optionalmap of PropertyAffordance
actionsAll Action-based interaction affordance of the Thing.optionalmap of ActionAffordance
eventsAll Event-based interaction affordance of the Thing.optionalmap of EventAffordance
formsIndicates one or more endpoints at which operation(s) on this resource are accessible. In this version of TD, all operations that can be described at the Thing level are concerning how to interact with the Thing's property affordances collectively at once.optionalarray of Form
securitySet of security definition names, chosen from those defined in securityDefinitions. These must all be satisfied for access to resources.mandatorystring or array of string
securityDefinitionsSet of named security configurations (definitions only). Not actually applied unless names are used in a security section.mandatorymap of SecurityScheme

The mandatory context definition of the string "https://www.w3.org/2019/wot/td/v1" MUST be the first item in the @context array. The mandatory context definition MAY be followed by one or more context definitions as strings or objects.

As suggested in JSON-LD [[json-ld]] specification, if a context definition is a string, it SHOULD be a dereferenceable URL. Likewise, if a context definition is an object, it SHOULD be a map of namespaces, in which keys are namespace prefixes. Each optional namespace specified in the @context array of a Thing MUST be bound to an unique prefix.

Similar to PropertyAffordance, ActionAffordance and EventAffordance classes, all of which are subclasses of InteractionAffordance, the definition of Thing class also contains the forms term. When a forms term member is present in a Thing instance, the value(s) in the op term member of the forms MUST be one or more of readallproperties, writeallproperties, readmultipleproperties or writemultipleproperties. (See an example for an usage of form in a Thing instance.)

For readallproperties operation's output, readmultipleproperties operation's output, writeallproperties operation's input and writemultipleproperties operation's input, payloads are assigned an object type schema with its properties equal to the Thing's property affordances. For readmultipleproperties operation's input, payloads are assigned a string array type schema with its items each equal to one of the names of The Thing's property affordances.

InteractionAffordance

Metadata of a Thing that shows the possible choices to clients, thereby suggesting how clients may interact with the Thing. There are many types of potential affordances, but W3C WoT defines three types of Interaction Affordances: Properties, Actions, and Events.

Vocabulary termDescriptionAssignmentType
@typeKnown from JSON-LD [[json-ld11]], @type is used to state that an interaction resource is an instance of a class.

Each string in the value array represents a class.
optionalstring or array of string
titleProvides a human-readable title (e.g., display a text for UI representation) of the interaction pattern based on a default language.optionalstring
titlesProvides multi-language human-readable titles (e.g., display a text for UI representation in different languages) of the interaction pattern.optionalMultiLanguage
descriptionProvides additional (human-readable) information based on a default language.optionalstring
descriptionsCan be used to support (human-readable) information in different languages.optionalMultiLanguage
formsIndicates one or more endpoints at which operation(s) on this resource are accessible.mandatoryarray of Form
uriVariablesDefine URI template variables as collection based on DataSchema declarations.optionalmap of DataSchema

The class InteractionAffordance has the following subclasses:

Each instance of a Property, Action, and Event class MUST have an identifier that is unique within the context of a Thing Description document.

PropertyAffordance

An Interaction Affordance that exposes state of the Thing. This state can then be retrieved (read) and optionally updated (write). Things can also choose to make Properties observable by pushing the new state after a change.

Vocabulary termDescriptionAssignmentType
observableA hint that indicates whether a remote client can subscribe to ("observe") the Property, to receive change notifications or periodic updates (true/false).optionalboolean

Property class is a subclass of the class InteractionAffordance. When a forms term member is present in a Property instance, the value(s) in the op term member of the forms MUST be one or more of readproperty, writeproperty, observeproperty or unobserveproperty.

Property instances are also instances of the class DataSchema. Therefore, it can contain the type, unit, readOnly and writeOnly members, among others.

When the value of readOnly member is true in an instance of PropertyAffordance, the value(s) in the op term member of the forms MUST NOT contain writeproperty. Similarly, when the value of writeOnly member is true in an instance of PropertyAffordance, the value(s) in the op term member of the forms MUST NOT contain readproperty.

ActionAffordance

An Interaction Affordance that allows to invoke a function of the Thing, which manipulates state (e.g., toggling a lamp on or off) or triggers a process on the Thing (e.g., dimm a lamp over time).

Vocabulary termDescriptionAssignmentType
inputUsed to define the input data schema of the action.optionalDataSchema
outputUsed to define the output data schema of the action.optionalDataSchema
safeSignals if the action is safe (=true) or not. Used to signal if there is no internal state (cf. resource state) is changed when invoking an Action. In that case responses can be cached as example.with defaultboolean
idempotentIndicates whether the action is idempotent (=true) or not. Informs whether the action can be called repeatedly with the same result, if present, based on the same input.with defaultboolean

Action class is a subclass of the class InteractionAffordance. When a forms term member is present in an Action instance, the value in the op term member of the forms MUST be invokeaction.

EventAffordance

An Interaction Affordance that describes an event source, which asynchronously pushes event data to clients (e.g., overheating alerts).

Vocabulary termDescriptionAssignmentType
subscriptionDefines data that needs to be passed upon subscription, e.g., filters or message format for setting up Webhooks.optionalDataSchema
dataDefines the data schema of the Event instance messages pushed by the Thing.optionalDataSchema
cancellationDefines any data that needs to be passed to cancel a subscription, e.g., a specific message to remove a Webhook.optionalDataSchema

Event class is a subclass of the class InteractionAffordance. When a forms term member is present in an Event instance, the value(s) in the op term member of the forms MUST be either or both of subscribeevent or/and unsubscribeevent.

Form

Communication metadata indicating where a service can be accessed by a client application. An interaction might have more than one form.

Vocabulary termDescriptionAssignmentType
hrefURI of the endpoint where an interaction pattern is provided.mandatoryanyURI
contentTypeAssign a content type based on a media type [[IANA-MEDIA-TYPES]] (e.g., 'application/json) and (optional) parameters (e.g., 'charset=utf-8').with defaultstring
contentCodingContent coding values indicate an encoding transformation that has been or can be applied to a representation. Content codings are primarily used to allow a representation to be compressed or otherwise usefully transformed without losing the identity of its underlying media type and without loss of information. Examples of content coding include "gzip", "deflate", etc. .optionalstring
responseThis optional term can be used if, e.g., the output communication metadata differ from input metdata (e.g., output contentType differ from the input contentType). The response name contains metadata that is only valid for the reponse messages.optionalExpectedResponse
opIndicates the semantic intention of performing the operation(s) described by the form. For example, the Property interaction allows get and set operations. The protocol binding may contain a form for the get operation and a different form for the set operation. The op attribute indicates which form is for which and allows the client to select the correct form for the operation required. op can be assigned one or more interaction verb(s) each representing a semantic intention of an operation.with defaultstring or array of string (one of readproperty, writeproperty, observeproperty, unobserveproperty, invokeaction, subscribeevent, unsubscribeevent, readallproperties, writeallproperties, readmultipleproperties, or writemultipleproperties)
subprotocolIndicates the exact mechanism by which an interaction will be accomplished for a given protocol when there are multiple options. For example, for HTTP and Events, it indicates which of several available mechanisms should be used for asynchronous notifications such as long polling, websub (also see https://www.w3.org/TR/websub/), or server sent events (also see https://www.w3.org/TR/eventsource/). Please note that there is no restriction on the sub-protocol selection and other mechanisms can also be announced by this subprotocol term.optionalstring (e.g. longpoll, websub, or sse)
securitySet of security definition names, chosen from those defined in securityDefinitions. These must all be satisfied for access to resources.optionalstring or array of string
scopesSet of authorization scope identifiers provided as an array. These are provided in tokens returned by an authorization server and associated with forms in order to identify what resources a client may access and how. The values associated with a form should be chosen from those defined in an OAuth2SecurityScheme active on that form.optionalstring or array of string

VersionInfo

Carries version information about the TD instance. If required, additional version information such as firmware and hardware version (term definitions outside of the TD namespace) can be extended here.

Vocabulary termDescriptionAssignmentType
instanceProvides a version identicator of this TD instance.mandatorystring

ExpectedResponse

Communication metadata for response messages (e.g., contentType of the response).

Vocabulary termDescriptionAssignmentType
contentTypeAssign a content type based on a media type [[IANA-MEDIA-TYPES]] (e.g., 'application/json) and (optional) parameters (e.g., 'charset=utf-8').with defaultstring

MultiLanguage

Container to provide human-readable text in different languages using language tags described in [[BCP47]]. Each used language tags code MUST be decleared as vocabulary term member of this container (e.g., en, de, ja, zh-Hans, zh-Hant). See for example usages of this container in a Thing Description instance.

Note that in protocols such as HTTP that have an ability to negotiate content based on languages, those terms (e.g. description and title) intended for carrying texts in a default language SHOULD be used instead of MultiLanguage container when the texts are served as a result such negotiation.

Data Schema Vocabulary Definition

The data schema definition reflecting a very common subset of the terms defined in JSON Schema [[?JSON-SCHEMA-VALIDATION]]. It is noted that data schema definitions within Thing Description instances are not limited to this defined subset and MAY use additional terms you find in JSON Schema. It that case it is recommended to use context association for that additional terms as described in , otherwise these terms are semantically ignored (also see ).

DataSchema

A JSON specification.

Vocabulary termDescriptionAssignmentType
@typeKnown from JSON-LD [[json-ld11]], @type is used to state that values described by the DataSchema are instances of a class.

Each string in the value array represents a class.
optionalstring or array of string
titleProvides a human-readable title (e.g., display a text for UI representation) of the interaction pattern based on a default language.optionalstring
titlesProvides multi-language human-readable titles (e.g., display a text for UI representation in different languages) of the interaction pattern.optionalMultiLanguage
descriptionProvides additional (human-readable) information based on a default language.optionalstring
descriptionsCan be used to support (human-readable) information in different languages.optionalMultiLanguage
typeAssignment of JSON-based data types compatible with JSON Schema (one of boolean, integer, number, string, object, array, or null).optionalstring (one of object, array, string, number, integer, boolean, or null)
constProvides a constant value.optionalany type
unitProvides unit information that is used, e.g., in international science, engineering, and business.optionalstring
oneOfUsed to ensure that the data is valid against one of the specified schemas in the array.optionalarray of DataSchema
enumRestricted set of values provided as an array.optionalarray of any type
readOnlyBoolean value that is a hint to indicate whether a property interaction / value is read only (=true) or not (=false).with defaultboolean
writeOnlyBoolean value that is a hint to indicate whether a property interaction / value is write only (=true) or not (=false).with defaultboolean
formatDefines format pattern validation on certain kinds of string values. It is open to use pattern values that may originate from JSON schema presets (e.g., date/time, email, URL) or other (custom-based) definitions.with defaultstring

The class DataSchema has the following subclasses:

ArraySchema

A JSON array specification ("type": "array").

Vocabulary termDescriptionAssignmentType
itemsUsed to define the characteristics of an array.optionalDataSchema or array of DataSchema
minItemsDefines the minimum number of items that have to be in the array.optionalunsignedInt
maxItemsDefines the maximum number of items that have to be in the array.optionalunsignedInt

BooleanSchema

A JSON boolean value specification ("type": "boolean").

NumberSchema

A JSON number value specification ("type": "number").

Vocabulary termDescriptionAssignmentType
minimumSpecifies a minimum numeric value. Only applicable for associated number or integer types.optionaldouble
maximumSpecifies a maximum numeric value. Only applicable for associated number or integer types.optionaldouble

IntegerSchema

A JSON integer value specification, that is, numbers without a fractional part ("type": "integer").

Vocabulary termDescriptionAssignmentType
minimumSpecifies a minimum numeric value. Only applicable for associated number or integer types.optionalinteger
maximumSpecifies a maximum numeric value. Only applicable for associated number or integer types.optionalinteger

ObjectSchema

A JSON object specification ("type": "object").

Vocabulary termDescriptionAssignmentType
propertiesData schema nested definitions.optionalmap of DataSchema
requiredDefines which members of the object type are mandatory.optionalarray of string

StringSchema

A JSON string value specification ("type": "string").

NullSchema

A JSON null value specification ("type": "null"). If the type of null then it has only one acceptable value, namely null. E.g., it can be used as part of oneOf declaration, where it is used to indicate, that a data schema can also be null.

Security Vocabulary Definition

For the core TD vocabulary only well-established security mechanisms are supported, such as those built into protocols supported by WoT or already in wide use with those protocols. The current set of HTTP security schemes is partly based on OpenAPI 3.0.1 (see also [[?OPENAPI]]). However while the HTTP security schemes, vocabulary and syntax given in this specification share many similarities with OpenAPI they are not compatible.

The vocabulary extension mechanism of the WoT Thing Description allows for additional security schemes if needed. For more information about what additional security schemes or modifications are under discussion (and to file issues if you have a request) please visit the WoT Security TF repository.

SecurityScheme

Vocabulary termDescriptionAssignmentType
@typeKnown from JSON-LD [[json-ld11]], @type is used to state that a security mechanism configured by the SecurityScheme is an instance of a class.

Each string in the value array represents a class.
optionalstring or array of string
schemeIdentification of security mechanism being configured.mandatorystring (one of nosec, basic, cert, digest, bearer, pop, psk, public, oauth2, or apikey)
descriptionProvides additional (human-readable) information based on a default language.optionalstring
descriptionsCan be used to support (human-readable) information in different languages.optionalMultiLanguage
proxyURI of the proxy server this security configuration provides access to. If not given, the corresponding security configuration is for the endpoint.optionalanyURI

The class SecurityScheme has the following subclasses:

NoSecurityScheme

A security configuration corresponding to ("scheme": "nosec"), indicating there is no authentication or other mechanism required to access the resource.

BasicSecurityScheme

Basic authentication security configuration ("scheme": "basic"), using an unencrypted username and password. This scheme should be used with some other security mechanism providing confidentiality, for example, TLS.

Vocabulary termDescriptionAssignmentType
inSpecifies the location of security authentication information (one of header, query, body, or cookie).with defaultstring
nameName for query, header, or cookie parameters.optionalstring

DigestSecurityScheme

Digest authentication security configuration ("scheme": "digest"). This scheme is similar to basic authentication but with added features to avoid man-in-the-middle attacks.

Vocabulary termDescriptionAssignmentType
qopQuality of protection (one of auth or auth-int).with defaultstring
inSpecifies the location of security authentication information (one of header, query, body, or cookie).with defaultstring
nameName for query, header, or cookie parameters.optionalstring

APIKeySecurityScheme

This section is at risk.

API key authentication security configuration ("scheme": "apikey"). This is for the case where the access token is opaque and is not using a standard token format.

Vocabulary termDescriptionAssignmentType
inSpecifies the location of security authentication information (one of header, query, body, or cookie).with defaultstring
nameName for query, header, or cookie parameters.optionalstring

BearerSecurityScheme

Bearer token authentication security configuration ("scheme": "bearer"). This scheme is intended for situations where bearer tokens are used independently of OAuth2. If the oauth2 scheme is specified it is not generally necessary to specify this scheme as well as it is implied.

Vocabulary termDescriptionAssignmentType
authorizationURI of the authorization server.optionalanyURI
algEncoding, encryption, or digest algorithm (one of MD5, ES256, or ES512-256).with defaultstring
formatSpecifies format of security authentication information (one of jwt, jwe, or jws).with defaultstring
inSpecifies the location of security authentication information (one of header, query, body, or cookie).with defaultstring
nameName for query, header, or cookie parameters.optionalstring

CertSecurityScheme

This section is at risk.

Certificate-base asymmetric key security configuration ("scheme": "cert").

Vocabulary termDescriptionAssignmentType
identityPre-shared key identity.optionalstring

PSKSecurityScheme

This section is at risk.

Pre-shared key authentication security configuration ("scheme": "psk").

Vocabulary termDescriptionAssignmentType
identityPre-shared key identity.optionalstring

PublicSecurityScheme

This section is at risk.

Raw public key asymmetric key security configuration ("scheme": "public").

Vocabulary termDescriptionAssignmentType
identityPre-shared key identity.optionalstring

PoPSecurityScheme

This section is at risk.

Proof-of-possession token authentication security configuration ("scheme": "pop").

Vocabulary termDescriptionAssignmentType
authorizationURI of the authorization server.optionalanyURI
algEncoding, encryption, or digest algorithm (one of MD5, ES256, or ES512-256).with defaultstring
formatSpecifies format of security authentication information (one of jwt, jwe, or jws).with defaultstring
inSpecifies the location of security authentication information (one of header, query, body, or cookie).with defaultstring
nameName for query, header, or cookie parameters.optionalstring

OAuth2SecurityScheme

This section is at risk.

OAuth2 authentication security configuration ("scheme": "oauth2"). For the implicit flow the authorization and scopes are required. For the password and client flows both token and scopes are required. For the code flow authorization, token, and scopes are required.

Vocabulary termDescriptionAssignmentType
authorizationURI of the authorization server.optionalanyURI
tokenURI of the token server.optionalanyURI
refreshURI of the refresh server.optionalanyURI
scopesSet of authorization scope identifiers provided as an array. These are provided in tokens returned by an authorization server and associated with forms in order to identify what resources a client may access and how. The values associated with a form should be chosen from those defined in an OAuth2SecurityScheme active on that form.optionalstring or array of string
flowAuthorization flow (one of implicit, password, client, or code).with defaultstring

Web Linking Vocabulary Definition

The present model provides a representation for (typed) Web links exposed by a Thing. The web linking definition reflecting a very common subset of the terms defined in Web Linking [[!RFC8288]]. The defined terms can be used, e.g., to describe the relation to another Thing such as a Lamp Thing is controlled by a Switch Thing.

Link

A link can be viewed as a statement of the form "link context has a link relation type resource at link target, which has target attributes".

Vocabulary termDescriptionAssignmentType

Thing Description Serialization

Thing Description instances are modeled and structured based on Section .

A TD processor MUST be able to serialize TDs in the JSON format and deserialize TDs from that format, according to the rules noted in Sections and .

The JSON serialization of TDs follows the syntax of JSON-LD 1.1 [[json-ld11]] in order to streamline semantic evaluation. Hence, TD serializations can be processed either as raw JSON or with a JSON-LD 1.1 processor, as later developed in .

In order to support interoperable internationalization, TDs MUST be serialized according to the requirements defined in Section 8.1 of RFC8259 [[RFC8259]] for open ecosystems. In summary, this requires the following:

Basic Representation Format Assumptions

As a fundamental basis, all vocabulary terms defined in Section will have a JSON name representation.

Mapping to JSON Types

The data types of the vocabulary as defined in Section will be transformed to JSON-based types. The following rules are used for vocabulary terms based on some simple type definitions:

  • Vocabulary terms that use simple types string and anyURI MUST be serialized as JSON string.
  • Vocabulary terms that use simple type dateTime MUST be serialized as JSON string and have the lexical form YYYY-MM-DDThh:mm:ssZ. This lexical form represents a subset of the XSD built-in dateTime datatype , itself inspired by the ISO standard for dates and times [[ISO8601]].
  • Vocabulary terms that use simple type integer MUST be serialized as JSON number without a fraction or exponent part.
  • Vocabulary terms that use simple type double MUST be serialized as JSON number.

In addition, Thing Description instances MAY contain additional JSON-LD [[json-ld11]] keywords such as @context and @type. With these the Thing Description can be easily extended. You can find additional details in the Section . In the case of @type usage in the Thing Description instance, the @type MUST be serialized as JSON String or as JSON array of strings when multiple values are assigned to @type.

All vocabulary terms in Section associated with more complex class-based types are defined separately for structured JSON type transformation in Section .

Omitting Default Values

A Thing Description instance serialization may omit one ore more vocabulary terms () that have default values assumed based on the table in .

The following example shows the TD instance from Example 1 with a checkbox to make the TD terms with the default values explicit present (=checkbox checked). Alternatively, those terms can be omitted (=checkbox unchecked) to simplify the TD representation. Note that a Thing Description processor interprets these omitted terms identically as if these terms were explicitly present with the default values.

Please note that, depending on the underlying protocol binding, additional protocol-specific terms can be used that are associated with default value assumptions and can be omitted similar as explained in this subsection. Further information can be found in the section .

Information Model Serialization

Thing as a whole

The root object of a Thing Description instance MUST include the @context name known from JSON-LD [[json-ld11]] with the value URI of the Thing description context file https://www.w3.org/2019/wot/td/v1.

{  
    "@context": "https://www.w3.org/2019/wot/td/v1",
    ...
}

https://www.w3.org/2019/wot/td/v1 uses content negotiation to return the context file. Thus, it must be fetched with an Accept header set to application/ld+json.

When a single Thing Description instance involves several contexts, additional namespaces with prefixes MUST be appended to the @context array structure. This option proves relevant if one wants to extend the existing Thing Description context without modifying it. For instance:

{
    "@context": ["https://www.w3.org/2019/wot/td/v1",
                {"iot": "http://example.org/iot"}],
    ...
}

Each mandatory and optional member name as defined in the class Thing MUST be serialized as a JSON name in the root object of the Thing Description instance.

The type of the members properties, actions, events, version, and securityDefinitions MUST be a JSON object.

The type of the members forms, links, scopes, and security MUST be a JSON array.

A TD snippet based on the defined members of the class Thing without the optional member @context is given below:

{
    "id": "urn:dev:wot:com:example:servient:myThing",
    "name": "MyThing",
    "description": "Human readable information.",
    "descriptions": {...},
    "support": "mailto:support@example.com",
    "securityDefinitions": {...},
    "security": [...],
    "base": "https://servient.example.com/",
    "lastModified" : "2018-11-15T09:12:43.124Z",
    "created" : "2018-11-14T19:10:23.824Z",
    "version" : {...},
    "properties": {...},
    "actions": {...},
    "events": {...},
    "links": [...],
    "forms": [...]
}

Alternatively, the same example can be written instead to explicitly include the (semantic) names used by JSON-LD [[!json-ld11]], namely @context and @type:

{
    "@context": "https://www.w3.org/2019/wot/td/v1",
    "@type": "Thing",
    "id": "urn:dev:wot:com:example:servient:myThing",
    "name": "MyThing",
    "description": "Human readable information.",
    "descriptions": {...},
    "support": "mailto:support@example.com",
    "securityDefinitions": {...},
    "security": [...],
    "base": "https://servient.example.com/",
    "lastModified" : "2018-11-15T09:12:43.124Z",
    "created" : "2018-11-14T19:10:23.824Z",
    "version" : {...},
    "properties": {...},
    "actions": {...},
    "events": {...},
    "links": [...],
    "forms": [...]
}

In that case the content can be directly associated as Thing Description based on the namespace http://www.w3.org/ns/td provided in the @context. The "@type": "Thing" associates an instantiations of the Thing class as defined in Section .

properties

Properties (and sub-properties) offered by a Thing MUST be collected in the JSON-object based properties member with (unique) Property names as JSON names.

Each mandatory and optional vocabulary term as defined in the class Property, as well as its two superclasses InteractionAffordance and DataSchema, MUST be serialized as a JSON name within a Property object. This means that at the level of an interaction property instance, the vocabulary terms of InteractionAffordance and DataSchema can be presented at the same time.

The type of the member forms MUST be serialized as a JSON array.

A TD snippet based on the defined members is given below:

actions

Actions offered by a Thing MUST be collected in the JSON-object based actions member with (unique) Action names as JSON names.

Each optional vocabulary term as defined in the class Action and its superclass InteractionAffordance MUST be serialized as a JSON name within an Action object.

The type of the members input and output MUST be serialized as a JSON object.

The names input and output rely on the the class DataSchema and will follow the serialization introduction provided in .

The type of the member forms MUST be serialized as a JSON array.

A TD snippet based on the defined members is given below:

events

Events offered by a Thing MUST be collected in the JSON-object based events member with (unique) Event names as JSON names.

Each optional vocabulary term as defined in the class Event, as well as its two superclasses InteractionAffordance and DataSchema, MUST be serialized as a JSON name within an Event object.

The type of the members subscription, data, and cancellation MUST be serialized as a JSON object.

The JSON names of subscription, data, and cancellation rely on the the class DataSchema and will follow the serialization introduction provided in .

The type of the member forms MUST be serialized as a JSON array.

A TD snippet based on the defined members is given below:

Please note that the definition of the event affordance is flexibly defined in order to adopt existing (e.g. WebSub) or customer-oriented event mechanisms. For this reason, subscription and cancellation can be defined according to the desired mechanism. Please find further details in [[WoT-Binding-Templates]]. Example provides a Thing-to-Thing (T2T) use case that offers an event and uses subscription and cancellation.

forms

Each mandatory and optional vocabulary term as defined in the class Form, MUST be serialized as a JSON name.

If required, the type of the member response MUST be serialized as a JSON object.

If required, forms MAY be supplemented with protocol-specific vocabulary terms identified with a prefix. See also .

A TD snippet based on the defined members is given below:

{
  "@context": "https://www.w3.org/2019/wot/td/v1",
    ...
  "securityDefinitions": {
      "basic_sc": {"scheme":"basic", "in":"header"}
  },
    ...
    "forms": [{
        "href" : "http://mytemp.example.com:5683/temp",
        "contentType": "application/json",
        "htv:methodName": "POST",
        "op": ["writeproperty"],
        "security": ["basic_sc"]
    }]
    ...
}

href may also carry an URI that contains dynamic variables such as p and d in http://192.168.1.25/left?p=2&d=1. In that case the URI can be defined as template as defined in [[RFC6570]]: http://192.168.1.25/left{?p,d}

In such a case these variables in the URI MUST be collected in the JSON-object based uriVariables member with the associated (unique) variables names as JSON names.

Each defined JSON name of the uriVariables collection MUST rely on the the class DataSchema.

A TD snippet using URI template and uriVariables is given below:

        "@context": ["https://www.w3.org/2019/wot/td/v1",
            {"eg": "http://www.example.org/iot"}],
        ...
        "actions": {
            "LeftDown": {
              "uriVariables": {
                "p" : { "type": "integer", "minimum": 0, "maximum": 16, "@type": "eg:SomeKindOfAngle" },
                "d" : { "type": "integer", "minimum": 0, "maximum": 1, "@type": "eg:Direction" }
                }
              },
              "forms": [{
                "htv:methodName": "GET",
                "href" : "http://192.168.1.25/left{?p,d}"
              }]
            }
        ...
    

The contentType is used to assign a media types [[!IANA-MEDIA-TYPES]] and MAY contain one or more parameters as attribute-value pair separated by a ; character. Example:

    ...
    "contentType" : "text/plain; charset=utf-8"
    ...

In some use cases, the form metadata of the interaction affordance must be distinguished between request and response based messages. E.g., an action 'takePhoto' defines an input to submit parameter settings of a camera (aperture priority, timer,..) using json as content type (="contentType":"application/json"). The output of this action is the photo taken, which is available in jpeg format, for example. In such cases, the response can be used to provide a response content type (e.g., "contentType":"image/jpeg").

If the response member is used in forms, it MUST contain the contentType as defined in class ExpectedResponse.

A form snippet with the response member is listed below based on the use case of the action 'takePhoto' described above:

    "@context": "https://www.w3.org/2019/wot/td/v1",
    ...
    "forms": [
        {
          "href": "http://upsq1c.local:9191/api/frame/crop",
          "contentType": "application/json",
          "op": ["invokeaction"],
          "htv:methodName": "POST",
          "response": {
            "contentType": "image/jpeg"
          }
        }
      ]
    ...

When forms is present at the top level, it can be used to describe meta interactions supported by a Thing instance. For example, the operation types "readallproperties" and "writeallproperties" are for meta interactions with the Thing by which Consumers can read and write all properties at once. In the example below, forms is used at the top level, and the Consumer can use the submission target https://mylamp.example.com/allproperties both to read or write all Properties (i.e., on, brightness and timer property) of the Thing in a single interaction.

{
    "@context": "https://www.w3.org/2019/wot/td/v1",
    "id": "urn:dev:wot:com:example:servient:lamp",
    ...
    "forms": [
        {
          "href": "https://mylamp.example.com/allproperties",
          "contentType": "application/json",
          "op": ["readallproperties"],
          "htv:methodName": "GET"
        },
        {
          "href": "https://mylamp.example.com/allproperties",
          "contentType": "application/json",
          "op": ["writeallproperties"],
          "htv:methodName": "PUT"
        }
    ],
    ...
    "properties": {
        "on": {
          "type": "boolean",
          "forms": [...]
        },
        "brightness": {
          "type": "number",
          "forms": [...]
        },
        "timer": {
          "type": "integer",
          "forms": [...]
        }
    },
    ...
}

securityDefinitions and security

Each mandatory and optional vocabulary term as defined in the class SecurityScheme, MUST be serialized as a JSON name.

The following TD snippet shows a simple security configuration specifying basic username/password authentication in the header. The value of in given is actually the default value of header. First, a named security configuration must be given in a securityDefinitions block. Second, that definition must be activated in a security block.

   ...
   "securityDefinitions": {
       "basic_sc": {
           "scheme": "basic",
           "in": "header"
       }
   },
   ...
   "security": ["basic_sc"]
   ...

Here is a more complex example: a TD snippet showing digest authentication on a proxy combined with bearer token authentication on an endpoint. Here the default value of in in the digest scheme, header, is implied.

    ...
    "securityDefinitions": {
        "basic_sc": {
           "scheme": "digest",
           "proxy": "https://portal.example.com/"
        },
        "bearer_sc": {
           "in":"header",
           "scheme": "bearer",
           "format": "jwt",
           "alg": "ES256",
           "authorization": "https://servient.example.com:8443/"
        }
    },
    ...
    "security": ["basic_sc","bearer_sc"],
    ...

Security configuration is mandatory. Every Thing MUST have at least one security scheme specified at the top level. Security schemes MAY also be specified at the form level. In this case, definitions at the form level override (completely replace) all definitions given at the top level.

The nosec security scheme is provided for the case that no security is needed. The minimal security configuration for a Thing is configuration of the nosec security scheme at the top level, as in the following example:

{
    "id": "urn:dev:wot:com:example:servient:myThing",
    "name": "MyThing",
    "description": "Human readable information.",
    "support": "https://servient.example.com/contact",
    "securityDefinitions": {"nosec_sc": {"scheme": "nosec"}},
    "security": ["nosec_sc"],
    "properties": {...},
    "actions": {...},
    "events": {...},
    "links": [...]
}

To give a more complex example, suppose we have a Thing where all interactions require basic authentication except for one interaction for which no authentication is required. In the following, the nosec scheme for the security configuration in the overheating event to indicate no authentication is required. For the status property and the toggle action, however, basic authentication is required as defined at the top level of the Thing.

{
    ...
    "securityDefinitions": {
        "nosec_sc": {"scheme": "nosec"},
        "basic_sc": {"scheme": "basic"}
    },
    "security": ["basic_sc"],
    ...
    "properties": {
        "status": {
            ...
            "forms": [{
                "href": "https://mylamp.example.com/status",
                "contentType": "application/json",
            }]
        }
    },
    "actions": {
        "toggle": {
            ...
            "forms": [{
                "href": "https://mylamp.example.com/toggle",
                "contentType": "application/json"
            }]
        }
    },
    "events": {
        "overheating": {
            ...
            "forms": [{
                "href": "https://mylamp.example.com/oh",
                "contentType": "application/json",
                "security": ["nosec_sc"] 
            }]
        }
    }
}

Security configurations can also can be specified for different forms within the same interaction. This may be required for devices that support multiple protocols, for example CoAP [[?RFC7252]] and HTTP, with support for different security mechanisms. This is also useful when alternative authentication mechanisms are allowed. Here is a TD snippet demonstrating three possible ways to access a resource: via HTTPS with basic authentication, via HTTPS via digest authentication, or via CoAPS with an API key. In other words, the use of multiple security configurations at the same level provides a way to combine security mechanisms an in "OR" fashion. In contrast, putting multiple security configurations in the same security member combines them in an "AND" fashion, since in that case they would all need to be satisfied to allow access to the resource. Note that a security declaration is still mandatory at the Thing level. Here we use a nosec scheme for symmetry but could also have used any one of the other ones as it will be overridden in each form.

    "securityDefinitions": {
        "nosec_sc": {"scheme": "nosec"},
        "basic_sc": {"scheme": "basic"},
        "digest_sc": {"scheme": "digest","qop":"auth","in":"header"},
        "apikey_sc": {"scheme": "apikey","in":"header"}
    },
    "security": ["nosec_sc"]
    ...
    "properties": {
        "status": {
            ...
            "forms": [
                {
                    "href": "https://mylamp.example.com/status",
                    "contentType": "application/json",
                    "security": ["basic_sc"]
                },
                {
                    "href": "https://mylamp.example.com/status",
                    "contentType": "application/json",
                    "security": ["digest_sc"]
                },
                {
                    "href": "coaps://mylamp.example.com:5683/status",
                    "contentType": "application/json",
                    "security": ["apikey_sc"]
                }
            ]
        }
    },
    ...

As another more complex example, OAuth2 makes use of scopes. These are identifiers that may appear in tokens and must match with corresponding identifiers in a resource to allow access to that resource. For example, in the following, the "status" property can be read by users using bearer tokens containing the scope "limited" but the "configure" action can only be used when the interaction is invoked with a token containing the "special" scope. Scopes are not identical to roles but are often associated with them; for example, perhaps only those in an administrative role can perform "special" interactions. Tokens can have more than one scope. In this example, an administrator would probably be issued tokens with both the "limited" and "special" scopes while ordinary users would only be issued tokens with the "limited" scope.

    ...
    "securityDefinitions": {
        "oauth2_sc": {
            "scheme": "oauth2",
            ...
            "flow": "implicit",
            "authorization": "https://example.com/authorization",
            "scopes": ["limited","special"]
        }
    },
    "security": ["oauth2_sc"],
    "properties": {
        "status": {
            ...
            "forms": [
                {
                    "href": "https://scopes.example.com/status",
                    "contentType": "application/json",
                    "scopes": ["limited"]
                }
            ]
        }
    },
    "action": {
        "configure": {
            ...
            "forms": [
                {
                    "href": "https://scopes.example.com/configure",
                    "contentType": "application/json",
                    "scopes": ["special"]
                }
            ]
        }
    },
    ...

Finally, new security schemes can be defined using the vocabulary extension mechanism. For this example, we will use OAuth2 via the extension mechanism. Note that vocabulary outside SecurityScheme objects, in this case oauth2v:scope, can also be included as part of the definition. To use the extension mechanism an @context also needs to be defined, including the default for TDs as well as a definition of the vocabulary and prefix to be used for the security scheme.

{
    @context: ["https://www.w3.org/2019/wot/td/v1",
               {"oauth2v": "http://example.org/sec/oauth2"}],
    ...
    "securityDefinitions": {
        "oauth2_sc": {
            "scheme": "oauth2v:oauth2",
            ...
            "oauth2v:flow": "implicit",
            "oauth2v:authorization": "https://example.com/authorization",
            "oauth2v:scopes": ["limited","special"]
        }
    },
    "security": ["oauth2_sc"],
    "properties": {
        "status": {
            ...
            "forms": [
                {
                    "href": "https://scopes.example.com/status",
                    "contentType": "application/json",
                    "oauth2v:scopes": ["limited"]
                }
            ]
        }
    },
    "action": {
        "configure": {
            ...
            "forms": [
                {
                    "href": "https://scopes.example.com/configure",
                    "contentType": "application/json",
                    "oauth2v:scopes": ["special"]
                }
            ]
        }
    },
    ...
}

version

The mandatory vocabulary term as defined in the class VersionInfo, MUST be serialized as a JSON name.

The recommended version identification pattern value is to rely on the semantic versioning policy: [[?SemVer]]

A TD snippet based on the defined members is given below:

        ...
        "version": {"instance":"1.2.1"}
        ...
    

The version container MAY be used to provide additional application and/or device specific version information based on terms from non-TD namespaces.

A TD snippet based on such additional version metadata from a v context is given below:

        "@context": ["https://www.w3.org/2019/wot/td/v1",
                    {"v": "http://www.example.org/versioningTerms#"}],
        ...
        "version": {"instance":"1.2.1", "v:firmware": "0.9.1", "v:hardware": "1.0"}
        ...
    

Data Schema Representation

The data schema concept within the Thing Description is based on a subset of JSON schema terms. The data schema concept is applied to the properties interaction declaration, input and output within actions interaction declaration, subscription, data and cancellation within events interaction declaration, and uriVariables that can be used within the forms container.

Each mandatory and optional vocabulary term as defined in the class DataSchema, MUST be serialized as a JSON name.

The type of the members properties MUST be serialized as a JSON object.

The type of the member enum, required, and oneOf MUST be serialized as a JSON array.

The type of the members items MUST be serialized as a JSON object or a JSON array.

A TD snippet based on the defined members is given below:

        ...
        "type": "object",
        "properties": {
            "status": {
                "title": "Status",
                "type": "string",
                "enum": ["On", "Off", "Error"]
            },
            "brightness": {
                "title": "Brightness value",
                "type": "number",
                "minimum": 0.0,
                "maximum": 100.0
            },
            "rgb": {
                "title": "RGB color value",
                "type": "array",
                "items" : {
                    "type" : "number",
                    "minimum": 0,
                    "maximum": 255
                },
                "minItems": 3,
                "maxItems": 3
            }
        },
        ...
        

The terms readOnly and writeOnly MAY be used as hints to signalize which data members are exchanged for a read request (e.g., read an interaction property) and which one for a write process (e.g. write an interaction property).

An TD snippet with the usage of readOnly and writeOnly is given below:

    ...
        "properties": {
            "status": {
              "description": "Read or write On/Off status.",
              "type": "object",
              "properties": {
                "latestStatus": {
                  "type": "string",
                  "enum": ["On", "Off"],
                  "readOnly": true
                },
                "newStatusValue": {
                  "type": "string",
                  "enum": ["On", "Off"],
                  "writeOnly": true
                }
              },
              forms:[...]
            }
          }
    ...

If the interaction property status is read, the status data is returned using latestStatus in the payload. To manipulate the status of the interaction property, the new value must be provided by assigning newStatusValue in the payload.

As an additional feature, a Thing Description instance allows the usage of the term unit within data schema definitions. This can be used to associates some unit information to some data members. The unit values can be free selected, however, it is recommended to select units based on existing definitions by integrating the corresponding namespace context (e.g., from Smart Appliances REFerence (SAREF) ontology or Ontology of units of Measure (OM)).

    {
    "@context": ["https://www.w3.org/2019/wot/td/v1",
                {"om": "http://www.wurvoc.org/vocabularies/om-1.8/"}],
    ...
    "properties": {
        "latestValues": {
            "description": "Provides all current values of the weather station.",
            "type": "object",
            "properties": {
            "temperature": {
                "type": "number",
                "minimum" : -32.5,
                "maximum" : -55.2,
                "unit": "om:degree_Celsius"
            },
            "humidity": {
                "type": "number",
                "minimum" : 0,
                "maximum" : 100,
                "unit": "om:percent"
            }
            },
            forms:[...]
        }
    }
    ...

titles and descriptions

The vocabulary terms titles and descriptions enables human-readable text description in multi-languages using language tags described in [[!BCP47]]. Whenever the vocabulary terms titles and descriptions can be used, both MUST be serialized as JSON Object. The member names of the JSON Object MUST be the language tags as defined in [[!BCP47]] (e.g., "en", "de", "ja", "zh-Hans", "zh-Hant"). The value of each member MUST be serialized as JSON string.

A TD snippet using titles and descriptions in different levels is given below:

                    {
                        "name": "MyThing",
                        "descriptions": {
                            "en":"Human readable information.",
                            "de": "Menschenlesbare Informationen.",
                            "ja" : "人間が読むことができる情報",
                            "zh-Hans" : "人们可阅读的信息", 
                            "zh-Hant" : "人們可閱讀的資訊"
                        },
                        ...
                        "properties": {
                            "on": {
                                "titles": {
                                    "en": "On/Off",
                                    "de": "An/Aus",
                                    "ja": "オンオフ",
                                    "zh-Hans": "开关",
                                    "zh-Hant": "開關" },
                                "type": "boolean",
                                "forms": [...]
                            },
                            "status": {
                                "titles": {
                                    "en": "Status",
                                    "de": "Zustand",
                                    "ja": "状態",
                                    "zh-Hans": "状态",
                                    "zh-Hant": "狀態" },
                                "type": "object",
                                ...
                    }
                    

TD instances may also additional use title and description beside of titles and descriptions. If title and titles description and descriptions are defined at the same time at the JSON level, title and description MAY be seen as default text.

            {
                "name": "MyThing",
                "description": "Menschenlesbare Informationen.",
                "descriptions": {
                    "en":"Human readable information.",
                    "de": "Menschenlesbare Informationen.",
                    "ja" : "人間が読むことができる情報",
                    "zh-Hans" : "人们可阅读的信息", 
                    "zh-Hant" : "人們可閱讀的資訊"
                },
                ...
                "properties": {
                    "on": {
                        "title" : "An/Aus",
                        "titles": {
                            "en": "On/Off",
                            "de": "An/Aus",
                            "ja": "オンオフ",
                            "zh-Hans": "开关",
                            "zh-Hant": "開關" },
                        "type": "boolean",
                        "forms": [...]
                    },
                    "status": {
                        "title" : "Zustand",
                        "titles": {
                            "en": "Status",
                            "de": "Zustand",
                            "ja": "状態",
                            "zh-Hans": "状态",
                            "zh-Hant": "狀態" },
                        "type": "object",
                        ...
            }
            

Context Extension

In addition to the standard vocabulary definitions as defined in Section , the Thing Description offers the possibility to add context knowledge from different namespaces. This mechanism can be used to enrich the content of the Thing Description instances with additional (e.g., domain specific) semantics. In addition, it can also be used to specify some configurations and behaviors of the underlying communication protocols announced in the forms field.

For this extension the Thing Description uses the @context mechanism known from JSON-LD [[!json-ld11]]. The usage and serialization of the @context within the Thing Description is specified in Section .

When adding additional vocabulary to a Thing Description instance, it is recommended that these vocabulary be linked to a namespace context that is within the JSON name @context container is specified.

If included namespaces are based on class definitions such as those provided by the RDF Schema or OWL, the Things Description also allows the use of @type known from JSON-LD [[!json-ld11]] to associate the affiliation to a class.

        {
            "@context": [
                "https://www.w3.org/2019/wot/td/v1",
                {
                "om": "http://www.wurvoc.org/vocabularies/om-1.8/",
                "saref": "https://w3id.org/saref#"
            }],
            "@type": "Thing",
            ...
            "properties": {
                "Temperature": {
                    "@type": "saref:Temperature",
                    "description": "Temperature value of the weather station",
                    "om:unit_of_measure": "om:degree_Celsius",
                    "readOnly": true,
                    "observable": true,
                    "writeOnly": false,
                    "type": "number",
                    "forms" : [...]
                },
                ...
            }
        }
    

With the context extension in the Thing Description, communication metadata can be supplemented or specified in the declarations forms (also see ).

The following TD example uses the CoAP protocol binding based on [[!WoT-Binding-Templates]] and assumes that there is a CoAP RDF vocabulary set definition which is accessable via the namespace http://www.example.org/coap-binding#. The supplemented cov:methodCode guides the Consumer which CoAP method has to be applied, e.g., methodCode=1 corresponds to a CoAP GET to read the brightness value or methodCode=2 corresponds to a CoAP POST to write/change the brightness value.

Media Type

The JSON-based serialization of the TD is identified by the media type [[IANA-MEDIA-TYPES]] application/td+json.

CoAP-based WoT implementations can use the experimental Content-Format 65100 until a proper identifier has been registered.

Neither the application/td+json content type nor a CoAP Content-Format identifier have been registered with IANA yet.

Behavioral Assertions

The following assertions relate to the behavior of components of a WoT system, as opposed to the representation or information model of the TD. However, note that TDs are descriptive, and may in particular be used to describe pre-existing network interfaces. In these cases, assertions cannot be made that constrain the behaviour of such pre-existing interfaces. Instead, the assertions must be interpreted as constraints on the TD to accurately represent such interfaces.

Security Configurations

To enable secure interoperation, security configurations must accurately reflect the requirements of the Thing:

Some security protocols may ask for authentication information dynamically, including required encoding or encryption schemes. One consequence of the above is that if a protocol asks for a form of security credentials or an encoding or encryption scheme not declared in the Thing Description then the Thing Description is to be considered invalid.

Data Schemas

The data schemas provided in the TD should accurately represent the data payloads returned and accepted by the described Thing in the interactions specified in the TD. 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 Decription. In general, Things are described by WoT Thing Descriptions, but Consumers are constrained to follow WoT Thing Descriptions when interacting with Things.

Protocol Bindings

A Protocol Binding is the mapping from an Interaction Affordance to concrete messages of a specific protocol such as HTTP [[!RFC7231]], CoAP [[!RFC7252]], or MQTT [[!MQTT]]. Protocol Bindings of Interaction Affordances are serialized as forms as defined in .

Every form in a WoT Thing Description must have a submission target, given by the href member. The URI scheme of this submission target indicates what Protocol Binding the Thing implements [[WoT-Architecture]]. For instance, if the target starts with http or https, a Consumer can then infer the Thing implements the HTTP binding and it should expect HTTP-specific terms in the form instance (see next section, ).

HTTP Protocol Binding

Per default the Thing Description supports the HTTP protocol binding and includes the HTTP RDF vocabulary set definitions from [[HTTP-in-RDF10]] and can be directly used within TD instances by the usage of the prefix htv, which points to http://www.w3.org/2011/http#.

To interact with a Thing that implements the HTTP Protocol Binding, a Consumer needs to know what HTTP method to use when submitting a form. In the general case, a Thing Description can explicitly include a term indicating the method, i.e., htv:methodName. For the sake of conciseness, the HTTP Protocol Binding defines default values for each operation type, which also aims at convergence of the methods expected by Things (e.g., GET to read, PUT to write). When no method is indicated in a form representing an HTTP Protocol Binding, a default value MUST be assumed as shown in the following table.

Vocabulary term Default value Context
htv:methodName GET Form with operation type readproperty
htv:methodName PUT Form with operation type writeproperty
htv:methodName POST Form with operation type invokeaction

For example, the following default values should be assumed for forms in the introductory TD example:

Other Protocol Bindings

The number of WoT Protocol Bindings a WoT Thing can implement is not restricted. Other bindings, e.g. for CoAP, MQTT or OPC UA will be standardized in separate documents such as a protocol vocabulary similar to HTTP in RDF [[HTTP-in-RDF10]] or specifications including default value definitions. Such protocols can be simply integrated into the TD by the usage of the context extension mechanism (). A general guideline for Protocol Bindings is given in [[WoT-Binding-Templates]].

Example Thing Description Instances

MyLampThing Example with CoAP Binding

Feature list of the Thing:

{
    "id": "urn:dev:wot:com:example:servient:lamp",
    "name": "MyLampThing",
    "description" : "MyLampThing uses JSON serialization",
    "securityDefinitions": {"psk_sc":{"scheme": "psk"}},
    "security": ["psk_sc"],
    "properties": {
        "status": {
            "description" : "Shows the current status of the lamp",
            "type": "string",
            "forms": [{
                "href": "coaps://mylamp.example.com/status"
            }]
        }
    },
    "actions": {
        "toggle": {
            "description" : "Turn on or off the lamp",
            "forms": [{
                "href": "coaps://mylamp.example.com/toggle"
            }]
        }
    },
    "events": {
        "overheating": {
            "description" : "Lamp reaches a critical temperature (overheating)",
            "data": {"type": "string"},
            "forms": [{
                "href": "coaps://mylamp.example.com/oh"
            }]
        }
    }
}

MyLightSensor Example with MQTT Binding

Feature list of the Thing:

        {
            "name": "MyLightSensor",
            "id": "urn:dev:wot:com:example:servient:lightsensor",
            "securityDefinitions": {"nosec_sc": {"scheme": "nosec"}},
            "security": ["nosec_sc"],
            "events": {
                "lightSensor": {
                    "data":{"type": "integer"},
                    "forms": [
                        {
                            "href": "mqtt://192.168.1.187:1883/lightSensor",
                            "contentType" : "text/plain"
                        }
                    ]
                }
            } 
        }

Thing-2-Thing (T2T) Event Example

Feature list of the Thing:

        {
            "@context": "https://www.w3.org/2019/wot/td/v1",
            "id": "urn:dev:wot:org:eclipse:thingweb:event-example",
            "name": "TemperatureForT2T",
            "description": "Event with subscription / cancellation (Thing-2-Thing use case).",
            "securityDefinitions": {"nosec_sc": {"scheme": "nosec"}},
            "security": ["nosec_sc"],
            "events": {
                "temperatureValueForT2T": {
                    "description": "Provides periodic temperature values as event affordance.",
                    "subscription": {
                        "input": {
                            "targetURL": {
                                "type": "string",
                                "format": "uri",
                                "description": "Requester provides target URL to initate T2T."
                        }},
                        "output": {
                            "subscriptionID": {
                                "type": "integer",
                                "description": "Responses an unique subscription ID."
                        }}
                    },
                    "data": {
                        "type": "number",
                        "description": "Actual temperature value that is sent to the target URL. "
                    },
                    "cancellation": {
                        "input": {
                            "subscriptionID": {
                                "type": "integer",
                                "writeOnly": true,
                                "description": "Provide subscription ID that have to be cancelled."
                    }}},
                    "forms": [
                        {
                            "href": "http://192.168.0.124:8080/events/TempForT2T/subscribe",
                            "op": ["subscribeevent"],
                            "htv:methodName": "POST",
                            "contentType": "application/json"
                        },
                        {
                            "href": "http://192.168.0.124:8080/events/TempForT2T/unsubscribeevent",
                            "op": ["unsubscribeevent"],
                            "htv:methodName": "PUT",
                            "contentType": "application/json"
                        }
                    ]
            }}
        }
  

Security and Privacy Considerations

In general the security measures taken to protect a WoT system will depend on the threats and attackers that system may face and the value of the assets needs to protect. A detailed discussion of security and privacy considerations for the Web of Things, including a threat model that can be adapted to various circumstances, is presented in the informative document [[WOT-SECURITY-CONSIDERATIONS]]. This section discusses only security and privacy risks and possible mitigations directly relevant to the WoT Thing Description.

A WoT Thing Description can describe both secure and insecure network interfaces. When a Thing Description is retro-fitted to an existing network interface, no change in the security status of the network interface is to be expected.

When designing new devices and services for use with the WoT, we have documented a suggested set of best practices in [[WOT-SECURITY-BEST-PRACTICES]] to improve security. This best-practices document may be updated as security measures evolve. Following these practices does not guarantee security, but it at least will help to avoid common known vulnerabilities.

The use of a WoT Thing Description introduces the security and privacy risks given in the following sections. After each risk, we suggest some possible mitigations.

Context Dereferencing Privacy Risk

Deferencing the vocabulary files given in the @context member of any JSON-LD [[json-ld11]] document can be a privacy risk. In the case of the WoT, an attacker can observe the network traffic produced by such deferences and can use the metadata of the dereference, such as the destination IP address, to infer information about the device especially if domain-specific vocabularies are used. This is a risk even if the connection is encrypted, and is related to DNS privacy leaks.

Mitigation:
Avoid actual dereferencing of vocabulary files. Vocabulary files should be cached whenever possible. Ideally they would be made immutable, built into the interpreting device, and not derefenced at all, with the URI in the @context member serving only as an identifier of the (known) vocabulary. This requires the use of strict version control, as updates should use a new URI to ensure that existing URIs can refer to immutable data. Use well-known standard vocabulary files whenever possible to improve the chances that the context file will be available locally to systems interpreting the metadata in a Thing Description.
Immutable Identifiers Privacy Risk

The fact that a Thing Description contains a unique identifier means that should it be associated with a person it can be used to track that person and therefore pose a risk to privacy.

Mitigation:
All identifiers should be mutable, and there should be a mechanism to update the id of a Thing. Specifically, the id of a Thing should not be fixed in hardware. This does, however, conflict with the Linked Data ideal that identifiers are fixed URIs. In many circumstances it will be acceptable to only allow updates to identifiers if a Thing is reinitialized. In this case as a software entity the old Thing ceases to exist and a new Thing is created. This can be sufficient to break a tracking chain when, for example, a device is sold to a new owner. Alternatively, if more frequent changes are desired during the operational phase of a device, a mechanism can be put into place to notify only authorized users of the change in identifier when a change is made. Note however that some classes of devices, e.g. medical devices, may require immutable IDs by law in some jurisdictions. In this case extra attention should be paid to secure access to files, such as Thing Descriptions, containing such immutable identifiers.

Fingerprinting Privacy Risk

As noted above, the id member in a TD can pose a privacy risk. However, even if the id is updated as described to mitigate its tracking risk, it may still be possible to associate a TD with a particular physical device, and from there to a person, through fingerprinting.

Mitigation:
Only authorized users should be provided access to the Thing Description for a Thing. If the TD is only distributed to authorized users through secure and confidential channels, for example through a directory service that requires authentication, the risk can be minimized.
TD Interception and Tampering Security Risk

Intercepting and tampering with TDs can be used to launch man-in-the-middle attacks, for example by rewriting URLs in TDs to redirect accesses to a malicious intermediary that can capture or manipulate data.

Mitigation:
Obtain Thing Descriptions only through mutually authenticated channels. This ensures that the Consumer and the server are both sure of the identity of the other party to the communication. This is also necessary in order to deliver TDs only to authorized users.
Context Interception and Tampering Security Risk

Intercepting and tampering with context files can be used to facilitate attacks by modifying the interpretation of vocabulary.

Mitigation:
Ideally context files would only be obtained through authenticated channels but it is notable (and unfortunate) that many contexts are indicated using HTTP URLs, which are vulnerable to interception and modification if dereferenced. However, if context files are immutable and cached, and dereferencing is avoided whenever possible, then this risk can be reduced.
Inferencing of Personally Identifiable Information Privacy Risk

In many locales, in order to protect the privacy of users, there are legal requirements for the handling of personally identifiable information, that is, information that can be associated with a particular person. Such information can of course be generated by IoT devices directly. However, the existence and metadata of IoT devices (the kind of data stored in a Thing Description) can also contain or be used to infer personally identifiable information. This information can be as simple as the fact that a certain person owns a certain type of device, which can lead to additional inferences about that person.

Mitigation:
Treat a Thing Description associated with a personal device as if it contained personally identifiable information. As an example application of this principle, consider how to obtain user consent. Consent for usage of personally identifiable data generated by a Thing is often obtained when a Thing is paired with system consuming the data, which is frequently also when the Thing Description is registered with a local directory or the system consuming the Thing Description in order to access the device. In this case consent for using data from a Thing can be combined with consent for accessing the Thing's Thing Description. As a second example, if we consider a TD to contain personally identifiable information, then it should not be retained indefinitely or used for purposes other than those for which consent was given.

JSON Schema for TD Instance Validation

Below is a JSON Schema [[?JSON-SCHEMA-VALIDATION]] document for syntactically validating Thing Description instances serialized in JSON based format.

The Thing Description defined by this document allows for adding external vocabularies by using @context mechanism known from JSON-LD [[json-ld11]], and the terms in those external vocabularies can be used in addition to the terms defined in Section . For this reason, the below JSON schema is intentionally non-strict in that regard. You can replace the value of additionalProperties schema property true with false in different scopes/levels in order to perform a stricter validation in case no external vocabularies are used.

The following JSON Schema for validating TD instances does not require the terms with default values to be present. Thus the terms with default values are optional. (see also )

    {
    "title": "WoT TD Schema - 29 March 2019",
    "description": "JSON Schema for validating TD instances against the TD model. TD instances can be with or without terms that have default values",
    "$schema ": "http://json-schema.org/draft-06/schema#",
    "definitions": {
        "thing-context": {
            "oneOf": [{
                    "type": "array",
                    "items": {
                        "anyOf": [{
                                "$ref": "#/definitions/url"
                            },
                            {
                                "type": "object"
                            }
                        ]
                    },
                    "contains": {
                        "type": "string",
                        "enum": [
                            "http://www.w3.org/ns/td", "http://w3.org/ns/td"
                        ]
                    }
                },
                {
                    "type": "string",
                    "enum": [
                        "http://www.w3.org/ns/td", "http://w3.org/ns/td"
                    ]
                }
            ]
        },
        "type_declaration": {
            "oneOf": [{
                    "type": "string"
                },
                {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                }
            ]
        },
        "property_element": {
            "type": "object",
            "properties": {
                "@type": {
                    "$ref": "#/definitions/type_declaration"
                },
                "description": {
                    "$ref": "#/definitions/description"
                },
                "title": {
                    "$ref": "#/definitions/title"
                },
                "descriptions": {
                    "$ref": "#/definitions/descriptions"
                },
                "titles": {
                    "$ref": "#/definitions/titles"
                },
                "uriVariables": {
                    "type": "object",
                    "additionalProperties": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "forms": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                        "$ref": "#/definitions/form_element_property"
                    }
                },
                "observable": {
                    "type": "boolean"
                },
                "writeOnly": {
                    "type": "boolean"
                },
                "readOnly": {
                    "type": "boolean"
                },
                "oneOf": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "unit": {
                    "type": "string"
                },
                "enum": {
                    "type": "array",
                    "minItems": 1,
                    "uniqueItems": true
                },
                "format": {
                    "type": "string"
                },
                "const": {},
                "type": {
                    "type": "string",
                    "enum": [
                        "boolean",
                        "integer",
                        "number",
                        "string",
                        "object",
                        "array",
                        "null"
                    ]
                },
                "items": {
                    "oneOf": [{
                            "$ref": "#/definitions/dataSchema"
                        },
                        {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/dataSchema"
                            }
                        }
                    ]
                },
                "maxItems": {
                    "type": "integer",
                    "minimum": 0
                },
                "minItems": {
                    "type": "integer",
                    "minimum": 0
                },
                "minimum": {
                    "type": "number"
                },
                "maximum": {
                    "type": "number"
                },
                "properties": {
                    "additionalProperties": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "required": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                }
            },
            "required": [
                "forms"
            ],
            "additionalProperties": true
        },
        "action_element": {
            "type": "object",
            "properties": {
                "description": {
                    "type": "string"
                },
                "descriptions": {
                    "$ref": "#/definitions/descriptions"
                },
                "title": {
                    "type": "string"
                },
                "titles": {
                    "$ref": "#/definitions/titles"
                },
                "uriVariables": {
                    "type": "object",
                    "additionalProperties": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "@type": {
                    "$ref": "#/definitions/type_declaration"
                },
                "forms": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                        "$ref": "#/definitions/form_element_action"
                    }
                },
                "input": {
                    "$ref": "#/definitions/dataSchema"
                },
                "output": {
                    "$ref": "#/definitions/dataSchema"
                },
                "safe": {
                    "type": "boolean"
                },
                "idempotent": {
                    "type": "boolean"
                }
            },
            "required": [
                "forms"
            ],
            "additionalProperties": true
        },
        "event_element": {
            "type": "object",
            "properties": {
                "description": {
                    "type": "string"
                },
                "title": {
                    "type": "string"
                },
                "descriptions": {
                    "$ref": "#/definitions/descriptions"
                },
                "titles": {
                    "$ref": "#/definitions/titles"
                },
                "uriVariables": {
                    "type": "object",
                    "additionalProperties": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "@type": {
                    "$ref": "#/definitions/type_declaration"
                },
                "forms": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                        "$ref": "#/definitions/form_element_event"
                    }
                },
                "subscription": {
                    "$ref": "#/definitions/dataSchema"
                },
                "data": {
                    "$ref": "#/definitions/dataSchema"
                },
                "cancellation": {
                    "$ref": "#/definitions/dataSchema"
                },
                "type": {
                    "not": {}
                },
                "enum": {
                    "not": {}
                },
                "const": {
                    "not": {}
                }
            },
            "required": [
                "forms"
            ],
            "additionalProperties": true
        },
        "form_element_property": {
            "type": "object",
            "properties": {
                "href": {
                    "$ref": "#/definitions/url"
                },
                "op": {
                    "oneOf": [{
                            "type": "string",
                            "enum": [
                                "readproperty",
                                "writeproperty",
                                "observeproperty",
                                "unobserveproperty"
                            ]
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string",
                                "enum": [
                                    "readproperty",
                                    "writeproperty",
                                    "observeproperty",
                                    "unobserveproperty"
                                ]
                            }
                        }
                    ]
                },
                "contentType": {
                    "type": "string"
                },
                "security": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "scopes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "subProtocol": {
                    "type": "string",
                    "enum": [
                        "longpoll",
                        "websub",
                        "sse"
                    ]
                },
                "response": {
                    "type": "object",
                    "properties": {
                        "contentType": {
                            "type": "string"
                        }
                    }
                }
            },
            "required": [
                "href"
            ],
            "additionalProperties": true
        },
        "form_element_action": {
            "type": "object",
            "properties": {
                "href": {
                    "$ref": "#/definitions/url"
                },
                "op": {
                    "oneOf": [{
                            "type": "string",
                            "enum": [
                                "invokeaction"
                            ]
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string",
                                "enum": [
                                    "invokeaction"
                                ]
                            }
                        }
                    ]
                },
                "contentType": {
                    "type": "string"
                },
                "security": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "scopes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "subProtocol": {
                    "type": "string",
                    "enum": [
                        "longpoll",
                        "websub",
                        "sse"
                    ]
                },
                "response": {
                    "type": "object",
                    "properties": {
                        "contentType": {
                            "type": "string"
                        }
                    }
                }
            },
            "required": [
                "href"
            ],
            "additionalProperties": true
        },
        "form_element_event": {
            "type": "object",
            "properties": {
                "href": {
                    "$ref": "#/definitions/url"
                },
                "op": {
                    "oneOf": [{
                            "type": "string",
                            "enum": [
                                "subscribeevent",
                                "unsubscribeevent"
                            ]
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string",
                                "enum": [
                                    "subscribeevent",
                                    "unsubscribeevent"
                                ]
                            }
                        }
                    ]
                },
                "contentType": {
                    "type": "string"
                },
                "security": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "scopes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "subProtocol": {
                    "type": "string",
                    "enum": [
                        "longpoll",
                        "websub",
                        "sse"
                    ]
                },
                "response": {
                    "type": "object",
                    "properties": {
                        "contentType": {
                            "type": "string"
                        }
                    }
                }
            },
            "required": [
                "href"
            ],
            "additionalProperties": true
        },
        "form_element_root": {
            "type": "object",
            "properties": {
                "href": {
                    "$ref": "#/definitions/url"
                },
                "op": {
                    "oneOf": [{
                            "type": "string",
                            "enum": [
                                "readallproperties",
                                "writeallproperties",
                                "readmultipleproperties",
                                "writemultipleproperties"
                            ]
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string",
                                "enum": [
                                    "readallproperties",
                                    "writeallproperties",
                                    "readmultipleproperties",
                                    "writemultipleproperties"
                                ]
                            }
                        }
                    ]
                },
                "contentType": {
                    "type": "string"
                },
                "security": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "scopes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "subProtocol": {
                    "type": "string",
                    "enum": [
                        "longpoll",
                        "websub",
                        "sse"
                    ]
                },
                "response": {
                    "type": "object",
                    "properties": {
                        "contentType": {
                            "type": "string"
                        }
                    }
                }
            },
            "required": [
                "href"
            ],
            "additionalProperties": true
        },
        "description": {
            "type": "string"
        },
        "title": {
            "type": "string"
        },
        "descriptions": {
            "type": "object"
        },
        "titles": {
            "type": "object"
        },
        "dataSchema": {
            "type": "object",
            "properties": {
                "@type": {
                    "$ref": "#/definitions/type_declaration"
                },
                "description": {
                    "$ref": "#/definitions/description"
                },
                "title": {
                    "$ref": "#/definitions/title"
                },
                "descriptions": {
                    "$ref": "#/definitions/descriptions"
                },
                "titles": {
                    "$ref": "#/definitions/titles"
                },
                "writeOnly": {
                    "type": "boolean"
                },
                "readOnly": {
                    "type": "boolean"
                },
                "oneOf": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "unit": {
                    "type": "string"
                },
                "enum": {
                    "type": "array",
                    "minItems": 1,
                    "uniqueItems": true
                },
                "format": {
                    "type": "string"
                },
                "const": {},
                "type": {
                    "type": "string",
                    "enum": [
                        "boolean",
                        "integer",
                        "number",
                        "string",
                        "object",
                        "array",
                        "null"
                    ]
                },
                "items": {
                    "oneOf": [{
                            "$ref": "#/definitions/dataSchema"
                        },
                        {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/dataSchema"
                            }
                        }
                    ]
                },
                "maxItems": {
                    "type": "integer",
                    "minimum": 0
                },
                "minItems": {
                    "type": "integer",
                    "minimum": 0
                },
                "minimum": {
                    "type": "number"
                },
                "maximum": {
                    "type": "number"
                },
                "properties": {
                    "additionalProperties": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "required": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                }
            }
        },
        "link_element": {
            "type": "object",
            "properties": {
                "anchor": {
                    "$ref": "#/definitions/url"
                },
                "href": {
                    "$ref": "#/definitions/url"
                },
                "rel": {
                    "type": "string"
                },
                "type": {
                    "type": "string"
                }
            },
            "required": [
                "href"
            ],
            "additionalProperties": true
        },
        "securityScheme": {
            "oneOf": [{
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/url"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "nosec"
                            ]
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/url"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "basic"
                            ]
                        },
                        "in": {
                            "type": "string",
                            "enum": ["header", "query", "body", "cookie"]
                        },
                        "name": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/url"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "cert"
                            ]
                        },
                        "identity": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/url"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "digest"
                            ]
                        },
                        "qop": {
                            "type": "string",
                            "enum": ["auth", "auth-int"]
                        },
                        "in": {
                            "type": "string",
                            "enum": ["header", "query", "body", "cookie"]
                        },
                        "name": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/url"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "bearer"
                            ]
                        },
                        "authorization": {
                            "$ref": "#/definitions/url"
                        },
                        "alg": {
                            "type": "string",
                            "enum": ["MD5", "ES256", "ES512-256"]
                        },
                        "format": {
                            "type": "string",
                            "enum": ["jwt", "jwe", "jws"]
                        },
                        "in": {
                            "type": "string",
                            "enum": ["header", "query", "body", "cookie"]
                        },
                        "name": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/url"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "psk"
                            ]
                        },
                        "identity": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/url"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "public"
                            ]
                        },
                        "identity": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/url"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "oauth2"
                            ]
                        },
                        "authorization": {
                            "$ref": "#/definitions/url"
                        },
                        "token": {
                            "$ref": "#/definitions/url"
                        },
                        "refresh": {
                            "$ref": "#/definitions/url"
                        },
                        "scopes": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        },
                        "flow": {
                            "type": "string",
                            "enum": ["implicit", "password", "client", "code"]
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/url"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "apikey"
                            ]
                        },
                        "in": {
                            "type": "string",
                            "enum": ["header", "query", "body", "cookie"]
                        },
                        "name": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/url"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "pop"
                            ]
                        },
                        "authorization": {
                            "$ref": "#/definitions/url"
                        },
                        "format": {
                            "type": "string",
                            "enum": ["jwt", "jwe", "jws"]
                        },
                        "alg": {
                            "type": "string",
                            "enum": ["MD5", "ES256", "ES512-256"]
                        },
                        "in": {
                            "type": "string",
                            "enum": ["header", "query", "body", "cookie"]
                        },
                        "name": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                }
            ]
        },
        "url": {
            "type": "string",
            "format": "uri-reference"
        }
    },
    "type": "object",
    "properties": {
        "id": {
            "type": "string",
            "format": "uri"
        },
        "name": {
            "type": "string"
        },
        "properties": {
            "type": "object",
            "additionalProperties": {
                "$ref": "#/definitions/property_element"
            }
        },
        "actions": {
            "type": "object",
            "additionalProperties": {
                "$ref": "#/definitions/action_element"
            }
        },
        "events": {
            "type": "object",
            "additionalProperties": {
                "$ref": "#/definitions/event_element"
            }
        },
        "description": {
            "$ref": "#/definitions/description"
        },
        "descriptions": {
            "$ref": "#/definitions/descriptions"
        },
        "version": {
            "type": "object",
            "properties": {
                "instance": {
                    "type": "string"
                }
            },
            "required": [
                "instance"
            ]
        },
        "links": {
            "type": "array",
            "items": {
                "$ref": "#/definitions/link_element"
            }
        },
        "forms": {
            "type": "array",
            "minItems": 1,
            "items": {
                "$ref": "#/definitions/form_element_root"
            }
        },
        "base": {
            "$ref": "#/definitions/url"
        },
        "securityDefinitions": {
            "type": "object",
            "minProperties": 1,
            "additionalProperties": {
                "$ref": "#/definitions/securityScheme"
            }
        },
        "support": {
            "type": "string"
        },
        "created": {
            "type": "string"
        },
        "lastModified": {
            "type": "string"
        },
        "security": {
            "type": "array",
            "minItems": 1,
            "items": {
                "type": "string"
            }
        },
        "@type": {
            "$ref": "#/definitions/type_declaration"
        },
        "@context": {
            "$ref": "#/definitions/thing-context"
        }
    },
    "required": [
        "name",
        "id",
        "security",
        "securityDefinitions",
        "@context"
    ],
    "additionalProperties": true
}
    

Thing Templates

A Thing Template is a description for a class of devices or things. It describes the properties, actions, events and common metadata that are shared for an entire group of things, to enable the common handling of thousands of devices by a cloud server, which is not practical on a per-thing basis. The Thing Template uses the same core vocabulary and information model from section 5.

The Thing Template enables:

The Thing Template is a logical description of the interface and possible interaction with devices (properties, actions and events), however it does not contain device-specific information, such as a serial number, GPS location, security information or concrete protocol endpoints.

Since a Thing Template does not contain a Protocol Binding to specific endpoints and does not define a specific security mechanism, the forms and securityDefinitions and security keys must not be present.

The same Thing Template can be implemented by things from multiple vendors, a thing can implement multiple thing templates, define additional metadata (vendor, location, security) and define bindings to concrete protocols. To avoid conflicts between properties, actions and events from different thing templates that are combined into a common thing, all thse identifiers must be unique within a thing.

A common Thing Template for a class of devices enables writing applications across vendors and creates a more attractive market for application developers. A concrete Thing Description can implement multiple Thing Templates and thus can aggregate function blocks into a combined device.

The business models of cloud vendors are typically built on managing thousands of identical devices. All devices with the same Thing Template can be managed in the same way by cloud applications. It is easy to create multiple simulated devices, if the interface and the instance are treated separately.

Since a Thing Template is a subset of the Thing Description in which some optional and mandatory vocabulary terms does not exist, however, it can be serialized in the same way and in the same formats as a Thing Description. Note that Thing Template instances cannot be validated in the same way as Thing Description instances due to missing mandatory terms.

Thing Template Examples

This section defines a Thing Template for a lamp and a Thing Template for a a buzzer. The combined thing BuzzerLamp includes both thing templates.

Thing Template: Lamp

    {
        "@context": ["https://www.w3.org/2019/wot/td/v1"], 
        "@type" : "ThingTemplate",
        "id": "urn:dev:wot:com:example:servient:lamp:model",
        "name": "Lamp Thing Template",
        "description" : "Lamp Thing Template",
        "properties": {
            "status": {
                "description" : "current status of the lamp (on|off)",
                "type": "string",
                "readOnly": true
            }
        },
        "actions": {
            "toggle": {
                "description" : "Turn the lamp on or off"
            }
        },
        "events": {
            "overheating": {
                "description" : "Lamp reaches a critical temperature (overheating)",
                "data": {"type": "string"}
            }
        }
    }
    

Thing Template: Buzzer

    {
        "@context": ["https://www.w3.org/2019/wot/td/v1"], 
        "@type" : "ThingTemplate",
        "id": "urn:dev:wot:com:example:servient:buzzer:template",
        "name": "Buzzer Thing Template",
        "description" : "Thing template of a buzzer that makes noise for 10 seconds",
         "actions": {
            "buzz": {
                "description" : "buzz for 10 seconds"
            }
         }
    }
    

Combined Thing: Lamp + Buzzer

The following example illustrates how a combined thing can be defined using two different thing templates.

    {
       "@context": ["https://www.w3.org/2019/wot/td/v1",
       		    { "thing-templates": "http://www.w3.org/ns/thing-templates"] }, 
       "@type" : [
            "Thing",
            "urn:dev:wot:com:example:servient:lamp:template",
            "urn:dev:wot:com:example:servient:buzzer:template"
        ],
        "id": "urn:dev:wot:com:example:servient:combinedBuzzerLamp1",
        "name": "My Buzzing Lamp Thing",
        "description" : "A lamp that can issue an alert",
        "securityDefinitions": {"nosec_sc": {"scheme": "nosec"}},
        "security": ["nosec_sc"],
        "thing-templates:components": [{
            "id": "urn:dev:wot:com:example:servient:lamp:template",
            "name": "Lamp Thing Template",
            "description" : "Thing Template for a lamp",
            "properties": {
                "status": {
                    "description" : "current status of the lamp (on|off)",
                    "type": "string",
                    "readOnly": true,
                    "forms": [{
                    "href": "coaps://buzzlamp.example.com/status",
                    "contentType": "application/json"
                    }]
                }
            },
            "actions": {
                "toggle": {
                    "description" : "Turn on or off the lamp",
                    "forms": [{
                        "href": "coaps://buzzlamp.example.com/toggle",
                        "contentType": "application/json"
                    }]
                }
            },
            "events": {
                "overheating": {
                    "@type" : "iot:TemperatureAlarm",
                    "description" : "Lamp reaches a critical temperature (overheating)",
                    "data": {"type": "string"},
                    "forms": [{
                        "href": "coaps://buzzlamp.example.com/oh",
                        "contentType": "application/json"
                    }]
                }
            }
        },
        {
            "id": "urn:dev:wot:com:example:servient:buzzer:template",
            "name": "Buzzer Thing Template",
            "description" : "Thing Template of a buzzer that makes noise for 10 seconds",
             "actions": {
                "buzz": {
                    "description" : "buzz for 10 seconds",
                    "forms": [{
                        "href": "coaps://buzzlamp.example.com/buzz",
                        "contentType": "application/json"
                    }]
                }
             }
        }]
    }
      
computer keyboard have this Scroll Lock key that seems to serve no purpose whatsoever? In 15 years I don't remember ever pushing that button. I'm almost scared to touch it

Transformation to RDF

To integrate a Thing Description instance with external knowledge and contextual information (like iot.schema.org annotations), the use of JSON-LD 1.1 and its processing API [[json-ld11-api]], as well as RDF-based tools [[rdf11-concepts]] and libraries is highly recommended. This appendix introduces two non-normative elements of the Thing Description model that allow for a transformation to RDF: the default JSON-LD context for TD and the TD ontology.

Thing Description JSON-LD Context

A JSON TD document can be transformed in RDF (to then be uploaded to an RDF store for further analytics) by a standard JSON-LD processor. The following procedure loads the context of the TD, given by the term @context, and generates RDF triples:

JsonLdProcessor.toRdf

When applying this procedure to the introductory TD example with all default values, the following triples are obtained:

Most importantly, the JSON-LD context maps JSON strings to RDF IRIs (hence, the notion of context: in two different contexts, the same string can have different meanings). The mapping here is rather straightforward: every vocabulary of the TD information model is defined its own namespace and every vocabulary term maps to some name, appended to the corresponding namespace. Strings that are not part of any vocabulary map to RDF literals (strings with an optional datatype). For instance, name maps to http://www.w3.org/ns/td#name and MyLampThing remains unchanged. Applying this mapping is called context expansion.

The following table gives the correspondance between a vocabulary and its namespace:

Vocabulary Namespace
Core https://www.w3.org/ns/td#
Data Schema https://www.w3.org/ns/json-schema#
Security https://www.w3.org/2019/ns/wot-security#
Web Linking https://www.w3.org/2019/wot/web-linking#

Then, after expanding JSON strings to full IRIs, all map structures of the JSON TD document must be turned into RDF triples. In a simple case, a triple is produced for every key/value pair in the map. For instance, the very first triple of the example above was produced from "name": "myLampThing".

Other cases rely on specific JSON-LD features. Most of these features were introduced in the 1.1 version of the standard and thus require an appropriate JSON-LD 1.1 implementation. They are listed below:

The last two JSON-LD features (property-based data indexing and indexing without a predicate) are still experimental; they have not been published in any Editor's Draft yet.

An experimental JSON-LD 1.1 context for the TD model is provided in the repository: td-context-1.1.jsonld. Currently, it is not the context served at https://www.w3.org/2019/wot/td/v1, though.

Thing Description Ontology

TD classes and properties have RDF foundations, in the form of a Web ontology in the Web Ontology Language [[owl2-overview]]. Some assertions of this document are also expressed as OWL axioms.

Default values require special care when translating the TD information model into OWL.

Currently, the ontology documentation is available on w3c.github.io but it should eventually be put under the TD namespace, on w3.org.

Recent Specification Changes

Changes from Third Public Working Draft

Changes from Second Public Working Draft

Changes from Second Public Working Draft are described in the Third Public Working Draft

Acknowledgements

The editors would like to thank Dave Raggett, Matthias Kovatsch, Michael Koster, Kawaguchi Toru, Michael Lagally, Kazuyuki Ashimura, Ege Korkan, María Poveda, Daniel Peintner, Ben Francis for their contributions, comments, and guidance.