Skip to content
Philippe Coval edited this page Oct 10, 2018 · 88 revisions

WEBTHING-IOTJS

GitHub forks

INTRODUCTION:

For more insights on this "Privacy by design" Thing project, read Concept page.

In 2017 Mozilla announced intentions to provide a framework to connect “things” to the web in a safe, secure and interoperable way.

ProjectThings

In early 2018 Gateway was released to public and SDK to connect things to it.

So called Webthings are serving resources using Web technologies (WebOfThings or WoT).

Several languages are supported (including javascript):

Node.js is used to build and run WebThings that are designed to be connected to Gateway and controled by only owner or eventually shared.

Technically Node.js is working fine a many single board computers running on GNU/Linux like popular RaspberryPi or high range ARTIK boards (5, 10, 7 etc but not 0 series).

Mozilla is also supporting low range MCU like Arduino or ESP but using baremetal development (using a different language: C/C++).

Webthing-iotjs project is trying to support both range of devices with the same code base, this is possible thanks to IoT.js runtime powered by Jerryscript engine targeting constrained devices for IoT applications.

Javascript4IoT

As IoT.js tries to mimic Node.js, this Webthing library wants to stay aligned to webthing-node (designed for Node.js) too, so webthing-node was forked into webthing-iotjs and then adapted for IoT.js runtime.

Although it is functional, it has some limitations that worth to be known:

  • MDNS is not supported yet, so no auto discovery of devices so URL should be added from UI.
  • Websockets are not implemented yet, while IoT.js recently introduced WS, it's not used yet.
  • Actions and Events are also dropped (it's not critical for basic use).

It can run on many devices such as regular Linux system but maybe not your favorite MCU other MCU/MPU target to consider is ARTIK05x, as shown at end of demo, you could try to compare to Arduino, but I wouldn't dare.

ARTIK05x are running full featured OS, called TizenRT, don't confuse with Linux based Tizen, this one has a different kernel and is targeting lower class architectures.

One key feature of TizenRT is "native javascript" support, using JerryScript and IoT.js runtime.

Because IoT.js tries to align the most to nodejs's design and conventions I was tempted to try to port the Mozilla's webthing-node SDK to IoT.js and it worked!

Note that features were removed, and the code has been downgraded to earlier ECMA standards, since the code base was very small that task was partiatly done manually and then helped by babel transpiler.

ARTIK05x

DEMO:

For Demo Concept and Architecture overview, please visit Concept page

Watch this short video about different webthings working along:

web-of-things-agriculture-20180712rzr.webm

Many components were demonstrated as proof of Concept, each will be documented separately:

  • Gateway: using mozilla-iot-gateway on RaspberryPI (or ARTIK7)
  • Social: mastodon-lite running on IoT.js (notification alert on RaspbberyPi)
  • TizenRT: webthing-iotjs running on ARTIK05x (LEDs at end of video)
  • Sensor: webthing-node used to monitor the clap Sensor (on RaspbberyPi/Linux)
    • Also mozilla-iot-generic-sensor-adapter is used for AmbientLight and Temperature on (RaspberryPi I2C)
  • MCU: webthing-arduino for moisture sensor and RGB lamp on ESP8266,
  • WebApp: webthings-webapp as standalone WebApp, for browsers supporting PWA (SamsungInternet), or Tizen/WGT local app.

This Web of Thing demo "world first smart orchid ever" is not that new, I am sure but I hope those hints will inspire you to create different projects, let it know.

USAGE:

  • Setup Gateway as explained at: https://iot.mozilla.org/gateway/
  • Add thing URL adapter
  • Deploy iotjs on supported devices
  • Run webthing example on target device
  • Add thing by URL from gateway's UI
    • Enter URL: $ip:$port (conventionally 8888, because 80 can overlap of need privileges)
    • Press "Submit", "Save", then "Done"

Note: if no "Done" button visble at bottom of page. just click on the "back" arrow, to show the thing's icon on dashboard:

See next chapters for details.

USING IOTJS ON GNU/LINUX:

Only snapshot version is currently supported, if using GNU/Linux rebuild it from scratch or install snapshot debian packages:

IOTJS ON DEBIAN:

Even if iotjs-1.0 landed in debian (and derived: Ubuntu, Raspbian):

We'll use a snapshot version ( to enable all features in full profile )

The snapshot package can be installed from community repo:

To avoid rebuilding let's add a third party source and install snapshot package (that would eventually "downgrade" iotjs to unreleased version):

sudo sync 
sudo apt-get update -y
sudo apt-get install -y gnupg
cat /etc/os-release
distro="Debian_9.0" # TODO: or adapt to supported OS
url="http://download.opensuse.org/repositories/home:/rzrfreefr:/snapshot/$distro"
file="/etc/apt/sources.list.d/org_opensuse_home_rzrfreefr_snapshot.list"
echo "deb [allow-insecure=yes] $url /" | sudo tee "$file"
curl "$url/Release.key" | apt-key add -
sudo apt-get update -y
apt-cache show iotjs
apt-cache show iotjs-snapshot
package=iotjs
version=$(apt-cache show "$package-snapshot" | grep 'Version:' | cut -d' ' -f2 | sort -n | head -n1 || echo 0)
sudo apt-get install -y --allow-downgrades --allow-unauthenticated \
  ${package}-snapshot="$version" ${package}="$version"
dpkg-query --list 'iotjs' # Should print a 0.0* version

You can check if IoT.js is properly installed using:

cat example.js
console.log(process);

iotjs example.js

It will just log some environment info:

{
  "env": {
    "HOME": "/home/rzr",
    "IOTJS_PATH": "",
    "IOTJS_ENV": "",
    "IOTJS_EXTRA_MODULE_PATH": "",
    "IOTJS_WORKING_DIR_PATH": ""
  },
  "builtin_modules": {
    "adc": true,
// (...)
}
iotjs example/simplest-thing.js 
# Usage:
# 
# iotjs example/simplest-thing.js [port]
# 
# Try:
# curl -X PUT -H 'Content-Type: application/json' --data '{"on": true }' http://localhost:8888/properties/on

In other shell, you can query the thing description with a single HTTP request:

curl http://localhost:8888 | jq

{
  "name": "ActuatorExample",
  "href": "/",
  "@context": "https://iot.mozilla.org/schemas",
  "@type": [
    "OnOffSwitch"
  ],
  "properties": {
    "on": {
      "@type": "OnOffProperty",
      "label": "On/Off",
      "type": "boolean",
      "description": "Whether the output is changed",
      "href": "/properties/on"
    }
  },
  "links": [
    {
      "rel": "properties",
      "href": "/properties"
    }
  ],
  "description": "An actuator example that just log"
}

The description is composed of a name, type and a single property which can be read used using HTTP GET verb:

curl http://localhost:8888/properties/on
# {"on": true}

Or changed using HTTP PUT verb:

curl -X PUT -H 'Content-Type: application/json' --data '{"on": false }' http://localhost:8888/properties/on
# {"on":false}

Then check more advanced examples:

  • single-thing: simulating a lamp
  • multiple-things: simulating a humidity Sensor:
iotjs example/multiple-things
# setting new humidity level: 2.5340406503664528
# setting new humidity level: 3.0056843458792635
# (...)

WEBTHING-IOTJS ON RASPBIAN:

Raspbian is a fork of Debian OS recompiled for Raspberry Pi

Just install IoT.js snapshot package like we did for Debian but using this repository as source:

Precompiled package can be installed to system using those commands:

url='https://dl.bintray.com/rzr/raspbian-9-armhf'
source="/etc/apt/sources.list.d/bintray-rzr-raspbian-9-armhf.list"
package="iotjs"

echo "deb [allow-insecure=yes] $url raspbian main" | sudo tee "$source"
sudo apt-get update -y
apt-cache search ${package}
version=$(apt-cache show "$package" | grep 'Version:' | cut -d' ' -f2 | sort -n | head -n1 || echo 0)
sudo apt-get install -y --allow-downgrades --allow-unauthenticated \
  ${package}-snapshot="$version" ${package}="$version"
dpkg-query --list 'iotjs' # Should print a 0.0* version

/usr/bin/iotjs
# Usage: iotjs [options] {script | script.js} [arguments]

Note that snapshots packages' versions are in 0.0.* form, because we don't want to upgrade automatically released versions of iotjs if previously installed.

Then we can run a webthing server, this one is simulating a switch actuator that can be changed with HTTP PUT request:

iotjs  example/simplest-thing

curl -X PUT -H 'Content-Type: application/json' --data '{"on": false }' http://localhost:8888/properties/on
# {"on":false}

curl http://localhost:8888/properties/on
# {"on":false}

Back to the "Smart Orchid" demo, while showing interactions between the RaspberryPi's button and ARTIK05x's on board LED (also running an a webthing-iot on TizenRT.

Note that when real time monitoring is needed (for Sensors) you may consider to use webthing-node which is fully supporting websockets. this is demonstrated by "Clap Sensor" part of "Smart Orchid" demo

More details how to run or rebuild IoT.js at:

WEBTHING-IOTJS ON DOCKER:

For developer convenience previous instructions are also verified in a Docker container:

sudo apt-get install docker.io docker-compose # Or adapt for non Debian based OS
# sudo=sudo # if docker not configured for user
project="webthing-iotjs"
url="https://github.com/rzr/${project}"
branch="master"
git clone --recursive --depth 1 -b "$branch" "$url" ; cd "$project"
time $sudo docker-compose up 

Expected log (once log is flushed TODO):

Creating network "webthingiotjs_default" with the default driver
Building web
Step 1/16 : FROM debian:9
(...)
+ sudo apt-get install -y --allow-unauthenticated iotjs-snapshot=0.0+1.0+548+g44cda409-0~rzr0+1.0+635+gf5f1e5e8 iotjs=0.0+1.0+548+g44cda409-0~rzr0+1.0+635+gf5f1e5e8
(...)
Step 12/15 : RUN echo "#log: ${project}: Preparing sources"   && set -x   && make setup   && make   && make check   && sync
 ---> Running in b69facc67b6e
+ make setup
#log: webthing-iotjs: Preparing sources
iotjs -h || echo "log: Should have printed iotjs's usage..."
Usage: iotjs [options] {FILE | FILE.js} [arguments]
(...)
 ---> Running in d2428c8468b8
Removing intermediate container d2428c8468b8
 ---> de6408a5d31f
Successfully built de6408a5d31f
Successfully tagged webthingiotjs_web:latest
Creating webthingiotjs_web_1 ... 
Creating webthingiotjs_web_1 ... done
Attaching to webthingiotjs_web_1
web_1  | iotjs example/multiple-things.js
web_1  | setting new humidity level: 8.178182286316906
web_1  | setting new humidity level: 3.371208683777668
web_1  | setting new humidity level: 22.527728818490377

It is working the same as webthing-node's project.

For reference check docker file source:

IOTJS ON ARTIK530 OR 710:

Several OS are supported on this device, mine was on Fedora-24, now support moved to Ubuntu, some might also use Tizen too.

So for now we'll use Debian in a docker container mounted on external USB disk (4GB)

cat /etc/os-release # PRETTY_NAME="Fedora 24 (Twenty Four)"
sudo=sudo # Or configure your sudoers
$sudo sync

$sudo dnf install docker docker-compose screen time git etckeeper jq
screen # Press "Ctrl+a c" : to open a new terminal

$sudo systemctl stop docker
lsblk # Bottom USB slot is sda
disk="/dev/sda" # TODO: update if needed (ie: /dev/disk/by-id/usb-*)
mnt="/var/lib/docker"
$sudo mkfs.ext4 -L webthings "$disk" # TODO: verify $part variable

$sudo mkdir -p "$mnt"
$sudo mount "$disk" "$mnt"
$sudo systemctl restart docker
$sudo docker version # docker-common-1.10.3-55.gite03ddb8.fc24.armv7hl
cd "$mnt"

Then build container and start service (~500 Mb will be used):

project="webthing-iotjs"
board="artik530"
image="arm32v7/debian"
url="https://github.com/rzr/${project}"
branch="master"

git clone --recursive --depth 1 -b "$branch" "$url" && cd "$project"
sed -e "s|^FROM .*|FROM $image|g" -i Dockerfile

$sudo systemctl restart docker
time docker rm "${project}" ||:
time docker build -t "${USER}/${project}" . # <20min
time docker run -t \
  --volume /sys:/sys --publish 8888:8888 --net "host" \
  --name "${project}" --rm \
  "${USER}/${project}" start/board/${board}

Expected log:

/usr/bin/make -C example/platform board/artik530

(...)
sudo cat /sys/kernel/debug/gpio
(...)
gpio-28  (                    |sysfs               ) out hi
gpio-30  (                    |sysfs               ) in  hi
(...)
Usage: iotjs [options] {FILE | FILE.js} [arguments]
(...)
iotjs index.js artik530
log: board: artik530: Loading
(...)
curl -H "Accept: application/json" http://localhost:8888
(...)
log: board: artik530: Started

Test in an other shell:

curl http://${HOSTNAME}.local:8888 # | jq
{
  "name": "ARTIK530",
  "href": "/",
  "@context": "https://iot.mozilla.org/schemas",
  "@type": [],
  "properties": {
    "RedLED": {
      "@type": "OnOffProperty",
      "label": "On/Off: RedLED",
      "type": "boolean",
      "description": "Red LED on interposer board (on GPIO28)",
      "href": "/properties/RedLED"
    },
    "BlueLED": {
      "@type": "OnOffProperty",
      "label": "On/Off: BlueLED",
      "type": "boolean",
      "description": "Blue LED on interposer board (on GPIO38)",
      "href": "/properties/BlueLED"
    },
    "Up": {
      "@type": "BooleanProperty",
      "label": "On/Off: Up",
      "type": "boolean",
      "readOnly": true,
      "description": "SW403 Button: Nearest board edge, next to red LED (on GPIO30)",
      "href": "/properties/Up"
    },
    "Down": {
      "@type": "BooleanProperty",
      "label": "On/Off: Down",
      "type": "boolean",
      "readOnly": true,
      "description": "SW404 Button: Next to blue LED (on GPIO32)",
      "href": "/properties/Down"
    },
    "ADC0": {
      "@type": "LevelProperty",
      "label": "Level: ADC0",
      "type": "number",
      "readOnly": true,
      "description": "Analog port of ARTIK05x",
      "href": "/properties/ADC0"
    },
    "ADC1": {
      "@type": "LevelProperty",
      "label": "Level: ADC1",
      "type": "number",
      "readOnly": true,
      "description": "Analog port of ARTIK05x",
      "href": "/properties/ADC1"
    }
  },
  "links": [
    {
      "rel": "properties",
      "href": "/properties"
    }
  ],
  "description": "A web connected ARTIK530 or ARTIK720"
}

This time a new example is running, it is implenting Hardware Input/Output (GPIO) of the device itself.

Once connected to the Gateway using Gateway's thing URL adapter), user can log in the UI or WebApp and then control "on board" LEDs and monitor Buttons & ADC sensors.

artik710

Status: Merged upstream in webthing-node

Note, that we overrode the image because iotjs's snapshot is not supporting armel, but armhf or x86 etc. Debian:9 armv7l is supported and for Ubuntu you could build iotjs in container.

TODO: Check current schemas (buttons, ...):

Related links:

More info about this device:

WEBTHING-IOTJS ON INTEL EDISON:

You can also try a blinky example on Intel Edison (x86) on Jubilinux (a community Debian port) by following instructions on this blog post:

For reference the simplest thing was used as base to manage GPIO (as output):

webthing-iotjs-20180621rzr

IOTJS ON TIZENRT:

Check TizenRT page for detailed instructions to deploy on ARTIK05x devices.

USING NODEJS:

Generic code is also compatible with nodejs, and IO modules (Sensor) can be stubbed.

For future I plan to try align IoT.js API for IO modules for node, or provide wrappers, to be tracked:

EXTRA:

Here are Extra hints for demos parts not specific to IoT.js:

  • Web App : Tizen apps or PWA apps using SamsungInternet for Android
  • Sensor : Using sensors as adapter or webthings
  • MCU : Other microcontrolers like Arduino or ESP8266
  • Social : Notification service using W3C ActivityPub and Mastodon FLOSS

STATUS:

IoT.js port of webthing node is published at:

Current base is webthing-node-0.7.0 and it will be continuously rebased until next release: So for now consider this master branch unstable.

TODO:

RESOURCES:

LICENSE: CC-BY-SA-4.0

INDEX

Clone this wiki locally