Copyright © 2017-2018 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and permissive document license rules apply.
The overall Web of Things (WoT) concepts are described in the WoT Architecture document. The Web of Things is made of entities (Things) that can describe their capabilities in a machine-interpretable format, the Thing Description (TD) and expose these capabilities through the WoT Interface, that is, network interactions modeled as Properties for reading and writing values, Actions to execute remote procedures with or without return values and Events for signaling notifications.
This specification describes a programming interface representing the WoT Interface that allows scripts run on a Thing to discover and consume (retrieve) other Thing Descriptions and to expose Things characterized by WoT Interactions specified by a script.
Scripting is an optional "convenience" building block in WoT and it is typically used in gateways that are able to run a WoT Runtime and script management, providing a convenient way to extend WoT support to new types of endpoints and implement WoT applications like Thing Directory.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. 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 Issue feature 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 Working Draft. This document is intended to become a W3C Recommendation.
Comments regarding this document are welcome. Please send them to public-wot-wg@w3.org (subscribe, archives).
Changes from the previous publication can be found in Appendix A. A diff-marked version of this document is also available for comparison purposes.
Publication as a Working Draft does not imply endorsement by the W3C Membership. 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.
This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 1 February 2018 W3C Process Document.
WoT provides layered interoperability based on how Things are modeled: as being "consumed" and "exposed".
By consuming a TD, a client Thing creates a runtime resource model that allows accessing the Properties, Actions and Events exposed by the server Thing exposed on a remote device.
Exposing a Thing requires defining a Thing Description (TD) and instantiating a software stack to serve requests for accessing the exposed Properties, Actions and Events. This specification describes how to expose and consume Things by a script.
Typically scripts are meant to be used on devices able to provide resources (with a WoT Interface) for managing (installing, updating, running) scripts, such as bridges or gateways that expose and control simpler devices as WoT Things.
This specification does not make assumptions on how the WoT Runtime handles and runs scripts, including single or multiple tenancy, script deployment and lifecycle management. The API already supports the generic mechanisms that make it possible to implement script management, for instance by exposing a manager Thing whose Actions (action handlers) implement script lifecycle management operations.
For an introduction on how scripts could be used in Web of Things, check the Primer document. For some background on API design decisions check the Rationale document.
This section is non-normative.
The following scripting use cases are supported in this specification:
ExposedThing
to be exposed, based on
a Thing Description provided in
string serialized format, or out of a template or an
existing ConsumedThing
object.
WoT
objectThe WoT object is the API entry point and it is exposed by an implementation of the WoT Runtime. The WoT object does not expose properties, only methods for discovering, consuming and exposing a Thing.
Browser implementations SHOULD use a namespace object such as
navigator.wot
. Node.js-like runtimes MAY provide the API object through
the require() or
import mechanism.
// [SecureContext] // [NamespaceObject] interfaceWoT
{Observable
discover
(optionalThingFilter
filter); Promise<ThingDescription
>fetch
(USVString url);ConsumedThing
consume
(ThingDescription
td);ExposedThing
produce
(ThingModel
model); Promise<void>register
(USVString directory,ExposedThing
thing); Promise<void>unregister
(USVString directory,ExposedThing
thing); }; typedef objectThingFragment
; typedef objectPropertyFragment
; typedef objectActionFragment
; typedef objectEventFragment
; typedef objectDataSchema
; typedef objectSecurityScheme
; typedef objectLink
; typedef objectForm
; typedef USVStringThingDescription
; typedef (ThingFragment
orThingDescription
)ThingModel
;
The algorithms for the WoT methods will be specified later, including error handling and security considerations.
The ThingModel
type represents
either a ThingFragment
, or a
ThingDescription
.
discover()
methodStarts the discovery process that will provide ThingDescription
s that match the
optional argument filter of type
. Returns an
[ThingFilter
Observable
](https://github.com/tc39/proposal-observable)
object that can be subscribed to and unsubscribed from. The
handler function provided to the Observable during
subscription will receive an argument of type
USVString
representing a ThingDescription
.
DiscoveryMethod
enumerationtypedef DOMString DiscoveryMethod
;
DiscoveryMethod
represents the discovery type to be used:
ThingFilter
dictionaryThe ThingFilter
dictionary that represents the constraints for discovering
Things as key-value pairs.
dictionary ThingFilter
{
(DiscoveryMethod
or DOMString) method
= "any";
USVString? url
;
USVString? query
;
ThingFragment
? fragment
;
};
The method
property represents the discovery type that should be used
in the discovery process. The possible values are defined
by the
enumeration
that MAY be extended
by string values defined by solutions (with no guarantee of
interoperability).DiscoveryMethod
The url
property
represents additional information for the discovery method,
such as the URL of the target entity serving the discovery
request, for instance a Thing
Directory (if method
is
"directory"
) or a Thing (otherwise).
The query
property represents a query string accepted by the
implementation, for instance a SPARQL or JSON query.
Support may be implemented locally in the WoT Runtime or remotely as a service in a
Thing Directory.
The fragment
property
represents a ThingFragment
dictionary used for
matching property by property against discovered Things.
The discover(filter)
method MUST run the following steps:
discover()
is not allowed for
the current scripting context for security reasons, throw
SecurityError
and terminate these steps.Observable
obs and
execute the next steps in parallel.
obs.subscribe(handler, errorHandler,
complete)
is called, execute the following
sub-steps:
TypeError
and terminate the algorithm.
Otherwise configure handler to be invoked
when a discovery hit happens.TypeError
and terminate these steps.
Otherwise if defined, save it to be invoked in error
conditions.TypeError
and terminate these steps.
Otherwise if defined, save it to be invoked when the
discovery process finished for other reasons than
having been canceled.NotSupported
error and terminate these
steps.
ThingFragment
,
throw TypeError
and terminate these steps.
Otherwise save the object for matching the discovered
items against it.
"any"
, use the widest
discovery method supported by the underlying
platform.
"local"
, use the local Thing Directory for
discovery. Usually that defines Things deployed in the same device, or
connected to the device in slave mode (e.g.
sensors connected via Bluetooth or a serial
connection).
"directory"
, use the remote Thing Directory
specified in filter.url.
"multicast"
, use all the multicast
discovery protocols supported by the underlying
platform.false
, discard td and
continue the discovery process.false
in any checks, discard td
and continue the discovery process.Error
whose
message
property is set to
UnknownError
unless there was an error code
provided by the Protocol Bindings,
in which case set it to that value.
obs.unsubscribe()
method is
called, run the following cancel discovery steps:
false
.fetch()
methodAccepts an url
argument of type
USVString
that represents a URL (e.g.
"file://..."
or "https://..."
) and
returns a Promise
that resolves with a
ThingDescription
(a
serialized JSON-LD document of type
USVString
).
The fetch(url)
method MUST run the following steps:
Promise
promise and
execute the next steps in parallel.
fetch()
is not allowed for the
current scripting context for security reasons, reject
promise with SecurityError
and
terminate these steps.TypeError
and
terminate these steps.application/td+json
), as far
as a valid Thing Description
can be obtained as defined in [WOT-TD]. Let td
be the Thing Description
string-serialized from the returned content, as specified
in the
Thing Description serialization.
Error
object
error with error.message
set to
the error code seen by the Protocol Bindings and terminate
these steps.
consume()
methodAccepts an td
argument of type
and returns a
ThingDescription
ConsumedThing
object
instantiated based on parsing that description.
The consume(td)
method must run the following
steps:
TypeError
and terminate these steps.ThingFragment
with a default value,
add that property and value to stub.
ConsumedThing
object
thing initialized from stub that
implements Observable
.
read()
and write()
methods to the ThingProperty
elements so that they
make requests to access the remote Things and
wait for the reply, as defined by the Protocol Bindings. Also, all
ThingProperty
elements SHOULD
implement Observable
, i.e.
define a subscribe()
method that should make
request to observe the given Properties
as defined by the Protocol Bindings.
invoke()
methods to the ThingAction
elements so that they
make requests to the remote Thing to invoke its
actions, as defined by the Protocol
Bindings.
subscribe()
method to all
ThingEvent
elements
so that they make requests to subscribe to the events
defined by the remote Thing, as defined
by the Protocol Bindings.
produce()
methodAccepts a model
argument of type
and
returns an ThingModel
ExposedThing
object.
The produce(model)
method MUST run the following steps:
produce()
is not allowed for
the current scripting context for security reasons, throw
SecurityError
and terminate these steps.TypeError
and terminate these steps.ThingFragment
with a default value,
add that property and value to model.
ExposedThing
object thing
initialized from model.
ExposedThing
defined in ThingFragment
, initialize the
property based on the provided initial or default values
provided to the local WoT Runtime
implementation, for instance initialize:
id
property to be the final unique
identifier of the Thing,
security
object of type SecurityScheme
to
represent the actual security scheme and its properties
as set up by the implementation,
properties
property to be an
object with all properties being ThingProperty
objects in which the read()
and
write()
methods are provided to define
local methods to get and set the Property values,
actions
property to be an object
with all properties being ThingAction
objects in which the
invoke()
method is provided to define a
local method to run the defined Actions,
events
property to be an object
with all properties being ExposedEvent
objects in which
the emit()
method is provided to define a
local way to trigger sending notifications to all
subscribed clients,
The TD parsing algorithm takes a string td as argument and runs the following steps:
register()
methodTakes two mandatory arguments:
directory
denoting a Thing Directory, and
thing
denoting an ExposedThing
object.
Generate the Thing Description as
td, given the Properties, Actions and Events defined for
this ExposedThing
object.
Then make a request to register td to the given
WoT Thing Directory.
unregister()
methodTakes two mandatory arguments:
directory
denoting a Thing Directory, and
thing
denoting an ExposedThing
object.
Makes a request to unregister the thing
from
the given WoT Thing Directory.
let discoveryFilter = {
method: "directory",
url: "http://directory.wotservice.org"
};
let subscription = wot.discover(discoveryFilter).subscribe(
td => {
console.log("Found Thing " + td.name);
// fetch the TD and create a ConsumedThing
let thing = wot.consume(td);
},
error => { console.log("Discovery finished because an error: " + error.message); },
() => { console.log("Discovery finished successfully");}
);
setTimeout( () => {
subscription.unsubscribe();
console.log("Discovery timeout");
},
5000);
let subscription = wot.discover({ method: "local" }).subscribe(
td => { console.log("Found local Thing " + td.name); },
error => { console.log("Discovery error: " + error.message); },
() => { console.log("Discovery finished successfully");}
);
let subscription = wot.discover({ method: "local" }).subscribe({
td => { console.log("Found local Thing " + td.name); },
error: err => { console.log("Discovery error: " + err.message); },
complete: () => { console.log("Discovery finished successfully");}
});
ConsumedThing
interfaceRepresents an object that extends a ThingFragment
with methods for client
interactions (send request for reading and writing Properties), invoke Actions, subscribe and
unsubscribe for Property changes and Events.
interfaceConsumedThing
:ThingFragment
{ readonly attribute DOMStringid
; readonly attribute DOMStringname
; readonly attribute DOMString?base
; readonly attributePropertyMap
properties
; readonly attributeActionMap
actions
; readonly attributeEventMap
events
; // getter for ThingFragment properties getter any (DOMString name); }; [NoInterfaceObject] interfacePropertyMap
{ readonly maplike<DOMString,ThingProperty
>; }; [NoInterfaceObject] interfaceActionMap
{ readonly maplike<DOMString,ThingAction
>; }; [NoInterfaceObject] interfaceEventMap
{ readonly maplike<DOMString,ThingEvent
>; };ConsumedThing
includesObservable
; // for TD changes
The id
attribute
represents the unique identifier of the Thing instance,
typically a URI, IRI, or URN as USVString
.
The name
attribute
represents the name of the Thing as
DOMString
.
The base
attribute
represents the base URI that is valid for all defined local
interaction resources.
The properties
attribute represents a dictionary of ThingProperty
items. The
PropertyMap
interface
represents a maplike dictionary where all values are ThingProperty
objects. The
read()
and write()
methods make a
request to access the Properties on the remote
Thing represented by this ConsumedThing
proxy object.
The actions
attribute represents a dictionary of ThingAction
items. The
ActionMap
interface represents a
maplike dictionary where all values are ThingAction
objects. The
invoke()
method represents a request to invoke the
Action on the remote Thing.
The events
attribute represents a dictionary of ThingEvent
items. The EventMap
interface
represents a maplike dictionary where all values are ThingEvent
objects. Subscribing to the
events involves setting up an observation (subscription)
mechanism on the remote object.
Below a
interface example
is given.ConsumedThing
try {
let subscription = wot.discover({ method: "local" }).subscribe(
td => {
let thing = wot.consume(td);
console.log("Thing " + thing.name + " has been consumed.");
let subscription = thing["temperature"].subscribe(function(value) {
console.log("Temperature: " + value);
});
thing.actions["startMeasurement"].invoke({ units: "Celsius" })
.then(() => { console.log("Temperature measurement started."); })
.catch(e => {
console.log("Error starting measurement.");
subscription.unsubscribe();
})
},
error => { console.log("Discovery error: " + error.message); },
() => { console.log("Discovery finished successfully");}
);
} catch(error) {
console.log("Error: " + error.message);
};
ExposedThing
interfaceThe ExposedThing
interface is
the server API that allows defining request handlers,
properties, Actions, and Events to a
Thing. It also implements the Observable
interface. An ExposedThing
is created by the produce() method.
interfaceExposedThing
:ThingFragment
{ readonly attributePropertyMap
properties
; readonly attributeActionMap
actions
; readonly attributeExposedEvents
events
; // getter for ThingFragment properties getter any (DOMString name); // setter for ThingFragment properties setter void (DOMString name, any value); // methods to expose and destroy the Thing Promise<void>expose
(); Promise<void>destroy
(); // define PropertiesExposedThing
addProperty
(DOMString name,PropertyFragment
property, optional any initValue);ExposedThing
setPropertyReadHandler
(DOMString name,PropertyReadHandler
readHandler);ExposedThing
setPropertyWriteHandler
(DOMString name,PropertyWriteHandler
writeHandler);ExposedThing
removeProperty
(DOMString name); // define ActionsExposedThing
addAction
(DOMString name,ActionFragment
init,ActionHandler
action);ExposedThing
removeAction
(DOMString name);ExposedThing
setActionHandler
(DOMString name,ActionHandler
action); // define EventsExposedThing
addEvent
(DOMString name,EventFragment
event);ExposedThing
removeEvent
(DOMString name); }; [NoInterfaceObject] interfaceExposedEvents
{ maplike<DOMString,ExposedEvent
>; }; callbackPropertyReadHandler
= Promise<any> (); callbackPropertyWriteHandler
= Promise<void> (any value); callbackActionHandler
= Promise<any> (any parameters);
The properties
attribute represents a dictionary of ThingProperty
items in which the
read()
and write()
methods define
local methods that access the physical representations of the
Properties.
The actions
attribute represents a dictionary of ThingAction
items in which the
invoke()
method represents a local method to
invoke the Action.
The events
attribute represents a dictionary of ExposedEvent
items that add the
emit()
method to the ThingEvent
definition. The
ExposedEvents
interface
represents a maplike dictionary where all values are ExposedEvent
objects.
expose()
methodStart serving external requests for the Thing, so that WoT Interactions using Properties, Actions and Events will be possible.
The expose()
method MUST run the following steps:
Promise
promise and
execute the next steps in parallel.
expose()
is not allowed for
the current scripting context for security reasons, reject
promise with SecurityError
and
terminate these steps.Error
object
error with error.message
set to
the error code seen by the Protocol Bindings and terminate
these steps.
destroy()
methodStop serving external requests for the Thing and destroy the object. Note that eventual unregistering should be done before invoking this method.
The destroy()
method MUST run the following steps:
Promise
promise and
execute the next steps in parallel.
destroy()
is not allowed for
the current scripting context for security reasons, reject
promise with SecurityError
and
terminate these steps.Error
object
error with error.message
set to
the error code seen by the Protocol Bindings and terminate
these steps.
addProperty()
methodAdds a Property with name defined by the
name argument, the data schema provided by the
property argument of type PropertyFragment
, and optionally an
initial value provided in the argument initValue
whose type should match the one defined in the
type
property according to the value-matching algorithm. If
initValue is not provided, it SHOULD be initialized as
undefined
. Implementations SHOULD update the Thing Description. Throws on error. Returns a
reference to the same object for supporting chaining.
removeProperty()
methodRemoves the Property specified by the
name
argument and updates the Thing Description. Throws on error. Returns a
reference to the same object for supporting chaining.
addAction()
methodAdds to the actions
property of a Thing object an Action with name
defined by the name argument, defines input and
output data format by the init argument of type
ActionFragment
, and
adds the function provided in the action argument
as a handler, then updates the Thing Description. Throws on error. Returns a
reference to the same object for supporting chaining.
The provided action callback function will
implement invoking an Action and SHOULD be called by
implementations when a request for invoking the Action is received from the underlying platform.
The callback will receive a parameters
dictionary argument according to the definition in the
init.input argument and will return a value of
type defined by the init.output argument according
to the value-matching
algorithm.
There SHOULD be
exactly one handler for any given Action. If no
handler is initialized for any given Action,
implementations SHOULD throw a TypeError
.
removeAction()
methodRemoves the Action specified by the
name
argument and updates the Thing Description. Throws on error. Returns a
reference to the same object for supporting chaining.
addEvent()
methodAdds an event with name defined by the name
argument and qualifiers and initialization value provided by
the event argument of type EventFragment
to the Thing object and updates the Thing Description. Throws on error. Returns a
reference to the same object for supporting chaining.
removeEvent()
methodRemoves the event specified by the name
argument and updates the Thing
Description. Returns a reference to the same object for
supporting chaining.
PropertyReadHandler
callbackA function that is called when an external request for
reading a Property is received. It should
return a Promise and resolves it with the value of the
Property matching the name
argument to
the setPropertyReadHandler
function, or rejects
with an error if the property is not found or the value
cannot be retrieved.
PropertyWriteHandler
callbackA function that is called when an external request for
writing a Property is received. It is given
the requested new value
as argument and should
return a Promise which is resolved when the value of the
Property that matches the name
argument has been updated with value
, or rejects
with an error if the property is not found or the value
cannot be updated.
Note that this function is invoked by
implementations before the property is updated and it
actually defines what to do when a write request is
received. The code in this callback function can invoke the
read()
method to find out the old value of the
property, if needed. Therefore the old value is not
provided to this function.
ActionHandler
callbackA function called with a parameters
dictionary argument assembled by the WoT runtime based on the Thing Description and the external client request.
It returns a Promise that rejects with an error or resolves
if the action is successful or ongoing (may also resolve with
a control object such as an Observable
for actions that need
progress notifications or that can be canceled).
setPropertyReadHandler()
methodTakes name
as string argument and
readHandler
as argument of type PropertyReadHandler
.
Sets the handler function for reading the specified Property matched by name
. Throws on
error. Returns a reference to the same object for supporting
chaining.
The readHandler
callback function will
implement reading a Property and
SHOULD be called by
implementations when a request for reading a Property is received from the underlying
platform.
There SHOULD be at most one handler for any given Property and newly added handlers replace the old handlers. If no handler is initialized for any given Property, implementations SHOULD implement a default property read handler.
When an external request for reading Property propertyName is received, the runtime SHOULD execute the following steps:
Promise
promise and
execute the next steps in parallel.
ReferenceError
and
terminate these steps.
setPropertyWriteHandler()
methodTakes name
as string argument and
writeHandler
as argument of type PropertyWriteHandler
.
Sets the handler function for writing the specified Property matched by name
. Throws on
error. Returns a reference to the same object for supporting
chaining.
There SHOULD be at most one write handler for any given Property and newly added handlers replace the old handlers. If no write handler is initialized for any given Property, implementations SHOULD implement default property update and notifying observers on change.
When an external request for writing a Property propertyName with a new value value is received, the runtime SHOULD execute the following steps:
Promise
promise and
execute the next steps in parallel.
ReferenceError
and
terminate these steps.
setActionHandler()
methodTakes name
as string argument and
action
as argument of type ActionHandler
. Sets the handler
function for the specified Action matched by
name
. Throws on error. Returns a reference to
the same object for supporting chaining.
The action
callback function will implement
an Action and SHOULD be called by implementations when a
request for invoking the Action is received
from the underlying platform.
There SHOULD be at most one handler for any given Action and newly added handlers replace the old handlers.
When an external request for invoking the Action identified by name is received, the runtime SHOULD execute the following steps:
Promise
promise and
execute the next steps in parallel.
ReferenceError
and
terminate these steps.
ReferenceError
and terminate these steps.
Below some
interface examples
are given.ExposedThing
try {
var temperatureValueDefinition = {
type: "number",
minimum: -50,
maximum: 10000
};
var temperaturePropertyDefinition = temperatureValueDefinition;
// add the 'forms' property
temperaturePropertyDefinition.forms = [ ... ];
var thing = WoT.produce({
name: "tempSensor",
properties: {
temperature: temperaturePropertyDefinition
},
actions: {
reset: {
description: "Reset the temperature sensor",
input: {
temperature: temperatureValueDefinition
},
output: null,
forms: []
},
},
events: {
onchange: temperatureValueDefinition
},
links: []
});
await thing.expose();
await wot.register("https://mydirectory.org", thing);
// define Thing business logic
setInterval( async () => {
let mock = Math.random()*100;
let old = await thing["temperature"].read();
if (old < mock) {
await thing["temperature"].write(mock);
thing.emitEvent("onchange", mock);
}
}, 1000);
} catch (err) {
console.log("Error creating ExposedThing: " + err);
}
try {
var statusValueDefinition = {
type: "object",
properties: {
brightness: {
type: "number",
minimum: 0.0,
maximum: 100.0,
required: true
},
rgb: {
type: "array",
"minItems": 3,
"maxItems": 3,
items : {
"type" : "number",
"minimum": 0,
"maximum": 255
}
}
};
var statusPropertyDefinition = statusValueDefinition;
// add the 'forms' property
statusPropertyDefinition["forms"] = [];
var thing = WoT.produce({
name: "mySensor",
properties: {
brightness: {
type: "number",
minimum: 0.0,
maximum: 100.0,
required: true,
},
status: statusPropertyDefinition
},
actions: {
status: {
description: "Get status object",
input: null,
output: {
status : statusValueDefinition;
},
forms: []
},
},
events: {
onstatuschange: statusValueDefinition;
},
links: []
});
thing.expose().then(() => {
thing.register();
});
} catch (err) {
console.log("Error creating ExposedThing: " + err);
}
let thingDescription = '{ \
"name": "mySensor", \
"@context": [ "http://www.w3.org/ns/td",\
"https://w3c.github.io/wot/w3c-wot-common-context.jsonld" ],\
"@type": [ "Thing", "Sensor" ], \
"geo:location": "testspace", \
"properties": { \
"prop1": { \
"type": "number",\
"@type": [ "Property", "Temperature" ], \
"saref:TemperatureUnit": "degree_Celsius" \
} } }';
try {
// note that produce() fails if thingDescription contains error
let thing = WoT.produce(thingDescription);
// Interactions were added from TD
// WoT adds generic handler for reading any property
// define a specific handler for one property
let name = "examplePropertyName";
thing.setPropertyReadHandler(name, () => {
console.log("Handling read request for " + name);
return new Promise((resolve, reject) => {
let examplePropertyValue = 5;
resolve(examplePropertyValue);
},
e => {
console.log("Error");
});
});
thing.expose();
} catch(err) {
console.log("Error creating ExposedThing: " + err);
}
// fetch an external TD, e.g., to set up a proxy for that Thing
WoT.fetch("http://myservice.org/mySensor/description").then(td => {
// WoT.produce() ignores instance-specific metadata (security, form)
let thing = WoT.produce(td);
// Interactions were added from TD
// add server functionality
// ...
});
The [WOT-TD] specification defines the WoT information model, i.e. the data types and data structures used in WoT Interactions. In this API these definitions translate to dictionary objects that are extended with methods by the interfaces defined in this specification.
In order to avoid duplication of definitions, references to these data types and structures is defined in this section, but for their full description please refer to the Thing Description specification.
DataSchema
dictionary and its subclassesValue types basically represent types that may be used in
JSON object definitions and are used in ThingFragment
to define Properties, Events and Action parameters. Value types are represented as
dictionary objects whose properties and possible sub-classes
are defined in the
DataSchema section of [WOT-TD].
One property of all DataSchema
dictionary is the
type
property whose value is from a set of
enumerated strings defined in the DataSchema
section of [WOT-TD] and is referred as
DataType in
this specification.
Based on type
, the following sub-classes of
DataSchema
are defined in
[WOT-TD]: BooleanSchema, NumberSchema, IntegerSchema, StringSchema, ObjectSchema, ArraySchema.
SecurityScheme
dictionary
and its subclassesSecurity metadata is represented as dictionary objects whose properties and sub-classes are defined in the SecurityScheme section of [WOT-TD].
One property of the SecurityScheme
dictionary is the
scheme
property whose value is from a set of
enumerated strings defined in the
SecurityScheme section of [WOT-TD]. Based on type
,
multiple subclasses of SecurityScheme
are defined.
Link
dictionaryRepresents a Web Link with properties defined in the Link section of [WOT-TD].
Form
dictionaryRepresents metadata describing service details, with properties defined in the Form section of [WOT-TD].
InteractionFragment
dictionaryRepresents the common properties of WoT Interactions, one of Property,
Action or Event, as defined in the
InteractionPattern section of [WOT-TD]. Its subclasses are
referred as PropertyFragment
, ActionFragment
and EventFragment
.
PropertyFragment
dictionaryRepresents the Property interaction
data that initializes a ThingProperty
object. Its properties
are defined in the Property
and
InteractionPattern sections of [WOT-TD].
ActionFragment
dictionaryRepresents the Action interaction data that
initializes a ThingAction
object. Its
properties are defined in the Action
and
InteractionPattern sections of [WOT-TD].
EventFragment
dictionaryRepresents the Event interaction data that
initializes a ThingEvent
object. Its
properties are defined in the Event
section of [WOT-TD].
ThingFragment
dictionaryThe ThingFragment
dictionary is defined as Thing
in [WOT-TD]. It is a dictionary that
contains properties representing semantic metadata and
interactions (Properties, Actions and
Events). It is used for initializing an internal
representation of a Thing Description and
its properties may be used in ThingFilter
.
ThingDescription
typeSerialized representation of the Thing Description (a JSON-LD document).
In this version of the API, Thing Descriptions are represented
as an opaque USVString
that can be transmitted
between devices.
The data types and structures imported from [WOT-TD] are extended by this specification in order to provide the interfaces for WoT Interactions.
Every Thing describes its metadata as
defined in ThingFragment
, and basic
interactions defined as Properties, Actions and Events. The following interfaces are
used for representing these interactions.
Interaction
interfaceThe Interaction
interface
is an abstract class to represent Thing
interactions: Properties, Actions and
Events.
The InteractionFragment
dictionary holds the common properties of PropertyFragment
, ActionFragment
and EventFragment
dictionaries used for
initializing ThingProperty
, ThingAction
and ThingEvent
objects in a ThingFragment
dictionary used for
creating an ExposedThing
object.
interfaceInteraction
{ readonly attribute (Form
or FrozenArray<Form
>)forms
; };Interaction
includesInteractionFragment
;
The forms
read-only
property represents the protocol bindings initialization data
and is initialized by the WoT Runtime.
ThingProperty
interfaceThe ThingProperty
interface
is used in ConsumedThing
and
ExposedThing
objects to
represent Thing Property
interactions.
The PropertyFragment
dictionary is used for initializing Property objects
in a ThingFragment
dictionary used for creating an ExposedThing
object. It MUST implement one of the
DataSchema
dictionaries.
interfaceThingProperty
:Interaction
{ // getter for PropertyFragment properties getter any (DOMString name); // get and set interface for the Property Promise<any>read
(); Promise<void>write
(any value); };ThingProperty
includesPropertyFragment
;ThingProperty
includesObservable
;
The ThingProperty
interface
contains all the properties defined on PropertyFragment
as read-only
properties.
The type
read-only property represents the type definition for the
Property as a DataSchema
dictionary object.
The writable read-only property tells
whether the Property value can be updated. If it
is false
, then the set(value)
method SHOULD always
reject.
The observable read-only
property tells whether the Property supports
subscribing to value change notifications. If it is
false
, then the subscribe()
method
SHOULD always
fail.
The constant read-only property
- defined in DataSchema
- tells
whether the Property value is a constant. If
true
, the set()
and
subscribe()
methods SHOULD always fail.
The required read-only property
- defined in DataSchema
- tells
whether the Property should be always present on
the ExposedThing
object.
The read()
method will fetch the value of the Property.
Returns a Promise that resolves with the
value, or rejects with an error.
The
write()
method will attempt to set the value of
the Propertyspecified in the
value
argument whose type SHOULD match the one specified by the
type
property. Returns a Promise that
resolves on success, or rejects on an error.
ThingAction
interfaceinterfaceThingAction
:Interaction
{ Promise<any>invoke
(optional any inputValue); };ThingAction
includesActionFragment
;
The
invoke()
method when invoked, starts the
Action interaction with the input value provided by
the inputValue argument. If inputValue
is null
, the action does not take any arguments
and rejects if any arguments are provided. If the value is
undefined
, the action will ignore any arguments
provided. Otherwise the type of inputValue
SHOULD match the
DataSchema
definition in the
input
property. Returns a Promise that
will reject with an error or will resolve with a value of
type defined by the output
property.
ThingEvent
interfaceinterfaceThingEvent
:Interaction
{ };ThingEvent
includesEventFragment
;ThingEvent
includesThingProperty
;
Since ThingEvent
implements
Observable
through the ThingProperty
interface, event
subscription is done by invoking the subscribe()
method on the event object that returns a cancelable Subscription
.
ExposedEvent
interfaceinterface ExposedEvent
: ThingEvent
{
void emit
(any payload);
};
emit()
methodEmits an event that carries data specified by the
payload
argument.
The value-matching algorithm is applied to a
value input in relation to a valueType
property of type DataSchema
, for instance the
value
and type
properties of a
PropertyFragment
object, or the inputValue parameter to the
invoke()
method of a ThingAction
object in relation to the
same object. It executes the following steps:
false
.
"null"
: if value is
null
, return true
, otherwise
return false
."boolean"
: if value is either
true
or false
, then return
true
, otherwise return
false
."integer"
: if value is not an
integer type defined by the underlying platform (such as
long
or long long
), then return
false
, otherwise execute the following
sub-steps:
true
."number"
, if value is not an
integer or floating point type defined by the underlying
platform (such as long
or long
long
or double
), then return
false
, otherwise otherwise execute the
following sub-steps:
true
."string"
: if value is not a string
type defined by the underlying platform, then return
false
, otherwise return true
. In this
case the algorithm expects a third parameter
valueType.enum and runs the following
sub-steps:
"array"
, execute the following sub-steps:
false
.undefined
, return false
.null
, return true
(i.e. any
type is accepted as array element, including
heterogenous arrays).false
, then return
false
.
true
."object"
,
execute the following sub-steps:
Object
,
return false
.false
.null
, return true
(i.e.
accept any object value).false
.true
.This section is non-normative.
Observables are proposed to be included in ECMAScript and are used for handling pushed data associated with various possible sources, for instance events, timers, streams, etc. A minimal required implementation is described here.
This section is informal and contains rather laconic information for implementations on what to support for interoperability.
interfaceObservable
{Subscription
subscribe
(EventHandler handler, optionalErrorHandler
errorHandler, optionalOnComplete
onComplete); }; interfaceSubscription
{ voidunsubscribe
(); readonly attribute booleanclosed
; }; callbackEventHandler
= void (any value); callbackErrorHandler
= void (Error error); callbackOnComplete
= void ();
The following callbacks can be provided when subscribing to
an Observable
:
EventHandler
callback takes
the next sample for the data in the value
argument.ErrorHandler
callback takes
an error in the value
argument. It is called
when an error occurred in producing the data the client should
know about.OnComplete
callback is called
when the data source has finished sending values.Subscription
interfaceContains the closed
property of type boolean
that tells if the
subscription is closed or active.
Also, contains the unsubscribe
()
method that cancels the subscription, i.e. makes a request to
the underlying platform to stop receiving data from the
source, and sets the closed
property to
false
.
Observable
interfaceThe Observable
interface
enabled subscribing to pushed data notifications by the
subscribe
()
method:
In general the security measures taken to protect a WoT system will depend on the threats and attackers that system may face and the value of the assets needs to protect. 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-CONSIDERATIONS]. This section includes only normative recommendations relevant to the WoT Thing Description.
When designing new devices and services for use with the WoT, we have documented a set of best practices in [WOT-SECURITY-BEST-PRACTICES] that SHOULD be followed. This best-practices document may be updated as security measures evolve. Following these practices does not guarantee security, but it at least will help to avoid common known vulnerabilities and pitfalls.
Below are specific recommendations related to WoT runtime implementations:
Some additional specific recommendations relevant for WoT script developers:
The generic WoT terminology is defined in [WOT-ARCHITECTURE]: Thing, Thing Description (in short TD), Web of Things (in short WoT), WoT Interface, Protocol Bindings, WoT Runtime, Consuming a Thing Description, Thing Directory, WoT Interactions, Property, Action, Event etc.
JSON-LD is defined in [JSON-LD] as a JSON document that is augmented with support for Linked Data.
The terms URL and URL path are defined in [URL].
The following terms are defined in [HTML52] and are used in the context of browser implementations: browsing context, top-level browsing context, global object, incumbent settings object, Document, document base URL, Window, WindowProxy, origin, ASCII serialized origin, executing algorithms in parallel, queue a task, task source, iframe, valid MIME type.
A browsing context refers to the
environment in which Document objects are
presented to the user. A given browsing context
has a single WindowProxy
object, but it can have many Document
objects, with their associated Window
objects. The script execution context
associated with the browsing context identifies the
entity which invokes this API, which can be a web app, a
web page, or an iframe.
The term secure context is defined in [WEBAPPSEC].
Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError , script execution context, Promise, JSON, JSON.stringify and JSON.parse are defined in [ECMASCRIPT].
DOMString, USVString, ArrayBuffer, BufferSource and any are defined in [WEBIDL].
The algorithms utf-8 encode, and utf-8 decode are defined in [ENCODING].
IANA media types (formerly known as MIME types) are defined in RFC2046.
The terms hyperlink reference and relation type are defined in [HTML52] and RFC8288.
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, SHOULD, and SHOULD NOT are to be interpreted as described in [RFC2119].
This document defines conformance criteria that apply to a single product: the UA (user agent) that implements the interfaces it contains.
This specification can be used for implementing the WoT Scripting API in multiple programming languages. The interface definitions are specified in [WEBIDL].
The user agent (UA) may be implemented in the browser, or in a separate runtime environment, such as Node.js or 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].
This document serves a general description of the WoT Scripting API. Language and runtime specific issues are discussed in separate extensions of this document.
The following is a list of major changes to the document. For a complete list of changes, see the github change log. You can also view the recently closed issues.
The following problems are being discussed and need most attention:
ExposedThing
(https://github.com/w3c/wot-scripting-api/issues/45).
Special thanks to former editor Johannes Hund (until August 2017, when at Siemens AG) for developing this specification. Also, the editors would like to thank Dave Raggett, Matthias Kovatsch, Michael Koster and Michael McCool for their comments and guidance.