Eclipse Thingweb node-wot
W3C Web of Things implementation on NodeJS.
Visit http://www.thingweb.io for a practical node-wot API usage, hands-on tutorials or additional information.
Useful labels: question | good first issue
Table of Contents
- License
- Implemented/supported features
- Prerequisites
- How to get the library
- No time for explanations - show me a running example!
- How to use the library
License
Dual-licensed under both
Pick one of these two licenses that fits your needs. Please also see the additional notices and how to contribute.
Implemented/supported features
Protocol Support
- HTTP
โ๏ธ - HTTPS
โ๏ธ - CoAP
โ๏ธ - CoAPS
โ๏ธ - MQTT
โ๏ธ - Firestore
โ๏ธ - Websocket
โ (Server only) - OPC-UA
โ (Client only) - NETCONF
โ (Client only) - Modbus
โ (Client only) - M-Bus
โ (Client only)
Note: More protocols can be easily added by implementing ProtocolClient
, ProtocolClientFactory
, and ProtocolServer
interface.
Note: the bindings for binding-fujitsu and binding-oracle were removed after v0.7.x
due to lack of maintainers.
MediaType Support
- JSON
โ๏ธ - Text (HTML, CSS, XML, SVG)
โ๏ธ - Base64 (PNG, JPEG, GIF)
โ๏ธ - Octet stream
โ๏ธ - CBOR
โ๏ธ - EXI
โฒ๏ธ
Note: More mediaTypes can be easily added by implementing ContentCodec
interface.
const ContentSerdes = require('@node-wot/core').ContentSerdes
const JsonCodec = require('@node-wot/core').JsonCodec
// e.g., assign built-in codec for *new* contentType
let cs = ContentSerdes.get();
cs.addCodec(new JsonCodec("application/calendar+json"));
// e.g., assign *own* MyCodec implementation (implementing ContentCodec interface)
cs.addCodec(new MyCodec("application/myType"));
Prerequisites
To use with Node.js
All systems require:
Linux
Meet the node-gyp requirements:
- Python v3.6, v3.7, or v3.8
- make
- A proper C/C++ compiler toolchain, like GCC
Windows
Install the Windows build tools through a CMD shell as administrator:
npm install -g --production windows-build-tools
WSL: Windows Services for Linux should follow Linux instructions.
Mac OS
Meet the node-gyp requirements:
xcode-select --install
To use in a browser
To use node-wot as a browser-side JavaScript Library, the browser needs to support ECMAScript 2015. Supported browsers include:
- Microsoft Edge 15 and later
- Firefox 54 and later
- Chrome 58 and later
- Safari 10 and later
Using a browser with only ES5 support (eg. IE 11) might be possible if you add polyfills.
How to get the library
As a Node.js dependency
You can install node-wot in the following ways:
- As a normal dependency (i.e., like loadsh). In this case, you are embedding a servient inside your application.
- As a CLI to run scripts. In this case, your application is running inside the default servient.
Normal Dependency
If you want to use node-wot as a library in your Node.js application, you can use npm to install the node-wot packages that you need. To do so, cd
inside you application folder, and run:
npm i @node-wot/core @node-wot/binding-http --save
Now, you can implement a thing as follows:
// server.js
// Required steps to create a servient for creating a thing
const Servient = require('@node-wot/core').Servient;
const HttpServer = require('@node-wot/binding-http').HttpServer;
const servient = new Servient();
servient.addServer(new HttpServer());
servient.start().then((WoT) => {
// Then from here on you can use the WoT object to produce the thing
// i.e WoT.produce({.....})
});
A client consuming a thing can be implemented like this:
// client.js
// Required steps to create a servient for a client
const { Servient, Helpers } = require("@node-wot/core");
const { HttpClientFactory } = require('@node-wot/binding-http');
const servient = new Servient();
servient.addClientFactory(new HttpClientFactory(null));
const WoTHelpers = new Helpers(servient);
WoTHelpers.fetch("http://localhost:8080/example").then(async (td) => {
try {
servient.start().then(async (WoT) => {
// Then from here on you can consume the thing
// i.e let thing = await WoT.consume(td) ...
});
}
catch (err) {
console.error("Script error:", err);
}
}).catch((err) => { console.error("Fetch error:", err); });
You can then start the applications with node by running node server.js
and node client.js
.
CLI Tool
You can alternatively use node-wot via its command line interface (CLI). Please visit the CLI tool's Readme to find out more.
As a standalone application
Clone and build
Clone the repository:
git clone https://github.com/eclipse-thingweb/node-wot
Go into the repository:
cd thingweb.node-wot
Install root dependencies (locally installs tools such as typescript):
npm ci
Use tsc
to transcompile TS code to JS in dist directory for each package:
Note: This step automatically calls npm run bootstrap
.
npm run build
Optional steps
Link Packages
Make all packages available on your local machine (as symlinks). You can then use each package in its local version via npm link <module>
instead of npm install <module>
(see also https://docs.npmjs.com/cli/link).
sudo npm run link
(On Windows omit sudo
)
Link Local wot-typescript-definitions
To evolve the Scripting API in development, you need to use a locally changed version of the wot-typescript-definitions. Use npm link for this as well:
git clone https://github.com/w3c/wot-scripting-api/
cd wot-scripting-api/typescript/
sudo npm link
(On Windows omit sudo
)
In each node-wot package, link the local version made available in the previous step:
sudo npm link wot-typescript-definitions
(On Windows omit sudo
)
Optimization
To reduce the size of the installation from about 800 MByte down to about 200 MByte, you can run the following commands (currently only tested on Linux):
npm prune --production
Trouble shooting
- Build error about
No matching version found for @node-wot/...
or something aboutmatch
- try
npm run unlock
from project root before building
- try
sudo npm run link
does not work- try
npm run unlock
from project root before calling[sudo] npm run link
- try
npm link
in each package directory in this order: td-tools, core, binding-*, cli, demo-servients
- try
- Error mesage for
npm link @node-wot/<module>
ELOOP: too many symbolic links encountered, stat '/usr/lib/node_modules/@node-wot/<module>
- Run
npm run link
inthingweb.node-wot
again - Remove
node_modules
in the targeted project - Remove all
@node-wot/<module>
dependencies in yourpackage.json
- Run
npm i
again - Install the packages with
npm link @node-wot/<module>
- Run
- Build error around
prebuild: npm run bootstrap
- This has been seen failing on WSL. Try using a more recent NodeJS version
As a Docker image
Alternatively, node-wot can be built as a Docker image with the Dockerfile
.
Make sure you are under linux or under WSL if you are running on Windows.
Clone the repository:
git clone https://github.com/eclipse-thingweb/node-wot
Go into the repository:
cd thingweb.node-wot
Build the Docker image named wot-servient
from the Dockerfile
:
npm run build:docker
Run the wot-servient as a container:
docker run --rm wot-servient -h
As a browser library
node-wot can also be imported as browser-side library. To do so, include the following script
tag in your html:
<script src="https://cdn.jsdelivr.net/npm/@node-wot/browser-bundle@latest/dist/wot-bundle.min.js"></script>
In the browser, node wot only works in client mode with limited binding support. Supported bindings: HTTP / HTTPS / WebSockets You can access all node-wot functionality through the "Wot" global object:
var servient = new Wot.Core.Servient();
var client = new Wot.Http.HttpClient();
No time for explanations - show me a running example!
Using Node.js
Run all the steps above including "Link Packages" and then run this:
wot-servient -h
cd examples/scripts
wot-servient
Without the "Link Packages" step, the wot-servient
command is not available and node
needs to be used (e.g., Windows CMD shell):
# expose
node packages\cli\dist\cli.js examples\scripts\counter.js
# consume
node packages\cli\dist\cli.js --client-only examples\scripts\counter-client.js
- Go to http://localhost:8080/counter and you'll find a thing description
- Query the count by http://localhost:8080/counter/properties/count
- Modify the count via POST on http://localhost:8080/counter/actions/increment and http://localhost:8080/counter/actions/decrement
- Application logic is in
examples/scripts/counter.js
Using Docker
First build the docker image and then run the counter example:
# expose
docker run -it --init -p 8080:8080/tcp -p 5683:5683/udp -v "$(pwd)"/examples:/srv/examples --rm wot-servient /srv/examples/scripts/counter.js
# consume
docker run -it --init -v "$(pwd)"/examples:/srv/examples --rm --net=host wot-servient /srv/examples/scripts/counter-client.js --client-only
- The counter exposes the HTTP endpoint at 8080/tcp and the CoAP endpoint at 5683/udp and they are bound to the host machine (with
-p 8080:8080/tcp -p 5683:5683/udp
). - The counter-client binds the network of the host machine (
--net=host
) so that it can access the counter thing's endpoints. --init
allows the containers to be killed with SIGINT (e.g., Ctrl+c)-v "$(pwd)"/examples:/srv/examples
mounts theexamples
directory to/srv/examples
on the container so that the node inside the container can read the example scripts.
Using a browser
An example of how to use node-wot as a browser-side library can be found under examples/browser/index.html
.
To run it, open examples/browser/index.html
in a modern browser, and consume the test Thing available under http://plugfest.thingweb.io:8083/testthing
to interact with it.
The JavaScript code that uses node-wot as a library to power this application can be found under: examples/browser/index.js
Online Things
We offer online simulated Things that are available to be used by anyone.
Their TDs are available at the following links:
- Counter: HTTP at http://plugfest.thingweb.io:8083/counter and CoAP at coap://plugfest.thingweb.io:5683/counter
- Smart Coffee Machine: HTTP at http://plugfest.thingweb.io:8083/smart-coffee-machine and CoAP at coap://plugfest.thingweb.io:5683/smart-coffee-machine
- TestThing: HTTP at http://plugfest.thingweb.io:8083/testthing and CoAP at coap://plugfest.thingweb.io:5683/testthing
All of them require no security mechanism to be communicated with and have same behavior from CoAP or HTTP endpoints. Below are small explanations on what they can be used for:
- Counter: It has a count property that can be read or observed and can be incremented or decremented via separate actions. It is also possible to reset the count the value, obtain when the last change occured, subscribe to a change in the count value or get the count value as an image.
- TestThing: This Thing exists primarily for testing different data schemas and payload formats. It also has events attached to affordances that notify when a value changes.
- Smart Coffee Machine: This is a simulation of a coffee machine that also has a simple user interface that displays the values of properties.
In addition to proving a real life device example, it can be used for testing
uriVariables
. You can ask it to brew different coffees and monitor the available resource level.
How to use the library
The API
This library implements the WoT Scripting API:
- Editors Draft in master
- Working Draft corresponding to node-wot release versions
Additionally, you can have a look at our API Documentation.
To learn by examples, see examples/scripts
to have a feeling of how to script a Thing or a Consumer.
TD Tooling
The package td-tools provides utilties around ThingDescription (TD) tooling:
- ThingDescription (TD) parsing
- ThingModel (TM) tooling
- Asset Interface Description (AID) utility
- ...
Logging
Logging in node-wot is implemented via the debug
package.
This allows users to enable log messages for specific logging levels (info
, debug
, warn
, or error
) or packages.
Which log messages are emitted is controlled by the DEBUG
environment variable.
In the following, we will show a couple of examples for its usage using wildcard characters (*
).
Note, however, that the syntax for setting an environment variable depends on your operating system and the terminal you use.
See the debug
documentation for more details on platform-specific differences.
First, you can enable all log messages by setting DEBUG
to a wildcard like so:
DEBUG=* npm start
To only show node-wot
-specific logging messages, prefix the wildcard with node-wot
:
DEBUG=node-wot* npm start
To only show a specific log level, use one of info
, debug
, warn
, or error
as the suffix.
Note in this context that you can provide multiple values for DEBUG
.
For example, if you want to show only debug
and info
messages, you can use the following:
DEBUG='*debug,*info' npm start
Finally, you can choose to only display log messages from a specific node-wot
package.
For example, if you only want to see log messages for the core
package, use the following:
DEBUG=node-wot:core* npm start
Using the log levels above, you can also apply more fine-grained parameters for logging.
For instance, if you only want to see error
messages from the binding-coap
package, use this:
DEBUG=node-wot:binding-coap*error npm start
Install new/different versions of NodeJS
Using NPM, you can install NodeJS independent from the usually outdated package managers such as apt. This is nicely done by n:
sudo npm cache clean -f
sudo npm install -g n
To get the "stable" version:
sudo n stable
To get the "latest" version:
sudo n latest
Finally, make the node command available through:
sudo ln -sf /usr/local/n/versions/node/<VERSION>/bin/node /usr/bin/node
Development Internals
details
Publishing on NPM
Run npm publish --workspaces
in root node-wot folder.
Regenerating package-lock.json
- Delete
package-lock.json
file - Delete any local cache (like
node_modules
folders etc.) - Run
npm install
- Run
npm dedupe
(see #765 (comment))