AWS IoT and Node.js on the Raspberry Pi

There are many approaches for installing node.js on the Raspberry Pi (Google and you’ll find lots of guides), presumably because for a while there didn’t seem to be any official binaries in the official apt repos so people were building and sharing their own.

I installed a version from somewhere (can’t actually remember where as it was a while back) and it doesn’t support ES6 class syntax used by some of the dependent libraries in the AWS IoT SDK:

$ node index.js
/home/pi/aws-iot-nodejs-pi-lights/node_modules/aws-iot-device-sdk/node_modules/mqtt/node_modules/websocket-stream/server.js:6
class Server extends WebSocketServer{
^^^^^
SyntaxError: Unexpected reserved word
    at Module._compile (module.js:439:25)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (/home/pi/aws-iot-nodejs-pi-lights/node_modules/aws-iot-device-sdk/node_modules/mqtt/node_modules/websocket-stream/index.js:2:14)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)

The version I currently have installed is:

pi@raspberrypi:~ $ node -v
v0.10.29

Since I’m not sure where this version came from originally, (and apt-get upgrade is not finding any updates), I uninstalled:

sudo apt-get remove nodejs
sudo apt-get remove npm

Then I followed the steps in the AWS IoT SDK guide here to install using the version provided from Adafruit’s repo  (official node.js binaries for ARM are also available from nodejs.org here).

With version provided from Adafruit, this gives v 0.12.6 but unfortunately this still gives the same error with the ES6 class keyword.

$ node -v
v0.12.6

Next, lets try the ARM version from nodejs.org. There’s step by step instructions here showing how to download the tar, extract and copy to /usr/local/

Now we have:

$ node -v
v8.9.1

And now trying to run my AWS IoT node.js based app, success!

 

 

Homebrew contest 1st place: Packet Radio Go-Kit with node.js Packet to Twitter bridge

Super excited (and rather surprised!) to win the 1st place prize in the Homebrew Contest at this month’s River City Amateur Radio Communications Society club meeting last night!

My entry was something I’ve been working on over the past few months on and off to get ready in time for this month’s contest. There were two parts to my entry:

1. A self-contained, portable 2m Packet Radio Go-Kit. I put this together using:

  • 10″ waterproof gear case (from MCM)
  • 2m HT radio
  • Raspberry Pi 3
  • 7″ touchscreen
  • a TNC-PI packet add-on board for the Pi, from Coastal Chipworks (which I assembled as a kit)
  • ax25 apps (for axlisten and axcall)

2. A Packet Radio to Twitter bridge (implemented using JavaScript on node.js). While the goals and benefits of a portable Packet radio kit are somewhat more obvious, writing an app that receives Packet Radio transmissions and then retransmits them as Tweets on Twitter doesn’t have many practical applications. The main motivation for this part of the project was that I thought it would be an interesting blend of old tech and new tech. The popularity of Packet Radio declined with the arrival of easy access dial-up information services and BBSes in the 80s and then access to the internet in the early 90s, so linking the two together seemed an interesting idea. Plus, it’s an interesting stepping stone and talking point from common-place tech used on our wireless devices today, with data communications enabled via Amateur Radio.

I put together a number of articles as I was assembling my project and working on the Packet to Twitter interface. If you’d like to read more, here’s links to my previous posts:

Building and running a Packet Radio Winlink solution in a Docker container, on a Raspberry Pi

Running Packet Radio apps in a Docker container, on a Raspberry Pi? Are you mad I hear you ask?Isn’t it hard enough to get ax25 and Packet Radio up and running on the Pi anyway? Having done this a few times already, this was my thinking, and I had the crazy idea that encapsulating most of the config and setup in Dockerfiles to build preconfigured containers might be an idea worth exploring.

Installing and configuring ax25 for the Raspberry Pi and Winlink clients that use ax25 like paclink-unix or PAT can be done and work well, but the steps, as for example documented in this comprehensive guide for building and installing paclink-unix which span several pages of instructions – this can be daunting even for those more familiar with building and installing apps from source on Linux.

Since the steps are well documented, I wondered if they could be captured in a Dockerfile to automate building a self-contained and ready to run Docker container.

tldr; The short story

I did eventually did get this working building ax25 from source and using Pat, but it took me down a rabbit hole for several hours. Skip to the end if you just want to find out how to build and run the completed Docker containers.

The Longer Explanation

I could not get ax25 to work self-contained in it’s own Docker container, as I ran into issues either accessing my serial device connected to my TNC Pi from inside the Container, and/or creating an ax0 interface when running kissattach.

If you expose the serial port on the Raspberry Pi to the Container running paclink-unix:

docker run -it --device=/dev/ttyAMA0 rpi-paclink

… When trying kissattach in the container it gives:

kissattach: Error setting line discipline: TIOCSETD: Operation not permitted

Are you sure you have enabled MKISS support in the kernel

or, if you made it a module, that the module is loaded?

Alternatively, starting with –privileged:

docker run -it --privileged  -v /dev/ttyAMA0:/dev/ttyAMA0  rpi-paclink

gives:

sudo kissattach /dev/ttyAMA0 1

kissattach: SIOCSIFMTU: No such device

I was initially trying to get this working because I wanted to run paclink-unix for Winlink email. Part of this app when you run the make script it will create wl2kserial and wl2ktelnet, but not wl2kax25. I had already run into this before, as it seems it doesn’t compile unless it has a later version of the ax25 stack compiled from source.

I changed gears and looked for how you could share an up and running ax25 stack from the Docker host, and it turns out this is easy to do, you just pass the –network=host param, and then ax0 appears in your network interfaces in your container.

The next issue I ran into is that configuring postfix as your email transport take some effort. bazaudi.com have a very detailed set of instructions, but I couldn’t get it working for outgoing email. It was working for incoming via wl2ktelnet and wl2kax25, but only for receiving emails and not sending. Time to try something else.

Installing and configuring Pat in a Container

I tried to get Pat working once before – I think I had it working on either a Debian or Ubuntu box, but couldn’t get it working on Raspbian on a Pi. I decided to try it again in this setup, and reusing the base image with ax25 already compiled from source, it was actually very easy to get Pat up and running.

This is dependent on having ax25 installed and configure on the host Pi OS, and the shared to the container with –network=host. I know, this seems redundant, but this is the only way I managed to get this working.

My base image for Raspbian including ax25 built form source is here: https://github.com/kevinhooke/DockerRPiAX25FromSource 

To build the image passing in the parameterized value for your callsign (passing your callsign in place of ‘yourcall’):

docker build --build-param MYCALL=yourcall -t rpi-ax25 .

Next build an image containing Pat, based on the image we just built – the source for this Dockerfile is here: https://github.com/kevinhooke/DockerRPiPATWinlink.git

Build this image with:

docker build --build-arg MYCALL=yourcall --build-arg MYCALLSSID=yourcall-1 
    --build-arg MYLOC=AA11aa --build-arg WINLINKPASS=yourwlpass 
    -t rpi-wl-pat .

Now to start it up remember we’re relying on an ax25 connection from the host, and we’re going to share it with the guest container. My TNC-Pi board connected to my Raspberry Pi is available on serial device as /dev/ttyAMA0, so I start up my ax0 port like:

sudo kissattach /dev/ttyAMA0 1 10.1.1.1

Next, run the container as a daemon, share the host networking, and expose port 8080 so we can access the Pat webapp:

docker run -d –network=host -p 8080:8080 rpi-wl-pat

Now let’s fire up the webapp:

Looks good, this is the Pat inbox. Let’s send a test email to myself – this is going to be sent using Packet over 2m VHF via my local Winlink gateway, AG6QO-10. I have this preconfigured in my Pat config file. You can configure this yourself before creating the rpi-wl-pat image:

Remember the Pat webapp that we’re interacting with here is running in a Docker container, on a Raspberry Pi. I just happen to be accessing it remotely from my Mac. For mobile operation or out in the field, you could attach a touchscreen to the Pi and connect a keyboard and mouse too.

To send my email over RF to the Winlink gateway, click Action, then Connect:

In the Pat status window we now see a log of the Packet exchange between my station and AG6QO-10 via BERR37:

A few seconds later the email arrives in my gmail inbox:

If I reply to the email in gmail, it will go back over the Winlink network, and be waiting for me when I connect to the Winlink gateway again over RF. Let’s give that a go in Pat – select Action and Connect, we connect to AG6QO0-10 again over 2m VHF, and now the reply is in my inbox in Pat:

Success!

Building ARM Docker images on the Raspberry Pi

Install Docker for ARM using the install script:

curl -sSL https://get.docker.com | sh

From: https://www.raspberrypi.org/blog/docker-comes-to-raspberry-pi/

Set to startup as a service:

sudo systemctl enable docker

Start the service manually now (or reboot to start automatically):

sudo systemctl start docker

Add user to docker group (to run docker cli without sudo):

sudo usermod -aG docker pi

 

To create a new image from a Raspbian base for ARM, use the Raspbian images from resin (in your Dockerfile):

FROM resin/rpi-raspbian:latest

From: http://blog.alexellis.io/getting-started-with-docker-on-raspberry-pi/

Edit your Dockerfile to include and configure whatever you need, and build an image as normal on the Pi using:

docker build -t tagname .

… and off you go.