Node.js + RPi + IKEA = Trophy Lighting

My first foray into home automation, using Express to expose an API to control a set of shelf lights.

Combining my love for lighting and IKEA furniture with a need to find a new way to tinker with a Raspberry Pi, built a remote-controllable shelf light.

What I used:

  • EXPEDIT shelving
  • DIODER LED light strips (4-pack)
  • FIXA, a 114-piece cable managment
  • Raspberry Pi Series B
  • PowerTail Switch II, a 120V opto-isolated relay accepting anything from 3V to 12V for a simple control input to activate the switch.
  • I also have a breadboard, jumpers, and the GPIO cobber/cable kit which came with the Adafruit Raspberry Pi Starter Pack, but aren’t necessary if you’ve got another way to connect GPIO pins to an external component.

Assembly

IKEA

IKEA, as always, provided delightful instructions for EXPEDIT. But seriously, this shelving is actually a very easy IKEA build, and it looks great; I highly recommend it. After the build, I started by mounting one DIODER strip in each of the four shelves in the top row:

DIODER mounted in EXPEDIT

Using the FIXA pieces and a little obsessive cable management, I pulled each lead straight to the back of the shelf and ran along the bottom edge of the shelving.

Cable management

All of that terminated in a bit of a mess of excess cable which I just folded in a bundle and ziptied to the back of the unit.

Cable tangle

Then I connected that up to the PowerSwitch and the RPi to get started on the Node fun.

RPi and PowerSwitch Tail

Node.js control of RPi GPIO pins

Controlling the PowerSwitch Tail is really easy. All it needs is 3-12VDC applied to the control terminal:

PowerTail Switch

We can do that with the Raspberry Pi’s GPIO, by attaching a GPIO pin to + and then connecting - to a grounding pin. Controlling this in Python is really easy:

#!/usr/bin/env python

import RPi.GPIO as io
io.setmode(io.BCM)

power_pin = 18

io.setup(power_pin, io.OUT)
io.output(power_pin, True)

But my experience is in Node.js and I wanted a fun way to make it controllable via a browser or other URL call. In short, I wanted:

  • / – A very simple static site with on and off link buttons. We’ll use Express to host those assets.
  • /on – Turn the light on (GPIO pin “on”)
  • /off – Turn the light off (GPIO pin “off”)

Full control of RPi GPIO using Node.js is currently a little lacking. There are two primary npm modules, but neither seems actively maintained and both appear to be on track for being replaced. Luckily, our needs are quite simple. I used pi-gpio because at the time, I couldn’t get gpio to work (although it has been updated since I last looked).

Remember that the GPIO pins can either be addressed as they are printed on the board or in actual pin order. The pi-gpio library uses the physical pinout, not the printed numbers.

RPi Pinout

Image from Hobby Electronics illustrating the printed GPIO numbers compared to the physical pinout for the Raspberry Pi B.

We load up the two necessary libraries and also note the pin as 16 (which is labeled on the board as GPIO 23).

var gpio = require('pi-gpio');
var pin = 16;

var express = require('express');
var app = express();

A simple function to open the pin for writing, write x (a boolean to turn on or off the pin), and close the pin for output after half a second.

var lightSwitch = function(x){
  gpio.open(pin, "output", function(err) {
    gpio.write(pin, x, function() {
      setTimeout(function(){gpio.close(pin)}, 500);
    });
  });
}

Now our utility URLs /on and /off

app.get('/on', function(req, res){
  lightSwitch(1);

  var body = 'Lights On';
  res.setHeader('Content-Type', 'text/plain');
  res.setHeader('Content-Length', body.length);
  res.end(body);
});

app.get('/off', function(req, res){
  lightSwitch(0);

  var body = 'Lights Off';
  res.setHeader('Content-Type', 'text/plain');
  res.setHeader('Content-Length', body.length);
  res.end(body);
});

Lastly, we set up the Express server to listen for HTTP requests on 8080, and, for any path that hasn’t already been declared, serve assets out of the project’s /public directory which contains a standard index.html and assorted CSS and JS assets.

app.listen(8080);
app.use(express.static(__dirname + '/public'));
console.log('Listening on port 8080');

The litesite

Interaction outside the browser

I use Tasker on my phone. Essentially, it waits for contexts and takes actions. For example, when I plug my phone in at night, Tasker silences text and email notifications. Now that my lights are web-controlled, I have added a step in that profile to also fire a request to /off to turn of the lights.

In the future, I’d also like to set up similar actions on my computer (either with a taskbar/dock icon or automated actions) to turn the lights on when I start using my computer. Also, I have a second PowerSwitch Tail, so it would be trivial to add a second “circuit” to my system. Guess I’ll have to go buy more light fixtures!

Question

I’d love to find a better way of interacting with the GPIO pins, especially if I ever do anything more complicated. Are there any more mature GPIO libraries for Node.js? Join in the comments.