How to Control an RF Outlet with Siri using HomeKit via Homebridge
Tags:
Bottom Line: Here’s how to control cheap RF outlets directly from Siri using HomeKit by way of homebridge.
Introduction
Apple’s home automation suite is called HomeKit. It works with Siri, which is great. In true Apple fashion, it seems like they are making it really difficult for third parties to get “HomeKit Certified,” and so you won’t see a whole lot of devices carrying this:
Luckily, some people much smarter than me have developed an alternative route to use Siri to control devices around the house: make a server that emulates the HomeKit API: homebridge. This tutorial covers how to go about setting up homebridge on a Raspberry Pi, and how to install my version of the nodejs implementation of RCSwitch in order to control cheap RF outlets with Siri.
Here’s the obligatory YouTube video showing it in action (NB: if you watch it on or near an iOS device with “Hey Siri” enabled, it might activate it). Also note that everything is much quicker when run through my iPhone 6S or when run through the app instead of Siri, but I wanted to demonstrate on my old 1st gen iPad Mini so I could record with the iPhone.
Update 20161111: In the original
version
of this post I talked about using GNU Stow to manage my nodejs installation.
However, I have since realized that Stow seems mostly aimed at helping people
manage apps that they are compiling from source, and I’m using the pre-compiled
nodejs binaries, which led to a few subtle bugs related to node upgrades. In
the end, I’ve relocated my nodejs
installation to /opt/nodejs
, as you’ll be
able to see in my updated gist, below. I’ve gone back to try to remove
references to Stow from the post to avoid confusion; please let me know if I’ve
missed any. Shout out to mefynn for bringing this
to my attention in the comments!
Overview
- Install a HomeKit controller app for iOS
- Install and configure
homebridge
- Install and configure
homebridge-rcswitch-gpiomem
Equipment
- Raspberry Pi model B+ (likely possible with other models, but only tested on B+)
- Optimized to run on Raspbian Jessie (
cat /etc/issue
and look forGNU/Linux 8
), but likely works on Raspbian Wheezy - 433 MHz RF transmitter
- 433 MHz remote controlled outlets
- Optional: 433 MHz remote for outlets (needed if you don’t know your RF codes, included in the outlet kit linked above)
- Optional: 433 MHz RF receiver (needed if you don’t know your RF codes, included in the transmitter kit I linked above)
Recommended: Install and test rf_pi
- My post on rf_pi: Control RF Outlets From Your Raspberry Pi Without Sudo / Root
this step isn’t strictly necessary, but will be enormously helpful as a sanity-check and for debugging, as well as making sure you have working rf codes and that your transmitter functions as expected.
Step 1: Install a HomeKit controller app for iOS
I recently covered how to install Apple’s open source HomeKit Catalog app for free, which is my preference as it allows you total control of your data, but there are easier options. Here’s a link to my post and a few of the popular HomeKit apps you could also try.
- My post: How to Install Apple’s HomeKit Catalog App on iOS with Xcode
- Elgato Eve (free)
- Insteon+ (free)
- MyTouchHome ($1.99)
- Home — Smart Home Automation ($14.99)
- MyHome App (free, looks like it may be an exact copy of Apple’s HomeKit Catalog)
Step 2: Install nodejs
I made a script to help me quickly install the latest nodejs v4 (5 is out and also works, 4 is the “long term support” version currently). I put my installer script into a GitHub Gist — you’re welcome to check out the content below and either follow the steps manually, or just wget https://gist.githubusercontent.com/n8henrie/709a04e53a8569c14c1f/raw -O get_nodejs.sh
and sudo bash get_nodejs.sh
.
A few things to note if you use my script here:
- Will likely require sudo / root permissions (depending on the permissions of the folder you choose to install into; on Jessie
/usr/local
isroot:staff
owned by default) - The script is set to install node to
/opt/nodejs
; you’ll need to edit the script if you want to install to a different directory. - I haven’t included these directories in my
PATH
, so to use them you’ll either need to do so, or just use the full/path/to/node
(e.g./opt/nodejs/bin/node
), or move / symlink them into a directory that is in your path instead of/opt/nodejs
. - Be forewarned, at the end of the script, I have it set to change ownership of the
nodejs
folder to allow you to install npm packages globally without requiring sudo. On my first run of installing homebridge I left the defaultroot:staff
ownership and just didsudo npm install -g
for everything and it led to headaches. See some alternative solutions at the official nodejs docs.
If you add /opt/nodejs/bin
to your PATH
, you can confirm you have the
node
and npm
commands with command -v node
or command -v npm
, which
should output the path to these commands. As I mentioned, I didn’t add them to
my PATH
, so I’m just using the full path to the command in the examples
below. You might save yourself a lot of typing by just adding them to your path
with export PATH=/opt/nodejs/bin:"${PATH}"
, after which you can confirm they
are found with command -v node
(should output /opt/nodejs/bin/node
) and
command -v npm
-> /opt/nodejs/bin/npm
; in this case, you could just use
node
and npm
instead of the full path to these commands in the code below,
but you’ll probably also want to make sure your changes to PATH
are reloaded
on reboot, which is outside the scope of this post. (Hint: Google .bashrc
PATH
)
As a sanity check, here’s what I ended up with:
$ /opt/nodejs/bin/node --version
v4.5.0
$ /opt/nodejs/bin/npm --version
2.15.9
$ ls -ld /opt/nodejs
drwxr-sr-x 7 n8henrie n8henrie 4096 Sep 6 12:05 /opt/nodejs
Step 3: Install homebridge
# Install homebridge and homebridge-rcswitch-gpiomem
sudo apt-get install libavahi-compat-libdnssd-dev
/opt/nodejs/bin/npm install -g homebridge
Step 4: Configure and test homebridge
# Add an account for `homebridge` to avoid needing to run as root
sudo useradd -r -s /bin/false homebridge
# Add `homebridge` user to `gpio` group to give permissions to use gpio
sudo usermod -a -G gpio homebridge
# Add required directories and permissions since it needs to be able
# to create `/etc/homebridge/persist` folder itself
sudo mkdir -p /etc/homebridge
sudo chown homebridge /etc/homebridge
I highly recommend that you do another “sanity check” at this point by installing a fake Homebridge accessory and making sure that everything is working. If things aren’t working right at this point, you’ll drive yourself nuts trying to figure out where the problem is if you keep going. I think the easiest way is to install the homebridge-dummy
package. I’ve made a config file that you should be able to just wget
and test (NB: this will overwrite your existing config, so back it up somewhere before you use the wget
step below).
# Install homebridge-dummy
/opt/nodejs/bin/npm install --global homebridge-dummy
# Download my fake config file
sudo wget https://gist.github.com/n8henrie/639c7f5d72b4202cce7e/raw -O /etc/homebridge/config.json
# Delete the persist folder
sudo rm -rf /etc/homebridge/persist
# Run homebridge in debug mode as the `homebridge` user -- you may need to adjust the paths
sudo -u homebridge DEBUG=* /opt/nodejs/bin/homebridge -D -U /etc/homebridge
If it looks like it’s running, open your iOS device and launch the HomeKit app you installed in Step 1. Each app will be different; with HomeKit Catalog, you’ll add and name a “home,” and then add an “accessory.” Hopefully at this point you’ll see homebridge — if so, most of the hard work is done and you’re almost there! Click homebridge, manually type in the PIN (I could never get it to scan in), and hopefully it will confirm it worked. If it fails, try again — I had to do it 3 or 4 times at one point. Also consider trying some of the troubleshooting steps below.
If it seemed to work okay and you were able to add homebridge to the app, you should clean out the “dummy” configuration and proceed.
- On iOS in HomeKit Catalog: hit
Configure
button in bottom right twice -> swipe left to delete the “home” you set up - On iOS:
Settings.app
->Privacy
->HomeKit
->Reset HomeKit Configuration
- On Raspberry Pi:
sudo rm -rf /etc/homebridge/persist
Step 5: Install and configure homebridge-rcswitch-gpiomem
Now for the final touch — installing my modified versions of the node-rcswitch
and homebridge-rcswitch
libraries to control those RF outlets. My code has pretty minor changes, all credit should go to the original developers:
- https://github.com/marvinroger/node-rcswitch
- https://github.com/FWeinb/homebridge-rcswitch
- https://github.com/32leaves/rcswitch-NodeOnPi
- https://github.com/r10r/rcswitch-pi
- http://code.google.com/p/rc-switch
- https://projects.drogon.net/raspberry-pi/wiringpi
Links to my versions:
- https://github.com/n8henrie/node-rcswitch-gpiomem
- https://github.com/n8henrie/homebridge-rcswitch-gpiomem
Important differences with my -rcswitch-gpiomem
versions:
- They use the BCM pin, not the wiringPi pin, e.g.
17
instead of `` rcswitch.setPulseLength
is exposed- They will use Raspbian Jessie’s
/dev/gpiomem
by default, so they don’t require sudo / root access - wiringPi requires a
WIRINGPI_GPIOMEM
env variable to use this interface, and it doesn’t matter what the value is set to (e.g.WIRINGPI_GPIOMEM=0 vs
WIRINGPI_GPIOMEM=1vs
WIRINGPI_GPIOMEM=999`) - My
-rcswitch-gpiomem
libs automatically exportWIRINGPI_GPIOMEM=1
if the value is not already set - If can’t (e.g. Wheezy) or don’t want to use
/dev/gpiomem
, you have toexport WIRINGPI_GPIOMEM=0
- You will need to use wiringPi’s
gpio
tool toexport
your pin beforehand, and the module will usewiringPiSetupSys
instead
- You will need to use wiringPi’s
- If you have
libcap2-bin
installed and yousudo setcap cap_sys_nice+ep /opt/nodejs/bin/node
, my modules will usesched.h
to try to give the RF transmission high priority in order to optimize reliability (e.g. in case of high CPU use)
To install homebridge-rcswitch-gpiomem
: /opt/nodejs/bin/npm install -g homebridge-rcswitch-gpiomem
FYI, homebridge-rcswitch-gpiomem
depends on (and automatically installs) rcswitch-gpiomem
, which you can also install and use independently like so:
$ export NODE_PATH=/opt/nodejs/lib/node_modules
$ /opt/nodejs/bin/npm install --global rcswitch-gpiomem
$ /opt/nodejs/bin/node
> var rcswitch = require("rcswitch-gpiomem")
> rcswitch.enableTransmit(17)
> rcswitch.setPulseLength(190)
> // Where `12345` is your RF code and `24` is your bit length:
> rcswitch.send(12345, 24)
After installing, you’ll need to edit the config.json
, and once again you can start out with my sample:
sudo rm -rf /etc/homebridge/persist
sudo wget https://raw.githubusercontent.com/n8henrie/homebridge-rcswitch-gpiomem/master/config-sample.json -O /etc/homebridge/config.json
sudo vim /etc/homebridge/config.json
Please note that I tried to keep compatibility with the systemcode
/ unitcode
system used by the prior authors, but for my RF switches I just use an onCode
and offCode
. As long as one of these pairs of codes is defined it should work. You can provide these either as the “decimal” value (like I use in rf_pi
), in which case the json needs to be an integer and not a string (e.g. "onCode": 12345
), or as the “binary” value, in which case the json needs to be a string and not an integer (e.g. (e.g. "onCode": "010010110"
) — note the difference in quotes. If using the decimal version, you can optionally provide an integer bitLength
, which will default to 24
if unset. In either case you can also set an integer pin
, which defaults to 17
, and pulseLength
, which defaults to 190
.
If you want to use the “high priority” feature:
- You should probably at minimum read about this in
rf_pi
if — like myself — you don’t really know what you’re doing - Give
node
high priority:sudo setcap cap_sys_nice+ep /opt/nodejs/bin/node
- Check that it was set:
getcap /opt/nodejs/bin/node
- Remove high priority:
sudo setcap -r /opt/nodejs/bin/node
At this point, you should probably run again in debug mode to see if everything worked — you’ll likely need to delete the persist
folder and set up your iOS app from scratch. With any luck, you’ll see your switches in the iOS app and be able to control them from there and with Siri!
sudo rm -rf /etc/homebridge/persist
sudo -u homebridge DEBUG=* /opt/nodejs/bin/homebridge -D -U /etc/homebridge
Step 6: Run automatically at boot
Once everything is working, you’ll probably want this service to be available all the time. To make a startup script for Raspbian Jessie: sudo vim /etc/systemd/system/homebridge.service
Here is what seems to be working for me, you may need to change the paths:
[Unit]
Description=homebridge daemon
Requires=network.target
[Service]
Type=simple
User=homebridge
ExecStart=/opt/nodejs/lib/node_modules/homebridge/bin/homebridge -U /etc/homebridge
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
Then to load and start it:
sudo systemctl daemon-reload
sudo systemctl enable homebridge.service
sudo systemctl start homebridge.service
You should be able to see the output with sudo journalctl -x -b -u homebridge
.
Troubleshooting
Most everything with regard to configuration and setup is very similar to my rf_pi project, which is much easier to test and debug with in my opinion. Again, I strongly recommend you install and use this to make sure you have everything set up correctly with regards to hardware, wiringPi, and RF codes.
Other things to try:
- Make sure your json is valid:
/opt/nodejs/bin/npm install --global jsonlint && jsonlint -q /etc/homebridge/config.json
(no output means it looks good) - Remove the
persist
directory:sudo rm -r /etc/homebridge/persist
. This folder caches settings that may screw you up if you’re changing the config. Note that you’ll like need to redo your iOS setup. - Reset your iOS device HomeKit settings:
Settings
->Privacy
->HomeKit
->Reset HomeKit Configuration
- Delete your “Home” from HomeKit Catalog: hit the
Configure
button (bottom right) twice, swipe left on your “Home” - Run homebridge in debug mode:
sudo -u homebridge DEBUG=* /opt/nodejs/lib/node_modules/homebridge/bin/homebridge -D -U /etc/homebridge
- If you’re testing directly in nodejs and it can’t find your modules:
export NODE_PATH=/opt/nodejs/lib/node_modules
- Test with
node-rcswitch-gpiomem
. Install:/opt/nodejs/bin/npm install --global rcswitch-gpiomem
then make a file e.g.fake.js
that you can give a test RF code:/opt/nodejs/bin/node fake.js 12345
// fake.js
var rcswitch = require('rcswitch-gpiomem');
var code = process.argv[2]
rcswitch.enableTransmit(17);
rcswitch.setPulseLength(190);
rcswitch.send(parseInt(code), 24);
That’s it! Hope you get things running smoothly. I don’t know much about Javascript or C++, so I might refer you to the homebridge
team for setup issues, but I’m happy to try to answer questions and comments here, or feel free to open an issue or pull request on the GitHub repos.