October 3, 2018 | Lizzie Prader, Software Engineer
IMPORTANT: Web Thing API support in the Moddable SDK is deprecated as of August 28, 2019.
One of the issues that plagues IoT is the lack of standards for interoperability. There are too many IoT products that connect to only one cloud service or interoperate only with other products from the same company.
At Moddable we believe IoT products should be open and customizable by the end user. And we are not the only ones who feel this way—there is a Web of Things community that is working to find solutions to this problem based on existing and well-known web standards. One of the groups involved is Mozilla, which is known for its commitment to the open web. L..ast year, the Mozilla IoT team launched a Web of Things initiative with the goal of moving "towards a more decentralized Internet of Things that is safe, open and interoperable."
At the forefront of Mozilla's Web of Things initiative is Project Things, an experimental framework of software and services that aims to "bridge the communication gap between connected devices." For the past few months, we have been experimenting with two features of Project Things: the Web Thing API and the Things Gateway. This post describes these features in more detail and shares some of the example applications we have built by combining Project Things with the Moddable SDK.
The basic idea is as follows:

Standardizing the ways to communicate with devices has many obvious benefits. It makes it possible for users to control their devices using custom web apps, mobile apps, or other devices. Manufacturers can still provide default cloud services and apps, but an IoT product will not become a brick if those services and apps become unavailable. It also makes it possible for different companies to make products that interoperate with each other.
The Things Gateway searches for devices on the local network using mDNS. Note that the Web Thing API does not specify that Web Things must announce themselves as discoverable resources via mDNS, but doing so makes it easier to discover them in the gateway. There is currently no official documentation on how devices announce themselves, but this thread on GitHub explains how to do it. The Web Things module in the Moddable SDK takes care of this step for you automatically.
If a device does not automatically appear, you can manually search for it by clicking Add by URL... and entering the URL used to retrieve the description of it.
@type and @context parameters to provide more information about the device's properties and capabilities. You can read about these parameters in the Web Thing Description section of the Web Thing API. The Things Gateway checks for these parameters when it adds the device to your collection of Web Things and uses them to determine which icon to use in the Things tab and the style of other property controllers on the device's page.
For example, the OnOffLight class in the onOffLight example uses two of Mozilla's schemas—Light and OnOffSwitch—to describe itself:
class OnOffLight extends WebThing {
...
static get description() {
return {
"@context": "https://iot.mozilla.org/schemas",
"@type": ["Light", "OnOffSwitch"],
...
}
If you remove the @type and @context parameters from the OnOffLight description, it simply shows the default icon and you have to tap the
above its name to go to the device's page. This page has a controller for the on property.
You can also customize the icon manually if your device does not fit one of the Mozilla schemas.
If a device has more than one controllable property, the controllers are always on the device's page that you access by tapping the
.
The Things Gateway sends HTTP requests to the device to monitor and control it. You may note that commands sent from the gateway to devices are acted upon very quickly, but it sometimes takes a few seconds for the gateway's UI to update with the state change. This is because the device does not send an HTTP request to the gateway every time its state changes; the gateway polls to monitor the state of the device by sending an HTTP request every 5 seconds asking for its status.
This example may seem trivial, but this feature is a great example of how Mozilla's initiative is working towards openness and interoperability of devices. As long as two IoT products are compatible with the Gateway, they can be used with each other. And they can be used to add functionality to devices without any changes to the application code on the device.
Creating a Web Thing is a straightforward process. Start by editing the Web Things manifest.json so it includes your network credentials. This manifest is used by all of the examples to add the required network files and the Web Things module.
The Web Things module defines WebThing and WebThings classes that implement features that are common to all Web Things. For example, they set up the HTTP server and handle incoming requests.
The properties and functionalities of specific devices are defined in separate classes that extend the WebThing class. These are found in the main.js module of each example application.
Per the Web Thing API, every Web Thing must have a description property. The description is a JSON object that describes the device and its properties. Here's an example from the Web Thing API of a description for a basic on/off switch:
The switch in the onOffSwitch example has a similar description.
class OnOffSwitch extends WebThing {
...
static get description() {
return {
"@context": "https://iot.mozilla.org/schemas",
"@type": ["OnOffSwitch"],
name: "switch",
type: "onOffSwitch",
description: "On/off switch",
properties: {
on: {
type: "boolean",
description: "switch state",
}
}
}
}
}
@context and @type parameters, and the properties.onobject does not have an href parameter, which specifies the url to monitor/control a property. This is excluded because the Web Things module automatically adds an href parameter for each property.
Each property from the properties object in the description has its own getter and setter. The Web Things module calls these automatically when a request comes in to the device to read or write the property.
In this example, the getter simply returns the value of the property and the setter updates the value and distributes the onSwitchUpdate event to the application. The on-screen switch button updates accordingly when this event is triggered.
class OnOffSwitch extends WebThing {
...
get on() {
return this.state;
}
set on(state) {
if (this.state == state) return;
this.state = state;
application.distribute("onSwitchUpdate", state);
}
...
}
Stay tuned for a future post on our experiments with direct device-to-device communication using the Web Thing API and lessons we learned from using the Things Gateway.