Copyright © 2017-2023 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
The Web of Things is made of entities (Things) that can describe their capabilities in a machine-interpretable Thing Description (TD) and expose these capabilities through the WoT Interface, that is, network interactions modeled as Properties (for reading and writing values), Actions (to execute remote procedures with or without return values) and Events (for signaling notifications).
The main Web of Things (WoT) concepts are described in the Web of Things (WoT) Architecture 1.1 specification.
Scripting is an optional building block in WoT and it is typically used in gateways or browsers that are able to run a WoT Runtime and script management, providing a convenient way to extend WoT support to new types of endpoints and implement WoT applications such as TD Directory.
This specification describes an application programming interface (API) representing the WoT Interface that allows scripts to discover, operate Things and to expose locally defined Things characterized by WoT Interactions specified by a script.
The APIs defined in this document deliberately follow the Web of Things (WoT) Thing Description 1.1 specification closely. It is possible to implement more abstract APIs on top of them, or implementing directly the WoT network facing interface (i.e. the WoT Interface).
This specification is implemented at least by the Eclipse Thingweb project also known as node-wot, which is considered the reference open source implementation at the moment. Check its source code, including examples.
This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
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.
Please contribute to this draft using the GitHub Issues page of the WoT Scripting API repository. For feedback on security and privacy considerations, please use the WoT Security and Privacy Issues.
This document was published by the Web of Things Working Group as a Group Note using the Note track.
This Group Note is endorsed by the Web of Things Working Group, but is not endorsed by W3C itself nor its Members.
This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
The W3C Patent Policy does not carry any licensing requirements or commitments on this document.
This document is governed by the 12 June 2023 W3C Process Document.
WoT provides layered interoperability based on how Things are used: "consumed" and "exposed", as defined in the Web of Things (WoT) Architecture 1.1 terminology.
By consuming a TD, a client Thing creates a local runtime resource model that allows accessing the Properties, Actions and Events exposed by the server Thing on a remote device.
Typically scripts are meant to be used on bridges or gateways that expose and control simpler devices as WoT Things and have means to handle (e.g. install, uninstall, update etc.) and run scripts.
This specification does not make assumptions on how the WoT Runtime handles and runs scripts, including single or multiple tenancy, script deployment and lifecycle management. The API already supports the generic mechanisms that make it possible to implement script management, for instance by exposing a manager Thing whose Actions (action handlers) implement script lifecycle management operations.
This section is non-normative.
The business use cases listed in the [WOT-USE-CASES] document may be implemented using this API, based on the scripting use case scenarios described here.
After evaluating dynamic modifications to Thing Descriptions through several versions of this API, the editors concluded that the simplest way to represent these use cases is to take an existing TD, modify it (i.e. add or remove definitions) and then create a new Thing based on the modified TD.
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MAY, MUST, and SHOULD in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
This specification used to be a Working Draft which was expected to become a W3C Recommendation. However, it is now a WG Note which contains informative statements only. Therefore we need to consider how to deal with the description within this Conformance section.
This specification describes the conformance criteria for the following classes of user agent (UA).
Due to requirements of small embedded implementations,
    splitting WoT client and server interfaces was needed. Then,
    discovery is a distributed application, but typical scenarios
    have been covered by a generic discovery API in this
    specification. This resulted in using 3 conformance classes for
    a UA that implements this API, one for
    client, one for server, and one for discovery. An application
    that uses this API can introspect for the presence of the
    consume(), produce() and
    discover() methods on the WoT API object in order
    to determine which conformance class the UA implements.
Implementations of this conformance class MUST implement the ConsumedThingconsume() method on the
        WoT
        API object.
Implementations of this conformance class MUST implement ExposedThingproduce() method on the
        WoT
        API object.
Implementations of this conformance class MUST implement the ThingDiscoveryProcessdiscover() method, the
        exploreDirectory() method, and the
        requestThingDescription() method on the
        WoT
        API object.
These conformance classes MAY be implemented in a single UA.
This specification can be used for implementing the WoT Scripting API in multiple programming languages. The interface definitions are specified in [WEBIDL].
The UA may be implemented in the browser, or in a separate runtime environment, such as Node.js or in small embedded runtimes.
Implementations that use ECMAScript executed in a browser to implement the APIs defined in this document MUST implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [WEBIDL].
Implementations that use TypeScript or ECMAScript in a runtime to implement the APIs defined in this document MUST implement them in a manner consistent with the TypeScript Bindings defined in the TypeScript specification [TYPESCRIPT].
The generic WoT terminology is defined in [WOT-ARCHITECTURE]: Thing, Thing Description (in short TD), Partial TD, Web of Things (in short WoT), WoT Interface, Protocol Bindings, WoT Runtime, Consuming a Thing Description, TD Directory, Property, Action, Event, DataSchema, Form, SecurityScheme, NoSecurityScheme etc.
WoT Interaction is a synonym for Interaction Affordance. An Interaction Affordance (or shortly, affordance) is the term used in [WOT-TD] when referring to Thing capabilities, as explained in TD issue 282. However, this term is not well understood outside the TD semantic context. Hence for the sake of readability, this document will use the previous term WoT interaction or, simply, interaction instead.
WoT network interface synonym for WoT Interface.
JSON Schema is defined in these specifications.
Promise,
    Error,
    JSON,
    JSON.stringify,
    JSON.parse,
    
    internal method and 
    internal slot are defined in [ECMASCRIPT].
WebIDLtypedef object ThingDescription;
    Represents a Thing Description (TD) as defined in [WOT-TD]. It is expected to be a parsed JSON object that is validated using JSON Schema validation.
Fetching a TD given a URL should be done with an external method, such as the Fetch API or a HTTP client library, which offer already standardized options on specifying fetch details.
try {
  let res = await fetch('https://tds.mythings.biz/sensor11');
  // ... additional checks possible on res.headers
  let td = await res.json();
  let thing = await WOT.consume(td);
  console.log("Thing name: " + thing.getThingDescription().title);
} catch (err) {
  console.log("Fetching TD failed", err.message);
}Note that the Web of Things (WoT) Thing Description 1.1 specification allows using a shortened Thing Description by the means of defaults and requiring clients to expand them with default values specified in the Web of Things (WoT) Thing Description 1.1 specification for the properties that are not explicitly defined in a given TD.
The [WOT-TD]
      specification defines how a TD should be validated. Therefore,
      this API expects the ThingDescription
      objects be validated before used as parameters. This
      specification defines a basic TD validation as follows.
TypeError"
            and stop.
          Additional steps may be added to fill the default values of mandatory fields.
Defines the WoT API object as a singleton and contains the API methods, grouped by conformance classes.
WebIDL[SecureContext, Exposed=(Window,Worker)]
namespace WOT {
  // methods defined in UA conformance classes
};
    WebIDLpartial namespace WOT {
  Promise<ConsumedThing> consume(ThingDescription td);
};
      
        Promise that resolves with a
        ConsumedThing
        object that represents a client interface to operate with
        the Thing.
        The method MUST run the following
        steps:
        PromiseSecurityError
            and stop.
          ConsumedThing
            object constructed from td.
          Implementations encapsulate the complexity of how to use the Protocol Bindings for implementing WoT interactions. In the future elements of that could be standardized.
Note the difference between constructing
          ConsumedThing
          and using the consume() method: the latter
          also initializes the protocol bindings, whereas a simple
          constructed object will not have WoT Interactions
          initialized until they are invoked.
WebIDLtypedef object ExposedThingInit;
partial namespace WOT {
  Promise<ExposedThing> produce(ExposedThingInit init);
};
      
        Promise that resolves with an
        ExposedThing
        object that extends ConsumedThing
        with a server interface, i.e. the ability to define request
        handlers. The init
        object is an instance of the ExposedThingInit
        type. Specifically, an ExposedThingInit
        value is a dictionary used for the initialization of an
        ExposedThing
        and it represents a Partial TD as described in
        the [WOT-ARCHITECTURE].
        As such, it has the same structure of a Thing Description
        but it may omit some information. The method MUST run the following steps:
        PromiseSecurityError
            and stop.
          ExposedThing
            object constructed with init.
          SyntaxError
            and stop.
          "securityDefinitions"],
          make a request to the underlying platform to check if it
          is supported by at least one Protocol Binding.
          If not, then remove scheme from td.
          "security"]
          does not exist in
          td.["securityDefinitions"],
          then remove security from td.
          authority it is
                  not recognized by the runtime as valid, remove
                  href from
                  form.The editors find this step vague. It will be improved or removed in the next iteration.
title
              generate a runtime unique name and assign to
              title.@context
              assign the latest supported Thing Description context
              URI.instance
              assign the string 1.0.0.forms
              generate a list of Forms using the available
              Protocol
                Bindings and content types encoders. Then
                assign the obtained list to forms.
              security
              assign the label of the first supported SecurityScheme in
              securityDefinitions field. If no
                SecurityScheme
                is found generate a NoSecurityScheme
                called nosec and assign the string
                nosec to security.
                The discussion about how to properly
                  generate a value for security is
                  still open. See issue 
                  #299
href define
              formStub as the partial Form that does not
                have href. Generate a valid
                url using the first
                Protocol
                Binding that satisfy the requirements of
                formStub. Assign url to href. If not
                Protocol
                Binding can be found remove formStub
                from td.
              title,
          @context, instance,
          forms, security, and
          href.required execute the following
          steps:
            Array then remove all its elements equal
              to the elements in optionalstring then if value is equal
              to one of the elements in optional remove key from
              exposedThingInitSchemaThe validating an object with JSON Schema steps are still under discussion. Currently this specification reference to the validation process of JSONSchema. Please follow this document when validating init with exposedThingInitSchema. Notice that the working group is evaluating an alternative formal approach.
WebIDLpartial namespace WOT {
  Promise<ThingDiscoveryProcess> discover(optional ThingFilter filter = {});
};
      ThingDescription
        objects for Thing Descriptions
        that match an optional filter argument of type
        ThingFilter.
        The method MUST run the following
        steps:
        PromiseSecurityError
            and stop.
          
            NotSupportedError and stop.
          ThingDiscoveryProcess
            object.
          [[filter]] to
            filter.
          [[url]] to
            undefined.
          undefined
          or null, reject
            promise with
            
            NotSupportedError and stop.
          OperationError
            and stop.
          WebIDLpartial namespace WOT {
  Promise<ThingDiscoveryProcess> exploreDirectory(USVString url,
      optional ThingFilter filter = {});
};
      ThingDescription
        objects for Thing Descriptions
        that match an optional filter argument of type
        ThingFilter.
        The method MUST run the following
        steps:
        PromiseSecurityError
            and stop.
          
            NotSupportedError and stop.
          ThingDiscoveryProcess
            object.
          [[url]] to
            url.
          [[filter]] to
            filter.
          This is a placeholder for more details in the discovery algorithm. Implementations should follow the procedures described in the [WOT-DISCOVERY] and [WOT-PROTOCOL-BINDINGS] specifications. Some normative steps are indicated below.
NotSupportedError and terminate
                these steps.
              undefined or null,
              reject
              promise with
              
                NotSupportedError and stop.
              From this point on, errors are
                  recorded only on 
                  error, but don't affect
                  promise any
                  longer.
WebIDLpartial namespace WOT {
  Promise<ThingDescription> requestThingDescription(USVString url);
};
      PromiseSecurityError
            and stop.
          
            NotSupportedError and stop.
          NotFoundError
            and stop.
          As specified in the 
    Web of Things (WoT) Thing Description 1.1
    specification, WoT interactions extend
    DataSchema and include
    a number of possible Forms, out of
    which one is selected for the interaction. The 
    Form contains a contentType to describe the
    data. For certain content types, a DataSchema is defined, based on
    JSON Schema, making
    possible to represent these contents as JavaScript types and
    eventually set range constraints on the data.
WebIDLtypedef any DataSchemaValue;
typedef (ReadableStream or DataSchemaValue) InteractionInput;
      Belongs to the WoT Consumer conformance class and represents the WoT Interaction data provided by application scripts to the UA.
DataSchemaValue is an 
      ECMAScript value that is accepted for DataSchema defined in
      [WoT-TD].
      The possible values MUST be of type
      
      null, 
      boolean, 
      number, 
      string, array,
      or object.
ReadableStream
      is meant to be used for WoT Interactions that
      don't have a DataSchema in the Thing
      Description, only a Form's
      contentType that can be represented by a
      stream.
In practice, any 
      ECMAScript value may be used for WoT
      Interactions that have a DataSchema defined in the
      Thing Description, or
      which can be mapped by implementations to the
      Form's
      contentType defined in the Thing
      Description.
The algorithms in this document specify how exactly input data is used in WoT Interactions.
Belongs to the WoT Consumer conformance
      class. An InteractionOutput
      object is always created by the implementations and exposes
      the data returned from WoT Interactions to
      application scripts.
This interface exposes a convenience function which should
      cover the vast majority of IoT use cases: the value() function. Its
      implementation will inspect the data, parse it if adheres to
      a DataSchema, or otherwise fail
      early, leaving the underlying stream undisturbed so that
      application scripts could attempt reading the stream
      themselves, or handling the data as ArrayBuffer.
WebIDL[SecureContext, Exposed=(Window,Worker)]
interface InteractionOutput {
  readonly attribute ReadableStream? data;
  readonly attribute boolean dataUsed;
  readonly attribute Form? form;
  readonly attribute DataSchema? schema;
  Promise<ArrayBuffer> arrayBuffer();
  Promise<DataSchemaValue> value();
};
      The data property represents the raw
      payload in WoT
      Interactions as a ReadableStream,
      initially null.
The dataUsed property tells whether
      the data stream has been 
      disturbed. Initially false.
The form attribute
      represents the Form
      selected from the Thing Description for
      this WoT
      Interaction, initially null.
The schema attribute represents the
      DataSchema (defined
      in [WoT-TD])
      of the payload as a JSON
      object, initially null.
The [[value]] internal slot represents the parsed
      value of the WoT Interaction,
      initially undefined (note that null
      is a valid value).
contentType of the interaction
        Form. The method
        MUST run the following steps:
        Promiseundefined, resolve
          promise with that value
          and stop.
          
            ReadableStream or if dataUsed is
            true, or if form is not an
            object
            or if schema or its type are
            null or undefined, then
            reject
            promise with
            
            NotReadableError and stop.
          application/json and if a mapping is not
          available in the Protocol Bindings
            from form.contentType to
            [JSON-SCHEMA],
            reject
            promise with
            
            NotSupportedError and stop.
          true.application/json and if a mapping is
          available in the Protocol
            Bindings from
            form.contentType to
            [JSON-SCHEMA],
            transform bytes with that mapping.
          Promise
            ReadableStream or if dataUsed is
            true, reject
            promise with
            
            NotReadableError and stop.
          true.
            ArrayBuffer whose contents are
            bytes. If that throws, reject
            promise with that
            exception and stop.
          "null" and if
          payload is not null, throw
          
            TypeError and stop, otherwise return
            null.
          "boolean" and
          payload is a falsy value or its byte length is
          0, return false, otherwise return
          true."integer" or
          "number",
            TypeError and stop.
              RangeError and stop.
              "string", return
          payload."array", run these
          sub-steps:
            TypeError and stop.
              RangeError and stop.
              "object", run
          these sub-steps:
            object,
                throw 
                TypeError and stop.
              
                SyntaxError and stop.
              ConsumedThing
        object thing, in order
        to create
        interaction request given a source, form and schema,
        run these steps:
        InteractionOutput
          object.
          null and set 
            idata.[[value]] to
            undefined.
          
            ReadableStream object, let
            idata.data be source, return
            idata and stop.
          null, run
            these sub-steps:
            "null" and
              source is not
              "null", throw 
                TypeError and stop.
              "boolean" and
              source is a
              falsy value, set
                idata.[[value]] to
                false, otherwise set it to
                true.
              "integer" or
              "number" and source is not a number, or
              if form.minimum is defined and
              source is
              smaller, or if form.maximum is defined and
              source is
              bigger, throw 
                RangeError and stop.
              "string" and
              source is not
              a string, let idata.[[value]] be
              the result of running 
                serialize JSON to bytes given source. If that is
                failure, throw 
                SyntaxError and stop.
              "array", run
              these sub-steps:
                TypeError and stop.
                  RangeError and stop.
                  [[value]]
                    to source.
                  "object", run
              these sub-steps:
                TypeError and stop.
                  TypeError and stop.
                  
                    SyntaxError and stop.
                  [[value]]
                    to source.
                  
            ReadableStream created from
            idata.[[value]]
            
            internal slot as its underlying
            source.
          ConsumedThing
        object thing, in order
        to parse
        interaction response given response,
        form and schema, run these steps:
        InteractionOutput
          object.
          
            ReadableStream with the payload data of
            response as its underlying
            source.
          false.InteractionInput
        and InteractionOutputAs illustrated in the next pictures, the
      InteractionOutput
      interface is used every time implementations provide data to
      scripts, while InteractionInput
      is used when the scripts pass data to the implementation.
 
        When a ConsumedThing
      reads data, it receives it from the implementation as an
      InteractionOutput
      object.
An ExposedThing
      read handler
      provides the read data to the implementation as
      InteractionInput.
 
        When a ConsumedThing
      writes data, it provides it to the implementation as
      InteractionInput.
An ExposedThing
      write
      handler receives data from to implementation as an
      InteractionOutput
      object.
 
        When a ConsumedThing
      invokes an Action,
      it provides the parameters as InteractionInput
      and receives the output of the Action as an InteractionOutput
      object.
An ExposedThing
      action handler
      receives arguments from the implementation as an
      InteractionOutput
      object and provides Action output as
      InteractionInput
      to the implementation.
The algorithms in this API define the errors to be reported to application scripts.
The errors reported to the other communication end are mapped and encapsulated by the Protocol Bindings.
 
        This topic is still being discussed in Issue #200. A standardized error mapping would be needed in order to ensure consistency in mapping script errors to protocol errors and vice versa. In particular, when algorithms say "error received from the Protocol Bindings", that will be factored out as an explicit error mapping algorithm. Currently, that is encapsulated by implementations.
Represents a client API to operate a Thing. Belongs to the WoT Consumer conformance class.
WebIDL[SecureContext, Exposed=(Window,Worker)]
interface ConsumedThing {
  constructor(ThingDescription td);
  Promise<InteractionOutput> readProperty(DOMString propertyName,
                              optional InteractionOptions options = {});
  Promise<PropertyReadMap> readAllProperties(
                              optional InteractionOptions options = {});
  Promise<PropertyReadMap> readMultipleProperties(
                              sequence<DOMString> propertyNames,
                              optional InteractionOptions options = {});
  Promise<undefined> writeProperty(DOMString propertyName,
                              InteractionInput value,
                              optional InteractionOptions options = {});
  Promise<undefined> writeMultipleProperties(
                              PropertyWriteMap valueMap,
                              optional InteractionOptions options = {});
  /*Promise<undefined> writeAllProperties(
                              PropertyWriteMap valueMap,
                              optional InteractionOptions options = {});*/
  Promise<InteractionOutput> invokeAction(DOMString actionName,
                              optional InteractionInput params = {},
                              optional InteractionOptions options = {});
  Promise<Subscription> observeProperty(DOMString name,
                              InteractionListener listener,
                              optional ErrorListener onerror,
                              optional InteractionOptions options = {});
  Promise<Subscription> subscribeEvent(DOMString name,
                              InteractionListener listener,
                              optional ErrorListener onerror,
                              optional InteractionOptions options = {});
  ThingDescription getThingDescription();
};
dictionary InteractionOptions {
  unsigned long formIndex;
  object uriVariables;
  any data;
};
[SecureContext, Exposed=(Window,Worker)]
interface Subscription {
  readonly attribute boolean active;
  Promise<undefined> stop(optional InteractionOptions options = {});
};
[SecureContext, Exposed=(Window,Worker)]
interface PropertyReadMap {
  readonly maplike<DOMString, InteractionOutput>;
};
[SecureContext, Exposed=(Window,Worker)]
interface PropertyWriteMap {
  readonly maplike<DOMString, InteractionInput>;
};
callback InteractionListener = undefined(InteractionOutput data);
callback ErrorListener = undefined(Error error);
    The writeAllProperties() method is
      still under discussion. Meanwhile, use the
      writeMultipleProperties() method instead.
ConsumedThingA ConsumedThing
      object has the following 
      internal slots:
| Internal Slot | Initial value | Description (non-normative) | 
|---|---|---|
| [[td]] | null | The Thing
              Description of the ConsumedThing. | 
| [[activeSubscriptions]] | {} | An ordered
              map keyed on
              a string
              name representing the Event and
              value is a Subscriptionobject. | 
| [[activeObservations]] | {} | An ordered
              map keyed on
              a string
              name representing a Property and
              value is a Subscriptionobject. | 
After fetching
      a Thing Description as
      a JSON object, one can create a ConsumedThing
      object.
ConsumedThing
        with the ThingDescription
        td, run the
        following steps:
        SyntaxError
            and stop.
          ConsumedThing
            object.
          [[td]] of
            thing to
            td.
          Returns the [[td]] of the
      ConsumedThing
      object that represents the Thing Description of
      the ConsumedThing.
      Applications may consult the Thing metadata stored in
      [[td]] in order to
      introspect its capabilities before interacting with it.
        Promise that resolves with a
        Property value represented
        as an InteractionOutput
        object or rejects on error. The method MUST run the following steps:
        PromiseSecurityError
            and stop.
          [[td]].properties.propertyName.
          undefined,
          reject
            promise with a
            NotFoundError
            and stop.
          readproperty, selected by
          the implementation.
          SyntaxError
            and stop.
          SyntaxError
            and stop.
          
        Promise that resolves with a
        PropertyReadMap
        object that maps keys from propertyNames to values returned by
        this algorithm. The method MUST
        run the following steps:
        PromiseSecurityError
            and stop.
          [[td]].forms
            array, otherwise let form be the Form in
            [[td]].forms
            array whose op is
            readmultipleproperties, as selected by the
            implementation.
          SyntaxError
            and stop.
          null.
            NotSupportedError and stop.
          [[td]].properties[key].
              
        Promise that resolves with a
        PropertyReadMap
        object that maps keys from Property names to values
        returned by this algorithm. The method MUST run the following steps:
        PromiseSecurityError
            and stop.
          [[interaction]].forms.
          undefined,
          reject
            promise with a
            SyntaxError
            and stop.
          undefined and is less than
          forms.length, set
          subscription.[[form]] to
          forms.[formIndex].
          [[form]] to a
          Form
            in forms whose op is
            "readallproperties", as selected by the
            implementation.
          [[form]] is
          failure, reject
          promise with a
          SyntaxError
            and stop.
          
            NotSupportedError and stop.
          [[td]].properties[key].
              
        Promise that resolves on success
        and rejects on failure. The method MUST run the following steps:
        PromiseSecurityError
            and stop.
          [[td]].properties[propertyName].
          undefined,
          reject
            promise with a
            NotFoundError
            and stop.
          undefined, let form be the
          Form
            associated with formIndex in the
            interaction.forms array,
            otherwise let form be a Form in
            interaction.forms whose
            op is writeproperty, as
            selected by the implementation.
          SyntaxError
            and stop.
          promise with that exception and stop.
          As discussed in Issue #193, the design decision is that write interactions only return success or error, not the written value (optionally). TDs should capture the schema of the Property values, including precision and alternative formats. When a return value is expected from the interaction, an Action should be used instead of a Property.
        Promise that resolves on success
        and rejects on failure. The method MUST run the following steps:
        PromiseSecurityError
            and stop.
          [[td]].forms
            array, otherwise let form be a Form in
            [[td]].forms
            array whose op is
            writemultipleproperties, as selected by
            the implementation.
          SyntaxError
            and stop.
          [[td]].properties[name].
          null or 
            undefined or is not writeable
            reject
            promise with
            
            NotSupportedError and stop.
          null.[[td]].properties[name].
          promise with that exception and stop.
          
            NotSupportedError and stop.
          
        Promise that resolves on success
        and rejects on failure.
        This algorithm allows for only one active
          Subscription
          per Property. If a new
          Subscription
          is made while an existing Subscription
          is active the runtime will throw an NotAllowedError.
ConsumedThing
          object.
          PromiseSecurityError
            and stop.
          Function,
          reject
            promise with a
            
            TypeError and stop.
          null and is not a Function,
          reject
            promise with a
            
            TypeError and stop.
          [[activeObservations]][propertyName]
            [=map/exists], reject
            promise with a
            
            NotAllowedError and stop.
          Subscription
          object with its 
            internal slots set as follows:
            [[type]] be
                "property".
              [[name]] be
                propertyName.
              [[interaction]]
              be [[td]].properties[propertyName].
              [[thing]] be
              thing.
              [[interaction]].forms.
              undefined,
              reject
              promise with a
              
                SyntaxError and stop.
              undefined and is less than
              forms.length, set
              subscription.[[form]] to
                forms.[formIndex].
              [[form]] to a
                Form in forms
                whose op is
                "observeproperty", as selected by the
                implementation.
              [[form]] is
                failure, reject
                promise with a
                
                SyntaxError and stop.
              [[interaction]]
              is undefined, reject
              promise with a
              
                NotFoundError and stop.
              [[activeObservations]][|propertyName]
            to subscription and resolve
            promise.
          [[form]] and
                subscription.[[interaction]].
                If that throws, reject
                promise with that
                exception and stop.
              false and suppress further
              notifications.
                NetworkError and set its
                message to reflect the underlying error
                condition.
              Function,
              invoke it given error.
              
        Promise that resolves with the
        result of the Action
        represented as an InteractionOutput
        object, or rejects with an error. The method MUST run the following steps:
        PromiseSecurityError
            and stop.
          [[td]].actions[actionName].
          object,
            reject
            promise with a
            NotFoundError
            and stop.
          [[interaction]].forms.
          undefined,
          reject
            promise with a
            SyntaxError
            and stop.
          undefined and is less than
          forms.length, set
          subscription.[[form]] to
          forms.[formIndex].
          [[form]] to a
          Form
            in forms whose op is
            "invokeaction", as selected by the
            implementation.
          [[form]] is
          failure, reject
          promise with a
          SyntaxError
            and stop.
          promise with that exception and stop.
          
        Promise to signal success or
        failure.
        This algorithm allows for only one active
          Subscription
          per Event. If a new
          Subscription
          is made while an existing Subscription
          is active the runtime will throw an NotAllowedError.
ConsumedThing
          object.
          PromiseSecurityError
            and stop.
          Function,
          reject
            promise with a
            
            TypeError and stop.
          null and is not a Function,
          reject
            promise with a
            
            TypeError and stop.
          [[activeSubscriptions]][eventName]
            does not exist,
            reject
            promise with a
            
            NotAllowedError and stop.
          Subscription
          object with its 
            internal slots set as follows:
            [[type]] be
                "event".
              [[name]] be
                eventName.
              [[interaction]]
              be thing. [[td]].events[eventName].
              [[interaction]]
              is undefined, reject
              promise with a
              
                NotFoundError and stop.
              [[thing]] be
              thing.
              [[form]] be
                thing.[[interaction]].forms[formIndex].
              [[form]] be
                an 
                implementation-defined Form from the
                subscription.[[interaction]].forms
                array whose op is
                "subscribeevent".
              [[form]]
                does not exist,
                reject
                promise with a
                
                SyntaxError and stop.
              [[form]], optional URI templates given
            in options.uriVariables
            and optional subscription data given in options.data.
          [[activeSubscriptions]][eventName]
            to subscription.
          [[form]] and
                subscription.[[interaction]].
              false and suppress further
              notifications.
                NetworkError and set its
                message to reflect the underlying error
                condition.
              Function,
              invoke it given error.
              Holds the interaction options that need to be exposed for application scripts according to the Thing Description.
The formIndex property, if defined,
      represents an application hint for which Form
      definition, identified by this index, of the TD to use for the given WoT
      interaction. Implementations SHOULD
      use the Form with this index for making the
      interaction, but MAY override this
      value if the index is not found or not valid. If not defined,
      implementations SHOULD attempt to
      use the Form definitions in order of appearance
      as listed in the TD for the
      given Wot Interaction.
The uriVariables property if defined,
      represents the URI template variables to be used with the WoT
      Interaction that are represented as 
      parsed JSON objects defined in [WOT-TD].
The support for URI variables comes from the need, exposed by the Web of Things (WoT) Thing Description 1.1 specification, to be able to describe existing RESTful endpoints that use them. However, it should be possible to write a Thing Description that would use Actions for representing this kind of interactions and model the URI variables as action parameters. In that case, implementations can serialize the parameters as URI variables, and therefore, the options parameter could be dismissed.
The data
      property if defined, represents additional opaque data that
      needs to be passed to the interaction.
Represents a map of Property names to an InteractionOutput
      object that represents the value the Property can take. It is
      used as a property bag for interactions that involve multiple
      Properties at
      once.
Represents a map of Property names to an InteractionInput
      that represents the value the Property can take. It is used
      as a property bag for interactions that involve multiple
      Properties at
      once.
User provided callback that is given an argument of type
      InteractionOutput
      and is used for observing Property changes and handling
      Event notifications.
      Since subscribing to Events are WoT interactions and
      might take options or even data, they are not modelled with
      software events.
User provided callback that is given an argument of type
      Error
      and is used for conveying critical and non-critical errors
      from the Protocol Bindings to
      applications.
Represents a subscription to Property change and Event interactions.
The active
      boolean property denotes if the subscription is active, i.e.
      it is not stopped because of an error or because of
      invocation of the stop() method.
SubscriptionSubscription
        object has the following 
        internal slots:
        | Internal Slot | Initial value | Description (non-normative) | 
|---|---|---|
| [[type]] | null | Indicates what WoT
                Interaction the Subscriptionrefers to. The value can be either"property"or"event"ornull. | 
| [[name]] | null | The Property or Event name. | 
| [[interaction]] | null | The Thing Description fragment that describes the WoT interaction. | 
| [[form]] | null | The Form associated with the subscription. | 
| [[thing]] | null | The ConsumedThingassociated with the subscription. | 
Stops delivering notifications for the subscription. It
        takes an optional parameter options and returns a
        
        . When invoked, the method
        MUST execute the following
        steps:Promise
PromiseSecurityError
            and stop.
          [[interaction]]'s
            forms array.
          [[form]].
          SyntaxError
            and stop.
          [[type]] is 
            "property", make a request to the underlying
            platform via the Protocol
            Bindings to stop observing the Property
            identified by [[name]] with
            unsubscribeForm and optional URI templates
            given in options'
            uriVariables.
          [[type]] is
            "event", make a request to the underlying
            platform via the Protocol
            Bindings to unsubscribe from the Event identified by
            [[name]] with
            unsubscribeForm, with optional URI templates
            given in options'
            uriVariables and optional unsubscribe data
            given in options.data.
          false.
              [[type]] is
              "event", remove [[name]] from
                [[thing]].[[activeSubscriptions]]
                .
              [[type]] is
              "property", remove [[name]] from
                [[thing]].[[activeObservations]]
                .
              This algorithm is under development and is
          non-normative. Implementations MAY choose another algorithm to find a
          matching unsubscribe Form to a given
          subscribe Form.
Subscription
        object, run the following steps:
        [[interaction]].forms,
            0.
              "unobserveproperty" if
                [[type]] is
                "property" or if
                form.op is
                "unsubscribeevent" if
                [[type]]
                is"event",
                null and terminate these steps.The next example illustrates how to fetch a TD by URL, create a
      ConsumedThing,
      read metadata (title), read property value, subscribe to
      property change, subscribe to a WoT event, unsubscribe.
try {
  let res = await fetch("https://tds.mythings.org/sensor11");
  let td = res.json();
  let thing = new ConsumedThing(td);
  console.log("Thing " + thing.getThingDescription().title + " consumed.");
} catch (e) {
  console.log("TD fetch error: " + e.message);
};
try {
  // subscribe to property change for “temperature”
  await thing.observeProperty("temperature", async (data) => {
    try {
      console.log("Temperature changed to: " + await data.value());
    } catch (error) {
      console.error("Cannot read the observed property temperature");
      console.error(error);
    }
  });
  // subscribe to the “ready” event defined in the TD
  await thing.subscribeEvent("ready", async (eventData) => {
    try {
      console.log("Ready; index: " + await eventData.value());
      // run the “startMeasurement” action defined by TD
      await thing.invokeAction("startMeasurement", { units: "Celsius" });
      console.log("Measurement started.");
    } catch (error) {
      console.error("Cannot read the ready event or startMeasurement failed");
      console.error(error)
    }
  });
} catch (e) {
  console.log("Error starting measurement.");
}
setTimeout(async () => {
  try {
    const temperatureData = await thing.readProperty("temperature")
    const temperature = await temperatureData.value();
    console.log("Temperature: " + temperature);
    await thing.unsubscribe("ready");
    console.log("Unsubscribed from the ‘ready’ event.");
  } catch (error) {
    console.log("Error in the cleanup function");
  }
}, 10000);The following shows an advance usage of InteractionOutput
      to read a property without a DataSchema.
/*
* takePicture affordance form:
* "form": {
*   "op": "invokeaction",
*   "href" : "http://camera.example.com:5683/takePicture",
*   "response": {
*     "contentType": "image/jpeg",
*     "contentCoding": "gzip"
*   }
*}
* See https://www.w3.org/TR/wot-thing-description/#example-23
*/
let response;
let image;
try {
  response = await thing.invokeAction(“takePicture”));
  image = await response.value() // throws NotReadableError --> schema not defined
} catch(ex) {
  image = await response.arrayBuffer();
  // image: ArrayBuffer [0x1 0x2 0x3 0x5 0x15 0x23 ...]
}Finally, the next two examples shows the usage of a
      ReadableStream
      from an InteractionOutput.
/*{
"video": {
  "description" : "the video stream of this camera",
  "forms": [
    {
      "op": "readproperty",
      "href": "http://camera.example.com/live",
      "subprotocol": "hls"
      "contentType": "video/mp4"
    }
  ]
}}*/
const video = await thing.readProperty("video")
const reader = video.data.getReader()
reader.read().then(function processVideo({ done, value }) {
  if (done) {
    console.log("live video stoped");
    return;
  }
  const decoded = decode(value)
  UI.show(decoded)
  // Read some more, and call this function again
  return reader.read().then(processText);
});Here consider that the JSON object is too big to be read wholly in the memory. Therefore, we use streaming processing to get the total number of the events recorded by the remote Web Thing.
/*
* "eventHistory":
* {
*   "description" : "A long list of the events recorded by this thing",
*   "type": "array",
*   "forms": [
*     {
*       "op": "readproperty",
*       "href": "http://recorder.example.com/eventHistory",
*     }
*   ]
* }
*/
// Example of streaming processing: counting json objects
let objectCounter = 0
const parser = new Parser() //User library for json streaming parsing (i.e. https://github.com/uhop/stream-json/wiki/Parser)
parser.on('data', data => data.name === 'startObject' && ++objectCounter);
parser.on('end', () => console.log(`Found ${objectCounter} objects.`));
const response = await thing.readProperty(“eventHistory”)
await response.data.pipeTo(parser);
// Found N objectsThe ExposedThing
    interface is the server API to operate the Thing that allows defining request
    handlers, Property, Action, and Event interactions.
WebIDL[SecureContext, Exposed=(Window,Worker)]
interface ExposedThing {
  ExposedThing setPropertyReadHandler(DOMString name,
          PropertyReadHandler handler);
  ExposedThing setPropertyWriteHandler(DOMString name,
          PropertyWriteHandler handler);
  ExposedThing setPropertyObserveHandler(DOMString name,
          PropertyReadHandler handler);
  ExposedThing setPropertyUnobserveHandler(DOMString name,
          PropertyReadHandler handler);
  Promise<undefined> emitPropertyChange(DOMString name,
          optional InteractionInput data);
  ExposedThing setActionHandler(DOMString name, ActionHandler action);
  ExposedThing setEventSubscribeHandler(DOMString name,
          EventSubscriptionHandler handler);
  ExposedThing setEventUnsubscribeHandler(DOMString name,
          EventSubscriptionHandler handler);
  Promise<undefined> emitEvent(DOMString name,
          optional InteractionInput data);
  Promise<undefined> expose();
  Promise<undefined> destroy();
  ThingDescription getThingDescription();
};
callback PropertyReadHandler = Promise<InteractionInput>(
        optional InteractionOptions options = {});
callback PropertyWriteHandler = Promise<undefined>(
        InteractionOutput value,
        optional InteractionOptions options = {});
callback ActionHandler = Promise<InteractionInput>(
        InteractionOutput params,
        optional InteractionOptions options = {});
callback EventSubscriptionHandler = Promise<undefined>(
        optional InteractionOptions options = {});
    An ExposedThing
      object has the following 
      internal slots:
| Internal Slot | Initial value | Description (non-normative) | 
|---|---|---|
| [[td]] | null | The Thing
              Description of the ExposedThing. | 
| [[readHandlers]] | {} | A Mapwith property names as keys andPropertyReadHandlers
              as values | 
| [[writeHandlers]] | {} | A Mapwith property names as keys andPropertyWriteHandlers
              as values | 
| [[observeHandlers]] | {} | A Mapwith property names as keys andPropertyReadHandlers
              as values | 
| [[unobserveHandlers]] | {} | A Mapwith property names as keys andFunctions
              as values | 
| [[actionHandlers]] | {} | A Mapwith action names as keys andActionHandlers
              as values | 
| [[subscribeHandlers]] | {} | A Mapwith event names as keys andEventSubscriptionHandlers
              as values | 
| [[unsubscribeHandlers]] | {} | A Mapwith event names as keys andEventSubscriptionHandlers
              as values | 
| [[propertyObservers]] | {} | A Mapwith property names as keys and
              anArrayof listeners as values | 
| [[eventListeners]] | {} | A Mapwith event names as keys andArrayof listeners as values | 
ExposedThingThe ExposedThing
      interface extends ConsumedThing.
      It is constructed from a full or partial ThingDescription
      object.
Note that an existing ThingDescription
        object can be optionally modified (for instance by adding
        or removing elements on its properties,
        actions and events internal
        properties) and the resulting object can used for
        constructing an ExposedThing
        object. This is the current way of adding and removing
        Property, Action and Event definitions, as
        illustrated in the examples.
Before invoking expose(), the
        ExposedThing
        object does not serve any requests. This allows first
        constructing ExposedThing
        and then initialize its Properties and service
        handlers before starting serving requests.
ExposedThing
        with the ExposedThingInit
        init, run the
        following steps:
        SecurityError
            and stop.
          ExposedThing
            object.
          [[td]] of
          thing to
          td.
          Returns the [[td]] of the
      ExposedThing
      object that represents the Thing Description of
      the Thing. Applications may
      consult the Thing
      metadata stored in [[td]] in order to
      introspect its capabilities before interacting with it.
A function that is called when an external request for
      reading a Property is received and
      defines what to do with such requests. It returns a
      
       and resolves with an
      PromiseReadableStream
      object or an 
      ECMAScript value conforming to DataSchema, or rejects with
      an error.
Takes as arguments name and handler. Sets the service handler that defines what to do when a request is received for reading the specified Property matched by name. Throws on error. Returns a reference to this object for supporting chaining.
Note that there is no need to register handlers
        for handling requests for reading multiple or all Properties. The request
        and reply are transmitted in a single network request, but
        the ExposedThing
        may implement them using multiple calls to the single read
        handler.
The handler callback function should implement reading a Property and SHOULD be called by implementations when a request for reading a Property is received from the underlying platform.
There MUST be at most one handler
      for any given Property, so newly added
      handlers MUST replace the previous
      handlers. If no handler is initialized for any given Property, implementations
      SHOULD implement a default property
      read handler based on the Thing Description
      provided in the [[td]]
      
      internal slot.
SecurityError
            and stop.
          [[td]].properties[name]
            does not exist,
            throw
            NotFoundError
            and stop.
          [[readHandlers]][name]
            to handler.
          
            NotSupportedError according to the Protocol
            Bindings and stop.
          
            NotAllowedError according to the Protocol
            Bindings and stop.
          [[td]].properties.name.
              
                NotFoundError and stop.
              null.PropertyReadHandler
              in 
                [[readHandlers]] 
                internal slot for interaction, let
                handler be that.
              null, throw 
                NotSupportedError and stop.
              The value returned here
                  SHOULD either conform to
                  DataSchema or it
                  SHOULD be an
                  
                  ReadableStream object created by
                  the handler.
            NotSupportedError according to the Protocol
            Bindings and stop.
          
            NotAllowedError according to the Protocol
            Bindings and stop.
          
            NotSupportedError according to the Protocol
            Bindings and stop.
          
            NotAllowedError according to the Protocol
            Bindings and stop.
          null.
          Takes as arguments name and handler. Sets the service handler that defines what to do when a request is received for observing the specified Property matched by name. Throws on error. Returns a reference to this object for supporting chaining.
The handler
      callback function should implement reading a Property and
      resolve with an
      InteractionOutput
      object or reject with
      an error.
There MUST be at most one handler for any given Property, so newly added handlers MUST replace the previous handlers. If no handler is initialized for any given Property, implementations SHOULD implement a default property read handler based on the Thing Description.
SecurityError
            and stop.
          [[td]].properties[name]
            does not exist,
            throw
            NotFoundError
            and stop.
          [[observeHandlers]][name]
            to handler.
          
            NotSupportedError according to the Protocol
            Bindings and stop.
          
            NotAllowedError according to the Protocol
            Bindings and stop.
          [[td]].properties[name]
            does not exist,
            send back a NotFoundError
            in the reply and stop.
          [[propertyObservers]][name],
            in order to be able to notify about Property value
            changes.
          Every time the value of property
        changes, emitPropertyChange()
        needs to be explicitly called by the application
        script.
Takes as arguments name and handler. Sets the service handler that defines what to do when a request is received for unobserving the specified Property matched by name. Throws on error. Returns a reference to this object for supporting chaining.
The handler callback function should implement what to do when an unobserve request is received by the implementation.
There MUST be at most one handler for any given Property, so newly added handlers MUST replace the previous handlers. If no handler is initialized for any given Property, implementations SHOULD implement a default handler based on the Thing Description.
SecurityError
            and stop.
          [[td]].properties[name]
            does not exist,
            throw
            NotFoundError
            and stop.
          [[unobserveHandlers]][name]
            to handler.
          
            NotSupportedError according to the Protocol
            Bindings and stop.
          
            NotAllowedError according to the Protocol
            Bindings and stop.
          [[td]].properties[name]
            does not exist,
            send back a NotFoundError
            in the reply and stop.
          [[unobserveHandlers]][name];
          Function,
          invoke that given options, then send back a
          reply following the Protocol Bindings
          and stop.
          [[propertyObservers]][name]
            exists,
            remove it from this.[[propertyObservers]],
            send back a reply as defined in the Protocol
            Bindings and stop.
          NotFoundError
          in the reply as defined in the Protocol Bindings
          and stop.
          PromiseSecurityError
            and stop.
          [[td]].properties[name].
          undefined,
          reject
            promise with
            NotFoundError
            and stop.
          undefined, run the following sub-steps:
            null.
                [[readHandlers]], reject
                promise and stop.
              
                [[readHandlers]][name].
              null or undefined,
              reject
              promise and stop.
              null.[[propertyObservers]][name],
            run the following sub-steps:
            This clause needs expanding and/or refer to an algorithm in [WOT-PROTOCOL-BINDINGS].
A function that is called when an external request for
      writing a Property is received and
      defines what to do with such requests. Takes as argument
      value and returns a
      
      , resolved when the value of
      the Property - identified by the
      name provided when setting the handler has been updated -, or
      rejects with an error if the property is not found or the
      value cannot be updated.Promise
Note that the code in this callback function can read the property before updating it in order to find out the old value, if needed. Therefore the old value is not provided to this function.
The value is provided by implementations as an
        InteractionOutput
        object in order to be able to represent values that are not
        described by a DataSchema, such as
        streams.
Takes as arguments name and handler. Sets the service handler that defines what to do when a request is received for writing the Property matched by name given when setting the handler. Throws on error. Returns a reference to this object for supporting chaining.
Note that even for readonly Properties it is possible to specify a write handler, as explained in Issue 199. In this case, the write handler may define in an application-specific way to fail the request.
There MUST be at most one write handler for any given Property, so newly added handlers MUST replace the previous handlers. If no write handler is initialized for any given Property, implementations SHOULD implement default property update if the Property is writeable and notifying observers on change if the Property is observable, based on the Thing Description.
SecurityError
            and stop.
          [[td]].properties[name]
            does not exist,
            throw
            NotFoundError
            and stop.
          [[writeHandlers]][name]
            to handler.
          "single":
        
            NotSupportedError according to the Protocol
            Bindings and stop.
          
            NotAllowedError according to the Protocol
            Bindings and stop.
          [[td]].properties[name].
          undefined,
          return a NotFoundError
            in the reply and stop.
          [[writeHandlers]][name].
          undefined and if there is a default write
          handler provided by the implementation, let
          handler be that.
            undefined, send back a 
            NotSupportedError with the reply and stop.
          "single", reply to
          the request reporting success, following the Protocol Bindings
          and stop.
          
            NotSupportedError according to the Protocol
            Bindings and stop.
          
            NotAllowedError according to the Protocol
            Bindings and stop.
          "multiple". If that
          fails, reply to the request with that error and stop.
          A function that is called when an external request for
      invoking an Action
      is received and defines what to do with such requests. It is
      invoked given params
      and optionally with an options object. It returns a
      
       that rejects with an error or
      resolves with the value returned by the Action as PromiseInteractionInput.
Application scripts MAY return a ReadableStream
        object from an ActionHandler.
        Implementations will then use the stream for constructing
        the Action's response.
Takes as arguments name and action. Sets the handler function that defines what to do when a request is received to invoke the Action matched by name. Throws on error. Returns a reference to this object for supporting chaining.
The action callback function will implement an Action and SHOULD be called by implementations when a request for invoking the Action is received from the underlying platform.
There MUST be at most one handler for any given Action, so newly added handlers MUST replace the previous handlers.
SecurityError
            and stop.
          [[td]].actions[name].
          undefined,
          throw
            a NotFoundError
            and stop.
          [[actionHandlers]][name]
            to action.
          
            NotSupportedError according to the Protocol
            Bindings and stop.
          
            NotAllowedError according to the Protocol
            Bindings and stop.
          [[td]].properties[name].
          undefined,
          return a NotFoundError
            in the reply and stop.
          [[actionHandlers]][name].
          
            undefined, return a 
            NotSupportedError with the reply created by
            following the Protocol
            Bindings and stop.
          A function that is called when an external request for
      subscribing to an Event is
      received and defines what to do with such requests. It is
      invoked given an options object provided by the
      implementation and coming from subscribers. It returns a
      
       that rejects with an error or
      resolves when the subscription is accepted.Promise
Takes as arguments name and handler. Sets the handler function that defines what to do when a subscription request is received for the specified Event matched by name. Throws on error. Returns a reference to this object for supporting chaining.
The handler callback function SHOULD implement what to do when an subscribe request is received, for instance necessary initializations. Note that the handler for emitting Events is set separately.
There MUST be at most one event subscribe handler for any given Event, so newly added handlers MUST replace the previous handlers.
SecurityError
            and stop.
          [[td]].events[name].
          undefined,
          throw
            a NotFoundError
            and stop.
          [[subscribeHandlers]][name]
            to handler.
          this.
            NotSupportedError according to the Protocol
            Bindings and stop.
          
            NotAllowedError according to the Protocol
            Bindings and stop.
          [[td]].events[name].
          undefined,
          send back a NotFoundError
          and stop.
          [[subscribeHandlers]][name]
          is a Function,
            invoke it given options and stop.
          [[eventListeners]][name]
                to subscriber.
              Takes as arguments name and handler. Sets the handler function that defines what to do when the specified Event matched by name is unsubscribed from. Throws on error. Returns a reference to this object for supporting chaining.
The handler callback function SHOULD implement what to do when an unsubscribe request is received.
There MUST be at most one handler for any given Event, so newly added handlers MUST replace the previous handlers.
SecurityError
            and stop.
          [[td]].events[name].
          undefined,
          throw
            a NotFoundError
            and stop.
          [[unsubscribeHandlers]][name]
            to handler.
          this.
            NotSupportedError according to the Protocol
            Bindings and stop.
          
            NotAllowedError according to the Protocol
            Bindings and stop.
          [[td]].events[name].
          undefined,
          send back a NotFoundError
          and stop.
          [[unsubscribeHandlers]][name]
          exists
            and is a Function,
            invoke it given options and stop.
          [[eventListeners]],
          remove
            name.
          this.[[eventListeners]].name.
          undefined, assume that the
              notification response will contain an
              empty data payload as specified by Protocol
              Bindings.
              The error reporting is protocol specific and it is encapsulated by implementations. On the client end, the error listener passed with the subscription will be invoked if the client UA detects the error.
PromiseSecurityError
            and stop.
          [[td]].events.name.
          NotFoundError
            and stop.
          PromiseSecurityError
            and stop.
          [[td]].
          [[td]]. If that fails,
            reject
            promise with a
            
            TypeError and stop.
          [[td]].properties
          initialize this.[[propertyObservers]].key
            to an empty 
            Array in order to store observe
            request data needed to notify the observers on value
            changes.
          [[td]].events
          initialize this.[[eventListeners]].key
            to an empty 
            Array in order to store subscribe
            request data needed to notify the subscribers on event
            emission.
          [[td]] as
            explained in [WOT-TD]
            and [WOT-PROTOCOL-BINDINGS].
            Make a request to the underlying platform to initialize
            the Protocol
            Bindings and then start serving external requests
            for WoT Interactions
            (read, write and observe Properties, invoke
            Actions and manage
            Event subscriptions), based
            on the Protocol
            Bindings. Implementations MAY reject this step for any reason
            (e.g. if they want to enforce further checks and
            constraints on interaction forms).
          
            Error object error with
            error.message set to the error
            code seen by the Protocol
            Bindings and stop.
          PromiseSecurityError
            and stop.
          
            Error object error with its
            message set to the error code seen by the
            Protocol
            Bindings and stop.
          The next example illustrates how to create an
      ExposedThing
      based on a partial TD object
      constructed beforehand.
try {
  let temperaturePropertyDefinition = {
    type: "number",
    minimum: -50,
    maximum: 10000
  };
  let tdFragment = {
    properties: {
      temperature: temperaturePropertyDefinition
    },
    actions: {
      reset: {
        description: "Reset the temperature sensor",
        input: {
          temperature: temperatureValueDefinition
        },
        output: null,
        forms: []
      },
    },
    events: {
      onchange: temperatureValueDefinition
    }
  };
  let thing1 = await WOT.produce(tdFragment);
  // initialize Properties
  await thing1.writeProperty("temperature", 0);
  // add service handlers
  thing1.setPropertyReadHandler("temperature", () => {
     return readLocalTemperatureSensor();  // Promise
  });
  // start serving requests
  await thing1.expose();
} catch (err) {
   console.log("Error creating ExposedThing: " + err);
}The next example illustrates how to add or modify a
      Property definition
      on an existing ExposedThing:
      take its td property, add or modify it, then
      create another ExposedThing
      with that.
try {
  // create a deep copy of thing1's TD
  let instance = JSON.parse(JSON.stringify(thing1.td));
  const statusValueDefinition = {
    type: "object",
    properties: {
      brightness: {
        type: "number",
        minimum: 0.0,
        maximum: 100.0,
        required: true
      },
      rgb: {
        type: "array",
        "minItems": 3,
        "maxItems": 3,
        items : {
            "type" : "number",
            "minimum": 0,
            "maximum": 255
        }
      }
  };
  instance["name"] = "mySensor";
  instance.properties["brightness"] = {
    type: "number",
    minimum: 0.0,
    maximum: 100.0,
    required: true,
  };
  instance.properties["status"] = statusValueDefinition;
  instance.actions["getStatus"] = {
    description: "Get status object",
    input: null,
    output: {
      status : statusValueDefinition;
    },
    forms: [...]
  };
  instance.events["onstatuschange"] = statusValueDefinition;
  instance.forms = [...];  // update
  var thing2 = new ExposedThing(instance);
  // TODO: add service handlers
  await thing2.expose();
  });
} catch (err) {
   console.log("Error creating ExposedThing: " + err);
}The following will cover a set of examples for the
      generation of a Thing Description
      from an ExposedThingInit
      using expand an
      ExposedThingInit steps. As hypothesis the runtime
      supports HTTP and COAP protocol bindings and it is hosted at
      192.168.0.1.
The next example shows how to exploit a ExposedThingInit
      to create a simple Thing Description
      with one Property with the default
      values.
TODO: add more examples where the ExposedThingInit
        contains suggested values that are replaced by the
        algorithm.
Discovery is a distributed application that requires provisioning and support from participating network nodes (clients, servers, directory services). This API models the client side of typical discovery schemes supported by various IoT deployments.
The ThingDiscoveryProcess
    object provides the properties and methods controlling the
    discovery process and returning the results.
WebIDL[SecureContext, Exposed=(Window,Worker)]
interface ThingDiscoveryProcess {
  constructor(optional ThingFilter filter = {});
  readonly attribute boolean done;
  readonly attribute Error? error;
  undefined stop();
  async iterable<ThingDescription>;
};
    The ThingDiscoveryProcess
    object has the following 
    internal slots.
| Internal Slot | Initial value | Description (non-normative) | 
|---|---|---|
| [[filter]] | undefined | The ThingFilterobject used in discovery. | 
| [[url]] | undefined | A URLrepresenting the TD Directory in a
            discovery. | 
The done property is true
    if the discovery has been stopped or completed with no more
    results to report.
The error property represents the last
    error that occurred during the discovery process. Typically
    used for critical errors that stop discovery.
The ThingDiscoveryProcess
    object implements the async
    iterator concept.
ThingDiscoveryProcessThingDiscoveryProcess
        with a filter, run the
        following steps:
        null, throw a
          
            TypeError and stop.
          ThingDiscoveryProcess
            object.
          [[filter]] to
            filter.
          done
            to false.
          error
            to null.
          Represents an object containing the constraints for discovering Things as key-value pairs.
WebIDLdictionary ThingFilter {
  object? fragment;
  
};
      The fragment property represents a
      template object used for matching property by property
      against discovered Things.
The query
        property was temporarily removed from ThingFilter,
        until it is standardized in the WoT Discovery task force.
        It represented a query string accepted by the
        implementation, for instance a SPARQL or JSON query.
        Support was to be implemented locally in the WoT Runtime or remotely
        as a service in a TD Directory.
The url property was removed. It used to represent the target entity serving the discovery request, for instance the URL of a TD Directory, or the URL of a directly targeted Thing, but these are implemented by dedicated methods now.
error
                property to 
                SyntaxError, discard td and continue the
                discovery process.
              At this point implementations MAY control the flow of the discovery process (depending on memory constraints, for instance queue the results, or temporarily stop discovery if the queue is getting too large, or resume discovery when the queue is emptied sufficiently). These steps are run for each discovered/fetched td.
[[filter]].fragment.
              object,
              then for each key defined in it:
                asyncIterator.
                Improve this step using proper asyncIterator terminology.
The last error is retained. Implementations MAY choose to stop the discovery process if they consider it should be reported.
Error object. Set
                error.name to
                "DiscoveryError".
              error
                to error.
              done
                to true and terminate these steps.
              SecurityError
            and stop.
          done
            property to true.
          The following example finds ThingDescription
      objects of Things
      that are exposed by local hardware, regardless how many
      instances of WoT
      Runtime it is running Using the 
      asyncIterator provided by the Discovery
      object, we can iterate asynchronously over the results and
      perform operations with the obtained ThingDescription
      objects.
let url = "https://mythings.com/thing1";
let td = await WOT.requestThingDescription(url);
console.log("Found Thing Description for " + td.title);The next example finds ThingDescription
      objects of Things
      listed in a TD
      Directory service. We set a timeout for safety.
let discovery = await WOT.exploreDirectory("http://directory.wotservice.org");
setTimeout( () => {
    discovery.stop();
    console.log("Discovery stopped after timeout.");
  },
  3000);
for await (const td of discovery) {
  console.log("Found Thing Description for " + td.title);
  let thing = new ConsumedThing(td);
  console.log("Thing name: " + thing.getThingDescription().title);
};
if (discovery.error) {
  console.log("Discovery stopped because of an error: " + error.message);
}The next example is for a generic discovery, by any means provisioned to the WOT runtime, including local Things, if any is available.
let discovery = await WOT.discover();
setTimeout( () => {
    discovery.stop();
    console.log("Stopped open-ended discovery");
  },
  10000);
for await (const td of discovery) {
  console.log("Found Thing Description for " + td.title);
};
if (discovery.error) {
  console.log("Discovery stopped because of an error: " + error.message);
}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]. This section discusses only security and privacy risks and possible mitigations directly relevant to the scripts and WoT Scripting API.
A suggested set of best practices to improve security for WoT devices and services has been documented in [WOT-SECURITY]. That document may be updated as security measures evolve. Following these practices does not guarantee security, but it might help avoid commonly known vulnerabilities.
This section is normative and contains specific risks relevant for the WoT Scripting Runtime.
A typical way to compromise any process is to send it a corrupted input via one of the exposed interfaces. This can be done to a script instance using WoT interface it exposes.
In case a script is compromised or misbehaving, the underlying physical device (and potentially surrounded environment) can be damaged if a script can use directly exposed native device interfaces. If such interfaces lack safety checks on their inputs, they might bring the underlying physical device (or environment) to an unsafe state (i.e. device overheats and explodes).
If the WoT Scripting Runtime supports post-manufacturing provisioning or updates of scripts, WoT Scripting Runtime or any related data (including security credentials), it can be a major attack vector. An attacker can try to modify any above described element during the update or provisioning process or simply provision attacker's code and data directly.
Typically the WoT Scripting Runtime needs to store the security credentials that are provisioned to a WoT device to operate in WoT network. If an attacker can compromise the confidentiality or integrity of these credentials, then it can obtain access to the WoT assets, impersonate WoT things or devices or create Denial-Of-Service (DoS) attacks.
This section is non-normative.
This section describes specific risks relevant for script developers.
A script instance may receive data formats defined by the TD, or data formats defined by the applications. While the WoT Scripting Runtime SHOULD perform validation on all input fields defined by the TD, scripts may be still exploited by input data.
If a script performs a heavy functional processing on received requests before the request is authenticated, it presents a great risk for Denial-Of-Service (DOS) attacks.
API rationale usually belongs to a separate document, but in the WoT case the complexity of the context justifies including basic rationale here.
The WoT Interest Group and Working Group have explored different approaches to application development for WoT that have been all implemented and tested.
It is possible to develop WoT applications that only use the WoT network interface, typically exposed by a WoT gateway that presents a RESTful API towards clients and implements IoT protocol plugins that communicate with supported IoT deployments. One such implementation is the Mozilla WebThings platform.
WoT Things show good synergy with software objects, so a Thing can be represented as a software object, with Properties represented as object properties, Actions as methods, and Events as events. In addition, metadata is stored in special properties. Consuming and exposing is done with factory methods that produce a software object that directly represents a remote Thing and its interactions. One such implementation is the Arena Web Hub project.
In the next example, a Thing that represents
        interactions with a lock would look like the following: the
        status property and the open()
        method are directly exposed on the object.
let lock = await WoT.consume(‘https://td.my.com/lock-00123’);
console.log(lock.status);
lock.open('withThisKey');Since the direct mapping of Things to software objects have had some challenges, this specification takes another approach that exposes software objects to represent the Thing metadata as data property and the WoT interactions as methods. One implementation is node-wot in the Eclipse ThingWeb project, which is the current reference implementation of the API specified in this document.
The same example now would look like the following: the
        status property and the open()
        method are represented indirectly.
let res = await fetch(‘https://td.my.com/lock-00123’);
let td = await res.json();
let lock = new ConsumedThing(td);
console.log(lock.readProperty(‘status’));
lock.invokeAction(‘open’, 'withThisKey');In conclusion, the WoT WG decided to explore the third option that closely follows the Web of Things (WoT) Thing Description 1.1 specification. Based on this, a simple API can also be implemented. Since Scripting is an optional module in WoT, this leaves room for applications that only use the WoT network interface. Therefore all three approaches above are supported by the Web of Things (WoT) Thing Description 1.1 specification.
Moreover, the WoT network interface can be implemented in many languages and runtimes. Consider this API an example for what needs to be taken into consideration when designing a Scripting API for WoT.
The fetch(url) method has been part of this
      API in earlier versions. However, now fetching a TD given a URL should be done with an
      external method, such as the Fetch API or a
      HTTP client library, which offer already standardized options
      on specifying fetch details. The reason is that while simple
      fetch operations (covering most use cases) could be done in
      this API, when various fetch options were needed, there was
      no point in duplicating existing work to re-expose those
      options in this API.
Since fetching a TD has been scoped out, and TD validation is defined externally in the Web of Things (WoT) Thing Description 1.1 specification, that is scoped out, too. This specification expects a TD as parsed JSON object that has been validated according to the Web of Things (WoT) Thing Description 1.1 specification.
The factory methods for consuming and exposing Things are asynchronous and fully
      validate the input TD. In
      addition, one can also construct ConsumedThing
      and ExposedThing
      by providing a parsed and validated TD. Platform initialization is then
      done when needed during the WoT interactions.
Earlier drafts used the Observer construct, but since it has not become standard, a new design was needed that was light enough for embedded implementations. Therefore observing Property changes and handling WoT Events is done with callback registrations.
The reason to use function names like
      readProperty(),
      readMultipleProperties() etc. instead of a
      generic polymorphic read() function is that the
      current names map exactly to the "op" vocabulary
      from the 
      Form definition in the 
      Web of Things (WoT) Thing Description 1.1
      specification.
formIndex,
            InteractionData including streams.For a complete list of changes, see the github change log. You can also view the recently closed issues.
WebIDLtypedef object ThingDescription;
[SecureContext, Exposed=(Window,Worker)]
namespace WOT {
  // methods defined in UA conformance classes
};
partial namespace WOT {
  Promise<ConsumedThing> consume(ThingDescription td);
};
typedef object ExposedThingInit;
partial namespace WOT {
  Promise<ExposedThing> produce(ExposedThingInit init);
};
partial namespace WOT {
  Promise<ThingDiscoveryProcess> discover(optional ThingFilter filter = {});
};
partial namespace WOT {
  Promise<ThingDiscoveryProcess> exploreDirectory(USVString url,
      optional ThingFilter filter = {});
};
partial namespace WOT {
  Promise<ThingDescription> requestThingDescription(USVString url);
};
typedef any DataSchemaValue;
typedef (ReadableStream or DataSchemaValue) InteractionInput;
[SecureContext, Exposed=(Window,Worker)]
interface InteractionOutput {
  readonly attribute ReadableStream? data;
  readonly attribute boolean dataUsed;
  readonly attribute Form? form;
  readonly attribute DataSchema? schema;
  Promise<ArrayBuffer> arrayBuffer();
  Promise<DataSchemaValue> value();
};
[SecureContext, Exposed=(Window,Worker)]
interface ConsumedThing {
  constructor(ThingDescription td);
  Promise<InteractionOutput> readProperty(DOMString propertyName,
                              optional InteractionOptions options = {});
  Promise<PropertyReadMap> readAllProperties(
                              optional InteractionOptions options = {});
  Promise<PropertyReadMap> readMultipleProperties(
                              sequence<DOMString> propertyNames,
                              optional InteractionOptions options = {});
  Promise<undefined> writeProperty(DOMString propertyName,
                              InteractionInput value,
                              optional InteractionOptions options = {});
  Promise<undefined> writeMultipleProperties(
                              PropertyWriteMap valueMap,
                              optional InteractionOptions options = {});
  /*Promise<undefined> writeAllProperties(
                              PropertyWriteMap valueMap,
                              optional InteractionOptions options = {});*/
  Promise<InteractionOutput> invokeAction(DOMString actionName,
                              optional InteractionInput params = {},
                              optional InteractionOptions options = {});
  Promise<Subscription> observeProperty(DOMString name,
                              InteractionListener listener,
                              optional ErrorListener onerror,
                              optional InteractionOptions options = {});
  Promise<Subscription> subscribeEvent(DOMString name,
                              InteractionListener listener,
                              optional ErrorListener onerror,
                              optional InteractionOptions options = {});
  ThingDescription getThingDescription();
};
dictionary InteractionOptions {
  unsigned long formIndex;
  object uriVariables;
  any data;
};
[SecureContext, Exposed=(Window,Worker)]
interface Subscription {
  readonly attribute boolean active;
  Promise<undefined> stop(optional InteractionOptions options = {});
};
[SecureContext, Exposed=(Window,Worker)]
interface PropertyReadMap {
  readonly maplike<DOMString, InteractionOutput>;
};
[SecureContext, Exposed=(Window,Worker)]
interface PropertyWriteMap {
  readonly maplike<DOMString, InteractionInput>;
};
callback InteractionListener = undefined(InteractionOutput data);
callback ErrorListener = undefined(Error error);
[SecureContext, Exposed=(Window,Worker)]
interface ExposedThing {
  ExposedThing setPropertyReadHandler(DOMString name,
          PropertyReadHandler handler);
  ExposedThing setPropertyWriteHandler(DOMString name,
          PropertyWriteHandler handler);
  ExposedThing setPropertyObserveHandler(DOMString name,
          PropertyReadHandler handler);
  ExposedThing setPropertyUnobserveHandler(DOMString name,
          PropertyReadHandler handler);
  Promise<undefined> emitPropertyChange(DOMString name,
          optional InteractionInput data);
  ExposedThing setActionHandler(DOMString name, ActionHandler action);
  ExposedThing setEventSubscribeHandler(DOMString name,
          EventSubscriptionHandler handler);
  ExposedThing setEventUnsubscribeHandler(DOMString name,
          EventSubscriptionHandler handler);
  Promise<undefined> emitEvent(DOMString name,
          optional InteractionInput data);
  Promise<undefined> expose();
  Promise<undefined> destroy();
  ThingDescription getThingDescription();
};
callback PropertyReadHandler = Promise<InteractionInput>(
        optional InteractionOptions options = {});
callback PropertyWriteHandler = Promise<undefined>(
        InteractionOutput value,
        optional InteractionOptions options = {});
callback ActionHandler = Promise<InteractionInput>(
        InteractionOutput params,
        optional InteractionOptions options = {});
callback EventSubscriptionHandler = Promise<undefined>(
        optional InteractionOptions options = {});
[SecureContext, Exposed=(Window,Worker)]
interface ThingDiscoveryProcess {
  constructor(optional ThingFilter filter = {});
  readonly attribute boolean done;
  readonly attribute Error? error;
  undefined stop();
  async iterable<ThingDescription>;
};
dictionary ThingFilter {
  object? fragment;
  
};
  Special thanks to former editor Johannes Hund (until August 2017, when at Siemens AG) and Kazuaki Nimura (until December 2018) for developing this specification. Also, the editors would like to thank Dave Raggett, Matthias Kovatsch, Michael Koster, Elena Reshetova, Michael McCool as well as the other WoT WG members for their comments, contributions and guidance.
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: