Home automation with Raspberry Pi + Homebridge

Homebridge is an extremely useful tool for home automation. With its versatile plugin architecture, numerous devices of all different types and manufacturers are supported (there are 300+ homebridge-plugins at the time of this writing) and you can easily write plugins for your own.

Written in JavaScript for Node.js, Homebridge can comfortably run on even a Raspberry Pi Zero, or similar low-powered single-board computers such as the Raspberry Pi 3 Model B. If you want to get started with home automation, a Raspberry Pi + Homebridge is a great place to start.

AC power outlet switch: homebridge-gpio-cmd

In my previous article Raspberry Pi Zero Wi-Fi USB Adapter Installation: TP-Link Archer T2U you may recall I wired up the Wi-Fi adapter to the Pi Zero for embedding inside a power supply to control AC outlets using a relay, through a GPIO output pin. Remotely logging into the machine and running a command-line script to toggle lights wasn’t very practical, but now we see how it can be useful with Homebridge.

There are a couple plugins to allow controlling the Pi’s GPIO ports:

Either of these are probably good options, although they depend on gpio-admin and wiring-pi modules, respectively. I didn’t want to bother with these dependencies, so I opted for a simpler route, using child_process to execute the /usr/bin/gpio command from the shell, published as:

The /usr/bin/gpio command is installed as part of WiringPi, included out-of-the-box in Raspbian, so no additional dependency setup is needed. Configuring the GPIO pins requires some explanation, however.

The Broadcom (BCM) chip has its own pin numbering scheme, and the WiringPi (wPi) library has its own numbering on top of it. The Pi boards themselves break out many of the pins onto a physical connector, also with its own numbering scheme. These physical, BCM, and wPi are all equivalent:

gpio -1 write 16 1
gpio -g write 23 1
gpio write 4 1

Since we’re wiring up a physical wire to the connector, using the physical pins (-1 flag to /usr/bin/gpio) is the most logical, in my opinion. homebridge-gpio-wpi in contrast uses BCM numbers, but homebridge-gpio and homebridge-gpio-cmd both use physical. That said, here’s my config:

The accessory shows up as a switch to Homebridge, you can turn it on/off.

Note there is an “outlet” accessory type available: see HAP-NodeJS for everything supported, but outlet requires both On and OutletInUse characteristics, whereas switch only requires On. The physical wiring:

System temperature sensor: homebridge-pi

If you don’t have many sensors, consider homebridge-pi a freebie: it adds your Raspberry Pi’s internal temperature to Homebridge, using the TemperatureSensor service. Simply install, add to ~/.homebridge/ config.json and give it a descriptive name, I used “Pi Zero Temperature”:

Note this caveat: the temperature reported is the Pi’s internal CPU, or more specifically, Broadcom’s System on a Chip on the single-board computer:

— it isn’t the ambient room temperature! You’ll see temperatures like 40º, varying depending on system load, not too useful for controlling e.g. thermostats or fans to regulate room temperature, but it’s neat to have this data available nonetheless. Quickly check how your Pi is doing.

Ambient light sensor: homebridge-lightsensor-analog

Previously in SPI interfacing experiments: EEPROMs, Bus Pirate, ADC/OPT101 with Raspberry Pi I used the MCP3304 analog-to-digital converter with an OPT101 photodiode to read ambient light levels. Used a Python script with the spidev module there, but Homebridge is Node.js/JavaScript, so a different module is needed.

mcp-spi-adc looks promising, but only supported: MCP3002/4/8, MCP3202/4/8. I have a MCP3304 instead. What’s the difference? The MCP3008, MCP3208, and MCP3304 are all 8-channel, but 10-bit, 12-bit, and 13-bit, respectively. The 3304 also optionally supports using pairs of channels as differential inputs, but I’m only interested in single-ended inputs for now.

From the MCP3304/3208 datasheet:

Ported over the Python code and plugged in the electrical specifications, implemented in mcp-spi-adc and submitted pull request #1:

Tested with this script to read all the channels, readall-mcp-spi-adc.js:

It reads 3.3 when channel 0 is tied t0 +3.3v, and near 0 when tied to ground, and a light-dependent value when tied to a photodiode, such as the OPT101:

Next step is Homebridge integration. Searching finds some existing plugins:

None were using mcp-spi-adc, so I whipped one up real quick, and called it homebridge-lightsensor-analog:

This plugin simply reads an ADC channel (I’m using channel #7 of the MCP3304) and presents it as the CurrentAmbientLightLevel characteristic of a LightSensor service. The ADC returns value from 0 to 1, but the API expects the light level in lux, so the plugin can be configured in ~/.homebridge/config.json to scale the value as needed. I didn’t have a light meter, so I guessed at 500 lux (typical office lighting) for full scale:

Start up Homebridge (I added it to a separate Raspberry Pi 3 system instead of the Pi Zero) and the light sensor should show up and give lux readings. Now you can toggle your Hue lights remotely and observe the light change!

Ambient temperature/humidity/pressure: homebridge-bme280

Now for something more comprehensive: a multi-function digital sensor.

There’s several temperature sensor plugins:

node-dht-sensor supports the DHT11 and DHT22/AM2302 temperature-humidity sensors. There’s also this for simulating a humidity sensor:

But I have none of those, instead I went with the Bosch BME280 temperature/humidity/pressure sensor, available in breakouts:

The SparkFun and Adafruit boards have some nice compatibility features including 5v support, but I opted for the cheaper version from Aliexpress. Wired it up to a Bus Pirate for initial testing, performed a scan:

I2C>(1)
Searching I2C address space. Found devices at:
0xEC(0x76 W) 0xED(0x76 R)

Found this driver on /r/raspberry_pi written in C by @robofly:

Building and running it with no BME280 hardware attached:

pi@raspberrypi:~/spi/raspberry-pi-bme280 $ make
gcc -g -Wall -Wextra -pedantic -std=c11 -D_DEFAULT_SOURCE -D_BSD_SOURCE -o bme280 bme280.c -lwiringPi -lm
pi@raspberrypi:~/spi/raspberry-pi-bme280 $ ./bme280
{“sensor”:”bme280", “humidity”:0.00, “pressure”:1.85, “temperature”:409.60, “altitude”:30973.32, “timestamp”:1475731130}

Wire up the sensor to Pi’s I²C bus (+3.3V, SDA, SCL, GND) and rerun:

{“sensor”:”bme280", “humidity”:42.76, “pressure”:1008.60, “temperature”:25.52, “altitude”:36.66, “timestamp”:1475737386}
{“sensor”:”bme280", “humidity”:42.77, “pressure”:1008.66, “temperature”:25.52, “altitude”:36.21, “timestamp”:1475737386}
{“sensor”:”bme280", “humidity”:42.77, “pressure”:1008.67, “temperature”:25.52, “altitude”:36.14, “timestamp”:1475737386}
{“sensor”:”bme280", “humidity”:42.76, “pressure”:1008.63, “temperature”:25.52, “altitude”:36.44, “timestamp”:1475737386}

Looks about right. Touching the sensor with a finger recognizably increases the temperature and humidity. The units are:

As for Homebridge, this sensor could provide these services:

  • TemperatureSensor: CurrentTemperature
  • HumiditySensor: CurrentRelativeHumidity

Couldn’t find anything related for pressure/altitude. Potentially a motion or occupancy sensor, if the IIR filter is disabled (from the datasheet: “After the measurement period, the pressure and temperature data can be passed through an optional IIR filter, which removes short-term fluctuations in pressure (e.g. caused by slamming a door) … or wind blowing into the sensor”), but I wasn’t able to pickup any perceptible changes from clapping, slamming lightly, etc (TODO: enable/disable IIR). Temperature and humidity is it for now. Perhaps filtered pressure and altitude could be useful for other applications, as shown here.

Now for JavaScript/Node.js integration: found a module, bme280-sensor. Running the example fails:

pi@raspberrypi:~/spi/bme280-sensor $ node example.js 
BME280 initialization failed: Error: EIO, Input/output error

By default it looks for the sensor at address 0x77, but I have mine configured for 0x76. Edit the example.js settings:

// The BME280 constructor options are optional.
// Defaults are i2cBusNo 1, i2cAddress 0x77.
//
const options = { i2cBusNo : 1,
//i2cAddress : BME280.BME280_DEFAULT_I2C_ADDRESS() };
i2cAddress : 0x76 };

then the data is read successfully:

data = {
“temperature_C”: 24.24,
“humidity”: 45.480609694765235,
“pressure_hPa”: 1008.5844707416113,
“temperature_F”: 75.632,
“pressure_inHg”: 29.783486823779743
}

The native values are temperature_C, humidity, and pressure_hPa. Created another new plugin, homebridge-bme280:

Now you can monitor your relative humidity and room temperature.


I put this sensor in the same box as the AC outlet relay, connecting to the same Pi Zero. Cost breakdown for comparing DIY to retail products:

Totals about ~$60, for a DIY smart outlet + temperature/humidity sensor. This cost of course could be brought down significantly if you can find a 99¢ Pi Zero at Microcenter or use a cheaper Wi-Fi adapter.

Server Intelligent Platform Management Interface: homebridge-ipmi

If you have a home server, it may support IPMI for out-of-band management:

This includes reading the system/peripheral temperatures, monitoring cooling fan speeds, power cycling the server (not bridged yet), or other useful server maintenance related functions. The command-line ipmitool (installed on FreeBSD with sysutils/ipmitools, or `sudo apt-get install ipmitool` on Raspbian) can be used to read all sensor values:

Found the node-ipmi package to call this tool in Node.js. Not much we can do about the voltage sensors (any ideas for what Homebridge service would be appropriate?) but creating the TemperatureSensor and Fan services is straightforward, developed the homebridge-ipmi plugin:

Since IPMI is networked, you can run this plugin on another system, such as a Raspberry Pi running Homebridge, or on another instance of Homebridge running locally on the server itself. My configuration, specifying local IPMI, two temperature sensors, and five fans:

There are lots of future possibilities for bridging IPMI: should the chassis intrusion detector be exposed as a ContactSensor? The power supply state as an Outlet? The out-of-band VNC server as a camera? For now, I am sticking with monitoring temperature and fans on my IPMI-capable server, but also added a “chassis identify” switch. Toggling it blinks the server’s identification LED via IPMI so it can be identified in a large rack of lots of servers.

CPU digital thermal sensors: homebridge-temperature-sysctl

Beyond IPMI, also on a server: measuring the on-die thermal sensors, inside the CPU itself. This is the only plugin in this article that doesn’t work on the Raspberry Pi, since it doesn’t expose temperatures in the same fashion, but it works well on *BSD servers using e.g. coretemp.

Monitoring an 8-core CPU, wrote homebridge-temperature-sysctl:

In principle, this plugin could be adopted for other platforms, but the stock Raspbian on the Pi doesn’t reveal the system temperature in `sysctl -a`. Instead, see homebridge-pi which I already covered above. On a server with an Intel Xeon E3–1230 V2 processor:

$ sysctl -a|grep temperature
hw.acpi.thermal.tz1.temperature: 29.9C
hw.acpi.thermal.tz0.temperature: 27.9C
dev.cpu.7.temperature: 38.1C
dev.cpu.6.temperature: 38.1C
dev.cpu.5.temperature: 35.1C
dev.cpu.4.temperature: 35.1C
dev.cpu.3.temperature: 42.1C
dev.cpu.2.temperature: 42.1C
dev.cpu.1.temperature: 39.1C
dev.cpu.0.temperature: 41.1C

All this data is now available through Homebridge as TemperatureSensors.

LG TV webOS: homebridge-lgtv2

Found the homebridge-lgtv2 plugin, using the lgtv2 WebOS Smart TV plugin to control LG television sets. This plugin is very vendor-specific, there may be other plugins for your TV models. Let’s see if it works with an 55EC9300:

First I had to connect the TV to the network over Wi-Fi. It listens on a WebSocket server, port 3000. Connecting with lgtv2 will show a prompt on the TV asking if you want to give it control.

After confirming this prompt, and installing the homebridge-lgtv2 plugin, I was able to turn off the TV through Homebridge. Turning on the TV is more problematic, however.

homebridge-lgtv2 uses Wake-on-LAN (WoL) via wake_on_lan to send a magic packet to the TV’s MAC address. I tried both over Wi-Fi and a hardwired Ethernet connection to the TV, with the corresponding MAC addresses, neither were able to successfully wake the TV (in fact, I don’t think I’ve ever seen wake-on-LAN work on anything ever in my entire life!). WoL is an Ethernet technology, there is a Wake on Wireless LAN (WoWLAN) standard for Wi-Fi. But I had zero luck with either on this LG 55EC9300 TV.

There are alternative technologies to consider. The LG 55EC9300 Owner’s Manual does not seem to mention WoL, but page 35 documents “external control devices”, first a USB to Serial converter (PL2303 chip-based (Vendor ID : 0x0557, Product ID : 0x2008)):

and phone jack type, via the service port:

Fortunately I happen to have some old broken headphones, unfortunately, soldering the thin wire is extremely difficult (but see some tips at Soldering The Thinnest Wires Ever Conceived: Headphone Modding), I was only able to successfully solder the outer sleeve wire:

However, the jack can be removed from the headphone wires, with careful application of an X-Acto knife and abuse of a large Hakko soldering iron tip:

There actually already is a small amount of solder present already, and wires can be practically soldered onto each of the pads:

then plugged into the Service Only port of the TV:

Wire up the other end to a USB-to-Serial adapter, I used a SparkFun FTDI Basic Breakout — 3.3V, then connect:

screen -L /dev/tty.usbserial* 9600

Turning on the TV while the serial port is connected shows.. something:

bBckcccKC

Based on my reading of the documentation, sending “ka 0 FF” then a carriage return should turn the TV on or off, and commands should be acknowledged. I wasn’t able to get this far in my initial tests, more investigation would be needed. Nonetheless, even if this did work, there’s the problem of turning on the set-top box I have connected to the TV: usually I use its remote control to turn it on or off simultaneously with the TV via IR.

For this reason, a potentially better option may be something like using an ESP8266 + an IR LED to build a “smartphone TV remote”, sending via Homebridge the exact same commands a remote control would. But for now, I’m sticking with homebridge-lgtv2 and only being able to turn the TV off. Update: I since removed this plugin, as it kept trying to connect when the TV was off (TODO: have it ping to show TV online, use WS only for on/off?)

Desk fan, 3-wire PC fan with tachometer: homebridge-pwm-fan

How about a combined sensor and actuator? Consider the humble PC fan, modern versions of which have adjustable speed and also report back their RPM. I had a few spare PC fans sitting unused in a cabinet, let’s try them.

@pavouk documents this 4-wire fan example motherboard logic:

but you have to wonder, why do some PC fans have 2-wires, 3-wires, and 4-wires? PCBHeaven explains How PC Fans Work, 4 wire is essentially:

3-wire lacks the control (although can still be pulse-width modulated through the power supply), but has a tachometer. 2-wire has neither. A 2-wire fan, the Thermaltake TT-9025A 90mm Case Cooling Fan:

This fan was wired up to the +12V wire of the Molex connector, but it can also be powered by +5V and +3.3V from the Raspberry Pi, albeit slower. Without a tachometer it is not too interesting. Moving onto the 3-wire fan, a slightly more modern Insignia NS-PCF8050 80mm Case Cooling Fan:

I didn’t have any 4-wire PC fans readily available for this project, since I was already using them inside a PC.

For this particular 3-wire fan, the red and black wires are for power, the blue is the tachometer (yellow is also common). So that the tachometer outputs an acceptable logic level for GPIO input, wire up the power to +3.3V, ground to ground, then the tach to a GPIO pin: I used physical pin #36, aka BCM 16, G16 on the Pi Wedge. Write a simple script to read and print the input, pulled up high:

#!/usr/bin/python -u
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
TACH = 36 # BCM 16
GPIO.setwarnings(False)
GPIO.setup(TACH, GPIO.IN, pull_up_down=GPIO.PUD_UP)
while True:
 print GPIO.input(TACH),

If it is working, when the fan is spinning you should see alternating runs of 1’s and 0's:

… 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 …

Corresponding to activation of the Hall effect sensor:

Adding a 0.001 second sleep and counting the length of the runs:

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = 21
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 = 29
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = 20
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 = 29
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = 20
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 = 27

The 1’s are consistently about 25–30, and 0’s about 19–21. Occasionally there are short runs of an individual 0 or 1. How to interpret this output? Found at StackExchange: How to interpret the output of a 3-pin computer fan speed sensor? which points to 4-Wire Pulse Width Modulation (PWM) Controlled Fans — Specification July 2004, Revision 1.2:

Since it is open-collector, we use pull_up_down=GPIO.PUD_UP to enable the Pi’s internal pull-up resistor, and the tachometer drives the output low when activated. The width of the low pulse itself shouldn’t matter as much as the timing of the falling-edges, which would be at a consistent position on the motor. Interrupts, as I covered in Interrupt-driven I/O on Raspberry Pi 3 with LEDs and pushbuttons: rising/falling edge-detection using RPi.GPIO, are a perfect application for this purpose:

t = time.time()
def fell(n):
 global t
 dt = time.time() - t # reject spuriously short pulses
 if dt < 0.01: return
 freq = 1 / dt
 rpm = (freq / 2) * 60
 print rpm
 t = time.time()

GPIO.add_event_detect(TACH, GPIO.FALLING, fell)
while True: time.sleep(1e9)

Consistently reads about 500 RPM, looks reasonable for low voltage. Slowing down the fan by (gently) touching it lowers to 400 RPM or lower. You may be tempted to try increasing the RPM by applying a higher voltage, but note that the tachometer outputs the same voltage, so additional circuitry would be needed to run it on anything other than +3.3V, for use with the Pi’s GPIO.

Complete script: tachfan.py. Now for controlling the fan speed. This is done using PWM, as previously described in Pulse-width modulation: using PWM to build a breathing nightlight and alarm. Using software PWM via pigpiod:

The limitations of the 3-wire PC fan design now become clear: as the power supply is cut between the pulses of the pulse-width modulated power supply, the RPM sensor readings become wildly inaccurate — since you’re also cutting the control circuitry power! At 1 Hz and 99.6% duty cycle:

494
1448
749
492
496
496
494
1838

At even higher frequencies and lower duty cycles, the RPM reading becomes completely worthless. The 4th wire on newer PC fans neatly solves this problem, by providing a control signal independent of the power rail.

Enough with the Python protoyping. As Homebridge is written in JavaScript, this script should be rewritten. Fortunately there is a pigpio NPM package which ought to make it straightforward. But there are some downsides:

  • The library uses Broadcom pin numbers not physical (ok, I can deal)
  • The pigpio NPM module uses the pigpio C library directly, conflicting with the pigpiod daemon I am running for other scripts to use within Python (attempts to use fail with an “already in use” error).
  • Consequentially, the script has to run as root (or permissions adjusted appropriately? but chmod’ing /dev/mem is insufficient):

pi@raspberrypi:~/gpio/homebridge-pwm-fan $ node fan.js
2016–10–09 07:24:36 initCheckPermitted:
+ — — — — — — — — — — — — — — — — — — — — — — — — — — — — -+
|Sorry, you don’t have permission to run this program. |
|Try running as root, e.g. precede the command with sudo. |
+ — — — — — — — — — — — — — — — — — — — — — — — — — — — — -+

There is a module to use the pigpiod daemon in Node.js: pi-fast-gpio. Looks promising, but the source code shows it only implements setPwmDutycycle. Also found pigpio.js, but @jedahan’s GitHub page no longer has https://github.com/jedahan/pigpio.js (broken link, 404 Not Found). To do this Homebridge plugin right, what would be really useful is a complete pigpiod daemon interface for Node.js.

Until then, as an ugly workaround I wrote the GPIO control code in Python, as a helper script, and spawned it from the Node.js module. The helper continuously monitors the RPM and emits on stdout, also accepting PWM frequency and duty cycle parameters as command-line arguments. Not the most elegant approach, but it works. Here it is, homebridge-pwm-fan:

The fan wiring diagram, to two Raspberry Pi GPIO ports:

And the addition to ~/.homebridge/config.json:

You can now monitor and adjust this fan’s speed through Homebridge.

Camera with Motion Detector: homebridge-camera-motion

Raspberry Pi has an official camera, aptly named the Pi Camera V2:

There is also a “NoIR” version, same price but without the infrared filter. I’ll be using the regular camera instead. Originally I was interested in using the camera on a Pi Zero 1.3, which now has a camera connector, but an additional FPC adapter cable is required so I’ll be using it on the Raspberry Pi 3, which has an appropriately sized CSI connector.

The Getting Started with picamera tutorial uses, you guessed it, Python. There will be no further Python in this blog post. Nothing against Python, but it doesn’t advance the goal of writing Homebridge plugins in JavaScript.

Good news: there exists an NPM module node-picamera. Curiously, it just executes the raspistill shell command. The official RaspiCam Documentation says raspistill and raspivid are command-line utilities “written to take advantage of the mmal API which runs over OpenMAX. The mmal API provides an easier to use system than that presented by OpenMAX. Note that mmal is a Broadcom specific API used only on Videocore 4 systems.”

Homebridge’s wiki page Supporting IP Camera says “a plugin can publish camera by invoking api.publishCameraAccessories(pluginName, [PlatformAccessory]).”, details at HAP-NodeJS: IP Camera.

There are two existing Homebridge camera plugins:

I opted instead for using the Motion project, which includes integrated motion detection:

sudo apt-get install motion

Motion is highly configurable, so be sure to read the extensive User’s Guide, but a decent initial config in ~/.motion/motion.conf to start out with is:

run motion then visit http://raspberrypi.local:8081 to watch it stream live!

To force writing a snapshot, visit http://raspberrypi.local:8082/0/action/snapshot

How to get notified from a Homebridge plugin when motion is detected? Motion supports event triggers, the most straightforward is to trigger when a new picture is written (either from motion detection, a periodic snapshot interval, or invoking /action/snapshot), and write various data in realtime:

on_picture_save printf ‘%f\t%n\t%v\t%i\t%J\t%K\t%L\t%N\t%D\n’ > /tmp/motion-pipe

If this is added to motion.conf as-is, it’ll be written to a file on disk, however, a FIFO named pipe would be more appropriate. To make one:

mkfifo /tmp/motion-pipe

or run the Homebridge plugin. The plugin can now stream motion events from this pipe using fifo-js. To get snapshots, edit motion.conf

target_dir /tmp

then the plugin will read from /tmp/lastsnap.jpg.

Live streaming requires transcoding through ffmpeg:

sudo apt-get install ffmpeg

fails with “no such package”, for some reason. To build it yourself see: Installing FFMPEG for Raspberry Pi. This takes an unreasonably long time, however. To speed up compilation you can cross-compile. Or just download a precompiled version, this one is from 2016/07/16: @fattylewis Latest ffmpeg cross-compiled for pi. Took 20+ minutes to download and I had to resume the transfer after it was interrupted. Rehosted on Dropbox if you want a copy, the hash for comparison is:

SHA1(/tmp/arm-ffmpeg-20161009.tar.gz)= 84dd63bca3cbfbc5fdefe30b71d1d0f6c935c353

Cribbed some code from homebridge-camera-ffmpeg, but so far I wasn’t able to get the client to perform a streaming request, needs more testing. In the meantime, you can still stream live from http://raspberrypi.local:8081/ directly instead of via Homebridge. Camera snapshots are working, as is the motion sensor. Anyways without further ado, homebridge-camera-motion:

Much more work is to be done on this plugin, but at least basic services (still image snapshots and motion detection) are functional.

Conclusions

This has been a been a whirlwind tour of an initial foray into home automation, built on top of Homebridge and Raspberry Pi. Plugins used:

Services used: Switch, TemperatureSensor, LightSensor, HumiditySensor, Fan, MotionSensor, and CameraControl.

Update 2016/10/11: also added the ContactSensor service using homebridge-contactsensor, see new article: Interrupt-driven contact sensors with Homebridge and Raspberry Pi GPIO

While a lot of ground was covered configuring/developing/using these 9 plugins, this is only the beginning. With home automation is still in its infancy, Homebridge serves an important niche in bridging the gap in vendor support, as well as a vibrant testbed for home automation hobbyists.

A Homebridge developer unlocking his door