The main overall Web of Things (WoT) concepts are described in the WoT Architecture document. The Web of Things is made of entities ( Thing s) that can describe their capabilities in a machine-interpretable format, the Thing Description (TD) and expose these capabilities through the WoT Interface , that is, network interactions modeled as Properties (for for reading and writing values), values, Action s (to to execute remote procedures with or without return values) values and Event s (for for signaling notifications). notifications.

This specification describes a programming interface representing the WoT Interface that allows scripts run on a Thing to discover and consume (retrieve) other Thing Description s and to expose Things characterized by WoT Interactions specified by a script.

Scripting is an optional "convenience" building block in WoT and it is typically used in gateways 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 like Thing Directory .

This specification describes a programming interface representing the WoT Interface that allows scripts to discover, operate Thing s and to expose locally defined Things characterized by WoT Interactions specified by a script. The specification deliberately follows the WoT Thing Description specification closely. It is possible to implement simpler APIs on top of this API, or implementing directly the WoT network facing interface (i.e. the WoT Interface ). This specification is implemented at least by the Thingweb project also known as node-wot , which is considered the reference open source implementation at the moment. Check its source code , including examples . Other, closed source implementations have been made by WG member companies and tested against node-wot in plug-fests.

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 Issue feature of the WoT Scripting API repository. For feedback on security and privacy considerations, please use the WoT Security and Privacy Issues.

Introduction

WoT provides layered interoperability based on how Thing s are used: modeled: as being "consumed" and "exposed", as defined in [[WOT-ARCHITECTURE]]. "exposed".

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 exposed on a remote device.

Exposing a Thing requires defining a Thing Description (TD), then (TD) and instantiating a software stack that implements the WoT Interface specified by the TD in order to serve requests for accessing the exposed Properties , Actions and Events , then eventually publishing the Thing Description (for instance to a Thing Directory directory for easier discovery). . This specification describes how to expose and consume Thing s by a script. Also, it defines a generic API for Thing discovery.

Typically scripts are meant to be used on devices able to provide resources (with a WoT Interface ) for managing (installing, updating, running) scripts, such as bridges or gateways that expose and control simpler devices as WoT Thing s and have means to handle (e.g. install, uninstall, update etc.) and run scripts. s.

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.

For an introduction on how scripts could be used in Web of Things , check the Primer document. For some background on API design decisions check the Rationale document.

Use Cases

The following scripting use cases are supported in this specification:

Discovery

Consuming a Thing

Exposing a Thing

Discovery Discover Thing s in a network

The WoT object

The WoT object is the API entry point and it is exposed by sending a broadcast request. Discover Thing s running in an implementation of the local WoT Runtime . Discover nearby Thing s, The WoT object does not expose properties, only methods for instance connected by NFC or Bluetooth. Discover Thing s by sending a discovery request to discovering, consuming and exposing a given registry. Discover Thing s filtered by filters defined on Thing Description s Discover Thing s filtered by semantic queries. Stop or suppress an ongoing discovery process. Optionally specify a timeout to the discovery process after which it is stopped/suppressed. 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

Browser implementations SHOULD use 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 namespace object such as discover() methods on navigator.wot . Node.js -like runtimes MAY provide the WoT API object in order to determine which conformance class through the UA require() implements. or import mechanism.

      // [SecureContext]
      // [NamespaceObject]
      interface WoT {
        Observable discover(optional ThingFilter filter);
        Promise<ThingDescription> fetch(USVString url);
        ConsumedThing consume(ThingDescription td);
        ExposedThing produce(ThingModel model);
        Promise<void> register(USVString directory, ExposedThing thing);
        Promise<void> unregister(USVString directory, ExposedThing thing);
      };
      typedef object ThingFragment;
      typedef object PropertyFragment;
      typedef object ActionFragment;
      typedef object EventFragment;
      typedef object DataSchema;
      typedef object SecurityScheme;
      typedef object Link;
      typedef object Form;
      typedef USVString ThingDescription;
      typedef (ThingFragment or ThingDescription) ThingModel;

The algorithms for the WoT Consumer UA methods will be specified later, including error handling and security considerations.

Implementations of this conformance class MUST implement the The ThingModel type represents either a ConsumedThing interface and the consume() method on the ThingFragment , or a WoT API object ThingDescription .

The WoT Producer discover() method

Starts the discovery process that will provide UA ThingDescription Implementations s that match the optional argument filter of this conformance class MUST implement type ExposedThing ThingFilter . Returns an [ Observable interface ](https://github.com/tc39/proposal-observable) object that can be subscribed to and unsubscribed from. The handler function provided to the Observable during subscription will receive an argument of type produce() USVString method on the representing a WoT API object ThingDescription .

The WoT Discovery DiscoveryMethod UA enumeration

          typedef DOMString DiscoveryMethod;

Implementations of this conformance class MUST implement the ThingDiscovery DiscoveryMethod interface and the discover() method on represents the WoT API object . These conformance classes MAY discovery type to be implemented in a single UA . used:

This specification can be used
  • "any" does not provide any restriction
  • "local" for implementing the WoT Scripting API in multiple programming languages. The interface definitions are specified in [[!WEBIDL]]. The discovering UA may be implemented in the browser, or in a separate runtime environment, such as Node.js Thing 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 s defined in the Web IDL specification [[!WEBIDL]]. Implementations that use TypeScript same device or ECMAScript in a runtime connected 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 device by wired or wireless means.
  • ThingDescription "directory" type typedef object ThingDescription; Represents for discovery based on a service provided by 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 Directory . Fetching a Thing Description Fetching a
  • "multicast" for discovering TD Thing given a URL should be done with an external method, such as s in the Fetch API or device's network by using 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 = new ConsumedThing(td); console.log("Thing name: " + thing.td.title); } catch (err) { console.log("Fetching TD failed", err.message); } supported multicast protocol.
Expanding a Thing Description

The ThingFilter dictionary

Note that [[WOT-TD]] allows using a shortened The Thing Description ThingFilter by dictionary that represents the means of defaults and requiring clients to expand them with default values specified in [[WOT-TD]] constraints for the properties that are not explicitly defined in a given discovering TD . Thing s as key-value pairs.

          dictionary ThingFilter {
            (DiscoveryMethod or DOMString) method = "any";
            USVString? url;
            USVString? query;
            ThingFragment? fragment;
          };

To The expand a TD method given td , run property represents the following steps: For each item discovery type that should be used in the TD default discovery process. The possible values table from [[!WOT-TD]], if the term is not are defined in td , add the term definition with by the default value specified in [[!WOT-TD]]. Validating a Thing Description The [[!WOT-TD]] specification defines how a TD should be validated. Therefore, this API expects the ThingDescription DiscoveryMethod objects enumeration that MAY be validated before used as parameters. This specification defines a basic TD validation as follows. extended by string values defined by solutions (with no guarantee of interoperability).

To The validate a TD url given td , run property represents additional information for the following steps: If td is not an object, throw "TypeError" and terminate these steps. If any discovery method, such as the URL of the mandatory properties defined in [[!WOT-TD]] target entity serving the discovery request, for instance a Thing Directory that don't have default definitions are missing from td , throw (if "TypeError" method and terminate these steps. If JSON schema validation fails on td , throw is "TypeError" "directory" and terminate these steps. ) or a Thing (otherwise).

The WoT API object query Defines the API entry point exposed as property represents a singleton and contains query string accepted by the API methods. The WOT interface [SecureContext, Exposed=(Window,Worker)] interface WOT { // methods defined in UA conformance classes }; Browser implementations should use implementation, for instance a namespace object such as navigator.wot . Standalone runtimes SPARQL or JSON query. Support may expose be implemented locally in the API object through mechanisms like require() WoT Runtime or import remotely as a service in a Thing Directory .

The consume() fragment method partial interface WOT { Promise<ConsumedThing> consume(ThingDescription td); }; Belongs to the WoT Consumer conformance class. Expects an td argument and returns a Promise that resolves with property represents a ConsumedThing ThingFragment object that represents a client interface to operate with the dictionary used for matching property by property against discovered Thing . s.

The discover(filter) method MUST run the following steps:

  1. Return a Promise promise and execute the next steps in parallel . If invoking this method discover() is not allowed for the current scripting context for security reasons, reject promise with throw SecurityError and terminate these steps.
  2. Run the Return an validate a TD Observable steps on td . If that throws, reject promise obs with the error and terminate these steps. Let thing be a new ConsumedThing object constructed from td . Set up execute the next steps WoT Interactions based on introspecting td as explained in [[!WOT-TD]] and [[!WOT-PROTOCOL-BINDINGS]]. Make a request to the underlying platform to initialize the Protocol Bindings parallel . The details are private to the implementations and out of scope of this specification.
  3. Resolve promise with thing . The produce() method partial interface WOT { Promise<ExposedThing> produce(ThingDescription td); }; Belongs to the WoT Producer conformance class. Expects a If td obs.subscribe(handler, errorHandler, complete) argument and returns a Promise that resolves with an ExposedThing object that extends ConsumedThing with a server interface, i.e. the ability to define request handlers. The method MUST run is called, execute the following steps: sub-steps:
    1. Return a Promise If the first argument promise handler and execute the next steps in parallel . If invoking this method is not allowed for the current scripting context for security reasons, reject promise with defined or it is not a function, throw SecurityError TypeError and terminate these steps. Let the algorithm. Otherwise configure thing handler to be invoked when a new ExposedThing object constructed with td . discovery hit happens.
    2. Run the validate a TD steps on td . If that throws, reject promise with the error second argument errorHandler is defined, but it is not a function, throw TypeError and terminate these steps. Otherwise if defined, save it to be invoked in error conditions.
    3. Let If the third argument thing.td onComplete is defined, but it is not a function, throw TypeError and terminate these steps. Otherwise if defined, save it to be td . invoked when the discovery process finished for other reasons than having been canceled.
    4. Resolve If promise filter.query with thing . The discover() method partial interface WOT { ThingDiscovery discover(optional ThingFilter filter = null); }; Belongs is defined, pass it as an opaque string to the WoT Discovery conformance class. Starts underlying implementation to be matched against discovered items. The underlying implementation is responsible to parse it e.g. as a SPARQL or JSON query and match it against the discovery process that will provide ThingDescription objects for Thing Description s that match an optional filter argument. The method MUST run found during the following steps: discovery process. If invoking this method is queries are not allowed for the current scripting context for security reasons, supported, implementations SHOULD throw a SecurityError NotSupported error and terminate these steps.
    5. Construct a ThingDiscovery object If discovery filter.fragment with filter . Invoke is defined, and if it contains other properties than the discovery.start() method. ones defined in ThingFragment , throw TypeError and terminate these steps. Otherwise save the object for matching the discovered items against it.
    6. Return discovery . Refer to Request the ThingDiscovery section for how discovery should be implemented. The ConsumedThing interface Represents a client API to operate a Thing . Belongs underlying platform to start the WoT Consumer conformance class. [Constructor(ThingDescription td), SecureContext, Exposed=(Window,Worker)] interface ConsumedThing { Promise<any> readProperty(DOMString propertyName); Promise<object> readAllProperties(); Promise<object> readMultipleProperties(sequence<DOMString> propertyNames); Promise<void> writeProperty(DOMString propertyName, any value); Promise<void> writeMultipleProperties(object valueMap); Promise<any> invokeAction(DOMString actionName, optional any params); Promise<void> observeProperty(DOMString name, WotListener listener); Promise<void> unobserveProperty(DOMString name); Promise<void> subscribeEvent(DOMString name, WotListener listener); Promise<void> unsubscribeEvent(DOMString name); readonly attribute ThingDescription td; }; callback WotListener = void(any data); Constructing ConsumedThing After fetching a Thing Description as a JSON object, one can create a ConsumedThing object. To create ConsumedThing discovery process, with the ThingDescription td , run the following steps: parameters:
      • If td filter.method is not an object, throw defined or the value is "TypeError" and terminate these steps. "any" , use the widest discovery method supported by the underlying platform.
      • Run Otherwise if filter.method is "local" , use the local expand a TD Thing Directory steps on td . for discovery. Usually that defines Thing s deployed in the same device, or connected to the device in slave mode (e.g. sensors connected via Bluetooth or a serial connection).
      • Let Otherwise if thing filter.method be a new is "directory" , use the remote ConsumedThing Thing Directory object and let thing.td be specified in td filter.url .
      • Return Otherwise if thing . The td property Represents the Thing Description of filter.method is "multicast" , use all the ConsumedThing . Applications may consult multicast discovery protocols supported by the Thing metadata stored in td in order to introspect its capabilities before interacting with it. The readProperty() method Reads a Property value. Takes underlying platform.
  4. Whenever a string argument new item propertyName td and returns a Property value represented as any type. The method MUST is discovered by the underlying platform, run the following steps: sub-steps:
    1. Return If filter.query is defined, check if td is a Promise match for the query. The matching algorithm is encapsulated by implementations. If that returns false , discard promise td and execute continue the next steps in parallel . discovery process.
    2. If invoking this method filter.fragment is not allowed for the current scripting context defined, for security reasons, reject each property defined in it, check if that property exists in promise td with and has the same value. If this is SecurityError false in any checks, discard td and terminate these steps. continue the discovery process.
    3. Make a request to the underlying platform (via the Protocol Bindings ) to retrieve Otherwise if td has not been discarded in the value of previous steps, invoke the Property given by propertyName . handler function with td as parameter.
  5. If Whenever an error occurs during the request fails, reject discovery process, and if promise errorHandler is defined, invoke it with the an argument of type Error whose message property is set to UnknownError unless there was an error received from code provided by the Protocol Bindings and terminate these steps. , in which case set it to that value.
  6. Let When the discovery process is finished, and if value onComplete be the result of is defined, invoke it run the request. cancel discovery steps.
  7. Run When the obs.unsubscribe() method is called, run the following validate Property value cancel discovery sub-steps on value : steps:
    1. Based on Request the DataSchema definition , value MUST be a JSON value and comply underlying platform to stop the data schema defined for the Property that is found in this.td.properties[ propertyName ] . discovery process. If this fails, throw SyntaxError , otherwise return value . returns an error, or if it is not possible, for instance when discovery is based on open ended multicast requests, the implementation SHOULD discard subsequent discovered items.
    2. If these above steps failed, reject Set promise obs.closed with to SyntaxError and terminate these steps. false .
    3. Otherwise resolve promise with value .

The readMultipleProperties() fetch() method

Reads multiple Accepts an url argument of type USVString that represents a URL (e.g. "file://..." or "https://..." ) and returns a Property Promise values that resolves with one or multiple requests. Takes one argument, a sequence ThingDescription (a serialized JSON-LD document of strings propertyNames and returns an object with keys from propertyNames and values returned by this algorithm. type USVString ).

The fetch(url) method MUST run the following steps:

  1. Return a Promise promise and execute the next steps in parallel .
  2. If invoking this method fetch() is not allowed for the current scripting context for security reasons, reject promise with SecurityError and terminate these steps.
  3. Let result be an object and for each string name in If the argument propertyNames url add is not a property with key URL, reject name promise and the value with null . TypeError and terminate these steps.
  4. Make a request to fetch the underlying platform (via content of url as described by the Protocol Bindings ) to retrieve and wait for the reply. Implementations encapsulate the fetching process and the accepted media types (such as application/td+json ), as far as a valid Property Thing Description values given by can be obtained as defined in [[!WOT-TD]]. Let propertyNames . If td be the Protocol Bindings Thing Description support this using one request, use that, otherwise run string-serialized from the readProperty() steps on each property name returned content, as specified in propertyNames and store the resulting values in result for each name in propertyNames . Thing Description serialization .
  5. If there was an error during the above step fails at any point, request, reject promise with an SyntaxError Error object error with error.message set to the error code seen by the Protocol Bindings and terminate these steps.
  6. Resolve Otherwise resolve promise with result . td and terminate these steps.

The readAllProperties() consume() method

Reads all properties Accepts an td argument of the type Thing ThingDescription with one or multiple requests. Takes no arguments. It and returns an object with keys from a Property ConsumedThing names and values returned by this algorithm. object instantiated based on parsing that description.

The consume(td) method MUST must run the following steps:

  1. Let If the argument propertyNames td be is not a sequence created from all the Property names of this Thing as found in this.td.properties . string, throw a TypeError and terminate these steps.
  2. Let result stub be the result of running the readMultipleProperties() TD parsing algorithm steps on propertyNames . If that fails, reject with promise td with as argument. If that throws an error, re-throw the error and terminate these steps.
  3. Resolve If promise stub with result . The writeProperty() method Writes a single does not have an own property that is defined in Property . Takes ThingFragment with a string argument propertyName default value, add that property and a value argument to value stub . It returns success or failure. The method MUST run the following steps:
  4. Return Create a Promise ConsumedThing object promise thing and execute the next steps initialized from stub that implements in parallel Observable .
  5. If invoking this method is not allowed for Add the current scripting context for security reasons, reject promise with SecurityError read() and terminate these steps. Run write() methods to the validate Property value ThingProperty steps on value . If elements so that fails, reject they make requests to access the remote promise Thing with SyntaxError s and terminate these steps. Make wait for the reply, as defined by the Protocol Bindings . Also, all ThingProperty elements SHOULD implement Observable , i.e. define a subscribe() method that should make request to observe the underlying platform (via given Properties as defined by the Protocol Bindings ) .
  6. Add the invoke() methods to write value the ThingAction elements so that they make requests to the remote Property Thing given to invoke its actions, as defined by propertyName . the Protocol Bindings .
  7. If Add the request fails, reject promise with subscribe() method to all ThingEvent elements so that they make requests to subscribe to the error received from events defined by the remote Thing , as defined by the Protocol Bindings and terminate these steps. .
  8. Otherwise resolve Return promise thing .

The writeMultipleProperties() produce() method

Writes Accepts a multiple Property values with one request. Takes one argument, an object properties with keys as model argument of type Property ThingModel names and values as returns an Property ExposedThing values. It returns success or failure. object.

The produce(model) method MUST run the following steps:

  1. Return a Promise promise and execute the next steps in parallel . If invoking this method produce() is not allowed for the current scripting context for security reasons, reject promise with throw SecurityError and terminate these steps.
  2. For each key If the argument name model on is a string, then run the TD parsing algorithm with properties , take its value model passed as parameter. If it throws an error, re-throw that error and terminate this algorithm. Otherwise let value model and run be the validate Property value steps on value . returned value.
  3. If that fails in for any name , reject promise with model is not an object, throw SyntaxError TypeError and terminate these steps.
  4. Make If model does not have an own property that is defined in ThingFragment with a single request default value, add that property and value to the underlying platform (via the model .
  5. Create an Protocol Bindings ExposedThing ) to write the object thing initialized from model .
  6. For each property of Property ExposedThing provided defined in properties . If this cannot be done with a single request with ThingFragment , initialize the property based on the provided initial or default values provided to the local Protocol Bindings WoT Runtime implementation, for instance initialize:
    1. the id property to be the final unique identifier of the Thing , then reject promise with NotSupportedError and terminate these steps.
    2. If the request fails, return the error received from the security object of type Protocol Bindings SecurityScheme to represent the actual security scheme and terminate these steps. its properties as set up by the implementation,
    3. Otherwise resolve promise . The WotListener callback User provided callback that takes the any properties argument and is used for observing property to be an object with all properties being Property ThingProperty changes objects in which the read() and handling write() methods are provided to define local methods to get and set the Event Property notifications. Since subscribing values,
    4. the actions property to these are WoT interactions, they are not modelled be an object with software events. The observeProperty() method Makes a request for all properties being Property ThingAction value change notifications. Takes a string argument propertyName and objects in which the invoke() method is provided to define a WotListener callback function listener . It returns success or failure. The local method MUST to run the following steps: Return a defined Promise Action promise and execute the next steps in parallel . s,
    5. If invoking this method is not allowed for the current scripting context for security reasons, reject promise events property to be an object with all properties being ExposedEvent objects in which the SecurityError emit() method is provided to define a local way to trigger sending notifications to all subscribed clients,
    6. and terminate these steps. initialize the other properties as initialized from model .
    7. If Return listener is not thing .

    The TD parsing algorithm takes a function, reject string promise td with "TypeError" as argument and terminate these steps. runs the following steps:

    1. Make a request Parse td according to the underlying platform (via the Protocol Bindings WoT Thing Description ) in order to observe Property produce a JSON object identified by propertyName json . If the request fails, reject Update promise thing with the error received from the Protocol Bindings properties and terminate these steps. Otherwise resolve values defined in promise json .
    2. Whenever the underlying platform receives a notification for this subscription with new Property value value , run the following sub-steps: If running there was an error during the validate Property value steps on value fails, parsing, throw that error and terminate these steps.
    3. Invoke listener with Otherwise return value as parameter. json .

The unobserveProperty() register() method

Makes a request for unsubscribing from Property value change notifications. Takes a string argument propertyName and returns success or failure. The method MUST run the following steps: two mandatory arguments:

Generate the Property Thing Description identified by as propertyName . If td , given the Properties , Action s and Event s defined for this ExposedThing object. Then make a request fails, reject to register promise td with the error received from to the given WoT Protocol Bindings Thing Directory .

The unregister() method

Takes two mandatory arguments:

Makes a request to unregister the thing from the given WoT Thing Directory .

Examples

        let discoveryFilter = {
          method: "directory",
          url: "http://directory.wotservice.org"
        };
        let subscription = wot.discover(discoveryFilter).subscribe(
          td => {
            console.log("Found Thing " + td.name);
            // fetch the TD and create a ConsumedThing
            let thing = wot.consume(td);
          },
          error => { console.log("Discovery finished because an error: " + error.message); },
          () => { console.log("Discovery finished successfully");}
        );
        setTimeout( () => {
            subscription.unsubscribe();
            console.log("Discovery timeout");
          },
          5000);
        let subscription = wot.discover({ method: "local" }).subscribe(
          td => { console.log("Found local Thing " + td.name); },
          error => { console.log("Discovery error: " + error.message); },
          () => { console.log("Discovery finished successfully");}
        );
        let subscription = wot.discover({ method: "local" }).subscribe({
          td => { console.log("Found local Thing " + td.name); },
          error: err => { console.log("Discovery error: " + err.message); },
          complete: () => { console.log("Discovery finished successfully");}
        });

The invokeAction() ConsumedThing method interface

Makes Represents an object that extends a ThingFragment with methods for client interactions (send request for invoking an reading and writing Properties ), invoke Action s, subscribe and return the result. Takes a string argument actionName , unsubscribe for Property changes and an optional argument parameters Event s.

      interface ConsumedThing: ThingFragment {
        readonly attribute DOMString id;
        readonly attribute DOMString name;
        readonly attribute DOMString? base;
        readonly attribute PropertyMap properties;
        readonly attribute ActionMap actions;
        readonly attribute EventMap events;
        // getter for ThingFragment properties
        getter any(DOMString name);
      };
      [NoInterfaceObject]
      interface PropertyMap {
        readonly maplike<DOMString, ThingProperty>;
      };
      [NoInterfaceObject]
      interface ActionMap {
        readonly maplike<DOMString, ThingAction>;
      };
      [NoInterfaceObject]
      interface EventMap {
        readonly maplike<DOMString, ThingEvent>;
      };
      ConsumedThing includes Observable;  // for TD changes

The id attribute represents the unique identifier of type the Thing instance, typically a URI, IRI, or URN as any USVString . It returns

The name attribute represents the result name of the Action Thing or an error. as DOMString .

The method MUST run base attribute represents the following steps: Return base URI that is valid for all defined local interaction resources.

The properties attribute represents a dictionary of Promise ThingProperty promise and execute the next steps items. The PropertyMap interface represents a maplike dictionary where all values are in parallel . If invoking this method is not allowed for the current scripting context for security reasons, reject promise with ThingProperty objects. The SecurityError read() and terminate these steps. Make write() methods make a request to access the underlying platform (via Properties on the remote Protocol Bindings Thing ) represented by this ConsumedThing proxy object.

The actions attribute represents a dictionary of ThingAction items. The ActionMap interface represents a maplike dictionary where all values are ThingAction objects. The invoke() method represents a request to invoke the Action identified by actionName with parameters provided in params . If on the request fails locally or returns remote Thing .

The events attribute represents a dictionary of ThingEvent items. The EventMap interface represents a maplike dictionary where all values are ThingEvent objects. Subscribing to the events involves setting up an error over observation (subscription) mechanism on the network, reject promise with remote object.

Examples

Below a ConsumedThing interface example is given.

        try {
          let subscription = wot.discover({ method: "local" }).subscribe(
            td => {
              let thing = wot.consume(td);
              console.log("Thing " + thing.name + " has been consumed.");
              let subscription = thing["temperature"].subscribe(function(value) {
                  console.log("Temperature: " + value);
                });
              thing.actions["startMeasurement"].invoke({ units: "Celsius" })
                .then(() => { console.log("Temperature measurement started."); })
                .catch(e => {
                   console.log("Error starting measurement.");
                   subscription.unsubscribe();
                 })
            },
            error => { console.log("Discovery error: " + error.message); },
            () => { console.log("Discovery finished successfully");}
          );
        } catch(error) {
          console.log("Error: " + error.message);
        };

The ExposedThing interface

The ExposedThing interface is the error received from server API that allows defining request handlers, properties, Actions , and Events to a Thing . It also implements the Protocol Bindings Observable and terminate these steps. Otherwise let value be interface. An ExposedThing is created by the result returned produce() method.

      interface ExposedThing: ThingFragment {
        readonly attribute PropertyMap properties;
        readonly attribute ActionMap actions;
        readonly attribute ExposedEvents events;
        // getter for ThingFragment properties
        getter any(DOMString name);
        // setter for ThingFragment properties
        setter void(DOMString name, any value);
        // methods to expose and destroy the Thing
        Promise<void> expose();
        Promise<void> destroy();
        // define Properties
        ExposedThing addProperty(DOMString name, PropertyFragment property, optional any initValue);
        ExposedThing setPropertyReadHandler(DOMString name, PropertyReadHandler readHandler);
        ExposedThing setPropertyWriteHandler(DOMString name, PropertyWriteHandler writeHandler);
        ExposedThing removeProperty(DOMString name);
        // define Actions
        ExposedThing addAction(DOMString name, ActionFragment init, ActionHandler action);
        ExposedThing removeAction(DOMString name);
        ExposedThing setActionHandler(DOMString name, ActionHandler action);
        // define Events
        ExposedThing addEvent(DOMString name, EventFragment event);
        ExposedThing removeEvent(DOMString name);
      };
      [NoInterfaceObject]
      interface ExposedEvents {
        maplike<DOMString, ExposedEvent>;
      };
      callback PropertyReadHandler = Promise<any>();
      callback PropertyWriteHandler = Promise<void>(any value);
      callback ActionHandler = Promise<any>(any parameters);

The properties attribute represents a dictionary of ThingProperty items in which the reply read() and run write() methods define local methods that access the physical representations of the validate Property value Properties .

The actions attribute represents a dictionary of ThingAction steps on it. If that fails, reject promise with items in which the SyntaxError invoke() and terminate these steps. Reject promise with value . method represents a local method to invoke the Action .

The events attribute represents a dictionary of ExposedEvent items that add the emit() method to the ThingEvent definition. The ExposedEvents interface represents a maplike dictionary where all values are ExposedEvent objects.

The subscribeEvent() expose() method

Makes a request Start serving external requests for subscribing to the Event Thing , so that WoT Interactions notifications. Takes a string argument eventName using Properties , Action s and a WotListener Event callback function listener . It returns success or failure. s will be possible.

The expose() method MUST run the following steps:

  1. Return a Promise promise and execute the next steps in parallel .
  2. If invoking this method expose() is not allowed for the current scripting context for security reasons, reject promise with SecurityError and terminate these steps.
  3. If listener is not a function, reject promise with "TypeError" and terminate these steps. Make a request to the underlying platform (via the to attach protocol handlers and start serving external requests for Protocol Bindings WoT Interactions ) to subscribe to an (read, write and observe Properties , invoke Action s and manage Event identified by eventName . subscriptions), based on the Protocol Bindings .
  4. If there was an error during the request fails, request, reject promise with an Error object error with error.message set to the error received from code seen by the Protocol Bindings and terminate these steps.
  5. Otherwise resolve promise . Whenever the underlying platform receives a notification for this Event subscription, implementations SHOULD invoke listener , giving the data provided with the Event as parameter. td and terminate these steps.

The unsubscribeEvent() destroy() method

Makes a request Stop serving external requests for unsubscribing from the Event Thing notifications. Takes a string argument eventName and returns success or failure. destroy the object. Note that eventual unregistering should be done before invoking this method.

The destroy() method MUST run the following steps:

  1. Return a Promise promise and execute the next steps in parallel .
  2. If invoking this method destroy() is not allowed for the current scripting context for security reasons, reject promise with SecurityError and terminate these steps.
  3. Make a request to the underlying platform (via to stop serving external requests for WoT Interactions , based on the Protocol Bindings ) to unsubscribe from the Event identified by eventName . .
  4. If there was an error during the request fails, request, reject promise with an Error object error with error.message set to the error received from code seen by the Protocol Bindings and terminate these steps.
  5. Otherwise resolve promise . with td and terminate these steps.

ConsumedThing Examples

The next example illustrates how to fetch addProperty() method

Adds a TD Property with name defined by URL, create a the name argument, the data schema provided by the property argument of type ConsumedThing PropertyFragment , read metadata (title), read property value, subscribe to and optionally an initial value provided in the argument initValue whose type should match the one defined in the type property change, subscribe according to the value-matching algorithm . If initValue is not provided, it SHOULD be initialized as undefined . Implementations SHOULD update the Thing Description . Throws on error. Returns a WoT event, unsubscribe. reference to the same object for supporting chaining.

try { let res = await fetch("https://tds.mythings.org/sensor11"); let td = res.json(); let thing = new ConsumedThing(td); console.log("Thing " + thing.td.title + " consumed."); } catch(e) { console.log("TD fetch error: " + e.message); }, }; try { // subscribe to property change for “temperature” await thing.observeProperty("temperature", value => { console.log("Temperature changed to: " + value); }); // subscribe to the “ready” event defined in the TD await thing.subscribeEvent("ready", eventData => { console.log("Ready; index: " + eventData); // run the “startMeasurement” action defined by TD await thing.invokeAction("startMeasurement", { units: "Celsius" }); console.log("Measurement started."); }); } catch(e) { console.log("Error starting measurement."); } setTimeout( () => { console.log(“Temperature: “ + await thing.readProperty(“temperature”)); await thing.unsubscribe(“ready”); console.log("Unsubscribed from the ‘ready’ event."); }, 10000);

The ExposedThing removeProperty() interface method

The Removes the ExposedThing Property interface is specified by the server API to operate name argument and updates the Thing that allows defining request handlers, Property , Action , and Event interactions. Description . Throws on error. Returns a reference to the same object for supporting chaining.

[SecureContext, Exposed=(Window,Worker)] interface ExposedThing: ConsumedThing { ExposedThing setPropertyReadHandler(DOMString name, PropertyReadHandler readHandler); ExposedThing setPropertyWriteHandler(DOMString name, PropertyWriteHandler writeHandler); ExposedThing setActionHandler(DOMString name, ActionHandler action); void emitEvent(DOMString name, any data); Promise<void> expose(); Promise<void> destroy(); }; callback PropertyReadHandler = Promise<any>(); callback PropertyWriteHandler = Promise<void>(any value); callback ActionHandler = Promise<any>(any parameters);

Constructing ExposedThing The addAction() method

The Adds to the ExposedThing actions interface extends ConsumedThing . It is constructed from property of a full or partial ThingDescription Thing object. Note that object an existing ThingDescription Action object can be optionally modified (for instance with name defined by adding or removing elements on its properties , the actions name argument, defines input and output data format by the events init internal properties) and the resulting object can used for constructing an ExposedThing object. This is the current way argument of adding and removing type Property ActionFragment , Action and Event definitions, and later adding adds the service handler functions. This is illustrated function provided in the examples action argument as a handler, then updates the Thing Description . Throws on error. Returns a reference to the same object for supporting chaining.

To construct The provided action callback function will implement invoking an ExposedThing Action with and SHOULD be called by implementations when a request for invoking the ThingDescription Action td , run the following steps: If invoking this method is not allowed for received from the current scripting context for security reasons, throw underlying platform. The callback will receive a SecurityError parameters dictionary argument according to the definition in the init.input argument and terminate these steps. If will return a value of type defined by the td init.output argument according to the value-matching algorithm .

There SHOULD be exactly one handler for any given Action . If no handler is not a an object, initialized for any given Action , implementations SHOULD throw a TypeError .

The removeAction() method

Removes the Action specified by the name argument and terminate these steps. Let thing be a new updates the ExposedThing object. Let thing.td be td . There is no validation or any transformation done Thing Description . Throws on error. Returns a reference to the same object for supporting chaining.

The addEvent() method

Adds an event with name defined by the td name at this stage. Return argument and qualifiers and initialization value provided by the thing . event argument of type EventFragment to the Thing object and updates the Thing Description . Throws on error. Returns a reference to the same object for supporting chaining.

The removeEvent() method

Removes the event specified by the name argument and updates the Thing Description . Returns a reference to the same object for supporting chaining.

The PropertyReadHandler callback

A function that is called when an external request for reading a Property is received and defines what to do with such requests. received. It returns should return a Promise and resolves it when with the value of the Property matching the name argument is obtained, to the setPropertyReadHandler function, or rejects with an error if the property is not found or the value cannot be retrieved.

The PropertyWriteHandler callback

A function that is called when an external request for writing a Property is received. It is given the requested new value as argument and should return a Promise which is resolved when the value of the Property that matches the name argument has been updated with value , or rejects with an error if the property is not found or the value cannot be updated.

Note that this function is invoked by implementations before the property is updated and it actually defines what to do when a write request is received. The code in this callback function can invoke the read() method to find out the old value of the property, if needed. Therefore the old value is not provided to this function.

The ActionHandler callback

A function called with a parameters dictionary argument assembled by the WoT runtime based on the Thing Description and the external client request. It returns a Promise that rejects with an error or resolves if the action is successful or ongoing (may also resolve with a control object such as an Observable for actions that need progress notifications or that can be canceled).

The setPropertyReadHandler() method

Takes name as string argument and readHandler as argument of type PropertyReadHandler . Sets the service handler function for reading the specified Property matched by name . Throws on error. Returns a reference to this the same object for supporting chaining.

The readHandler callback function should will 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 SHOULD be at most one handler for any given Property , so and newly added handlers MUST replace the previous old handlers. If no handler is initialized for any given Property , implementations MAY SHOULD implement a default property read handler based on the Thing Description . handler.

Handling Property read requests

When a network an external request for reading Property propertyName is received by received, the implementation, run runtime SHOULD execute the following steps:

  1. Return a Promise promise and execute the next steps in parallel .
  2. If a Property with propertyName does not exist, return reject promise with a ReferenceError in the reply and terminate these steps. If there is a user provided read handler registered with setPropertyReadHandler() , invoke that wih propertyName , return the value with the reply and terminate these steps.
  3. Otherwise, if there is a default read handler provided by the implementation, invoke it with propertyName , return the value with the reply and terminate these steps. if there is no default read handler has been defined by the implementation, return NotSupportedError with the reply and terminate these steps. Handling Property observe requests When a network request for observing a Property propertyName , resolve promise is received by with the implementation, run value of the following steps: If a Property with named propertyName does not exist, return ReferenceError in provided by the reply runtime implementation and terminate these steps.
  4. Save the request sender information to Otherwise, invoke the Property 's internal observer list in order to be able to notify about Property value changes. The PropertyWriteHandler callback A function that is called when an external request for writing a Property is received and defines what to do read handler associated with propertyName . If it rejects, then reject promise with such requests. It expects the requested new value as argument same error, and returns a Promise which is resolved when the value of the resolve Property promise that matches the name argument has been updated with value , or rejects with an error if the property is not found or the value cannot be updated. 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. same value.

The setPropertyWriteHandler() method

Takes name as string argument and writeHandler as argument of type PropertyWriteHandler . Sets the service handler function for writing the specified Property matched by name . Throws on error. Returns a reference to this the same object for supporting chaining.

There MUST SHOULD be at most one write handler for any given Property , so and newly added handlers MUST replace the previous old handlers. If no write handler is initialized for any given Property , implementations MAY SHOULD implement default property update and notifying observers on change, based on the Thing Description . change.

Handling Property write requests

When a network an external request for writing a Property propertyName with a new value value is received, implementations the runtime SHOULD run execute the following update property steps , given propertyName , value and mode set to "single" : steps:

  1. Return a Promise promise and execute the next steps in parallel .
  2. If a Property with propertyName does not exist, return reject promise with a ReferenceError in the reply and terminate these steps.
  3. If there is a user provided write handler registered with setPropertyWriteHandler() , or Otherwise, if there is a default no write handler, Invoke the handler with has been defined for propertyName . If it fails, return the error in the reply and terminate these steps. Otherwise, if mode is "single" , reply to the request with the new value, following to the Protocol Bindings . For each item stored in , the internal observer list of runtime implementation SHOULD update the Property value with propertyName , send an observe reply with the new value attached. If there is no handler to handle the request, return NotSupportedError in the reply , resolve promise and terminate these steps.
  4. When a network request for writing multiple Properties given in an object propertyNames is received, run the following steps:
  5. For each property with key name and value value defined in propertyNames , run Otherwise, invoke the update property steps write handler associated with name , propertyName providing value and as argument. If it rejects, then reject mode promise set to "multiple" . Reply to the request (by sending a single or multiple replies) according to the Protocol Bindings defined for the Property . The ActionHandler callback A function that is called when an external request for invoking an Action is received and defines what to do with such requests. It expects a parameters dictionary argument compiled by the implementation (based on the Thing Description same error, and the external client request). It returns a resolve Promise promise that rejects with an error or resolves if the action is successful. same value.

The setActionHandler() method

Takes name as string argument and action as argument of type ActionHandler . Sets the handler function for the specified Action matched by name . Throws on error. Returns a reference to this the same 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 SHOULD be at most one handler for any given Action , so and newly added handlers MUST replace the previous old handlers.

Handling Action requests

When a network an external request for invoking the Action identified by name is received, the runtime SHOULD execute the following steps:

  1. Return a Promise promise and execute the next steps in parallel .
  2. If an Action identified by name does not exist, return reject promise with a ReferenceError in the reply and terminate these steps.
  3. If there is a user provided Otherwise, if no action handler registered with setActionHandler() , invoke that wih has been defined for name , return the resulting value reject promise with the reply a ReferenceError and terminate these steps.
  4. Otherwise return Otherwise, invoke the NotSupportedError Action handler associated with name . If it rejects with error , then reject promise with the reply and terminate these steps. same error , otherwise if it resolves with value , then resolve promise with the same value .

The emitEvent() method

Examples

Takes name as string argument denoting an Below some Event ExposedThing name, and a data argument of any type. interface examples are given.

        try {
          var temperatureValueDefinition = {
            type: "number",
            minimum: -50,
            maximum: 10000
          };
          var temperaturePropertyDefinition = temperatureValueDefinition;
          // add the 'forms' property
          temperaturePropertyDefinition.forms = [ ... ];
          var thing = WoT.produce({
            name: "tempSensor",
            properties: {
              temperature: temperaturePropertyDefinition
            },
            actions: {
              reset: {
                description: "Reset the temperature sensor",
                input: {
                  temperature: temperatureValueDefinition
                },
                output: null,
                forms: []
              },
            },
            events: {
              onchange: temperatureValueDefinition
            },
            links: []
          });
          await thing.expose();
          await wot.register("https://mydirectory.org", thing);
          // define Thing business logic
          setInterval( async () => {
            let mock = Math.random()*100;
            let old = await thing["temperature"].read();
            if (old < mock) {
              await thing["temperature"].write(mock);
              thing.emitEvent("onchange", mock);
            }
          }, 1000);
        } catch (err) {
           console.log("Error creating ExposedThing: " + err);
        }
        try {
          var 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
                }
              }
          };
          var statusPropertyDefinition = statusValueDefinition;
          // add the 'forms' property
          statusPropertyDefinition["forms"] = [];
          var thing = WoT.produce({
            name: "mySensor",
            properties: {
              brightness: {
                type: "number",
                minimum: 0.0,
                maximum: 100.0,
                required: true,
              },
              status: statusPropertyDefinition
            },
            actions: {
              status: {
                description: "Get status object",
                input: null,
                output: {
                  status : statusValueDefinition;
                },
                forms: []
              },
            },
            events: {
              onstatuschange: statusValueDefinition;
            },
            links: []
          });
          thing.expose().then(() => {
              thing.register();
          });
        } catch (err) {
           console.log("Error creating ExposedThing: " + err);
        }
        let thingDescription = '{ \
          "name": "mySensor", \
          "@context": [ "http://www.w3.org/ns/td",\
             "https://w3c.github.io/wot/w3c-wot-common-context.jsonld" ],\
          "@type": [ "Thing", "Sensor" ], \
          "geo:location": "testspace", \
          "properties": { \
            "prop1": { \
              "type": "number",\
              "@type": [ "Property", "Temperature" ], \
              "saref:TemperatureUnit": "degree_Celsius" \
          } } }';
        try {
          // note that produce() fails if thingDescription contains error
          let thing = WoT.produce(thingDescription);
          // Interactions were added from TD
          // WoT adds generic handler for reading any property
          // define a specific handler for one property
          let name = "examplePropertyName";
          thing.setPropertyReadHandler(name, () => {
            console.log("Handling read request for " + name);
            return new Promise((resolve, reject) => {
                let examplePropertyValue = 5;
                resolve(examplePropertyValue);
              },
              e => {
                console.log("Error");
              });
          });
          thing.expose();
        } catch(err) {
           console.log("Error creating ExposedThing: " + err);
        }
        // fetch an external TD, e.g., to set up a proxy for that Thing
        WoT.fetch("http://myservice.org/mySensor/description").then(td => {
          // WoT.produce() ignores instance-specific metadata (security, form)
          let thing = WoT.produce(td);
          // Interactions were added from TD
          // add server functionality
          // ...
        });

Data types and structures

The method MUST run [[!WOT-TD]] specification defines the following steps: If invoking this method is not allowed for WoT information model , i.e. the current scripting context for security reasons, throw SecurityError data types and terminate these steps. If an data structures used in Event WoT Interactions . In this API these definitions translate to dictionary objects that are extended with methods by the name name is not found interfaces defined in this.td.events , throw NotFoundError and terminate these steps. Make a request this specification.

In order to the underlying platform avoid duplication of definitions, references to send an Event with these data attached as property, using types and structures is defined in this section, but for their full description please refer to the Protocol Bindings , then terminate these steps. Thing Description specification .

The expose() DataSchema method dictionary and its subclasses

Start serving external requests for the Thing , so Value types basically represent types that may be used in WoT Interactions JSON using object definitions and are used in ThingFragment to define Properties , Action Event s and Event Action s will be possible. The method MUST run parameters. Value types are represented as dictionary objects whose properties and possible sub-classes are defined in the following steps: Return a DataSchema section of [[!WOT-TD]].

One property of all Promise DataSchema promise dictionary is the type property whose value is from a set of enumerated strings defined in the DataSchema section of [[!WOT-TD]] and execute is referred as DataType in this specification.

Based on type , the next steps following sub-classes of DataSchema are defined in parallel [[!WOT-TD]]: BooleanSchema , NumberSchema , IntegerSchema , StringSchema , ObjectSchema , ArraySchema . If invoking this method

The SecurityScheme dictionary and its subclasses

Security metadata is not allowed for the current scripting context for security reasons, reject promise with SecurityError represented as dictionary objects whose properties and terminate these steps. Run sub-classes are defined in the expand a TD SecurityScheme steps on this.td . Run section of [[!WOT-TD]].

One property of the validate SecurityScheme dictionary is the scheme property whose value is from a TD set of enumerated strings defined in the SecurityScheme section of [[!WOT-TD]]. Based on this.td . If that fails, reject promise with "TypeError" and terminate these steps. For each type , multiple subclasses of Property SecurityScheme definition are defined.

The Link dictionary

Represents a Web Link with properties defined in this.instance.properties initialize an the Link section of [[!WOT-TD]].

The internal observer list Form internal slot dictionary

Represents metadata describing service details, with properties defined in order to store observe request data needed to notify the observers on value changes. Set up Form section of [[!WOT-TD]].

The InteractionFragment dictionary

Represents the common properties of WoT Interactions based on introspecting , one of td Property , Action or Event , as explained defined in [[!WOT-TD]] the InteractionPattern section of [[!WOT-TD]]. Its subclasses are referred as PropertyFragment , ActionFragment and [[!WOT-PROTOCOL-BINDINGS]]. Make EventFragment .

The PropertyFragment dictionary

Represents the Property interaction data that initializes a request to ThingProperty object. Its properties are defined in the underlying platform to initialize Property and InteractionPattern sections of [[!WOT-TD]].

The ActionFragment dictionary

Represents the Protocol Bindings Action interaction data that initializes a ThingAction object. Its properties are defined in the Action and then start serving external requests for InteractionPattern sections of [[!WOT-TD]].

The EventFragment dictionary

Represents the WoT Interactions Event (read, write interaction data that initializes a ThingEvent object. Its properties are defined in the Event section of [[!WOT-TD]].

The ThingFragment dictionary

The ThingFragment dictionary is defined as Thing in [[!WOT-TD]]. It is a dictionary that contains properties representing semantic metadata and observe interactions ( Properties , invoke Action s and manage Event subscriptions), based on the Protocol Bindings . The details are private to the implementations and out of scope of this specification. If there was an error during the request, reject promise with s). It is used for initializing an Error object error with error.message set to the error code seen by the internal representation of a Protocol Bindings Thing Description and terminate these steps. Otherwise resolve promise and terminate these steps. its properties may be used in ThingFilter .

The destroy() ThingDescription method type

Stop serving external requests for Serialized representation of the Thing Description and destroy the object. Note that eventual unregistering should be done before invoking this method. The method MUST run the following steps: Return a (a Promise JSON-LD promise and execute the next steps in parallel . If invoking document).

In this method is not allowed for version of the current scripting context for security reasons, reject promise with API, Thing Description s are represented as an opaque SecurityError USVString that can be transmitted between devices.

Interfaces for WoT Interactions

The data types and terminate these steps. Make a request structures imported from [[!WOT-TD]] are extended by this specification in order to provide the underlying platform to stop serving external requests interfaces for WoT Interactions , based on the Protocol Bindings . If there was an error during the request, reject promise with an Error object error with error.message set to the error code seen by the

Every Protocol Bindings Thing describes its metadata as defined in ThingFragment , and terminate these steps. Otherwise resolve promise basic interactions defined as Properties , Action s and terminate Event s. The following interfaces are used for representing these steps. interactions.

ExposedThing Examples

The Interaction interface

The next example illustrates how to create Interaction interface is an abstract class to represent ExposedThing Thing based on a partial interactions: TD Properties , Actions object constructed beforehands. and Events .

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); // TODO: add service handlers await thing1.expose(); // define Thing business logic setInterval( async () => { let mock = Math.random()*100; let old = await thing1.readProperty("temperature"); if (old < mock) { await thing1.writeProperty("temperature", mock); } }, 1000); } catch (err) { console.log("Error creating ExposedThing: " + err); }

The next example illustrates how to add or modify a Property InteractionFragment definition on an existing dictionary holds the common properties of ExposedThing PropertyFragment , ActionFragment : take its td property, add or modify it, then create another and EventFragment dictionaries used for initializing ThingProperty , ThingAction and ThingEvent objects in a ThingFragment dictionary used for creating an ExposedThing with that. object.

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); }
        interface Interaction {
          readonly attribute (Form or FrozenArray<Form>) forms;
        };
        Interaction includes InteractionFragment;

The ThingDiscovery forms interface Discovery is a distributed application that requires provisioning and support from participating network nodes (clients, servers, directory services). This API models read-only property represents the client side of typical discovery schemes supported protocol bindings initialization data and is initialized by various IoT deployments. the WoT Runtime .

The ThingProperty interface

The ThingDiscovery ThingProperty object interface is constructed given a filter and provides the properties and methods controlling the discovery process. [Constructor(optional ThingFilter filter = null), SecureContext, Exposed=(Window,Worker)] interface ThingDiscovery { readonly attribute ThingFilter? filter; readonly attribute boolean active; readonly attribute boolean done; readonly attribute Error? error; void start(); Promise<ThingDescription> next(); void stop(); }; The used in ThingDiscovery ConsumedThing interface has a next() method and a done property, but it is not an Iterable . Look into Issue 177 ExposedThing for rationale. objects to represent Thing Property interactions.

The discovery results internal slot PropertyFragment dictionary is an internal queue used for temporarily storing the found initializing ThingDescription Property objects until they are consumed by the application using the next() in a ThingFragment method. Implementations MAY optimize the size dictionary used for creating an ExposedThing object. It MUST implement one of this queue based on e.g. the available resources and the frequency of invoking DataSchema dictionaries.

        interface ThingProperty: Interaction {
          // getter for PropertyFragment properties
          getter any(DOMString name);
          // get and set interface for the Property
          Promise<any> read();
          Promise<void> write(any value);
        };
        ThingProperty includes PropertyFragment;
        ThingProperty includes Observable;

The ThingProperty interface contains all the next() properties defined on PropertyFragment method. as read-only properties.

The filter type read-only property represents the discovery filter of type ThingFilter specified definition for the discovery. Property as a DataSchema dictionary object.

The active writable read-only property is true when tells whether the discovery is actively ongoing on protocol level (i.e. new TD Property s may still arrive) and value can be updated. If it is false , then the set(value) otherwise. method SHOULD always reject.

The done observable read-only property is true if tells whether the discovery has been completed with no more results to report and discovery results Property supports subscribing to value change notifications. If it is also empty. false , then the subscribe() method SHOULD always fail.

The error property represents the last error that occured during the discovery process. Typically used for critical errors that stop discovery. Constructing ThingDiscovery constant To create read-only property - defined in ThingDiscovery DataSchema with - tells whether the ThingFilter Property filter , run the following steps: If filter value is not an object or a constant. If null true , throw the "TypeError" set() and terminate these steps. Let discovery be a new ThingDiscovery object. Set the filter property to filter . Set active and done to false . Set error to null . Return discovery . subscribe() methods SHOULD always fail.

The start() method sets active to true . The stop() method sets active required read-only property - defined in DataSchema to false , but done - tells whether the Property may should be still false if there are always present on the ThingDescription ExposedThing objects in object.

The read() method will fetch the value of the discovery results Property . Returns a Promise not yet consumed that resolves with next() . the value, or rejects with an error.

During successive calls The write() method will attempt to set the value of next() , active may be true or false , but done the Property is set to specified in the false value argument whose type SHOULD match the one specified by next() only when both active is the false type and property. Returns a discovery results Promise is empty. that resolves on success, or rejects on an error.

The DiscoveryMethod ThingAction enumeration interface

typedef DOMString DiscoveryMethod;
        interface ThingAction: Interaction {
          Promise<any> invoke(optional any inputValue);
        };
        ThingAction includes ActionFragment;

Represents the discovery type to be used: The "any" invoke() method when invoked, starts the Action interaction with the input value provided by the inputValue argument. If inputValue is null , the action does not provide take any restriction "local" for discovering arguments and rejects if any arguments are provided. If the value is undefined , the action will ignore any arguments provided. Otherwise the type of inputValue SHOULD match the Thing DataSchema s defined definition in the same device or connected to the device by wired input property. Returns a Promise that will reject with an error or wireless means. "directory" for discovery based on will resolve with a service provided value of type defined by a Thing Directory . the output property.

The "multicast" ThingEvent for discovering interface

        interface ThingEvent: Interaction {
        };
        ThingEvent includes EventFragment;
        ThingEvent includes ThingProperty;

Since Thing ThingEvent s in implements Observable through the device's network ThingProperty interface, event subscription is done by using invoking the subscribe() method on the event object that returns a supported multicast protocol. cancelable Subscription .

The ThingFilter ExposedEvent dictionary interface

Represents an object containing the constraints for discovering Thing s as key-value pairs. dictionary ThingFilter { (DiscoveryMethod or DOMString) method = "any"; USVString? url; USVString? query; object? fragment;
        interface ExposedEvent: ThingEvent {
          void emit(any payload);

        };

The method emit() property represents the discovery type method

Emits an event that should be used in the discovery process. The possible values are defined carries data specified by the DiscoveryMethod payload enumeration that MAY be extended by string values defined by solutions (with no guarantee of interoperability). argument.

The url value-matching algorithm

The value-matching algorithm is applied to a value input in relation to a valueType property represents additional information for the discovery method, such as the URL of the target entity serving the discovery request, type DataSchema , for instance the URL of a Thing Directory (if method value is and "directory" type ) or that properties of a Thing PropertyFragment (otherwise). The query property represents a query string accepted by the implementation, for instance a SPARQL object, or JSON query. Support may be implemented locally in the WoT Runtime or remotely as a service in a Thing Directory . The fragment property represents inputValue parameter to the invoke() method of a template object used for matching property by property against discovered Thing ThingAction s. The start() method Starts object in relation to the discovery process. The method MUST run same object. It executes the following steps:

  1. If invoking this method is not allowed for the current scripting context for security reasons, set this.error valueType.type to is not defined, or does not fully match a string enumerated in DataType , return SecurityError and terminate these steps. false .
  2. If discovery Otherwise, if valueType.type is not supported by the implementation, set "null" : if this.error value to is NotSupportedError and terminate these steps. null , return true , otherwise return false .
  3. If Otherwise, if this.filter valueType.type is defined, Let "boolean" : if filter value denote this.filter . is either true or false , then return true , otherwise return false .
  4. If Otherwise, if filter.query valueType.type is defined, pass it as "integer" : if value is not an opaque string to integer type defined by the underlying implementation to be matched against discovered items. The underlying implementation is responsible to parse it e.g. platform (such as a SPARQL long or JSON query and match it against the Thing Description s found during the discovery process. If queries are not supported, set this.error to NotSupportedError long long and terminate these steps. Create the discovery results internal slot for storing discovered ThingDescription objects. Request the underlying platform to start the discovery process, with ), then return false , otherwise execute the following parameters: sub-steps:
    1. If filter.method valueType.minimum is not defined or the and value is "any" , use the widest discovery method supported by the underlying platform. not greater or equal than that value, return false .
    2. Otherwise if If filter.method valueType.maximum is "local" , use the local Thing Directory for discovery. Usually that defines Thing s deployed in the same device, or connected to the device in slave mode (e.g. sensors connected via Bluetooth or a serial connection). Otherwise if defined and filter.method value is "directory" , use the remote Thing Directory specified in not less or equal than that value, return filter.url false .
    3. Otherwise Return true .
  5. Otherwise, if filter.method valueType.type is "multicast" "number" , use all the multicast discovery protocols supported if value is not an integer or floating point type defined by the underlying platform. When the underlying platform has started the discovery process, set the (such as active long property to or true . Whenever a new Thing Description td is discovered by the underlying platform, run long long or double ), then return false , otherwise otherwise execute the following sub-steps:
    1. Fetch If td valueType.minimum as a JSON object is defined and json value is not greater or equal than that value, return false .
    2. If that fails, set this.error valueType.maximum to SyntaxError , discard is defined and td value and continue the discovery process. is not less or equal than that value, return false .
    3. If Return true .
  6. Otherwise, if filter.query valueType.type is defined, check "string" : if json value is not a match for the query. The matching algorithm is encapsulated string type defined by implementations. If that returns the underlying platform, then return false , discard otherwise return true . In this case the algorithm expects a third parameter td valueType.enum and continue runs the discovery process. following sub-steps:
    • If filter.fragment valueType.enum is defined, for each property defined in it, check an array of strings, then if that property exists in json.properties value and has fully matches one of the same value. If this is false strings defined in any checks, discard td and continue the discovery process. array, return true .
    • Otherwise add Otherwise, return td to the discovery results . false .
  7. At this point implementations MAY control the flow of the discovery process (depending on memory constraints, for instance temporarily stop discovery Otherwise, if the queue is getting too large, or resume discovery when the queue valueType.type is emptied sufficiently). Whenever an error occurs during "array" , execute the discovery process, following sub-steps:
    1. Set this.error to a new Error object error . Set If error.name value to is not an array, return 'DiscoveryError' false .
    2. If there was an error code or message provided by the Protocol Bindings , set error.message valueType.minItems to that is defined, and value as string. does not contain at least valueType.minItems elements, return false .
    3. If the error valueType.maxItems is irrecoverable defined, and discovery has been stopped by the underlying platform, set value contains more than valueType.maxItems elements, return false .
    4. Otherwise, if valueType.items is this.active to undefined , return false .
    5. Otherwise, if valueType.items is null , return true (i.e. any type is accepted as array element, including heterogenous arrays).
    6. When Otherwise, for each element of the underlying platform reports array value run the value-matching algorithm against the discovery process has completed, set this.active valueType.items to object. If any of these runs returns false , then return false .
    7. Otherwise, return true .
    The next() method Provides the next discovered ThingDescription object. The method MUST run the following steps:
  8. Return a Promise Otherwise, if promise type and is "object" , execute the next steps in parallel . following sub-steps:
    1. If this.active value is not an true Object , wait until the discovery results internal slot is not empty. return false .
    2. If discovery results is empty and this.active valueType.properties is not defined, return false , set .
    3. If this.done valueType.properties to is null , return true and reject promise . (i.e. accept any object value).
    4. Remove For each string in the first ThingDescription valueType.required array, if it does not match a property name in the value.properties object or in the td value from discovery results . object, then return false .
    5. Resolve For each property with name promise propName with and value td propDataSchema found in valueType.properties , run the following sub-steps:
      1. If the result of applying the value-matching algorithm on the value value[propName] and terminate these steps. propDataSchema is false , then return false .
    6. Return true .

The

Observables

stop() Observables method Stops or suppresses the discovery process. It might not be supported by all discovery methods and endpoints, however, any further discovery results or errors will are proposed to be discarded included in ECMAScript and the discovery are used for handling pushed data associated with various possible sources, for instance events, timers, streams, etc. A minimal required implementation is marked inactive. described here.

This section is informal and contains rather laconic information for implementations on what to support for interoperability.

      interface Observable {
        Subscription subscribe(ObserverHandler handler,
                               optional ErrorHandler errorHandler,
                               optional OnComplete onComplete);
      };
      interface Subscription {
        void unsubscribe();
        readonly attribute boolean closed;
      };
      callback ObserverHandler = void (any value);
      callback ErrorHandler = void (Error error);
      callback OnComplete = void ();

The method MUST run the following steps: callbacks can be provided when subscribing to an Observable :

Discovery Examples The Subscription interface

The following example finds ThingDescription objects Contains the closed property of Thing s type boolean that are exposed by local hardware, regardless how many instances of WoT Runtime it tells if the subscription is running. Note closed or active.

Also, contains the unsubscribe () method that cancels the discovery can end (become inactive) before subscription, i.e. makes a request to the internal discovery results queue is emptied, so we need underlying platform to continue reading ThingDescription objects until done. This is typical with local stop receiving data from the source, and directory type discoveries. sets the closed property to false .

let discovery = new ThingDiscovery({ method: "local" }); do { let td = await discovery.next(); console.log("Found Thing Description for " + td.title); let thing = new ConsumedThing(td); console.log("Thing name: " + thing.td.title); } while (!discovery.done);

The Observable interface

The next example finds ThingDescription objects of Thing s listed in a Thing Directory Observable service. We set a timeout for safety. interface enabled subscribing to pushed data notifications by the subscribe () method:

let discoveryFilter = { method: "directory", url: "http://directory.wotservice.org" }; let discovery = new ThingDiscovery(discoveryFilter); setTimeout( () => { discovery.stop(); console.log("Discovery stopped after timeout."); }, 3000); do { let td = await discovery.next(); console.log("Found Thing Description for " + td.title); let thing = new ConsumedThing(td); console.log("Thing name: " + thing.td.title); } while (!discovery.done); if (discovery.error) { console.log("Discovery stopped because of an error: " + error.message); } The

Security and Privacy

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-GUIDELINES]]. [[!WOT-SECURITY-CONSIDERATIONS]]. 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-BEST-PRACTICES]]. That document may be updated as security measures evolve. Following these practices does not guarantee security, but it might help avoid common known vulnerabilities.

The WoT security risks and possible mitigations are concerning the following groups:

Scripting Runtime Security and Privacy Risks

This section is normative and contains specific risks relevant for the WoT Scripting Runtime.

Corrupted Input Security and Privacy Risk

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.

Mitigation:
Implementors of this API SHOULD perform validation on all script inputs. In addition to input validation, fuzzing should be used to verify that the input processing is done correctly. There are many tools and techniques in existence to do such validation. More details can be found in [[!WOT-SECURITY-TESTING]].

Physical Device Direct Access Security and Privacy Risk

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).

Mitigation:
The WoT Scripting Runtime SHOULD avoid directly exposing the native device interfaces to the script developers. Instead, a WoT Scripting Runtime should provide a hardware abstraction layer for accessing the native device interfaces. Such hardware abstraction layer should refuse to execute commands that might put the device (or environment) to an unsafe state. Additionally, in order to reduce the damage to a physical WoT device in cases a script gets compromised, it is important to minimize the number of interfaces that are exposed or accessible to a particular script based on its functionality.

Provisioning and Update Security Risk

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.

Mitigation:
Post-manufacturing provisioning or update of scripts, WoT Scripting Runtime or any related data should be done in a secure fashion. A set of recommendations for secure update and post-manufacturing provisioning can be found in [[!WOT-SECURITY-GUIDELINES]]. [[!WOT-SECURITY-CONSIDERATIONS]].

Security Credentials Storage Security and Privacy Risk

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.

Mitigation:
The WoT Scripting Runtime should securely store the provisioned security credentials, guaranteeing their integrity and confidentiality. In case there are more than one tenant on a single WoT-enabled device, a WoT Scripting Runtime should guarantee isolation of each tenant provisioned security credentials. Additionally, in order to minimize a risk that provisioned security credentials get compromised, the WoT Scripting Runtime should not expose any API for scripts to query the provisioned security credentials.

Script Security and Privacy Risks

This section describes specific risks relevant for script developers.

Corrupted Script Input Security and Privacy Risk

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.

Mitigation:
Script developers should perform validation on all application defined script inputs. In addition to input validation, fuzzing could be used to verify that the input processing is done correctly. There are many tools and techniques in existence to do such validation. More details can be found in [[!WOT-SECURITY-TESTING]].

Denial Of Service Security Risk

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.

Mitigation:
Scripts should avoid heavy functional processing without prior successful authentication of requestor. The set of recommended authentication mechanisms can be found in [[!WOT-SECURITY-BEST-PRACTICES]].

Stale TD Security Risk

During the lifetime of a WoT network, a content of a TD can change. This includes its identifier, which might not be an immutable one and might be updated periodically.

Mitigation:
Scripts should use this API to subscribe for notifications on TD changes and do not rely on TD values to remain persistent.

While stale TDs can present a potential problem for WoT network operation, it might not be a security risk.

Terminology and conventions

The generic WoT terminology is defined in [[!WOT-ARCHITECTURE]]: Thing , Thing Description (in short TD ), Web of Things (in short WoT ), WoT Interface (same as WoT network interface ), , Protocol Bindings , WoT Runtime , Consuming a Thing Description , Thing Directory , WoT Interactions , Property , Action , Event etc.

JSON-LD is defined in [[!JSON-LD]] as a JSON document that is augmented with support for Linked Data.

The terms URL , URL scheme , URL host , URL path , URL record , parse a URL , absolute-URL string , path-absolute-URL string , basic URL parser are defined in [[!URL]].

The terms MIME type , Parsing a MIME type , Serializing a MIME type , valid MIME type string , JSON MIME type are defined in [[!MIMESNIFF]].

The terms UTF-8 encoding , UTF-8 decode , encode , decode are defined in [[!ENCODING]].

ASCII decode , ASCII lowercase , string , byte , byte sequence , set , exists , list , for each , continue , is empty , is not empty , append , contains , parse JSON from bytes and serialize JSON to bytes , are defined in [[!INFRA]].

The terms throw , creating , DOMString , Dictionary , ArrayBuffer , BufferSource , any , not present , DOMException , AbortError , SyntaxError , NotSupportedError , NetworkError , TypeError , NotReadableError , TimeoutError , NoModificationAllowedError , SecurityError , are defined in [[!WEBIDL]].

Promise , Error , JSON , JSON.stringify , JSON.parse and internal slots are defined in [[!ECMASCRIPT]].

The terms browsing context , top-level browsing context , global object , current settings object , Document , document base URL , Window , WindowProxy , origin , serialized origin , executing algorithms in parallel , queue a task , task source , iframe , relevant settings object , active document , environment settings object , EventHandler , are defined in [[!HTML5]] and are used in the context of browser implementations.

A browsing context refers to the environment in which Document objects are presented to the user. A given browsing context has a single WindowProxy object, but it can have many Document objects, with their associated Window objects. The script execution context which invokes this API is associated with the browsing context , which can be a web app , a web page , or an iframe .

The term secure context is defined in [[!WEBAPPSEC]].

fire an event , AbortSignal , aborted flag , and add the following abort steps are defined in [[!DOM]].

IANA media type s (formerly known as MIME types) are defined in RFC2046 .

The terms hyperlink reference and relation type are defined in [[!HTML5]] and RFC8288 .

API design rationale API rationale usually belongs to a separate document, but in the WoT case the complexity of the context justifies including basic rationale here. Approaches to WoT application development

The WoT Interest Group and Working Group have explored different approaches to application development for WoT This document defines conformance criteria that have been all implemented and tested. No Scripting API It is possible apply to develop WoT applications that only use the WoT network interface , typically exposed by a WoT gateway that presents a REST-ful API towards clients and implements IoT protocol plugins that communicate with supported IoT deployments. One such implementation is single product: the Mozilla WebThings platform. Simple Scripting API WoT Thing s show good synergy with software objects, so a Thing can be represented as a software object, with Properties represented as object properties, Action s as methods, and Event s as events. In addition, metadata is stored in special properties. Consuming and exposing is done with factory methods that produce a software object UA (user agent) that directly represents a remote Thing and its interactions. One such implementation is implements the Arena Web Hub project. interfaces it contains.

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'); This API, aligned with [[WOT-TD]] Since the direct mapping of Thing s 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 can be used for implementing the WoT interactions as methods. One implementation is node-wot in the the Eclipse ThingWeb project, which is the current reference implementation of the Scripting API specified in this document. multiple programming languages. The same example now would look like the following: the status property and the open() method interface definitions 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 [[WOT-TD]] specification. Based on this, a simple API can also be implemented. Since Scripting is an optional module specified in WoT, this leaves room for applications that only use the WoT network interface. Therefore all three approaches above are supported by [[WOT-TD]]. [[!WEBIDL]].

Moreover, the WoT network interface can The user agent (UA) may 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. Fetching and validating a TD The fetch(url) method has been part of this API the browser, or in earlier versions. However, now fetching a TD given a URL should be done with an external method, separate runtime environment, such as the Fetch API Node.js or a HTTP client library, which offer already standardized options on specifying fetch details. The reason is small embedded runtimes.

Implementations 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 ECMAScript executed in duplicating existing work a browser to re-expose those options implement the APIs defined in this API. Since fetching document MUST implement them in a TD has been scoped out, and TD validation is manner consistent with the ECMAScript Bindings defined externally in [[WOT-TD]], that is scoped out, too. This specification expects a TD as parsed JSON object that has been validated according to the [[WOT-TD]] specification. Web IDL specification [[!WEBIDL]].

Factory vs constructors

The factory methods for consuming and exposing Thing s 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. So applications Implementations that prefer validating a TD themselves, may use the constructors, whereas applications that leave validation TypeScript or ECMAScript in a runtime to implementations and prefer interactions initialized up front SHOULD use the factory methods on the WoT API object . Observers Earlier drafts used implement the Observer construct, but since it has not become standard, APIs defined in this document MUST implement them in a new design was needed that was light enough for embedded implementations. Therefore observing Property changes and handling WoT Event s is done manner consistent with callback registrations. the TypeScript Bindings defined in the TypeScript specification [[!TYPESCRIPT]].

Using Events

This API ended up not using software events at all, for document serves a general description of the following reasons: Subscription to WoT Event s may be different from handling software events (subscription might need parameters, might involve security tokens etc). Most implementations are for Node.js Scripting API. Language and browser implementations will likely be libraries (because possible dependency management runtime specific issues are discussed in native implementations), using Events has been challenging. Observing Property changes and handling WoT Event s is done with the solution above. Polymorphic functions The reason to use function names like readProperty() , readMultipleProperties() etc. instead separate extensions of a generic polymorphic read() function is that the current names map exactly to the "op" vocabulary from the Form definition in [[WOT-TD]]. this document.

Changes

The following is a list of major changes to the document. Major versions of this specification are the following: First Public Working Draft September 2017 . Working Draft April 2018 . Working Draft November 2018 . This version, introducing the following major changes: Remove fetch() for fetching a TD (delegated to external API). Remove Observer and use W3C TAG recommended design patterns . Align the discovery API to other similar APIs (such as W3C Generic Sensor API ). Remove the large data definition API for constructing TD s and leverage using ThingDescription instead. Add missing algorithms and rework most existing ones. Allow constructors for ConsumedThing and ExposedThing . Add API rationale as an appendix to this document. For a complete list of changes, see the github change log . You can also view the recently closed issues .

Open issues

The following problems are being discussed and need most attention:

Full Web IDL

Acknowledgements

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, Koster and Michael McCool as well as the other WoT WG members for their comments, contributions comments and guidance.