Creating a Web-Enabled IoT Device with Intel Edison

The Internet of Things is on everyone's lips these days, and
it makes tinkerers and programmers like me very excited. Nothing
is cooler than bringing your own inventions to life and
being able to talk to them!

But IoT devices that install apps that you rarely use can be annoying, so we
take advantage of upcoming web technologies such as the Physical
Web and Web Bluetooth to make IoT devices more intuitive and less intrusive.

Web and IoT, a match to be

There are still a lot of hurdles to overcome before Internet
of Things can be a huge success. One obstacle is companies and products
that require people to install apps for each device they purchase,
cluttering users' phones with a multitude of apps that
they rarely use.

For this reason, we are very excited about the
Physical Web
project, which allows devices to broadcast a URL to an online
website, in a non-intrusive way. In combinations with emerging
web technologies such as
Web Bluetooth,
Web USB and
Web NFC, the sites can
connect directly to the device or at least explain the proper
way of doing so.

Although we focus primarily on Web Bluetooth in this article, some
use cases might be better suited for Web NFC or Web USB. For example,
Web USB is preferred if you require a physical connection for security
reasons.

The website can also serve as a Progressive Web App (PWA).
We encourage readers to check out
Google's explanation
of PWAs. PWAs are sites that have a responsive, app-like user
experience, can work offline and can be added to the device home screen.

As a proof of concept, I have been building a small device using
the Intel® Edison Arduino breakout board. The device contains
a temperature sensor (TMP36) as well as an actuator (colored LED
cathode). The schematics for this device can be found at the end
of this article.

The Intel Edison is an interesting product because it can run a full Linux*
distribution. Therefore I can easily program it using
Node.js. The installer
lets you install the Intel* XDK which makes it easy to get started, although
you can program and upload to your device manually as well.

Note: It is possible to use Brillo* or Ostro* OS instead of the
default OS software. If you do, follow the Brillo or Ostro OS
documentation to get a Node.js application running on the
device.

For my Node.js app, I required three node modules, as well as their
dependencies:

eddystone-beacon

parse-color

johnny-five

The former automatically installs noble, which is the node module
that I use to talk via Bluetooth Low Energy.

Note: It is important to not list noble as a dependency in the
package.json file, as you need to use the same noble instance as
eddystone-beacon, for them to work together.
You can find more info here

Announcing the website

Beginning with version 49, Chrome on Android supports Physical Web, which
allows Chrome to see URLs being broadcasted by devices around it.
There are some requirements the developer must be aware of, like the need for
the sites need to be publicly accessible and use HTTPS.

That really couldn't be easier. You see in the image below that
Chrome finds the device nicely.

Note: The Physical Web enabled devices only show up on your phone
when Bluetooth is turned on, and you launch Chrome (currently only
works with Beta). Additionally, you have to opt into the feature
first time you launch Chrome beta.

Communicating with the sensor/actuator

We use Johnny-Five* to talk to our board
enhancements. Johnny-Five has a nice abstraction for talking to the TMP36
sensor.

Below you can find the simple code for being notified of temperature changes
as well as setting the initial LED color.

You can ignore the above *Characteristic variables for now; these
will be defined in the later section about interfacing with Bluetooth.

As you might notice in the instantiation of the Thermometer object, I talk to
the TMP36 via the analog A0 port. The voltage legs on the color
LED cathode are connected to digital pins 3, 5 and 6, which happen
to be the pulse-width modulation (PWM) pins on the Edison Arduino breakout
board.

Talking to Bluetooth

Talking to Bluetooth couldn't be much easier than it is with noble.

In the following example, we create two Bluetooth Low Energy
characteristics: one for the LED and one for the temperature sensor.
The former allows us to read the current LED color and set
a new color. The latter allows us to subscribe to temperature change events.

Initially I had some problems with the Bluetooth connection
being unstable, not working on every startup, or bailing
out with a Frame Reassemble failure while connecting.

If that happens, run the rfkill block bluetooth command, followed by
rfkill unblock bluetooth over the serial connection to make it
work again. The startup issue went away when I started powering the
device from a power supply instead of using USB for power.

If you encounter Frame Reassemble failures, reduce how often you send
temperature change events until you no longer encounter the failure.

Generally you should always use external power when using Bluetooth
or when you connect something like a servo to your board.

With noble, creating a characteristic is quite easy. All you need to do
is to define how the characteristic communicates and define a UUID. The
communication options are read, write, notify, or any combination thereof.
The easiest way to do this is to create a new object and inherit from
bleno.Characteristic.

Note: I am not using ES2016 here as the Edison SDK currently uses an older
version of Node.js.

With the newly launched Ostro Project
which supports the Edison, that is no longer the case. If you
use Brillo as part of the Brillo
Early Access Program, then it is possible to compile and install a
recent version of Node.js.

For "notify" we need to add a method to handle subscriptions and
unsubscription. Basically, we simply store a callback. When we
have a new temperature reason we want to send, we then call that
callback with the new value (encoded as above).

As values can fluctuate a bit, we need to smooth out the values we
get from the TMP36 sensor. I opted to simply take the average of
100 samples and only send updates when the temperature changes by
at least 1 degree.

That was the temperature sensor. The color LED is
simpler. The object as well as the "read" method are shown below.
The characteristic is configured to allow for "read" and "write"
operations and has a different UUID than the temperature characteristic.

The "write" method receives a string (just like "read" sends
a string), which can consist of a CSS color code (For example: CSS names
such as rebeccapurple or hex codes such as #ff00bb). I use a node
module called parse-color
to always get the hex value which is what Johnny-Five expects.

Creating the client web app

Without getting into too many defails about how the non-bluetooth
parts of the client app work, we can demonstrate a responsive user
interface created in Polymer*
as an example. The resulting app is shown below:

The right side shows an earlier version, that showcases a simple error
log that I added to ease the development.

Web Bluetooth makes it easy to communicate with Bluetooth Low Energy
devices, so let's look at a simplified version of my connection code.
If you don't know how promises work, check out
this resource
before reading further.

Connecting to a Bluetooth device involves a chain of promises.
First we filter for the device (UUID: FC00, name: Edison). This
displays a dialog to allow the user to select the device given the
filter. Then we connect to the GATT service and get the primary
service and associated characteristics, and then we read the
values and set up notification callbacks.

Note: To make successive read/writes in the promise chain happen
property, it is best practice to avoid fetching the characteristics
in parallel with something like Promise.all([p1, p2]).

The simplified version of our code below only works
with the latest Web Bluetooth API and therefore thus requires Chrome
Dev (M49) on Android.

Summary

That was it folks! As you can see, communicating with Bluetooth Low
Energy using Web Bluetooth on the client side and Node.js on the
Edison is quite easy and very powerful.

Using the Physical Web and Web Bluetooth, Chrome finds the
device and allows the user to easily connect to it without installing
seldom-used applications that the user may not want, and which may update
from time to time.

Demo

You can try the client to get
inspired about how can you create your own web apps to connect to
your custom Internet of Things devices.

Source code

The source code is available here.
Feel free to report issues or send patches.

Sketch

If you are really adventurous and want to reproduce what I have done,
refer to the Edison and breadboard sketch below: