CARVIEW |
Web of Things (WoT) Scripting API
More details about this document
- This version:
- https://www.w3.org/TR/2023/NOTE-wot-scripting-api-20231003/
- Latest published version:
- https://www.w3.org/TR/wot-scripting-api/
- Latest editor's draft:
- https://w3c.github.io/wot-scripting-api/
- History:
- https://www.w3.org/standards/history/wot-scripting-api/
- Commit history
- Editors:
- Zoltan Kis (Intel)
- Daniel Peintner (Siemens AG)
- Cristiano Aguzzi (Invited Expert)
- Johannes Hund (Former Editor, when at Siemens AG)
- Kazuaki Nimura (Former Editor, at Fujitsu Ltd.)
- Feedback:
- GitHub w3c/wot-scripting-api (pull requests, new issue, open issues)
- public-wot-wg@w3.org with subject line [wot-scripting-api] … message topic … (archives)
- Repository
- On GitHub
- File a bug
- Contributors
- Contributors on GitHub
Copyright © 2017-2023 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
Abstract
The Web of Things is made of entities (Things) that can describe their capabilities in a machine-interpretable Thing Description (TD) and expose these capabilities through the WoT Interface, that is, network interactions modeled as Properties (for reading and writing values), Actions (to execute remote procedures with or without return values) and Events (for signaling notifications).
The main Web of Things (WoT) concepts are described in the Web of Things (WoT) Architecture 1.1 specification.
Scripting is an optional building block in WoT and it is typically used in gateways or browsers that are able to run a WoT Runtime and script management, providing a convenient way to extend WoT support to new types of endpoints and implement WoT applications such as TD Directory.
This specification describes an application programming interface (API) representing the WoT Interface that allows scripts to discover, operate Things and to expose locally defined Things characterized by WoT Interactions specified by a script.
The APIs defined in this document deliberately follow the Web of Things (WoT) Thing Description 1.1 specification closely. It is possible to implement more abstract APIs on top of them, or implementing directly the WoT network facing interface (i.e. the WoT Interface).
This specification is implemented at least by the Eclipse Thingweb project also known as node-wot, which is considered the reference open source implementation at the moment. Check its source code, including examples.
Status of This Document
This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
Implementers need to be aware that this specification is considered unstable. Vendors interested in implementing this specification before it eventually reaches the Candidate Recommendation phase should subscribe to the repository and take part in the discussions.
Please contribute to this draft using the GitHub Issues page of the WoT Scripting API repository. For feedback on security and privacy considerations, please use the WoT Security and Privacy Issues.
This document was published by the Web of Things Working Group as a Group Note using the Note track.
This Group Note is endorsed by the Web of Things Working Group, but is not endorsed by W3C itself nor its Members.
This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
The W3C Patent Policy does not carry any licensing requirements or commitments on this document.
This document is governed by the 12 June 2023 W3C Process Document.
WoT provides layered interoperability based on how Things are used: "consumed" and "exposed", as defined in the Web of Things (WoT) Architecture 1.1 terminology.
By consuming a TD, a client Thing creates a local runtime resource model that allows accessing the Properties, Actions and Events exposed by the server Thing on a remote device.
- defining a Thing Description (TD),
- then 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 TD Directory for easier discovery).
Typically scripts are meant to be used on bridges or gateways that expose and control simpler devices as WoT Things and have means to handle (e.g. install, uninstall, update etc.) and run scripts.
This specification does not make assumptions on how the WoT Runtime handles and runs scripts, including single or multiple tenancy, script deployment and lifecycle management. The API already supports the generic mechanisms that make it possible to implement script management, for instance by exposing a manager Thing whose Actions (action handlers) implement script lifecycle management operations.
This section is non-normative.
The business use cases listed in the [WOT-USE-CASES] document may be implemented using this API, based on the scripting use case scenarios described here.
- Consume a TD, i.e. create a programmatic object from a Thing Description that exposes WoT Interactions:
- Exposing the Thing includes generating the protocol bindings in order to access lower level functionality.
- Create a local Thing to be exposed, based on Thing Description.
- The following use cases can be implemented before
creating the Thing
by editing the Thing Description:
- Add a Property definition to the Thing.
- Remove a Property definition from the Thing.
- Add an Action definition to the Thing.
- Remove an Action definition from the Thing.
- Add a WoT Event definition to the Thing.
- Remove a WoT Event definition from the Thing.
Editor's noteAfter evaluating dynamic modifications to Thing Descriptions through several versions of this API, the editors concluded that the simplest way to represent these use cases is to take an existing TD, modify it (i.e. add or remove definitions) and then create a new Thing based on the modified TD.
- Emit a WoT Event, i.e. notify all subscribed listeners.
- Register service handlers for external requests:
- Discover Things in a network by sending a broadcast request.
- Discover Things running in the local WoT Runtime.
- Discover nearby Things, for instance connected by NFC or Bluetooth, or within a geo-fence.
- Discover Things by sending a discovery request to a given TD Directory.
- Discover Things filtered by filters defined on Thing Descriptions
- Discover Things 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.
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MAY, MUST, and SHOULD in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
This specification used to be a Working Draft which was expected to become a W3C Recommendation. However, it is now a WG Note which contains informative statements only. Therefore we need to consider how to deal with the description within this Conformance section.
This specification describes the conformance criteria for the following classes of user agent (UA).
Due to requirements of small embedded implementations,
splitting WoT client and server interfaces was needed. Then,
discovery is a distributed application, but typical scenarios
have been covered by a generic discovery API in this
specification. This resulted in using 3 conformance classes for
a UA that implements this API, one for
client, one for server, and one for discovery. An application
that uses this API can introspect for the presence of the
consume()
, produce()
and
discover()
methods on the WoT API object in order
to determine which conformance class the UA implements.
- WoT Consumer UA
-
Implementations of this conformance class MUST implement the
interface and theConsumedThing
consume()
method on the WoT API object. - WoT Producer UA
-
Implementations of this conformance class MUST implement
interface and theExposedThing
produce()
method on the WoT API object. - WoT Discovery UA
-
Implementations of this conformance class MUST implement the
interface, theThingDiscoveryProcess
discover()
method, theexploreDirectory()
method, and therequestThingDescription()
method on the WoT API object.
These conformance classes MAY be implemented in a single UA.
This specification can be used for implementing the WoT Scripting API in multiple programming languages. The interface definitions are specified in [WEBIDL].
The UA may be implemented in the browser, or in a separate runtime environment, such as Node.js or in small embedded runtimes.
Implementations that use ECMAScript executed in a browser to implement the APIs defined in this document MUST implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [WEBIDL].
Implementations that use TypeScript or ECMAScript in a runtime to implement the APIs defined in this document MUST implement them in a manner consistent with the TypeScript Bindings defined in the TypeScript specification [TYPESCRIPT].
The generic WoT terminology is defined in [WOT-ARCHITECTURE]: Thing, Thing Description (in short TD), Partial TD, Web of Things (in short WoT), WoT Interface, Protocol Bindings, WoT Runtime, Consuming a Thing Description, TD Directory, Property, Action, Event, DataSchema, Form, SecurityScheme, NoSecurityScheme etc.
WoT Interaction is a synonym for Interaction Affordance. An Interaction Affordance (or shortly, affordance) is the term used in [WOT-TD] when referring to Thing capabilities, as explained in TD issue 282. However, this term is not well understood outside the TD semantic context. Hence for the sake of readability, this document will use the previous term WoT interaction or, simply, interaction instead.
WoT network interface synonym for WoT Interface.
JSON Schema is defined in these specifications.
Promise
,
Error,
JSON,
JSON.stringify,
JSON.parse,
internal method and
internal slot are defined in [ECMASCRIPT].
WebIDLtypedef object ThingDescription
;
Represents a Thing Description (TD) as defined in [WOT-TD]. It is expected to be a parsed JSON object that is validated using JSON Schema validation.
Fetching a TD given a URL should be done with an external method, such as the Fetch API or a HTTP client library, which offer already standardized options on specifying fetch details.
try {
let res = await fetch('https://tds.mythings.biz/sensor11');
// ... additional checks possible on res.headers
let td = await res.json();
let thing = await WOT.consume(td);
console.log("Thing name: " + thing.getThingDescription().title);
} catch (err) {
console.log("Fetching TD failed", err.message);
}
Note that the Web of Things (WoT) Thing Description 1.1 specification allows using a shortened Thing Description by the means of defaults and requiring clients to expand them with default values specified in the Web of Things (WoT) Thing Description 1.1 specification for the properties that are not explicitly defined in a given TD.
- For each item in the TD default values table from [WOT-TD], if the term is not defined in td, add the term definition with the default value specified in [WOT-TD].
The [WOT-TD]
specification defines how a TD should be validated. Therefore,
this API expects the ThingDescription
objects be validated before used as parameters. This
specification defines a basic TD validation as follows.
- If
JSON Schema validation fails on td, throw a
"
TypeError
" and stop.
Additional steps may be added to fill the default values of mandatory fields.
Defines the WoT API object as a singleton and contains the API methods, grouped by conformance classes.
WebIDL[SecureContext, Exposed=(Window,Worker)]
namespace WOT
{
// methods defined in UA conformance classes
};
WebIDLpartial namespace WOT
{
Promise<ConsumedThing
> consume
(ThingDescription
td);
};
Promise
that resolves with a
ConsumedThing
object that represents a client interface to operate with
the Thing.
The method MUST run the following
steps:
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - Let thing be a
new
ConsumedThing
object constructed from td. - Set up the 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.
Editor's note
Implementations encapsulate the complexity of how to use the Protocol Bindings for implementing WoT interactions. In the future elements of that could be standardized.
- Resolve promise with thing.
Note the difference between constructing
ConsumedThing
and using the consume()
method: the latter
also initializes the protocol bindings, whereas a simple
constructed object will not have WoT Interactions
initialized until they are invoked.
WebIDLtypedef object ExposedThingInit
;
partial namespace WOT
{
Promise<ExposedThing
> produce
(ExposedThingInit
init);
};
Promise
that resolves with an
ExposedThing
object that extends ConsumedThing
with a server interface, i.e. the ability to define request
handlers. The init
object is an instance of the ExposedThingInit
type. Specifically, an ExposedThingInit
value is a dictionary used for the initialization of an
ExposedThing
and it represents a Partial TD as described in
the [WOT-ARCHITECTURE].
As such, it has the same structure of a Thing Description
but it may omit some information. The method MUST run the following steps:
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - Let thing be a
new
ExposedThing
object constructed with init. - Resolve promise with thing.
- Run validate
an ExposedThingInit on init. If that fails,
throw
SyntaxError
and stop. - Let td be the result of running clone given init.
- For each scheme
in td.[
"securityDefinitions"
], make a request to the underlying platform to check if it is supported by at least one Protocol Binding. If not, then remove scheme from td. - If td.[
"security"
] does not exist in td.["securityDefinitions"
], then removesecurity
from td. - For each affordance in td.properties, td.actions and td.events, run the following
sub-steps:
- For each form in
affordance.forms:
- If form.contentType is not recognized by the runtime as valid remove contentType from form.
- If form.href has an unknown schema, remove href from form.
- If form.href
is absolute and its
authority
it is not recognized by the runtime as valid, remove href from form. - If form.href is already in use by other ExposedThings, remove href from form.
- For each form in
affordance.forms:
- Search for missing required properties in
td accordingly to
TD JSON Schema.
Editor's note
The editors find this step vague. It will be improved or removed in the next iteration.
- For each missing property run these
sub-steps:
- If missing is
title
generate a runtime unique name and assign totitle
. - If missing is
@context
assign the latest supported Thing Description context URI. - If missing is
instance
assign the string1.0.0
. - If missing is
forms
generate a list of Forms using the available Protocol Bindings and content types encoders. Then assign the obtained list toforms
. - If missing is
security
assign the label of the first supported SecurityScheme insecurityDefinitions
field. If no SecurityScheme is found generate a NoSecurityScheme callednosec
and assign the stringnosec
tosecurity
.Issue 1The discussion about how to properly generate a value for
security
is still open. See issue #299 - If missing is
href
define formStub as the partial Form that does not havehref
. Generate a valid url using the first Protocol Binding that satisfy the requirements of formStub. Assign url tohref
. If not Protocol Binding can be found remove formStub from td. - Add missing to td with value as value
- If missing is
- Run validate a TD on td. If that fails re-throw the error and stop
- Return td
- Parse TD JSON Schema and load it in object called exposedThingInitSchema
- let optional be a list
containing the following strings:
title
,@context
,instance
,forms
,security
, andhref
. - For each property and sub-property key in
exposedThingInitSchema
equals to
required
execute the following steps:- if key value is an
Array
then remove all its elements equal to the elements in optional - if key value is a
string
then if value is equal to one of the elements in optional remove key from exposedThingInitSchema
- if key value is an
- Return the result of validating
an object with JSON Schema given init and exposedThingInitSchema.
Editor's note
The validating an object with JSON Schema steps are still under discussion. Currently this specification reference to the validation process of JSONSchema. Please follow this document when validating init with exposedThingInitSchema. Notice that the working group is evaluating an alternative formal approach.
WebIDLpartial namespace WOT
{
Promise<ThingDiscoveryProcess
> discover
(optional ThingFilter
filter = {});
};
ThingDescription
objects for Thing Descriptions
that match an optional filter argument of type
ThingFilter
.
The method MUST run the following
steps:
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - If discovery is not supported by the implementation,
reject
promise with
NotSupportedError
and stop. - Let discovery be a new
ThingDiscoveryProcess
object. - Set discovery.
[[filter]]
to filter. - Set discovery.
[[url]]
toundefined
. - If filters in general are not supported by the
implementation and filter is not
undefined
ornull
, reject promise withNotSupportedError
and stop. - If discovery cannot be started by the underlying
platform, reject
promise with
OperationError
and stop. - Request the underlying platform to start the discovery process by any means supported and provisioned in the WoT Runtime for which the script has access to, passing discovery to it.
- Resolve promise with discovery.
WebIDLpartial namespace WOT
{
Promise<ThingDiscoveryProcess
> exploreDirectory
(USVString url,
optional ThingFilter
filter = {});
};
ThingDescription
objects for Thing Descriptions
that match an optional filter argument of type
ThingFilter
.
The method MUST run the following
steps:
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - If directory discovery is not supported by the
implementation, reject
promise with
NotSupportedError
and stop. - Let discovery be a new
ThingDiscoveryProcess
object. - Set discovery.
[[url]]
to url. - Set discovery.
[[filter]]
to filter. - Request the underlying platform to start the
directory discovery process.
Note
This is a placeholder for more details in the discovery algorithm. Implementations should follow the procedures described in the [WOT-DISCOVERY] and [WOT-PROTOCOL-BINDINGS] specifications. Some normative steps are indicated below.
- If url is not a
TD Directory or if the underlying
implementation cannot support the Protocol
Binding indicated by url, reject
promise with
NotSupportedError
and terminate these steps. - If filters in general are not supported by the
implementation and filter is not
undefined
ornull
, reject promise withNotSupportedError
and stop. - Run the discovery
process given discovery.
Note
From this point on, errors are recorded only on
error
, but don't affect promise any longer.
- If url is not a
TD Directory or if the underlying
implementation cannot support the Protocol
Binding indicated by url, reject
promise with
- Resolve promise with discovery.
WebIDLpartial namespace WOT
{
Promise<ThingDescription
> requestThingDescription
(USVString url);
};
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - If fetching a Thing
Description is not supported by the implementation,
reject
promise with
NotSupportedError
and stop. - Let td be the
result of making a request to the underlying platform to
retrieve the Thing Description
using the Protocol Binding
specified by url. If retrieving
td fails,
reject
promise with
NotFoundError
and stop. - Resolve promise with td.
As specified in the
Web of Things (WoT) Thing Description 1.1
specification, WoT interactions extend
DataSchema and include
a number of possible Forms, out of
which one is selected for the interaction. The
Form contains a contentType
to describe the
data. For certain content types, a DataSchema is defined, based on
JSON Schema, making
possible to represent these contents as JavaScript types and
eventually set range constraints on the data.
WebIDLtypedef any DataSchemaValue
;
typedef (ReadableStream or DataSchemaValue
) InteractionInput
;
Belongs to the WoT Consumer conformance class and represents the WoT Interaction data provided by application scripts to the UA.
DataSchemaValue
is an
ECMAScript value that is accepted for DataSchema defined in
[WoT-TD].
The possible values MUST be of type
null,
boolean,
number,
string, array,
or object.
ReadableStream
is meant to be used for WoT Interactions that
don't have a DataSchema in the Thing
Description, only a Form
's
contentType
that can be represented by a
stream.
In practice, any
ECMAScript value may be used for WoT
Interactions that have a DataSchema defined in the
Thing Description, or
which can be mapped by implementations to the
Form
's
contentType
defined in the Thing
Description.
The algorithms in this document specify how exactly input data is used in WoT Interactions.
Belongs to the WoT Consumer conformance
class. An InteractionOutput
object is always created by the implementations and exposes
the data returned from WoT Interactions to
application scripts.
This interface exposes a convenience function which should
cover the vast majority of IoT use cases: the value() function. Its
implementation will inspect the data, parse it if adheres to
a DataSchema, or otherwise fail
early, leaving the underlying stream undisturbed so that
application scripts could attempt reading the stream
themselves, or handling the data as ArrayBuffer
.
WebIDL[SecureContext, Exposed=(Window,Worker)]
interface InteractionOutput
{
readonly attribute ReadableStream? data
;
readonly attribute boolean dataUsed
;
readonly attribute Form? form
;
readonly attribute DataSchema? schema
;
Promise<ArrayBuffer> arrayBuffer
();
Promise<DataSchemaValue
> value
();
};
The data
property represents the raw
payload in WoT
Interactions as a ReadableStream
,
initially null
.
The dataUsed
property tells whether
the data stream has been
disturbed. Initially false
.
The form
attribute
represents the Form
selected from the Thing Description for
this WoT
Interaction, initially null
.
The schema
attribute represents the
DataSchema (defined
in [WoT-TD])
of the payload as a JSON
object, initially null
.
The [[value]] internal slot represents the parsed
value of the WoT Interaction,
initially undefined
(note that null
is a valid value).
contentType
of the interaction
Form. The method
MUST run the following steps:
- Return a
promise and execute the next steps in parallel.Promise
- If this.[[value]] is not
undefined
, resolve promise with that value and stop. - If this.data is not a
ReadableStream
or if dataUsed istrue
, or if form is not anobject
or if schema or its type arenull
orundefined
, then reject promise withNotReadableError
and stop. - If form.contentType is not
application/json
and if a mapping is not available in the Protocol Bindings from form.contentType to [JSON-SCHEMA], reject promise withNotSupportedError
and stop. - Let reader be the result of getting a reader from data. If that threw an exception, reject promise with that exception and stop.
- Let bytes be the result of reading all bytes from data with reader.
- Set dataUsed to
true
. - If form.contentType is not
application/json
and if a mapping is available in the Protocol Bindings from form.contentType to [JSON-SCHEMA], transform bytes with that mapping. - Let json be the result of running parse JSON from bytes on bytes. If that throws, reject promise with that exception and stop.
- Set [[value]] to the result of running check data schema on json and schema. If that throws, reject promise with that exception and stop.
- Resolve promise with [[value]].
- Return a
promise and execute the next steps in parallel.Promise
- If data is not
ReadableStream
or if dataUsed istrue
, reject promise withNotReadableError
and stop. - Let reader be the result of getting a reader from data. If that threw an exception, reject promise with that exception and stop.
- Let bytes be the result of reading all bytes from data with reader.
- Set dataUsed to
true
. - Let arrayBuffer be a new
ArrayBuffer
whose contents are bytes. If that throws, reject promise with that exception and stop. - Resolve promise with arrayBuffer.
- Let type be schema.type.
- If type is
"null"
and if payload is notnull
, throwTypeError
and stop, otherwise returnnull
. - If type is
"boolean"
and payload is a falsy value or its byte length is 0, returnfalse
, otherwise returntrue
. - If type is
"integer"
or"number"
,- If payload is not a number, throw
TypeError
and stop. - If form.minimum is defined
and payload is smaller, or if
form.maximum is defined and
payload is bigger, throw a
RangeError
and stop.
- If payload is not a number, throw
- If type is
"string"
, return payload. - If type is
"array"
, run these sub-steps:- If payload is not an array, throw
TypeError
and stop. - If form.minItems is defined
and payload.length is less than
that, or if form.maxItems is
defined and payload.length is
more than that, throw
RangeError
and stop. - Let payload be an array of items obtained by running the check data schema steps on each element item of payload and schema.items. If this throws at any stage, re-throw that exception and stop.
- If payload is not an array, throw
- If type is
"object"
, run these sub-steps:- If payload or
schema.properties is not an
object
, throwTypeError
and stop. - For each key in payload:
- Let prop be payload[key].
- Let propSchema be interaction.properties[key].
- Let prop be the result of running the check data schema steps on prop and propSchema. If this throws, re-throw that exception and stop.
- Let required be schema.required if that is an array or an empty array otherwise.
- For each key in required,
if key is not present in
payload, throw
SyntaxError
and stop.
- If payload or
schema.properties is not an
- Return payload.
ConsumedThing
object thing, in order
to create
interaction request given a source, form and schema,
run these steps:
- Let idata be a new an
InteractionOutput
object. - Set idata.form
to form, set
idata.schema to
schema, set
|idata.data to
null
and set idata.[[value]]
toundefined
. - If source is
a
ReadableStream
object, let idata.data be source, return idata and stop. - If schema and its
type are defined and not
null
, run these sub-steps:- If type is
"null"
and source is not"null"
, throwTypeError
and stop. - If type is
"boolean"
and source is a falsy value, set idata.[[value]]
tofalse
, otherwise set it totrue
. - If type is
"integer"
or"number"
and source is not a number, or if form.minimum is defined and source is smaller, or if form.maximum is defined and source is bigger, throwRangeError
and stop. - If type is
"string"
and source is not a string, let idata.[[value]]
be the result of running serialize JSON to bytes given source. If that is failure, throwSyntaxError
and stop. - If type is
"array"
, run these sub-steps:- If source is not an array,
throw a
TypeError
and stop. - Let length be the length of source.
- If form.minItems is defined
and length is less than that, or if
form.maxItems is defined
and length is more than that, throw
RangeError
and stop. - For each item in source, let itemschema be schema.items and let item be the result of running the create interaction request steps given item, form and itemschema. If this throws, re-throw that exception and stop.
- Set data.
[[value]]
to source.
- If source is not an array,
throw a
- If type is
"object"
, run these sub-steps:- If source is not an object,
throw
TypeError
and stop. - If schema.properties is
not an object, throw
TypeError
and stop. - For each key in source,
- Let value be source[key].
- Let propschema be properties.interactions[key].
- Let value be the result of running the create interaction request steps on value, form and propschema. If this throws, re-throw that exception and stop.
- If schema.required is an
array, for each item in
required check if item is a
property name in source. If an
item is not found in source, throw
SyntaxError
and stop. - Set data.
[[value]]
to source.
- If source is not an object,
throw
- If type is
- Set idata.data to a new
ReadableStream
created from idata.[[value]]
internal slot as its underlying source. - Return idata.
ConsumedThing
object thing, in order
to parse
interaction response given response,
form and schema, run these steps:
- Let result be a new
InteractionOutput
object. - Let result.schema be schema.
- Let result.form be form.
- Let result.data be a new
ReadableStream
with the payload data of response as its underlying source. - Let result.dataUsed be
false
. - Return result.
7.3 Using InteractionInput
and InteractionOutput
As illustrated in the next pictures, the
InteractionOutput
interface is used every time implementations provide data to
scripts, while InteractionInput
is used when the scripts pass data to the implementation.

When a ConsumedThing
reads data, it receives it from the implementation as an
InteractionOutput
object.
An ExposedThing
read handler
provides the read data to the implementation as
InteractionInput
.

When a ConsumedThing
writes data, it provides it to the implementation as
InteractionInput
.
An ExposedThing
write
handler receives data from to implementation as an
InteractionOutput
object.

When a ConsumedThing
invokes an Action,
it provides the parameters as InteractionInput
and receives the output of the Action as an InteractionOutput
object.
An ExposedThing
action handler
receives arguments from the implementation as an
InteractionOutput
object and provides Action output as
InteractionInput
to the implementation.
The algorithms in this API define the errors to be reported to application scripts.
The errors reported to the other communication end are mapped and encapsulated by the Protocol Bindings.

This topic is still being discussed in Issue #200. A standardized error mapping would be needed in order to ensure consistency in mapping script errors to protocol errors and vice versa. In particular, when algorithms say "error received from the Protocol Bindings", that will be factored out as an explicit error mapping algorithm. Currently, that is encapsulated by implementations.
Represents a client API to operate a Thing. Belongs to the WoT Consumer conformance class.
WebIDL[SecureContext, Exposed=(Window,Worker)]
interface ConsumedThing
{
constructor
(ThingDescription
td);
Promise<InteractionOutput
> readProperty
(DOMString propertyName,
optional InteractionOptions
options = {});
Promise<PropertyReadMap
> readAllProperties
(
optional InteractionOptions
options = {});
Promise<PropertyReadMap
> readMultipleProperties
(
sequence<DOMString> propertyNames,
optional InteractionOptions
options = {});
Promise<undefined> writeProperty
(DOMString propertyName,
InteractionInput
value,
optional InteractionOptions
options = {});
Promise<undefined> writeMultipleProperties
(
PropertyWriteMap
valueMap,
optional InteractionOptions
options = {});
/*Promise<undefined> writeAllProperties(
PropertyWriteMap valueMap,
optional InteractionOptions options = {});*/
Promise<InteractionOutput
> invokeAction
(DOMString actionName,
optional InteractionInput
params = {},
optional InteractionOptions
options = {});
Promise<Subscription
> observeProperty
(DOMString name,
InteractionListener
listener,
optional ErrorListener
onerror,
optional InteractionOptions
options = {});
Promise<Subscription
> subscribeEvent
(DOMString name,
InteractionListener
listener,
optional ErrorListener
onerror,
optional InteractionOptions
options = {});
ThingDescription
getThingDescription
();
};
dictionary InteractionOptions
{
unsigned long formIndex
;
object uriVariables
;
any data
;
};
[SecureContext, Exposed=(Window,Worker)]
interface Subscription
{
readonly attribute boolean active
;
Promise<undefined> stop
(optional InteractionOptions
options = {});
};
[SecureContext, Exposed=(Window,Worker)]
interface PropertyReadMap
{
readonly maplike<DOMString, InteractionOutput
>;
};
[SecureContext, Exposed=(Window,Worker)]
interface PropertyWriteMap
{
readonly maplike<DOMString, InteractionInput
>;
};
callback InteractionListener
= undefined(InteractionOutput
data);
callback ErrorListener
= undefined(Error error);
The writeAllProperties()
method is
still under discussion. Meanwhile, use the
writeMultipleProperties()
method instead.
8.1 Internal slots for ConsumedThing
A ConsumedThing
object has the following
internal slots:
Internal Slot | Initial value | Description (non-normative) |
---|---|---|
[[td]] | null |
The Thing
Description of the ConsumedThing .
|
[[activeSubscriptions]] | {} |
An ordered
map keyed on
a string
name representing the Event and
value is a
Subscription
object.
|
[[activeObservations]] | {} |
An ordered
map keyed on
a string
name representing a Property and
value is a
Subscription
object.
|
After fetching
a Thing Description as
a JSON object, one can create a ConsumedThing
object.
ConsumedThing
with the ThingDescription
td, run the
following steps:
- Run the validate a TD steps on
td. If that
fails, throw
SyntaxError
and stop. - Run the expand a TD steps on td. If that fails, re-throw the error and stop.
- Let thing be a
new
ConsumedThing
object. - Set the
internal slot
[[td]]
of thing to td. - Return thing.
Returns the [[td]]
of the
ConsumedThing
object that represents the Thing Description of
the ConsumedThing
.
Applications may consult the Thing metadata stored in
[[td]]
in order to
introspect its capabilities before interacting with it.
Promise
that resolves with a
Property value represented
as an InteractionOutput
object or rejects on error. The method MUST run the following steps:
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - Let interaction be
[[td]]
.properties.propertyName. - If interaction is
undefined
, reject promise with aNotFoundError
and stop. - If option.formIndex is defined,
let form be the Form associated with
formIndex in
interaction.forms array, otherwise
let form be a Form in
interaction.forms whose
op is
readproperty
, selected by the implementation. - If form is failure, reject
promise with a
SyntaxError
and stop. - Make a request to the underlying platform (via the Protocol Bindings) to retrieve the value of the propertyName Property using form and the optional URI templates given in options.uriVariables.
- If the request fails, reject promise with the error received from the Protocol Bindings and stop.
- Let response be the response received to the request.
- Let data be the result of running
parse
interaction response on response,
form and interaction. If that
fails, reject
promise with a
SyntaxError
and stop. - Resolve promise with data.
Promise
that resolves with a
PropertyReadMap
object that maps keys from propertyNames to values returned by
this algorithm. The method MUST
run the following steps:
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - If option.formIndex is defined,
let form be the Form associated with
formIndex in the
[[td]]
.forms array, otherwise let form be the Form in[[td]]
.forms array whose op isreadmultipleproperties
, as selected by the implementation. - If form is failure, reject
promise with a
SyntaxError
and stop. - Let result be an object
and for each string name in
propertyNames add
a property with key name
and the value
null
. - Make a request to the underlying platform (via the Protocol Bindings) to retrieve the Property values given by propertyNames with form and optional URI templates given in options' uriVariables.
- If this cannot be done with a single request with the
Protocol Bindings,
reject
promise with a
NotSupportedError
and stop. - Process the response and for each key in
result, run the following
sub-steps:
- Let value be result[key].
- Let schema be
this.
[[td]]
.properties[key]. - Let property be the result of running parse interaction response on value, form and schema.
- If the above step throws at any point, reject promise with that exception and stop.
- Resolve promise with result.
Promise
that resolves with a
PropertyReadMap
object that maps keys from Property names to values
returned by this algorithm. The method MUST run the following steps:
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - Let forms be
subscription.
[[interaction]]
.forms. - If forms is
undefined
, reject promise with aSyntaxError
and stop. - If option.formIndex is not
undefined
and is less than forms.length, set subscription.[[form]]
to forms.[formIndex]. - Otherwise, set
subscription.
[[form]]
to a Form in forms whose op is"readallproperties"
, as selected by the implementation. - If subscription.
[[form]]
is failure, reject promise with aSyntaxError
and stop. - Make a request to the underlying platform using the Protocol Bindings to retrieve all the Property definitions from the TD given form and optional URI templates in options.uriVariables.
- If this cannot be done with a single request with the
Protocol Bindings
of the Thing, then
reject
promise with a
NotSupportedError
and stop. - If the request fails, reject promise with the error received from the Protocol Bindings and stop.
- Process the reply and let result be an object with the keys and values obtained in the reply.
- Process the response and for each key in
result, run the following
sub-steps:
- Let value be result[key].
- Let schema be
this.
[[td]]
.properties[key]. - Let property be the result of running parse interaction response on value, form and schema.
- Resolve promise with result.
Promise
that resolves on success
and rejects on failure. The method MUST run the following steps:
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - Let interaction be
this.
[[td]]
.properties[propertyName]. - If interaction is
undefined
, reject promise with aNotFoundError
and stop. - If option.formIndex is not
undefined
, let form be the Form associated with formIndex in the interaction.forms array, otherwise let form be a Form in interaction.forms whose op iswriteproperty
, as selected by the implementation. - If form is failure, reject
promise with a
SyntaxError
and stop. - Let data be the result of running the
create
interaction request steps given value, form and
interaction. If that throws, reject
promise
with that exception and stop. - Make a request to the underlying platform (via the Protocol Bindings) to write the Property given by propertyName using data and the optional URI templates given in options' uriVariables.
- If the request fails, reject promise with the error received from the Protocol Bindings and stop.
- Otherwise resolve promise.
As discussed in Issue #193, the design decision is that write interactions only return success or error, not the written value (optionally). TDs should capture the schema of the Property values, including precision and alternative formats. When a return value is expected from the interaction, an Action should be used instead of a Property.
Promise
that resolves on success
and rejects on failure. The method MUST run the following steps:
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - If option.formIndex is defined,
let form be the Form associated with
formIndex in the
[[td]]
.forms array, otherwise let form be a Form in[[td]]
.forms array whose op iswritemultipleproperties
, as selected by the implementation. - If form is failure, reject
promise with a
SyntaxError
and stop. - Let propertyNames be an array of string with as elements the keys of the properties object.
- For each name in
propertyNames, let property be
this.
[[td]]
.properties[name]. - If property is
null
orundefined
or is notwriteable
reject promise withNotSupportedError
and stop. - Let result be an object
and for each string name in
propertyNames add a property with key
name and let its value be
null
. - Let schemas be an
object and for each name in
propertyNames add a property with key
name and let its value be
this.
[[td]]
.properties[name]. - For each key key in
properties, run the
create
interaction request steps given properties[key], form and the value for
schema[key].
If that throws for any name, reject
promise
with that exception and stop. - Make a single request to the underlying platform (via the Protocol Bindings) to write each Property provided in properties with optional URI templates given in options' uriVariables.
- If this cannot be done with a single request with the
Protocol Bindings
of the Thing, then
reject
promise with a
NotSupportedError
and stop. - If the request fails, return the error received from the Protocol Bindings and stop.
- Otherwise resolve promise.
Promise
that resolves on success
and rejects on failure.
This algorithm allows for only one active
Subscription
per Property. If a new
Subscription
is made while an existing Subscription
is active the runtime will throw an NotAllowedError
.
- Let thing be the reference of this
ConsumedThing
object. - Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - If listener is not a
Function
, reject promise with aTypeError
and stop. - If onerror is
not
null
and is not aFunction
, reject promise with aTypeError
and stop. - If thing.
[[activeObservations]]
[propertyName] [=map/exists], reject promise with aNotAllowedError
and stop. - Let subscription be a new
Subscription
object with its internal slots set as follows:- Let subscription.
[[type]]
be"property"
. - Let subscription.
[[name]]
be propertyName. - Let subscription.
[[interaction]]
be[[td]]
.properties[propertyName]. - Let subscription.
[[thing]]
be thing. - Let forms be
subscription.
[[interaction]]
.forms. - If forms is
undefined
, reject promise with aSyntaxError
and stop. - If option.formIndex is not
undefined
and is less than forms.length, set subscription.[[form]]
to forms.[formIndex]. - Otherwise, set
subscription.
[[form]]
to a Form in forms whose op is"observeproperty"
, as selected by the implementation. - If subscription.
[[form]]
is failure, reject promise with aSyntaxError
and stop. - If subscription.
[[interaction]]
isundefined
, reject promise with aNotFoundError
and stop.
- Let subscription.
- Make a request to the underlying platform to observe the Property identified by propertyName with form and optional URI templates given in options' uriVariables.
- If the request fails, reject promise with the error received from the Protocol Bindings and stop.
-
Set
thing.
[[activeObservations]]
[|propertyName] to subscription and resolve promise. - Whenever the underlying platform detects a
notification for this subscription
keyed
on propertyName with a
new Property value
value, run the following sub-steps:
- Let reply be the result of running
parse
interaction response with value,
subscription.
[[form]]
and subscription.[[interaction]]
. If that throws, reject promise with that exception and stop. - Invoke listener given reply.
- Let reply be the result of running
parse
interaction response with value,
subscription.
- Whenever the underlying platform detects an error for
this subscription, run the following sub-steps:
- If the error is irrecoverable and stops the
subscription, set
subscription.active to
false
and suppress further notifications. - Let error be a new
NetworkError
and set its message to reflect the underlying error condition. - If onerror
is a
Function
, invoke it given error.
- If the error is irrecoverable and stops the
subscription, set
subscription.active to
Promise
that resolves with the
result of the Action
represented as an InteractionOutput
object, or rejects with an error. The method MUST run the following steps:
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - Let interaction be
this.
[[td]]
.actions[actionName]. - If interaction is not an
object
, reject promise with aNotFoundError
and stop. - Let forms be
subscription.
[[interaction]]
.forms. - If forms is
undefined
, reject promise with aSyntaxError
and stop. - If option.formIndex is not
undefined
and is less than forms.length, set subscription.[[form]]
to forms.[formIndex]. - Otherwise, set
subscription.
[[form]]
to a Form in forms whose op is"invokeaction"
, as selected by the implementation. - If subscription.
[[form]]
is failure, reject promise with aSyntaxError
and stop. - Let args be the result of running the
create
interaction request steps on params, form and
interaction. If that throws,
reject
promise
with that exception and stop. - Make a request to the underlying platform (via the Protocol Bindings) to invoke the Action identified by actionName given args and options.uriVariables.
- If the request fails locally or returns an error over the network, reject promise with the error received from the Protocol Bindings and stop.
- Let value be the reply returned in the reply.
- Let result be the result of running parse interaction response with value, form and interaction. If that throws, reject promise with that exception and stop.
- Resolve promise with result.
Promise
to signal success or
failure.
This algorithm allows for only one active
Subscription
per Event. If a new
Subscription
is made while an existing Subscription
is active the runtime will throw an NotAllowedError
.
- Let thing be the reference of this
ConsumedThing
object. - Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - If listener is not
a
Function
, reject promise with aTypeError
and stop. - If onerror is
not
null
and is not aFunction
, reject promise with aTypeError
and stop. - If thing.
[[activeSubscriptions]]
[eventName] does not exist, reject promise with aNotAllowedError
and stop. - Let subscription be a new
Subscription
object with its internal slots set as follows:- Let subscription.
[[type]]
be"event"
. - Let subscription.
[[name]]
be eventName. - Let subscription.
[[interaction]]
be thing.[[td]]
.events[eventName]. - If subscription.
[[interaction]]
isundefined
, reject promise with aNotFoundError
and stop. - Let subscription.
[[thing]]
be thing. - If options.formIndex
exists,
then let subscription.
[[form]]
be thing.[[interaction]]
.forms[formIndex]. - Otherwise, let
subscription.
[[form]]
be an implementation-defined Form from the subscription.[[interaction]]
.forms array whose op is"subscribeevent"
. - If subscription.
[[form]]
does not exist, reject promise with aSyntaxError
and stop.
- Let subscription.
- Make a request to the underlying platform via the
Protocol Bindings
to subscribe to the Event identified by
eventName with
[[form]]
, optional URI templates given in options.uriVariables and optional subscription data given in options.data. - If the request fails, reject promise with the error received from the Protocol Bindings and stop.
-
Set
eventName to
thing.
[[activeSubscriptions]]
[eventName] to subscription. - Resolve promise.
- Whenever the underlying platform detects a
notification for the Event subscription
keyed
on eventName, run the
following sub-steps:
- Invoke listener given the result of
running parse
interaction response on the data provided with
the Event,
subscription.
[[form]]
and subscription.[[interaction]]
.
- Invoke listener given the result of
running parse
interaction response on the data provided with
the Event,
subscription.
- Whenever the underlying platform detects an error for
Event
subscription keyed on
eventName, run the
following sub-steps:
- If the error is irrecoverable and stops the
subscription, set
subscription.active to
false
and suppress further notifications. - Let error be a new
NetworkError
and set its message to reflect the underlying error condition. - If onerror
is a
Function
, invoke it given error.
- If the error is irrecoverable and stops the
subscription, set
subscription.active to
Holds the interaction options that need to be exposed for application scripts according to the Thing Description.
The formIndex
property, if defined,
represents an application hint for which Form
definition, identified by this index, of the TD to use for the given WoT
interaction. Implementations SHOULD
use the Form
with this index for making the
interaction, but MAY override this
value if the index is not found or not valid. If not defined,
implementations SHOULD attempt to
use the Form
definitions in order of appearance
as listed in the TD for the
given Wot Interaction.
The uriVariables
property if defined,
represents the URI template variables to be used with the WoT
Interaction that are represented as
parsed JSON objects defined in [WOT-TD].
The support for URI variables comes from the need, exposed by the Web of Things (WoT) Thing Description 1.1 specification, to be able to describe existing RESTful endpoints that use them. However, it should be possible to write a Thing Description that would use Actions for representing this kind of interactions and model the URI variables as action parameters. In that case, implementations can serialize the parameters as URI variables, and therefore, the options parameter could be dismissed.
The data
property if defined, represents additional opaque data that
needs to be passed to the interaction.
Represents a map of Property names to an InteractionOutput
object that represents the value the Property can take. It is
used as a property bag for interactions that involve multiple
Properties at
once.
Represents a map of Property names to an InteractionInput
that represents the value the Property can take. It is used
as a property bag for interactions that involve multiple
Properties at
once.
User provided callback that is given an argument of type
InteractionOutput
and is used for observing Property changes and handling
Event notifications.
Since subscribing to Events are WoT interactions and
might take options or even data, they are not modelled with
software events.
User provided callback that is given an argument of type
Error
and is used for conveying critical and non-critical errors
from the Protocol Bindings to
applications.
Represents a subscription to Property change and Event interactions.
The active
boolean property denotes if the subscription is active, i.e.
it is not stopped because of an error or because of
invocation of the stop()
method.
8.17.1 Internal slots for
Subscription
Subscription
object has the following
internal slots:
Internal Slot | Initial value | Description (non-normative) |
---|---|---|
[[type]] | null |
Indicates what WoT
Interaction the Subscription
refers to. The value can be either
"property" or "event" or
null .
|
[[name]] | null |
The Property or Event name. |
[[interaction]] | null |
The Thing Description fragment that describes the WoT interaction. |
[[form]] | null |
The Form associated with the subscription. |
[[thing]] | null |
The ConsumedThing
associated with the subscription.
|
Stops delivering notifications for the subscription. It
takes an optional parameter options and returns a
. When invoked, the method
MUST execute the following
steps:Promise
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - If options'
formIndex is defined, let
unsubscribeForm be the Form associated with
formIndex in
[[interaction]]
's forms array. - Otherwise let unsubscribeForm be the
result of running the find a
matching unsubscribe form algorithm given
[[form]]
. - If unsubscribeForm is failure,
reject
promise with a
SyntaxError
and stop. - If
[[type]]
is"property"
, make a request to the underlying platform via the Protocol Bindings to stop observing the Property identified by[[name]]
with unsubscribeForm and optional URI templates given in options' uriVariables. - Otherwise, if
[[type]]
is"event"
, make a request to the underlying platform via the Protocol Bindings to unsubscribe from the Event identified by[[name]]
with unsubscribeForm, with optional URI templates given in options' uriVariables and optional unsubscribe data given in options.data. - If the request fails, reject promise with the error received from the Protocol Bindings and stop.
- Otherwise:
- set active to
false
. - if
[[type]]
is"event"
, remove[[name]]
from[[thing]]
.[[activeSubscriptions]]
. - if
[[type]]
is"property"
, remove[[name]]
from[[thing]]
.[[activeObservations]]
. - Resolve promise.
- set active to
- If the underlying platform receives further notifications for this subscription, implementations SHOULD silently suppress them.
8.17.3 Finding an unsubscribe Form
This algorithm is under development and is
non-normative. Implementations MAY choose another algorithm to find a
matching unsubscribe
Form to a given
subscribe
Form.
Subscription
object, run the following steps:
- Let results be an empty array.
- For each form in
[[interaction]]
.forms,- Add an
internal slot [[matchLevel]] on form
and set its value to
0
. - If form.op is
"unobserveproperty"
if[[type]]
is"property"
or if form.op is"unsubscribeevent"
if[[type]]
is"event"
,- Set the internal slot [[matchLevel]] on form to 1 and add form to results.
- If form.href and [[subscribeForm]].href are same origin-domain, increment form.[[matchLevel]].
- If form.contentType is equal to [[subscribeForm]]'s contentType and form.[[matchLevel]] is greater than 2, increment form.[[matchLevel]].
- Add an
internal slot [[matchLevel]] on form
and set its value to
- If results is empty, return
null
and terminate these steps. - Return the first form in results that has the highest [[matchLevel]] value.
The next example illustrates how to fetch a TD by URL, create a
ConsumedThing
,
read metadata (title), read property value, subscribe to
property change, subscribe to a WoT event, unsubscribe.
try {
let res = await fetch("https://tds.mythings.org/sensor11");
let td = res.json();
let thing = new ConsumedThing(td);
console.log("Thing " + thing.getThingDescription().title + " consumed.");
} catch (e) {
console.log("TD fetch error: " + e.message);
};
try {
// subscribe to property change for “temperature”
await thing.observeProperty("temperature", async (data) => {
try {
console.log("Temperature changed to: " + await data.value());
} catch (error) {
console.error("Cannot read the observed property temperature");
console.error(error);
}
});
// subscribe to the “ready” event defined in the TD
await thing.subscribeEvent("ready", async (eventData) => {
try {
console.log("Ready; index: " + await eventData.value());
// run the “startMeasurement” action defined by TD
await thing.invokeAction("startMeasurement", { units: "Celsius" });
console.log("Measurement started.");
} catch (error) {
console.error("Cannot read the ready event or startMeasurement failed");
console.error(error)
}
});
} catch (e) {
console.log("Error starting measurement.");
}
setTimeout(async () => {
try {
const temperatureData = await thing.readProperty("temperature")
const temperature = await temperatureData.value();
console.log("Temperature: " + temperature);
await thing.unsubscribe("ready");
console.log("Unsubscribed from the ‘ready’ event.");
} catch (error) {
console.log("Error in the cleanup function");
}
}, 10000);
The following shows an advance usage of InteractionOutput
to read a property without a DataSchema
.
/*
* takePicture affordance form:
* "form": {
* "op": "invokeaction",
* "href" : "https://camera.example.com:5683/takePicture",
* "response": {
* "contentType": "image/jpeg",
* "contentCoding": "gzip"
* }
*}
* See https://www.w3.org/TR/wot-thing-description/#example-23
*/
let response;
let image;
try {
response = await thing.invokeAction(“takePicture”));
image = await response.value() // throws NotReadableError --> schema not defined
} catch(ex) {
image = await response.arrayBuffer();
// image: ArrayBuffer [0x1 0x2 0x3 0x5 0x15 0x23 ...]
}
Finally, the next two examples shows the usage of a
ReadableStream
from an InteractionOutput
.
/*{
"video": {
"description" : "the video stream of this camera",
"forms": [
{
"op": "readproperty",
"href": "https://camera.example.com/live",
"subprotocol": "hls"
"contentType": "video/mp4"
}
]
}}*/
const video = await thing.readProperty("video")
const reader = video.data.getReader()
reader.read().then(function processVideo({ done, value }) {
if (done) {
console.log("live video stoped");
return;
}
const decoded = decode(value)
UI.show(decoded)
// Read some more, and call this function again
return reader.read().then(processText);
});
Here consider that the JSON object is too big to be read wholly in the memory. Therefore, we use streaming processing to get the total number of the events recorded by the remote Web Thing.
/*
* "eventHistory":
* {
* "description" : "A long list of the events recorded by this thing",
* "type": "array",
* "forms": [
* {
* "op": "readproperty",
* "href": "https://recorder.example.com/eventHistory",
* }
* ]
* }
*/
// Example of streaming processing: counting json objects
let objectCounter = 0
const parser = new Parser() //User library for json streaming parsing (i.e. https://github.com/uhop/stream-json/wiki/Parser)
parser.on('data', data => data.name === 'startObject' && ++objectCounter);
parser.on('end', () => console.log(`Found ${objectCounter} objects.`));
const response = await thing.readProperty(“eventHistory”)
await response.data.pipeTo(parser);
// Found N objects
The ExposedThing
interface is the server API to operate the Thing that allows defining request
handlers, Property, Action, and Event interactions.
WebIDL[SecureContext, Exposed=(Window,Worker)]
interface ExposedThing
{
ExposedThing
setPropertyReadHandler
(DOMString name,
PropertyReadHandler
handler);
ExposedThing
setPropertyWriteHandler
(DOMString name,
PropertyWriteHandler
handler);
ExposedThing
setPropertyObserveHandler
(DOMString name,
PropertyReadHandler
handler);
ExposedThing
setPropertyUnobserveHandler
(DOMString name,
PropertyReadHandler
handler);
Promise<undefined> emitPropertyChange
(DOMString name,
optional InteractionInput
data);
ExposedThing
setActionHandler
(DOMString name, ActionHandler
action);
ExposedThing
setEventSubscribeHandler
(DOMString name,
EventSubscriptionHandler
handler);
ExposedThing
setEventUnsubscribeHandler
(DOMString name,
EventSubscriptionHandler
handler);
Promise<undefined> emitEvent
(DOMString name,
optional InteractionInput
data);
Promise<undefined> expose
();
Promise<undefined> destroy
();
ThingDescription
getThingDescription
();
};
callback PropertyReadHandler
= Promise<InteractionInput
>(
optional InteractionOptions
options = {});
callback PropertyWriteHandler
= Promise<undefined>(
InteractionOutput
value,
optional InteractionOptions
options = {});
callback ActionHandler
= Promise<InteractionInput
>(
InteractionOutput
params,
optional InteractionOptions
options = {});
callback EventSubscriptionHandler
= Promise<undefined>(
optional InteractionOptions
options = {});
An ExposedThing
object has the following
internal slots:
Internal Slot | Initial value | Description (non-normative) |
---|---|---|
[[td]] | null |
The Thing
Description of the ExposedThing .
|
[[readHandlers]] | {} |
A
Map with property names as keys and
PropertyReadHandler s
as values
|
[[writeHandlers]] | {} |
A
Map with property names as keys and
PropertyWriteHandler s
as values
|
[[observeHandlers]] | {} |
A
Map with property names as keys and
PropertyReadHandler s
as values
|
[[unobserveHandlers]] | {} |
A
Map with property names as keys and
Function s
as values
|
[[actionHandlers]] | {} |
A
Map with action names as keys and
ActionHandler s
as values
|
[[subscribeHandlers]] | {} |
A
Map with event names as keys and
EventSubscriptionHandler s
as values
|
[[unsubscribeHandlers]] | {} |
A
Map with event names as keys and
EventSubscriptionHandler s
as values
|
[[propertyObservers]] | {} |
A
Map with property names as keys and
an
Array of listeners as values
|
[[eventListeners]] | {} |
A
Map with event names as keys and
Array of listeners as values
|
9.2 Constructing ExposedThing
The ExposedThing
interface extends ConsumedThing
.
It is constructed from a full or partial ThingDescription
object.
Note that an existing ThingDescription
object can be optionally modified (for instance by adding
or removing elements on its properties,
actions and events internal
properties) and the resulting object can used for
constructing an ExposedThing
object. This is the current way of adding and removing
Property, Action and Event definitions, as
illustrated in the examples.
Before invoking expose(), the
ExposedThing
object does not serve any requests. This allows first
constructing ExposedThing
and then initialize its Properties and service
handlers before starting serving requests.
ExposedThing
with the ExposedThingInit
init, run the
following steps:
- If invoking this method is not allowed for the
current scripting context for security reasons,
throw
a
SecurityError
and stop. - Run the expand an ExposedThingInit steps on init. if that fails re-throw the error and stop. Otherwise store the obtained td
- Run the expand a TD steps on td. If that fails, re-throw the error and stop.
- Let thing be a
new
ExposedThing
object. - Set the
[[td]]
of thing to td. - Return thing.
Returns the [[td]]
of the
ExposedThing
object that represents the Thing Description of
the Thing. Applications may
consult the Thing
metadata stored in [[td]]
in order to
introspect its capabilities before interacting with it.
A function that is called when an external request for
reading a Property is received and
defines what to do with such requests. It returns a
and resolves with an
Promise
ReadableStream
object or an
ECMAScript value conforming to DataSchema, or rejects with
an error.
Takes as arguments name and handler. Sets the service handler that defines what to do when a request is received for reading the specified Property matched by name. Throws on error. Returns a reference to this object for supporting chaining.
Note that there is no need to register handlers
for handling requests for reading multiple or all Properties. The request
and reply are transmitted in a single network request, but
the ExposedThing
may implement them using multiple calls to the single read
handler.
The handler callback function should implement reading a Property and SHOULD be called by implementations when a request for reading a Property is received from the underlying platform.
There MUST be at most one handler
for any given Property, so newly added
handlers MUST replace the previous
handlers. If no handler is initialized for any given Property, implementations
SHOULD implement a default property
read handler based on the Thing Description
provided in the [[td]]
internal slot.
- If invoking this method is not allowed for the
current scripting context for security reasons,
throw
a
SecurityError
and stop. - If
[[td]]
.properties[name] does not exist, throwNotFoundError
and stop. - Set this.
[[readHandlers]]
[name] to handler.
- If this operation is not supported, send back a
NotSupportedError
according to the Protocol Bindings and stop. - If this operation is not allowed, send back a
NotAllowedError
according to the Protocol Bindings and stop. - Let value be the result of running the
read server
property steps with name and options:
- Let interaction be
[[td]]
.properties.name. - If a Property with
name does not exist,
throw
NotFoundError
and stop. - Let handler be
null
. - If there is a user provided
PropertyReadHandler
in[[readHandlers]]
internal slot for interaction, let handler be that. - Otherwise, if there is a default read handler provided by the implementation, let handler be that.
- If handler is
null
, throwNotSupportedError
and stop. - Let value be the result of invoking handler given options. If that fails, throw the error and stop.
- Return value.
Note
The value returned here SHOULD either conform to DataSchema or it SHOULD be an
ReadableStream
object created by the handler.
- Let interaction be
- If the previous step has thrown an error, send the error back with the reply created by following the Protocol Bindings and stop.
- Serialize and add the returned value to the reply created by following the Protocol Bindings.
- If this operation is not supported, send back a
NotSupportedError
according to the Protocol Bindings and stop. - If this operation is not allowed, send back a
NotAllowedError
according to the Protocol Bindings and stop. - For each property with key name defined in
propertyNames,
- Let value be the result of running the read server property steps on name and options. If that throws, send back the error in the reply created by following the Protocol Bindings and stop.
- Set propertyNames.name to value.
- Reply to the request by sending a single reply created from propertyNames according to the Protocol Bindings.
- If this operation is not supported, send back a
NotSupportedError
according to the Protocol Bindings and stop. - If this operation is not allowed, send back a
NotAllowedError
according to the Protocol Bindings and stop. - Let properties be an object created with
all properties defined in the Thing with values set to
null
. - Run the read multiple properties steps on properties and options.
Takes as arguments name and handler. Sets the service handler that defines what to do when a request is received for observing the specified Property matched by name. Throws on error. Returns a reference to this object for supporting chaining.
The handler
callback function should implement reading a Property and
resolve with an
InteractionOutput
object or reject with
an error.
There MUST be at most one handler for any given Property, so newly added handlers MUST replace the previous handlers. If no handler is initialized for any given Property, implementations SHOULD implement a default property read handler based on the Thing Description.
- If invoking this method is not allowed for the
current scripting context for security reasons,
throw
a
SecurityError
and stop. - If this.
[[td]]
.properties[name] does not exist, throwNotFoundError
and stop. - Set this
[[observeHandlers]]
[name] to handler.
9.10 Handling Property observe requests
- If this operation is not supported, send back a
NotSupportedError
according to the Protocol Bindings and stop. - If this operation is not allowed, send back a
NotAllowedError
according to the Protocol Bindings and stop. - If this.
[[td]]
.properties[name] does not exist, send back aNotFoundError
in the reply and stop. - Internally save the request sender information
together with options and
this.
[[propertyObservers]]
[name], in order to be able to notify about Property value changes.
Every time the value of property
changes, emitPropertyChange()
needs to be explicitly called by the application
script.
Takes as arguments name and handler. Sets the service handler that defines what to do when a request is received for unobserving the specified Property matched by name. Throws on error. Returns a reference to this object for supporting chaining.
The handler callback function should implement what to do when an unobserve request is received by the implementation.
There MUST be at most one handler for any given Property, so newly added handlers MUST replace the previous handlers. If no handler is initialized for any given Property, implementations SHOULD implement a default handler based on the Thing Description.
- If invoking this method is not allowed for the
current scripting context for security reasons,
throw
a
SecurityError
and stop. - If this.
[[td]]
.properties[name] does not exist, throwNotFoundError
and stop. - Set this.
[[unobserveHandlers]]
[name] to handler.
9.12 Handling Property unobserve requests
- If this operation is not supported, send back a
NotSupportedError
according to the Protocol Bindings and stop. - If this operation is not allowed, send back a
NotAllowedError
according to the Protocol Bindings and stop. - If this.
[[td]]
.properties[name] does not exist, send back aNotFoundError
in the reply and stop. - Let handler be
this.
[[unobserveHandlers]]
[name]; - If handler is a
Function
, invoke that given options, then send back a reply following the Protocol Bindings and stop. - Otherwise, if this.
[[propertyObservers]]
[name] exists, remove it from this.[[propertyObservers]]
, send back a reply as defined in the Protocol Bindings and stop. - Otherwise, send back a
NotFoundError
in the reply as defined in the Protocol Bindings and stop.
- Let promise be a new
.Promise
- Return promise 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 a
SecurityError
and stop. - Let name be the first argument.
- Let property be
this.
[[td]]
.properties[name]. - If property is
undefined
, reject promise withNotFoundError
and stop. - Let data be the second argument.
- If data is
undefined
, run the following sub-steps:- Let handler be
null.
- If name does not
exist
in
[[readHandlers]]
, reject promise and stop. - Let handler be
[[readHandlers]]
[name]. - If handler is
null
orundefined
, reject promise and stop. - Let handled be the result of invoking
handler given
null
. - If handled is rejected, then reject promise and stop.
- Otherwise if handled resolved with value, let data be value.
- Let handler be
- For each observer in
[[propertyObservers]]
[name], run the following sub-steps:- Let options be the interaction options saved with observer.
- Request the underlying platform to create a
reply from data and
options according to the Protocol
Bindings.
Editor's note
This clause needs expanding and/or refer to an algorithm in [WOT-PROTOCOL-BINDINGS].
- Send reply to observer.
- Resolve promise.
A function that is called when an external request for
writing a Property is received and
defines what to do with such requests. Takes as argument
value and returns a
, resolved when the value of
the Property - identified by the
name provided when setting the handler has been updated -, or
rejects with an error if the property is not found or the
value cannot be updated.Promise
Note that the code in this callback function can read the property before updating it in order to find out the old value, if needed. Therefore the old value is not provided to this function.
The value is provided by implementations as an
InteractionOutput
object in order to be able to represent values that are not
described by a DataSchema, such as
streams.
Takes as arguments name and handler. Sets the service handler that defines what to do when a request is received for writing the Property matched by name given when setting the handler. Throws on error. Returns a reference to this object for supporting chaining.
Note that even for readonly Properties it is possible to specify a write handler, as explained in Issue 199. In this case, the write handler may define in an application-specific way to fail the request.
There MUST be at most one write handler for any given Property, so newly added handlers MUST replace the previous handlers. If no write handler is initialized for any given Property, implementations SHOULD implement default property update if the Property is writeable and notifying observers on change if the Property is observable, based on the Thing Description.
- If invoking this method is not allowed for the
current scripting context for security reasons,
throw
a
SecurityError
and stop. - If this.
[[td]]
.properties[name] does not exist, throwNotFoundError
and stop. - Set this.
[[writeHandlers]]
[name] to handler.
"single"
:
- If this operation is not supported, send back a
NotSupportedError
according to the Protocol Bindings and stop. - If this operation is not allowed, send back a
NotAllowedError
according to the Protocol Bindings and stop. - Let interaction be
this.
[[td]]
.properties[name]. - If interaction is
undefined
, return aNotFoundError
in the reply and stop. - Let handler be
this.
[[writeHandlers]]
[name]. - If handler is
undefined
and if there is a default write handler provided by the implementation, let handler be that. - If handler is
undefined
, send back aNotSupportedError
with the reply and stop. - Let promise be the result of invoking handler given name and options. If it fails, return the error in the reply and stop.
- If mode is
"single"
, reply to the request reporting success, following the Protocol Bindings and stop.
- If this operation is not supported, send back a
NotSupportedError
according to the Protocol Bindings and stop. - If this operation is not allowed, send back a
NotAllowedError
according to the Protocol Bindings and stop. - For each property with key name and value
value defined in propertyNames, run
the update property
steps with name, value,
options and
mode set to
"multiple"
. If that fails, reply to the request with that error and stop. - Reply to the request by sending a single reply according to the Protocol Bindings.
A function that is called when an external request for
invoking an Action
is received and defines what to do with such requests. It is
invoked given params
and optionally with an options object. It returns a
that rejects with an error or
resolves with the value returned by the Action as Promise
InteractionInput
.
Application scripts MAY return a ReadableStream
object from an ActionHandler
.
Implementations will then use the stream for constructing
the Action's response.
Takes as arguments name and action. Sets the handler function that defines what to do when a request is received to invoke the Action matched by name. Throws on error. Returns a reference to this object for supporting chaining.
The action callback function will implement an Action and SHOULD be called by implementations when a request for invoking the Action is received from the underlying platform.
There MUST be at most one handler for any given Action, so newly added handlers MUST replace the previous handlers.
- If invoking this method is not allowed for the
current scripting context for security reasons,
throw
a
SecurityError
and stop. - Let interaction be
this.
[[td]]
.actions[name]. - If interaction is
undefined
, throw aNotFoundError
and stop. - Set this.
[[actionHandlers]]
[name] to action.
9.20 Handling Action requests
- If this operation is not supported, send back a
NotSupportedError
according to the Protocol Bindings and stop. - If this operation is not allowed, send back a
NotAllowedError
according to the Protocol Bindings and stop. - Let interaction be
this.
[[td]]
.properties[name]. - If interaction is
undefined
, return aNotFoundError
in the reply and stop. - Let handler be
this.
[[actionHandlers]]
[name]. - If handler is
undefined
, return aNotSupportedError
with the reply created by following the Protocol Bindings and stop. - Let promise be the result of invoking handler given name, inputs and options.
- If promise rejects, send the error with the reply and stop.
- When promise resolves with data, use data to create and send the reply according to the Protocol Bindings.
A function that is called when an external request for
subscribing to an Event is
received and defines what to do with such requests. It is
invoked given an options object provided by the
implementation and coming from subscribers. It returns a
that rejects with an error or
resolves when the subscription is accepted.Promise
Takes as arguments name and handler. Sets the handler function that defines what to do when a subscription request is received for the specified Event matched by name. Throws on error. Returns a reference to this object for supporting chaining.
The handler callback function SHOULD implement what to do when an subscribe request is received, for instance necessary initializations. Note that the handler for emitting Events is set separately.
There MUST be at most one event subscribe handler for any given Event, so newly added handlers MUST replace the previous handlers.
- If invoking this method is not allowed for the
current scripting context for security reasons,
throw
a
SecurityError
and stop. - Let interaction be
this.
[[td]]
.events[name]. - If interaction is
undefined
, throw aNotFoundError
and stop. - Set this.
[[subscribeHandlers]]
[name] to handler. - Return
this
.
9.23 Handling Event subscribe requests
- If this operation is not supported, send back a
NotSupportedError
according to the Protocol Bindings and stop. - If this operation is not allowed, send back a
NotAllowedError
according to the Protocol Bindings and stop. - Let interaction be
this.
[[td]]
.events[name]. - If interaction is
undefined
, send back aNotFoundError
and stop. - If this.
[[subscribeHandlers]]
[name] is aFunction
, invoke it given options and stop. - Otherwise implement the default subscriber mechanism:
- Let subscriber be a tuple formed of options (from which uriVariables and data may be used) and the subscriber information needed to create an Event notification response.
- Set this.
[[eventListeners]]
[name] to subscriber.
Takes as arguments name and handler. Sets the handler function that defines what to do when the specified Event matched by name is unsubscribed from. Throws on error. Returns a reference to this object for supporting chaining.
The handler callback function SHOULD implement what to do when an unsubscribe request is received.
There MUST be at most one handler for any given Event, so newly added handlers MUST replace the previous handlers.
- If invoking this method is not allowed for the
current scripting context for security reasons,
throw
a
SecurityError
and stop. - Let interaction be
this.
[[td]]
.events[name]. - If interaction is
undefined
, throw aNotFoundError
and stop. - Set this.
[[unsubscribeHandlers]]
[name] to handler. - Return
this
.
9.25 Handling Event unsubscribe requests
- If this operation is not supported, send back a
NotSupportedError
according to the Protocol Bindings and stop. - If this operation is not allowed, send back a
NotAllowedError
according to the Protocol Bindings and stop. - Let interaction be
this.
[[td]]
.events[name]. - If interaction is
undefined
, send back aNotFoundError
and stop. - If this.
[[unsubscribeHandlers]]
[name] exists and is aFunction
, invoke it given options and stop. - Otherwise name [=map/exists] in
this.
[[eventListeners]]
, remove name. - Return
this
.
9.26 Handling Events
- Let listeners be
[[eventListeners]]
.name. - For each subscriber in
listeners, run the following sub-steps:
- Create an Event notification response according to the Protocol Bindings from data and subscriber, including its options.
- If data
is
undefined
, assume that the notification response will contain an empty data payload as specified by Protocol Bindings. - If the underlying protocol stack permits
conveying event errors and if an error condition has
been detected by the UA, create response
as an error notification according to the Protocol
Bindings, using data, subscriber
and its options.
Note
The error reporting is protocol specific and it is encapsulated by implementations. On the client end, the error listener passed with the subscription will be invoked if the client UA detects the error.
- Send response to the subscriber identified by subscriber.
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - Let interaction be
[[td]]
.events.name. - If an Event
with the name name is not
found, reject
promise with
NotFoundError
and stop. - Make a request to the underlying platform to emit an Event with optional data. Call the handling events steps.
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - Run the expand a TD steps on the
[[td]]
. - Run the validate a TD on
[[td]]
. If that fails, reject promise with aTypeError
and stop. - For each key in
[[td]]
.properties initialize this.[[propertyObservers]]
.key to an emptyArray
in order to store observe request data needed to notify the observers on value changes. - For each key in
this.
[[td]]
.events initialize this.[[eventListeners]]
.key to an emptyArray
in order to store subscribe request data needed to notify the subscribers on event emission. - Set up the 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 and then start serving external requests for WoT Interactions (read, write and observe Properties, invoke Actions and manage Event subscriptions), based on the Protocol Bindings. Implementations MAY reject this step for any reason (e.g. if they want to enforce further checks and constraints on interaction forms). - 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 Protocol Bindings and stop. - Otherwise resolve promise and stop.
- Return a
promise and execute the next steps in parallel.Promise
- If invoking this method is not allowed for the
current scripting context for security reasons,
reject
promise with a
SecurityError
and stop. - Make a request to the underlying platform to stop serving external requests for WoT Interactions, based on the Protocol Bindings.
- If there was an error during the request,
reject
promise with an
Error
object error with its message set to the error code seen by the Protocol Bindings and stop. - Otherwise resolve promise and stop.
The next example illustrates how to create an
ExposedThing
based on a partial TD object
constructed beforehand.
try {
let temperaturePropertyDefinition = {
type: "number",
minimum: -50,
maximum: 10000
};
let tdFragment = {
properties: {
temperature: temperaturePropertyDefinition
},
actions: {
reset: {
description: "Reset the temperature sensor",
input: {
temperature: temperatureValueDefinition
},
output: null,
forms: []
},
},
events: {
onchange: temperatureValueDefinition
}
};
let thing1 = await WOT.produce(tdFragment);
// initialize Properties
await thing1.writeProperty("temperature", 0);
// add service handlers
thing1.setPropertyReadHandler("temperature", () => {
return readLocalTemperatureSensor(); // Promise
});
// start serving requests
await thing1.expose();
} catch (err) {
console.log("Error creating ExposedThing: " + err);
}
The next example illustrates how to add or modify a
Property definition
on an existing ExposedThing
:
take its td property, add or modify it, then
create another ExposedThing
with that.
try {
// create a deep copy of thing1's TD
let instance = JSON.parse(JSON.stringify(thing1.td));
const statusValueDefinition = {
type: "object",
properties: {
brightness: {
type: "number",
minimum: 0.0,
maximum: 100.0,
required: true
},
rgb: {
type: "array",
"minItems": 3,
"maxItems": 3,
items : {
"type" : "number",
"minimum": 0,
"maximum": 255
}
}
};
instance["name"] = "mySensor";
instance.properties["brightness"] = {
type: "number",
minimum: 0.0,
maximum: 100.0,
required: true,
};
instance.properties["status"] = statusValueDefinition;
instance.actions["getStatus"] = {
description: "Get status object",
input: null,
output: {
status : statusValueDefinition;
},
forms: [...]
};
instance.events["onstatuschange"] = statusValueDefinition;
instance.forms = [...]; // update
var thing2 = new ExposedThing(instance);
// TODO: add service handlers
await thing2.expose();
});
} catch (err) {
console.log("Error creating ExposedThing: " + err);
}
The following will cover a set of examples for the
generation of a Thing Description
from an ExposedThingInit
using expand an
ExposedThingInit steps. As hypothesis the runtime
supports HTTP and COAP protocol bindings and it is hosted at
192.168.0.1.
The next example shows how to exploit a ExposedThingInit
to create a simple Thing Description
with one Property with the default
values.
TODO: add more examples where the ExposedThingInit
contains suggested values that are replaced by the
algorithm.
Discovery is a distributed application that requires provisioning and support from participating network nodes (clients, servers, directory services). This API models the client side of typical discovery schemes supported by various IoT deployments.
The ThingDiscoveryProcess
object provides the properties and methods controlling the
discovery process and returning the results.
WebIDL[SecureContext, Exposed=(Window,Worker)]
interface ThingDiscoveryProcess
{
constructor
(optional ThingFilter
filter = {});
readonly attribute boolean done
;
readonly attribute Error? error
;
undefined stop
();
async iterable<ThingDescription
>;
};
The ThingDiscoveryProcess
object has the following
internal slots.
Internal Slot | Initial value | Description (non-normative) |
---|---|---|
[[filter]] | undefined |
The ThingFilter
object used in discovery.
|
[[url]] | undefined |
A URL
representing the TD Directory in a
discovery.
|
The done
property is true
if the discovery has been stopped or completed with no more
results to report.
The error
property represents the last
error that occurred during the discovery process. Typically
used for critical errors that stop discovery.
The ThingDiscoveryProcess
object implements the async
iterator concept.
10.1 Constructing
ThingDiscoveryProcess
ThingDiscoveryProcess
with a filter, run the
following steps:
- If filter is not
an object or
null
, throw aTypeError
and stop. - Let discovery be a new
ThingDiscoveryProcess
object. - Set discovery.
[[filter]]
to filter. - Set discovery.
done
tofalse
. - Set discovery.
error
tonull
. - Return discovery.
Represents an object containing the constraints for discovering Things as key-value pairs.
WebIDLdictionary ThingFilter
{
object? fragment
;
};
The fragment
property represents a
template object used for matching property by property
against discovered Things.
The query
property was temporarily removed from ThingFilter
,
until it is standardized in the WoT Discovery task force.
It represented a query string accepted by the
implementation, for instance a SPARQL or JSON query.
Support was to be implemented locally in the WoT Runtime or remotely
as a service in a TD Directory.
The url property was removed. It used to represent the target entity serving the discovery request, for instance the URL of a TD Directory, or the URL of a directly targeted Thing, but these are implemented by dedicated methods now.
- Whenever a new link to a Thing Description
is discovered and provided by the underlying platform,
run the following sub-steps:
- Retrieve td as a JSON object, using the Protocol Binding used by the underlying discovery process (as specified by link). In the case of an HTTP(S) Binding, this process could use the Fetch API for the td's retrieval.
- If that fails, set the discovery.
error
property toSyntaxError
, discard td and continue the discovery process.
- Whenever a Thing Description
td is discovered
and provided by the underlying platform or by the
previous step, run the following sub-steps:
Note
At this point implementations MAY control the flow of the discovery process (depending on memory constraints, for instance queue the results, or temporarily stop discovery if the queue is getting too large, or resume discovery when the queue is emptied sufficiently). These steps are run for each discovered/fetched td.
- Let fragment be discovery.
[[filter]]
.fragment
. - If fragment is an
object
, then for each key defined in it:- Check if that key exists in json and json[key is equal to fragment.key.
- If this is fails in any checks, discard td and continue the discovery process.
- Yield td
using
asyncIterator
.Editor's noteImprove this step using proper asyncIterator terminology.
- Let fragment be discovery.
- Whenever an error occurs during the discovery
process, run the following sub-steps:
Note
The last error is retained. Implementations MAY choose to stop the discovery process if they consider it should be reported.
- Let error be a new
Error
object. Set error.name to"DiscoveryError"
. - If there was an error code or message provided by the Protocol Bindings, set error.message to that value as string.
- Set discovery.
error
to error. - If the error is irrecoverable and discovery has
been stopped by the underlying platform, or if the
implementation decided to stop the discovery process
and report the error, set discovery.
done
totrue
and terminate these steps.
- Let error be a new
- If invoking this method is not allowed for the
current scripting context for security reasons,
throw
a
SecurityError
and stop. - Request the underlying platform to stop the discovery process. If this 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.
- Set the
done
property totrue
.
The following example finds ThingDescription
objects of Things
that are exposed by local hardware, regardless how many
instances of WoT
Runtime it is running Using the
asyncIterator
provided by the Discovery
object, we can iterate asynchronously over the results and
perform operations with the obtained ThingDescription
objects.
let url = "https://mythings.com/thing1";
let td = await WOT.requestThingDescription(url);
console.log("Found Thing Description for " + td.title);
The next example finds ThingDescription
objects of Things
listed in a TD
Directory service. We set a timeout for safety.
let discovery = await WOT.exploreDirectory("https://directory.wotservice.org");
setTimeout( () => {
discovery.stop();
console.log("Discovery stopped after timeout.");
},
3000);
for await (const td of discovery) {
console.log("Found Thing Description for " + td.title);
let thing = new ConsumedThing(td);
console.log("Thing name: " + thing.getThingDescription().title);
};
if (discovery.error) {
console.log("Discovery stopped because of an error: " + error.message);
}
The next example is for a generic discovery, by any means provisioned to the WOT runtime, including local Things, if any is available.
let discovery = await WOT.discover();
setTimeout( () => {
discovery.stop();
console.log("Stopped open-ended discovery");
},
10000);
for await (const td of discovery) {
console.log("Found Thing Description for " + td.title);
};
if (discovery.error) {
console.log("Discovery stopped because of an error: " + error.message);
}
A detailed discussion of security and privacy considerations for the Web of Things, including a threat model that can be adapted to various circumstances, is presented in the informative document [WOT-SECURITY]. This section discusses only security and privacy risks and possible mitigations directly relevant to the scripts and WoT Scripting API.
A suggested set of best practices to improve security for WoT devices and services has been documented in [WOT-SECURITY]. That document may be updated as security measures evolve. Following these practices does not guarantee security, but it might help avoid commonly known vulnerabilities.
- Implementors of WoT Runtimes that do not implement a Scripting Runtime. The [WOT-ARCHITECTURE] document provides generic security guidelines for this group.
- Implementors of the WoT Scripting API in a WoT Scripting Runtime. This is the main scope and is covered in the Scripting Runtime Security and Privacy Risks sub-section that contains normative text regarding security.
- WoT script developers, covered in the Script Security and Privacy Risks sub-section that contains informative recommendations concerning security.
This section is normative and contains specific risks relevant for the WoT Scripting Runtime.
A typical way to compromise any process is to send it a corrupted input via one of the exposed interfaces. This can be done to a script instance using WoT interface it exposes.
- 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].
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.
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].
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.
This section is non-normative.
This section describes specific risks relevant for script developers.
A script instance may receive data formats defined by the TD, or data formats defined by the applications. While the WoT Scripting Runtime SHOULD perform validation on all input fields defined by the TD, scripts may be still exploited by input data.
- 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].
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].
API rationale usually belongs to a separate document, but in the WoT case the complexity of the context justifies including basic rationale here.
The WoT Interest Group and Working Group have explored different approaches to application development for WoT that have been all implemented and tested.
It is possible to develop WoT applications that only use the WoT network interface, typically exposed by a WoT gateway that presents a RESTful API towards clients and implements IoT protocol plugins that communicate with supported IoT deployments. One such implementation is the Mozilla WebThings platform.
WoT Things show good synergy with software objects, so a Thing can be represented as a software object, with Properties represented as object properties, Actions as methods, and Events as events. In addition, metadata is stored in special properties. Consuming and exposing is done with factory methods that produce a software object that directly represents a remote Thing and its interactions. One such implementation is the Arena Web Hub project.
In the next example, a Thing that represents
interactions with a lock would look like the following: the
status property and the open()
method are directly exposed on the object.
let lock = await WoT.consume(‘https://td.my.com/lock-00123’);
console.log(lock.status);
lock.open('withThisKey');
A.1.3 This API, aligned with the Web of Things (WoT) Thing Description 1.1 specification
Since the direct mapping of Things to software objects have had some challenges, this specification takes another approach that exposes software objects to represent the Thing metadata as data property and the WoT interactions as methods. One implementation is node-wot in the Eclipse ThingWeb project, which is the current reference implementation of the API specified in this document.
The same example now would look like the following: the
status property and the open()
method are represented indirectly.
let res = await fetch(‘https://td.my.com/lock-00123’);
let td = await res.json();
let lock = new ConsumedThing(td);
console.log(lock.readProperty(‘status’));
lock.invokeAction(‘open’, 'withThisKey');
In conclusion, the WoT WG decided to explore the third option that closely follows the Web of Things (WoT) Thing Description 1.1 specification. Based on this, a simple API can also be implemented. Since Scripting is an optional module in WoT, this leaves room for applications that only use the WoT network interface. Therefore all three approaches above are supported by the Web of Things (WoT) Thing Description 1.1 specification.
Moreover, the WoT network interface can be implemented in many languages and runtimes. Consider this API an example for what needs to be taken into consideration when designing a Scripting API for WoT.
The fetch(url)
method has been part of this
API in earlier versions. However, now fetching a TD given a URL should be done with an
external method, such as the Fetch API or a
HTTP client library, which offer already standardized options
on specifying fetch details. The reason is that while simple
fetch operations (covering most use cases) could be done in
this API, when various fetch options were needed, there was
no point in duplicating existing work to re-expose those
options in this API.
Since fetching a TD has been scoped out, and TD validation is defined externally in the Web of Things (WoT) Thing Description 1.1 specification, that is scoped out, too. This specification expects a TD as parsed JSON object that has been validated according to the Web of Things (WoT) Thing Description 1.1 specification.
The factory methods for consuming and exposing Things are asynchronous and fully
validate the input TD. In
addition, one can also construct ConsumedThing
and ExposedThing
by providing a parsed and validated TD. Platform initialization is then
done when needed during the WoT interactions.
Earlier drafts used the Observer construct, but since it has not become standard, a new design was needed that was light enough for embedded implementations. Therefore observing Property changes and handling WoT Events is done with callback registrations.
- Subscription to WoT Events may be different from handling software events (subscription might need parameters, might involve security tokens etc).
- Most implementations are for Node.js and browser implementations will likely be libraries (because possible dependency management issues in native implementations), using Events has been challenging.
- Observing Property changes and handling WoT Events is done with the solution above.
The reason to use function names like
readProperty()
,
readMultipleProperties()
etc. instead of a
generic polymorphic read()
function is that the
current names map exactly to the "op"
vocabulary
from the
Form definition in the
Web of Things (WoT) Thing Description 1.1
specification.
- First Public Working Draft September 2017.
- Working Draft April 2018.
- Working Draft November 2018.
- Working draft October 2019.
- This version, introducing the following major changes:
- Added support for
formIndex
,InteractionData
including streams. - Cleaned up the specification prose, aligned terminology and used modern ReSpec.
- Improved algorithm descriptions, included illustrative figures.
- Added support for
For a complete list of changes, see the github change log. You can also view the recently closed issues.
WebIDLtypedef object ThingDescription
;
[SecureContext, Exposed=(Window,Worker)]
namespace WOT
{
// methods defined in UA conformance classes
};
partial namespace WOT
{
Promise<ConsumedThing
> consume
(ThingDescription
td);
};
typedef object ExposedThingInit
;
partial namespace WOT
{
Promise<ExposedThing
> produce
(ExposedThingInit
init);
};
partial namespace WOT
{
Promise<ThingDiscoveryProcess
> discover
(optional ThingFilter
filter = {});
};
partial namespace WOT
{
Promise<ThingDiscoveryProcess
> exploreDirectory
(USVString url,
optional ThingFilter
filter = {});
};
partial namespace WOT
{
Promise<ThingDescription
> requestThingDescription
(USVString url);
};
typedef any DataSchemaValue
;
typedef (ReadableStream or DataSchemaValue
) InteractionInput
;
[SecureContext, Exposed=(Window,Worker)]
interface InteractionOutput
{
readonly attribute ReadableStream? data
;
readonly attribute boolean dataUsed
;
readonly attribute Form? form
;
readonly attribute DataSchema? schema
;
Promise<ArrayBuffer> arrayBuffer
();
Promise<DataSchemaValue
> value
();
};
[SecureContext, Exposed=(Window,Worker)]
interface ConsumedThing
{
constructor
(ThingDescription
td);
Promise<InteractionOutput
> readProperty
(DOMString propertyName,
optional InteractionOptions
options = {});
Promise<PropertyReadMap
> readAllProperties
(
optional InteractionOptions
options = {});
Promise<PropertyReadMap
> readMultipleProperties
(
sequence<DOMString> propertyNames,
optional InteractionOptions
options = {});
Promise<undefined> writeProperty
(DOMString propertyName,
InteractionInput
value,
optional InteractionOptions
options = {});
Promise<undefined> writeMultipleProperties
(
PropertyWriteMap
valueMap,
optional InteractionOptions
options = {});
/*Promise<undefined> writeAllProperties(
PropertyWriteMap valueMap,
optional InteractionOptions options = {});*/
Promise<InteractionOutput
> invokeAction
(DOMString actionName,
optional InteractionInput
params = {},
optional InteractionOptions
options = {});
Promise<Subscription
> observeProperty
(DOMString name,
InteractionListener
listener,
optional ErrorListener
onerror,
optional InteractionOptions
options = {});
Promise<Subscription
> subscribeEvent
(DOMString name,
InteractionListener
listener,
optional ErrorListener
onerror,
optional InteractionOptions
options = {});
ThingDescription
getThingDescription
();
};
dictionary InteractionOptions
{
unsigned long formIndex
;
object uriVariables
;
any data
;
};
[SecureContext, Exposed=(Window,Worker)]
interface Subscription
{
readonly attribute boolean active
;
Promise<undefined> stop
(optional InteractionOptions
options = {});
};
[SecureContext, Exposed=(Window,Worker)]
interface PropertyReadMap
{
readonly maplike<DOMString, InteractionOutput
>;
};
[SecureContext, Exposed=(Window,Worker)]
interface PropertyWriteMap
{
readonly maplike<DOMString, InteractionInput
>;
};
callback InteractionListener
= undefined(InteractionOutput
data);
callback ErrorListener
= undefined(Error error);
[SecureContext, Exposed=(Window,Worker)]
interface ExposedThing
{
ExposedThing
setPropertyReadHandler
(DOMString name,
PropertyReadHandler
handler);
ExposedThing
setPropertyWriteHandler
(DOMString name,
PropertyWriteHandler
handler);
ExposedThing
setPropertyObserveHandler
(DOMString name,
PropertyReadHandler
handler);
ExposedThing
setPropertyUnobserveHandler
(DOMString name,
PropertyReadHandler
handler);
Promise<undefined> emitPropertyChange
(DOMString name,
optional InteractionInput
data);
ExposedThing
setActionHandler
(DOMString name, ActionHandler
action);
ExposedThing
setEventSubscribeHandler
(DOMString name,
EventSubscriptionHandler
handler);
ExposedThing
setEventUnsubscribeHandler
(DOMString name,
EventSubscriptionHandler
handler);
Promise<undefined> emitEvent
(DOMString name,
optional InteractionInput
data);
Promise<undefined> expose
();
Promise<undefined> destroy
();
ThingDescription
getThingDescription
();
};
callback PropertyReadHandler
= Promise<InteractionInput
>(
optional InteractionOptions
options = {});
callback PropertyWriteHandler
= Promise<undefined>(
InteractionOutput
value,
optional InteractionOptions
options = {});
callback ActionHandler
= Promise<InteractionInput
>(
InteractionOutput
params,
optional InteractionOptions
options = {});
callback EventSubscriptionHandler
= Promise<undefined>(
optional InteractionOptions
options = {});
[SecureContext, Exposed=(Window,Worker)]
interface ThingDiscoveryProcess
{
constructor
(optional ThingFilter
filter = {});
readonly attribute boolean done
;
readonly attribute Error? error
;
undefined stop
();
async iterable<ThingDescription
>;
};
dictionary ThingFilter
{
object? fragment
;
};
Special thanks to former editor Johannes Hund (until August 2017, when at Siemens AG) and Kazuaki Nimura (until December 2018) for developing this specification. Also, the editors would like to thank Dave Raggett, Matthias Kovatsch, Michael Koster, Elena Reshetova, Michael McCool as well as the other WoT WG members for their comments, contributions and guidance.
- [ECMASCRIPT]
- ECMAScript Language Specification. Ecma International. URL: https://tc39.es/ecma262/multipage/
- [fetch]
- Fetch Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://fetch.spec.whatwg.org/
- [html]
- HTML Standard. Anne van Kesteren; Domenic Denicola; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
- [infra]
- Infra Standard. Anne van Kesteren; Domenic Denicola. WHATWG. Living Standard. URL: https://infra.spec.whatwg.org/
- [JSON-SCHEMA]
- JSON Schema: A Media Type for Describing JSON Documents. Austin Wright; Henry Andrews; Ben Hutton; Greg Dennis. Internet Engineering Task Force (IETF). 8 December 2020. Internet-Draft. URL: https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema
- [RFC2119]
- Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
- [RFC8174]
- Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba. IETF. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
- [streams]
- Streams Standard. Adam Rice; Domenic Denicola; Mattias Buelens; 吉野剛史 (Takeshi Yoshino). WHATWG. Living Standard. URL: https://streams.spec.whatwg.org/
- [TYPESCRIPT]
- TypeScript Language Specification. Microsoft. 1 October 2012. URL: https://www.typescriptlang.org/docs/handbook/intro.html
- [url]
- URL Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://url.spec.whatwg.org/
- [WEBIDL]
- Web IDL Standard. Edgar Chen; Timothy Gu. WHATWG. Living Standard. URL: https://webidl.spec.whatwg.org/
- [WOT-ARCHITECTURE]
- Web of Things (WoT) Architecture 1.1. W3C. 19 January 2023. URL: https://www.w3.org/TR/2023/CR-wot-architecture11-20230119/
- [WOT-PROTOCOL-BINDINGS]
- Web of Things (WoT) Binding Templates. W3C. 30 January 2020. URL: https://www.w3.org/TR/2020/NOTE-wot-binding-templates-20200130/
- [WOT-SECURITY]
- Web of Things (WoT) Security and Privacy Guidelines. W3C. 6 November 2019. URL: https://www.w3.org/TR/2019/NOTE-wot-security-20191106/
- [WOT-TD]
- Web of Things (WoT) Thing Description 1.1. W3C. 19 January 2023. URL: https://www.w3.org/TR/2023/CR-wot-thing-description11-20230119/
- [WOT-DISCOVERY]
- Web of Things (WoT) Discovery. W3C. 19 January 2023. URL: https://www.w3.org/TR/2023/CR-wot-discovery-20230119/
- [WOT-USE-CASES]
- Web of Things (WoT): Use Cases and Requirements. W3C. 7 March 2022. URL: https://www.w3.org/TR/2022/NOTE-wot-usecases-20220307/
Referenced in:
Referenced in:
Referenced in:
- § Abstract (2) (3)
- § 1. Introduction (2) (3) (4) (5) (6) (7) (8)
- § 2.1 Consuming a Thing
- § 2.2 Exposing a Thing (2) (3) (4) (5) (6) (7) (8) (9) (10)
- § 2.3 Discovery (2) (3) (4) (5) (6)
- § 4. Terminology and conventions
- § 6.1 The consume() method
- § 8. The ConsumedThing interface
- § 8.3 The getThingDescription() method
- § 8.6 The readAllProperties() method (2)
- § 8.8 The writeMultipleProperties() method
- § 9. The ExposedThing interface
- § 9.3 The getThingDescription() method (2)
- § 9.8 Handling requests for reading all Properties
- § 9.28 The expose() method
- § 9.29 The destroy() method
- § 10.2 The ThingFilter dictionary (2) (3)
- § 10.5 Discovery Examples (2)
- § A.1.2 Simple Scripting API (2) (3) (4)
- § A.1.3 This API, aligned with the Web of Things (WoT) Thing Description 1.1 specification (2)
- § A.3 Factory vs constructors
Referenced in:
- § Abstract
- § 1. Introduction (2)
- § 2.1 Consuming a Thing (2)
- § 2.2 Exposing a Thing (2) (3)
- § 2.3 Discovery
- § 5. The ThingDescription type
- § 5.2 Expanding a Thing Description
- § 6.2 The produce() method
- § 6.3 The discover() method
- § 6.4 The exploreDirectory() method
- § 6.5 The requestThingDescription() method (2) (3)
- § 7.1 The InteractionInput type (2) (3)
- § 7.2 The InteractionOutput interface
- § 8.1 Internal slots for ConsumedThing
- § 8.2 Constructing ConsumedThing
- § 8.3 The getThingDescription() method
- § 8.12 The InteractionOptions dictionary
- § 8.17.1 Internal slots for Subscription
- § 9.1 Internal slots for ExposedThing
- § 9.3 The getThingDescription() method
- § 9.5 The setPropertyReadHandler() method
- § 9.9 The setPropertyObserveHandler() method
- § 9.11 The setPropertyUnobserveHandler() method
- § 9.15 The setPropertyWriteHandler() method
- § 9.30 ExposedThing Examples (2)
- § 10.3 The discovery process algorithm (2)
Referenced in:
- § 1. Introduction
- § 2.2 Exposing a Thing (2)
- § 4. Terminology and conventions
- § 5. The ThingDescription type
- § 5.1 Fetching a Thing Description
- § 5.2 Expanding a Thing Description
- § 5.3 Validating a Thing Description (2)
- § 6.1 The consume() method
- § 8.6 The readAllProperties() method
- § 8.7 The writeProperty() method
- § 8.12 The InteractionOptions dictionary (2)
- § 8.18 ConsumedThing Examples
- § 9.30 ExposedThing Examples
- § A.2 Fetching and validating a TD (2) (3) (4)
- § A.3 Factory vs constructors (2)
Referenced in:
- § 6.1 The consume() method (2)
- § 6.2.1 Expand an ExposedThingInit (2) (3) (4)
- § 6.4 The exploreDirectory() method
- § 6.5 The requestThingDescription() method
- § 7.2.1 The value() function (2)
- § 7.4 Error handling (2)
- § 8.4 The readProperty() method (2)
- § 8.5 The readMultipleProperties() method (2)
- § 8.6 The readAllProperties() method (2) (3)
- § 8.7 The writeProperty() method (2)
- § 8.8 The writeMultipleProperties() method (2) (3)
- § 8.9 The observeProperty() method
- § 8.10 The invokeAction() method (2)
- § 8.11 The subscribeEvent() method (2)
- § 8.16 The ErrorListener callback
- § 8.17.2 The stop() method (2) (3)
- § 9.6 Handling requests for reading a Property (2) (3) (4)
- § 9.7 Handling requests for reading multiple Properties (2) (3) (4)
- § 9.8 Handling requests for reading all Properties (2)
- § 9.10 Handling Property observe requests (2)
- § 9.12 Handling Property unobserve requests (2) (3) (4) (5)
- § 9.13 The emitPropertyChange() method
- § 9.16 Handling requests for writing a Property (2) (3)
- § 9.17 Handling requests for writing multiple Properties (2) (3)
- § 9.20 Handling Action requests (2) (3) (4)
- § 9.23 Handling Event subscribe requests (2)
- § 9.25 Handling Event unsubscribe requests (2)
- § 9.26 Handling Events (2) (3)
- § 9.28 The expose() method (2) (3)
- § 9.29 The destroy() method (2)
- § 10.3 The discovery process algorithm (2)
Referenced in:
Referenced in:
Referenced in:
- § Abstract
- § 1. Introduction (2)
- § 2.1 Consuming a Thing (2) (3)
- § 2.2 Exposing a Thing (2) (3) (4) (5) (6)
- § 8.1 Internal slots for ConsumedThing
- § 8.4 The readProperty() method (2) (3)
- § 8.5 The readMultipleProperties() method (2)
- § 8.6 The readAllProperties() method (2)
- § 8.7 The writeProperty() method (2) (3) (4)
- § 8.8 The writeMultipleProperties() method (2) (3) (4)
- § 8.9 The observeProperty() method (2) (3) (4)
- § 8.13 The PropertyReadMap type (2) (3)
- § 8.14 The PropertyWriteMap type (2) (3)
- § 8.15 The InteractionListener callback
- § 8.17 The Subscription interface
- § 8.17.1 Internal slots for Subscription
- § 8.17.2 The stop() method
- § 9. The ExposedThing interface
- § 9.2 Constructing ExposedThing (2)
- § 9.4 The PropertyReadHandler callback
- § 9.5 The setPropertyReadHandler() method (2) (3) (4) (5) (6)
- § 9.6 Handling requests for reading a Property (2)
- § 9.7 Handling requests for reading multiple Properties
- § 9.8 Handling requests for reading all Properties
- § 9.9 The setPropertyObserveHandler() method (2) (3) (4)
- § 9.10 Handling Property observe requests (2) (3)
- § 9.11 The setPropertyUnobserveHandler() method (2) (3)
- § 9.12 Handling Property unobserve requests (2)
- § 9.13 The emitPropertyChange() method (2) (3)
- § 9.14 The PropertyWriteHandler callback (2)
- § 9.15 The setPropertyWriteHandler() method (2) (3) (4) (5) (6)
- § 9.16 Handling requests for writing a Property
- § 9.17 Handling requests for writing multiple Properties
- § 9.28 The expose() method (2)
- § 9.30 ExposedThing Examples (2)
- § A.1.2 Simple Scripting API
- § A.4 Observers
- § A.5 Using Events
Referenced in:
- § Abstract
- § 1. Introduction (2) (3)
- § 2.1 Consuming a Thing
- § 2.2 Exposing a Thing (2) (3)
- § 7.3 Using InteractionInput and InteractionOutput (2) (3)
- § 8.7 The writeProperty() method
- § 8.10 The invokeAction() method (2) (3)
- § 8.12 The InteractionOptions dictionary
- § 9. The ExposedThing interface
- § 9.2 Constructing ExposedThing
- § 9.18 The ActionHandler callback (2) (3)
- § 9.19 The setActionHandler() method (2) (3) (4)
- § 9.20 Handling Action requests (2)
- § 9.28 The expose() method (2)
- § A.1.2 Simple Scripting API
Referenced in:
- § Abstract
- § 1. Introduction (2)
- § 2.1 Consuming a Thing
- § 2.2 Exposing a Thing (2) (3) (4) (5)
- § 8.1 Internal slots for ConsumedThing
- § 8.11 The subscribeEvent() method (2) (3) (4) (5) (6)
- § 8.15 The InteractionListener callback (2)
- § 8.17 The Subscription interface
- § 8.17.1 Internal slots for Subscription
- § 8.17.2 The stop() method
- § 9. The ExposedThing interface
- § 9.2 Constructing ExposedThing
- § 9.21 The EventSubscriptionHandler callback
- § 9.22 The setEventSubscribeHandler() method (2) (3)
- § 9.23 Handling Event subscribe requests (2) (3)
- § 9.24 The setEventUnsubscribeHandler() method (2)
- § 9.25 Handling Event unsubscribe requests (2)
- § 9.26 Handling Events (2) (3)
- § 9.27 The emitEvent() method (2) (3) (4)
- § 9.28 The expose() method (2)
- § A.1.2 Simple Scripting API
- § A.4 Observers
- § A.5 Using Events (2)
Referenced in:
- § 7. Handling interaction data (2)
- § 7.1 The InteractionInput type (2) (3)
- § 7.2 The InteractionOutput interface (2) (3)
- § 7.2.1 The value() function
- § 8.18 ConsumedThing Examples
- § 9.4 The PropertyReadHandler callback
- § 9.6 Handling requests for reading a Property
- § 9.14 The PropertyWriteHandler callback
- § C. Full Web IDL
Referenced in:
- § 6.2.1 Expand an ExposedThingInit (2)
- § 7. Handling interaction data
- § 7.1 The InteractionInput type (2)
- § 7.2 The InteractionOutput interface (2)
- § 7.2.1 The value() function
- § 8.4 The readProperty() method (2)
- § 8.5 The readMultipleProperties() method (2)
- § 8.6 The readAllProperties() method
- § 8.7 The writeProperty() method (2)
- § 8.8 The writeMultipleProperties() method (2)
- § 8.9 The observeProperty() method
- § 8.10 The invokeAction() method
- § 8.11 The subscribeEvent() method
- § 8.17.1 Internal slots for Subscription
- § 8.17.2 The stop() method
- § 8.17.3 Finding an unsubscribe Form (2) (3)
- § C. Full Web IDL
Referenced in:
- § Abstract
- § 2.1 Consuming a Thing
- § 4. Terminology and conventions
- § 6.1 The consume() method (2) (3)
- § 7. Handling interaction data
- § 7.1 The InteractionInput type (2) (3) (4)
- § 7.2 The InteractionOutput interface (2) (3) (4)
- § 7.2.1 The value() function
- § 8.17.1 Internal slots for Subscription (2)
- § 9.28 The expose() method (2) (3)
- § 9.29 The destroy() method
Referenced in:
Referenced in:
- § 5. The ThingDescription type
- § 5.3 Validating a Thing Description
- § 6.1 The consume() method
- § 6.3 The discover() method
- § 6.4 The exploreDirectory() method
- § 6.5 The requestThingDescription() method
- § 8. The ConsumedThing interface (2)
- § 8.2 Constructing ConsumedThing
- § 9. The ExposedThing interface
- § 9.2 Constructing ExposedThing (2)
- § 10. The ThingDiscoveryProcess interface
- § 10.5 Discovery Examples (2) (3)
- § C. Full Web IDL (2) (3) (4) (5) (6) (7)
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
- § 7.1 The InteractionInput type
- § 7.3 Using InteractionInput and InteractionOutput (2) (3) (4) (5) (6)
- § 8. The ConsumedThing interface (2) (3)
- § 8.14 The PropertyWriteMap type
- § 9. The ExposedThing interface (2) (3) (4)
- § 9.18 The ActionHandler callback
- § C. Full Web IDL (2) (3) (4) (5) (6) (7) (8)
Referenced in:
Referenced in:
- § 7.2 The InteractionOutput interface (2)
- § 7.2.4 The create interaction request algorithm
- § 7.2.5 The parse interaction response algorithm
- § 7.3 Using InteractionInput and InteractionOutput (2) (3) (4) (5) (6)
- § 8. The ConsumedThing interface (2) (3) (4)
- § 8.4 The readProperty() method
- § 8.10 The invokeAction() method
- § 8.13 The PropertyReadMap type
- § 8.15 The InteractionListener callback
- § 8.18 ConsumedThing Examples (2)
- § 9. The ExposedThing interface (2)
- § 9.9 The setPropertyObserveHandler() method
- § 9.14 The PropertyWriteHandler callback
- § C. Full Web IDL (2) (3) (4) (5) (6) (7)
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
- § 3. Conformance
- § 6.1 The consume() method (2) (3) (4)
- § 6.2 The produce() method
- § 7.2.4 The create interaction request algorithm
- § 7.2.5 The parse interaction response algorithm
- § 7.3 Using InteractionInput and InteractionOutput (2) (3)
- § 8. The ConsumedThing interface
- § 8.1 Internal slots for ConsumedThing (2) (3)
- § 8.2 Constructing ConsumedThing (2) (3)
- § 8.3 The getThingDescription() method (2)
- § 8.9 The observeProperty() method
- § 8.11 The subscribeEvent() method
- § 8.17.1 Internal slots for Subscription
- § 8.18 ConsumedThing Examples
- § 9.2 Constructing ExposedThing
- § A.3 Factory vs constructors
- § C. Full Web IDL (2)
Referenced in:
- § 8.2 Constructing ConsumedThing
- § 8.3 The getThingDescription() method (2)
- § 8.4 The readProperty() method
- § 8.5 The readMultipleProperties() method (2) (3)
- § 8.6 The readAllProperties() method
- § 8.7 The writeProperty() method
- § 8.8 The writeMultipleProperties() method (2) (3) (4)
- § 8.9 The observeProperty() method
- § 8.10 The invokeAction() method
- § 8.11 The subscribeEvent() method
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
- § 3. Conformance
- § 6.2 The produce() method (2) (3) (4)
- § 6.2.1 Expand an ExposedThingInit
- § 7.3 Using InteractionInput and InteractionOutput (2) (3)
- § 9. The ExposedThing interface (2) (3) (4) (5) (6) (7) (8) (9)
- § 9.1 Internal slots for ExposedThing (2)
- § 9.2 Constructing ExposedThing (2) (3) (4) (5) (6) (7)
- § 9.3 The getThingDescription() method
- § 9.5 The setPropertyReadHandler() method
- § 9.30 ExposedThing Examples (2) (3)
- § A.3 Factory vs constructors
- § C. Full Web IDL (2) (3) (4) (5) (6) (7) (8) (9)
Referenced in:
- § 9.2 Constructing ExposedThing
- § 9.3 The getThingDescription() method (2)
- § 9.5 The setPropertyReadHandler() method (2)
- § 9.6 Handling requests for reading a Property
- § 9.9 The setPropertyObserveHandler() method
- § 9.10 Handling Property observe requests
- § 9.11 The setPropertyUnobserveHandler() method
- § 9.12 Handling Property unobserve requests
- § 9.13 The emitPropertyChange() method
- § 9.15 The setPropertyWriteHandler() method
- § 9.16 Handling requests for writing a Property
- § 9.19 The setActionHandler() method
- § 9.20 Handling Action requests
- § 9.22 The setEventSubscribeHandler() method
- § 9.23 Handling Event subscribe requests
- § 9.24 The setEventUnsubscribeHandler() method
- § 9.25 Handling Event unsubscribe requests
- § 9.27 The emitEvent() method
- § 9.28 The expose() method (2) (3) (4) (5)
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: