WoT standards developed by the W3C Web of Things (WoT) Working Group and their latest status:

specification The current state
WoT Architecture CR
WoT Thing Description CR
WoT Scripting API WD, Working Draft
WoT Binding Templates Working Group Note
WoT Security and Privacy Considerations Working Group Note

This series will start with the WoT standard itself, WoT Architecture (WoT Architecture), WoT Thing Description (WoT Thing Description), and WoT Scripting API (WoT Scripting) are currently in CR stage (W3C standard stage see figure below) Programming API) for a quick parse.

As shown in the figure below, the standard entering CR stage means that the content has been relatively stable, WD stage means greater uncertainty, and Working Group Note (Working Group Note) is very variable. So the “architecture” and “object description” in the CR phase are worth taking the time to understand (with a high probability of becoming the official recommended standard REC), while the PROGRAMMING API in the WD phase underwent a major content overhaul on October 28, 2019, almost completely discarding the previous version. Close to steady state, but programming apis are always something developers love, so this series will cover them.

W3C Process Document, www.w3.org/2019/Proces…

  1. Introduction to programming APIS

The WoT Scripting API describes how to expose and consume objects through Scripting, and defines a common object discovery API. Based on the ‘Consumed Thing’ and ‘Consumed thing’ defined by the WoT architecture, this specification provides different levels of interactive capabilities.

First, the client can create a local runtime resource model, namely the consumer, through the consumption TD (Thing Description). Consumers support access to attributes, actions, and events exposed by server-side objects on remote devices.

Second, the server is responsible for exposing objects, which requires:

  • Definition of TD
  • Initializes a software stack that implements the WoT interface defined by the TD to serve requests for exposed properties, actions, and events
  • Final TD release (e.g. to an object catalog for consumers to find)
  1. Supported Scenarios

The programming API supports the following script usage scenarios.

2.1 consumer goods

  • Create a programming object based on TDS that consume objects such as exposed WoT interactions:

    • Reads the value of one or more properties
    • Sets the value of one or more properties
    • Observe changes in attribute values
    • Call to action
    • Observe events emitted by objects
    • Infer (introspect) TD, including resources based on TD links

2.2 exposed content

  • Exposing objects involves generating protocol bindings to access the underlying functionality

  • Creates objects to be exposed locally based on TD or existing object objects in the provided string serialization format

  • Add attribute definitions to objects

  • Removes the property definition from the object

  • Add an action definition to the object

  • Removes action definitions from the object

  • Add an event definition to the object

  • Deletes event definitions from objects

  • Sends an event, such as notifying all listeners subscribed to the event

  • Register handlers for external requests

    • Gets the value of the property
    • Update the value of an attribute
    • Perform the action: Receives the parameters from the request, performs the defined action, and returns the result

2.3 finding

  • Discover all objects in the WoT network by sending a broadcast request
  • Found objects running in the local WoT runtime
  • Find nearby objects, such as objects connected via NFC or Bluetooth
  • Discover objects by sending a discovery request to a registry service
  • Objects are found through the filter defined by the object description
  • Discover objects by semantic query
  • Stop or block the discovery process in progress
  • Optionally assign a timeout to the discovery process, after which further discovery is stopped/blocked
  1. Interface and type definitions

3.1 ThingDescription type

typedef object ThingDescription;

Copy the code

Here is an example of getting an instance of the ThingDescription type from a URL:

Example 1: Get the TD

try { let res = await fetch('https://tds.mythings.biz/sensor11'); / /... Let td = await res.json(); let thing = new ConsumedThing(td); console.log("Thing name: " + thing.getThingDescription().title); } catch (err) { console.log("Fetching TD failed", err.message); }Copy the code

In addition, the specification defines how to extend AND validate TD.

3.2 WOT interface

[SecureContext, Exposed=(Window,Worker)]
interface WOT {
  // methods defined in UA conformance classes
  Promise<ConsumedThing> consume(ThingDescription td);
  Promise<ExposedThing> produce(ThingDescription td);
  ThingDiscovery discover(optional ThingFilter filter = null);
};

Copy the code

Instances of the WOT interface will be exposed to Windows and workers under certain names. The WOT interface contains three methods:

  • consume()To:tdReturns Promise, and resolves toConsumedThingObject, representing the client interface that operates on the object;
  • produce()To:tdReturns Promise, and resolves toExposedThingObject that contains the extension of the server-side interfaceConsumedThingObject;
  • discover(): Starts the discovery process and provides a matchfilterParameters of theThingDescriptionObject.

These three methods can be used to create consumers, generate exposures, and discover TDS on the client side and server side, respectively.

3.3 ConsumedThing interface

The ConsumedThing interface is defined as follows. An instance of ConsumedThing is a consumer with a set of client apis for manipulating objects.

[SecureContext, Exposed=(Window,Worker)]
interface ConsumedThing {
  constructor(ThingDescription td);
  Promise<any> readProperty(
        DOMString propertyName,
        optional InteractionOptions options = null
        );
  Promise<PropertyMap> readAllProperties(
        optional InteractionOptions options = null
        );
  Promise<PropertyMap> readMultipleProperties(
        sequence<DOMString> propertyNames,
        optional InteractionOptions options = null
        );
  Promise<void> writeProperty(
        DOMString propertyName,
        any value,
        optional InteractionOptions options = null
        );
  Promise<void> writeMultipleProperties(
        PropertyMap valueMap,
        optional InteractionOptions options = null
        );
  Promise<any> invokeAction(
        DOMString actionName,
        optional any params = null,
        optional InteractionOptions options = null
        );
  Promise<void> observeProperty(
        DOMString name,
        WotListener listener,
        optional InteractionOptions options = null
        );
  Promise<void> unobserveProperty(DOMString name);
  Promise<void> subscribeEvent(
        DOMString name,
        WotListener listener,
        optional InteractionOptions options = null
        );
  Promise<void> unsubscribeEvent(DOMString name);
  ThingDescription getThingDescription();
};
dictionary InteractionOptions {
  object uriVariables;
};
typedef object PropertyMap;
callback WotListener = void(any data);

Copy the code

Let’s take a quick look at the members defined by the ConsumedThing interface.

  • constructor() constructor: After obtaining the TD represented by the JSON object, it can be created with it as a parameterConsumedThingObject.
  • getThingDescription()Method: Return the representationConsumedThingObject TD. Before using an object, an application can examine the metadata in a TD to determine its capabilities.
  • InteractionOptionsDictionary: Holds interaction options that need to be exposed to application scripts as determined by TD. In the current version of the specification, only URI template variables are supported, represented as parsed JSON objects defined in Wot-TD.
  • PropertyMapType: Mapping between the name of an attribute representing a string type and the value of that attribute. Use to manipulate multiple properties at once.
  • readProperty()Method: Reads the value of an attribute. Receive string argumentpropertyNameAnd optionalInteractionOptionsThe type ofoptionsParameters. returnanyThe attribute value of the.
  • readMultipleProperties()Method: Read the values of multiple properties with one or more requests. Accepts a string sequence parameterpropertyNamesAnd an optional oneInteractionOptionsThe type ofoptionsParameters. Returns an object with a key ofpropertyNamesIs a string with the value of the corresponding attribute.
  • readAllProperties()Method: Reads the values of all attributes of an object with one or more requests. Accepts a string sequence parameterpropertyNamesAnd an optional oneInteractionOptionsThe type ofoptionsParameters. Returns an object with a key ofpropertyNamesIs a string with the value of the corresponding attribute.
  • writeProperty()Method: Write an attribute. Receive string argumentpropertyNameAnd the parameters of the valuevalueAnd optionalInteractionOptionsThe type ofoptionsParameters. Returns success or failure.
  • writeMultipleProperties()Method: Write multiple attributes to a request. Receiving object typepropertiesParameters, key for attribute name, value for attribute value, and optionalInteractionOptionsThe type ofoptionsParameters. Returns success or failure.
  • WotListenerCallback: User provides receiveanyParameter to observe property changes and handle event notifications.
  • observeProperty()Method: Request to subscribe to notifications of changes in the value of an attribute. Accepts a string argumentpropertyName, aWotListenerThe callbacklistenerAnd an optional oneInteractionOptionsThe type ofoptionsParameters. Returns success or failure.
  • unobserveProperty()Method: Request to unsubscribe notification of a change in the value of an attribute. Accepts a string argumentpropertyName, returns success or failure.
  • invokeAction()Method: request that an action be invoked and return the result. Accepts a string argumentactionNameOne optionalanyType parameterparamsAnd an optional oneInteractionOptionsThe type ofoptionsParameters. Returns the result or error of the action.
  • subscribeEvent()Method: Request to subscribe to event notifications. Accepts a string argumenteventName,,, aWotListenerThe callbacklistenerAnd an optional oneInteractionOptionsThe type ofoptionsParameters. Returns success or failure.
  • unsubscribeEvent()Method: Request to unsubscribe event notifications. Accepts a string argumenteventName, returns success or failure.

Here is an example client script that shows how to get a TD from a URL, create a ConsumedThing, read metadata (title), read property values, subscribe to property changes, subscribe to WoT events, and unsubscribe.

Example 2: Client API example

try { let res = await fetch("https://tds.mythings.org/sensor11"); let td = res.json(); let thing = new ConsumedThing(td); console.log("Thing " + thing.getThingDescription().title + " consumed."); } catch(e) { console.log("TD fetch error: " + e.message); }}; Try {// Subscribe to notify await things. observeProperty("temperature", value => { console.log("Temperature changed to: " + value); }); // Subscribe to the "ready" event defined in TD. Await things. subscribeEvent(" Ready ", eventData => {console.log(" ready; index: " + eventData); // Return "startMeasurement" action 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);Copy the code

3.4 ExposedThing interface

The ExposedThing interface is a server API for manipulating objects, supporting the definition of request handlers, attributes, actions, and event interfaces.

[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>(
        optional InteractionOptions options = null
            );
  callback PropertyWriteHandler = Promise<void>(
        any value,
            optional InteractionOptions options = null
            );
  callback ActionHandler = Promise<any>(
        any params,
            optional InteractionOptions options = null
            );

Copy the code

The ExposedThing interface extends the ConsumedThing interface to build instances based on a complete or incomplete ThingDescription object. ExposedThing inherited the following method from ConsumedThing:

  • readProperty()
  • readMultipleProperties()
  • readAllProperties()
  • writeProperty()
  • writeMultipleProperties()
  • writeAllProperties()

These methods have the same algorithm as those in ConsumedThing, except that requests to the underlying platform may be implemented as local methods or libraries and do not necessarily require network operations.

The implementation of the ConsumedThing interface in ExposedThing provides a default way to interact with ExposedThing.

Once ExposedThing is built, the application script can initialize its properties and set the optional read, write, and action request handlers (that is, the default values provided by the implementation). Handlers provided by application scripts can use default handlers to extend the default behavior, or they can bypass them and override the default behavior. Finally, the application script calls expose() on ExposedThing to start serving external requests.

The following are the members of the ExposedThing interface definition.

  • PropertyReadHandler callback: A function called when an external request is received to read a property, defining how to handle the request. Return the Promise and resolve as the value of the property if the name parameter matches the property, or reject with an error if the property is not found or the value of the property cannot be obtained.

  • The setPropertyReadHandler() method takes the string parameter name and the PropertyReadHandler parameter readHandler of type PropertyReadHandler. Sets the handler to execute when reading a property matching name. If there is an error, throw. Return this object to support the concatenated call.

    The readHandler callback function should implement the logic to read the property and should be called by the implementation when the underlying platform receives a request to read the property.

    There must be at most one handler for any attribute, so the new handler must replace the previous one. If there are no initial handlers for a given property, the implementation should implement a default property read handler based on TD.

  • PropertyWriteHandler Callback: Function called when an external request to write a property is received, defining how to handle the request. The parameter needs to contain the new value and return the Promise, resolved when the attribute matching name is updated to value, or rejected if no attribute is found or the value cannot be updated.

  • The setPropertyWriteHandler() method: receives the string parameter name and the PropertyWriteHandler parameter writeHandler. Sets the handler to execute when writing a property matching name. If there is an error, throw. Return this object to support the concatenated call.

    There must be at most one handler for any attribute, so the new handler must replace the previous one. If there are no initial handlers for a given attribute, the implementation should implement a default attribute update handler based on TD.

  • ActionHandler callback: A function called when an external request is received to perform an action, defining how to handle the request. The params dictionary needs to be included in the parameter. Return the Promise, reject it if it goes wrong, and resolve it if it succeeds.

  • The setActionHandler() method takes the string argument name and the ActionHandler type action. Sets the handler to execute on an action that matches name. If there is an error, throw. Return this object to support the concatenated call.

    The Action callback function should implement the logic of the action and should be called by the implementation when the underlying platform receives a request to perform the action.

    There must be at most one handler for any action, so the new handler must replace the previous handler.

  • The emitEvent() method: accepts the string parameter name representing the event name and the parameter data of type any.

  • The Expose () method: begins to service external requests for objects, enabling WoT interactions with properties, actions, and events.

  • The destroy() method: stops requests for objects outside the service and destroys objects. Note that the final deregistration should be done before this method is called.

The following example shows how to create an ExposedThing based on an incomplete TD object constructed earlier.

Example 3: Create an ExposedThing with simple attributes

try { let temperaturePropertyDefinition = { type: "number", minimum: -50, maximum: 10000 }; let tdFragment = { properties: { temperature: temperaturePropertyDefinition }, actions: { reset: { description: "Reset the temperature sensor", input: { temperature: temperatureValueDefinition }, output: null, forms: [] }, }, events: { onchange: temperatureValueDefinition } }; let thing1 = await WOT.produce(tdFragment); // Initialize the await thing1.writeProperty("temperature", 0); / / add service handler thing1. SetPropertyReadHandler (" temperature ", () = > {return readLocalTemperatureSensor (); // Promise }); // Start the service await thing1.expose(); } catch (err) { console.log("Error creating ExposedThing: " + err); }Copy the code

The following example shows how to add or modify an attribute definition to an existing ExposedThing: take its TD attribute, add or modify it, and then use it to create another ExposedThing.

Example 4: Adding object properties

Parse (json.stringify (thing1.td)); // Create a deep copy of 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); }Copy the code

3.5 ThingDiscovery interface

Discovery is a distributed application that requires the supply and support of network nodes (clients, servers, and directory services). This API models clients with typical discovery patterns supported by multiple IoT deployment scenarios.

The ThingDiscovery object takes a filter parameter and provides properties and methods that control the discovery process.

[SecureContext, Exposed=(Window,Worker)]
interface ThingDiscovery {
  constructor(optional ThingFilter filter = null);
  readonly attribute ThingFilter? filter;
  readonly attribute boolean active;
  readonly attribute boolean done;
  readonly attribute Error? error;
  void start();
  Promise<ThingDescription> next();
  void stop();
};

Copy the code

The internal slot corresponding to the discovery is an internal queue that temporarily stores the discovered ThingDescription object until the application consumes it via the next() method.

  • filterProperty represents the object specified for this discoveryThingFilterType of discovery filter.
  • actionProperty is used during a protocol lookup by the discovery process (such as receiving a new TD)true, or forfalse.
  • doneProperty when the discovery is complete, no more results andresultsFor is emptytrue.
  • errorProperty represents the last error that occurred during discovery. Often a critical error that causes discovery to stop.

The process for building ThingDiscovery is as follows.

  • start()Method will beactiveProperty set totrue.stop()Method will beactiveProperty set tofalse, but ifresultsIn theThingDescriptionThe object has not beennext()Consumption,doneThe property could still befalse.
  • On successful callnext()Method,activeThe property might betrueorfalse, butdoneProperties are only available inactiveforfalseThe value is set only when the result is nulltrue.

Let’s summarize the start(), next(), and stop() methods.

  • start()Method: Start the discovery process.
  • next()Method: Provide the next discoveryThingDescriptionObject.
  • stop()Method: Stop or block the discovery process. It may not be supported by all discovery methods or endpoints, but any subsequent discovery results or errors are discarded and the discovery object is marked as inactive.

3.5.1 track of DiscoveryMethod enumeration

typedef DOMString DiscoveryMethod;

Copy the code

Represents the type to discover:

  • Any: unlimited
  • Local: Only objects defined on the current device or devices connected to the current device via wired or wireless are discovered.
  • Directory: Service discovery provided by the object directory
  • Multicast: discovers multicast protocols supported by the network where the device resides

3.5.2 ThingFilter dictionary

Object that contains the name and value pairs of the object restriction type found.

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

Copy the code
  • methodProperty represents the discovery type that should be used by the discovery process. The possible values are given byDiscoveryMethodEnumeration definitions, which can be extended with string values by the solution (but interoperability is not guaranteed).
  • urlProperty represents additional information about the current discovery method, such as the URL of the target entity serving the current discovery request, such as an object directory (methodA value of"directory"When) or objects (methodFor other values).
  • queryProperty represents the query string that the implementation receives, such as a SPARQL or JSON query.
  • fragmentAttribute represents a template object that is used to match objects discovered attribute by attribute.

3.5.3 ThingDiscovery sample

The following example shows the process of finding thingDescriptions of objects exposed on local hardware, regardless of how many WoT runtimes are running on the local hardware. Note that the discovery object may end (become inactive) before the internal discovery result queue becomes empty, so you need to keep reading the ThingDescription object until the done attribute is true. This is a typical local and directory type discovery process.

Example 5: Finding exposed objects on local hardware

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.getThingDescription().title); } while (! discovery.done);Copy the code

The following example shows how to find the ThingDescription of an object listed on the object catalog service. Timeout is set for security.

Example 6: Discover objects by directory

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.getThingDescription().title); } while (! discovery.done); if (discovery.error) { console.log("Discovery stopped because of an error: " + error.message); }Copy the code

The following example shows an open multicast discovery process that may not end quickly (depending on the underlying protocol), so it is best to end with a timeout. This situation also tends to deliver results one by one.

Example 7: Finding objects on the network

let discovery = new ThingDiscovery({ method: "multicast" }); setTimeout( () => { discovery.stop(); console.log("Stopped open-ended discovery"); }, 10000); do { let td = await discovery.next(); let thing = new ConsumedThing(td); console.log("Thing name: " + thing.getThingDescription().title); } while (! discovery.done);Copy the code
  1. Further reading

For details on the WoT working Group set up by the W3C to develop the WoT standard, see this article.

  • W3C Universal Internet of Things Analysis: Description of things
  • W3C Universal Internet of Things Parsing: Architecture
  • “Introduction to W3C Universal Iot Standard”
  • Zhihu user “yao to jung’s” for an answer: www.zhihu.com/question/26…
  1. A link to the

  • WoT Architecture:www.w3.org/TR/wot-arch…
  • WoT Thing Description: www.w3.org/TR/wot-thin…
  • WoT Scripting API: www.w3.org/TR/wot-scri…
  • WoT Binding Templates:www.w3.org/TR/wot-bind…
  • WoT Security and Privacy Considerations: www.w3.org/TR/wot-secu…
  • WoT Interest Group: www.w3.org/2019/07/wot…
  • WoT working group: www.w3.org/2016/12/wot…