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…
- 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)
- 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
- 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:td
Returns Promise, and resolves toConsumedThing
Object, representing the client interface that operates on the object;produce()
To:td
Returns Promise, and resolves toExposedThing
Object that contains the extension of the server-side interfaceConsumedThing
Object;discover()
: Starts the discovery process and provides a matchfilter
Parameters of theThingDescription
Object.
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 parameterConsumedThing
Object.getThingDescription()
Method: Return the representationConsumedThing
Object TD. Before using an object, an application can examine the metadata in a TD to determine its capabilities.InteractionOptions
Dictionary: 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.PropertyMap
Type: 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 argumentpropertyName
And optionalInteractionOptions
The type ofoptions
Parameters. returnany
The attribute value of the.readMultipleProperties()
Method: Read the values of multiple properties with one or more requests. Accepts a string sequence parameterpropertyNames
And an optional oneInteractionOptions
The type ofoptions
Parameters. Returns an object with a key ofpropertyNames
Is 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 parameterpropertyNames
And an optional oneInteractionOptions
The type ofoptions
Parameters. Returns an object with a key ofpropertyNames
Is a string with the value of the corresponding attribute.writeProperty()
Method: Write an attribute. Receive string argumentpropertyName
And the parameters of the valuevalue
And optionalInteractionOptions
The type ofoptions
Parameters. Returns success or failure.writeMultipleProperties()
Method: Write multiple attributes to a request. Receiving object typeproperties
Parameters, key for attribute name, value for attribute value, and optionalInteractionOptions
The type ofoptions
Parameters. Returns success or failure.WotListener
Callback: User provides receiveany
Parameter 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
, aWotListener
The callbacklistener
And an optional oneInteractionOptions
The type ofoptions
Parameters. 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 argumentactionName
One optionalany
Type parameterparams
And an optional oneInteractionOptions
The type ofoptions
Parameters. Returns the result or error of the action.subscribeEvent()
Method: Request to subscribe to event notifications. Accepts a string argumenteventName
,,, aWotListener
The callbacklistener
And an optional oneInteractionOptions
The type ofoptions
Parameters. 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.
filter
Property represents the object specified for this discoveryThingFilter
Type of discovery filter.action
Property is used during a protocol lookup by the discovery process (such as receiving a new TD)true
, or forfalse
.done
Property when the discovery is complete, no more results andresultsFor is emptytrue
.error
Property 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 beactive
Property set totrue
.stop()
Method will beactive
Property set tofalse
, but ifresultsIn theThingDescription
The object has not beennext()
Consumption,done
The property could still befalse
.- On successful call
next()
Method,active
The property might betrue
orfalse
, butdone
Properties are only available inactive
forfalse
The 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 discoveryThingDescription
Object.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
method
Property represents the discovery type that should be used by the discovery process. The possible values are given byDiscoveryMethod
Enumeration definitions, which can be extended with string values by the solution (but interoperability is not guaranteed).url
Property 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 (method
A value of"directory"
When) or objects (method
For other values).query
Property represents the query string that the implementation receives, such as a SPARQL or JSON query.fragment
Attribute 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
- 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…
- 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…