Pinterest Stumbleupon Whatsapp
Ads by Google

HomeKit is finally out in the wild, enabling voice control through Siri for a handful of consumer smart home devices.

Sadly, I mean a literal handful – anything you’ve already bought probably isn’t compatible. However, the protocol has already been reverse engineered and an open source emulator for the HomeKit API is availble: or in plain English, you can now create “fake” HomeKit devices, and Siri will control them just like any other official HomeKit accessory.

Today, we’re going to create a Wi-Fi controllable light, and control it with Siri. Here’s a demo.

Here’s what you’ll need:

  • Raspberry Pi (I’ve used an RPi2, there is a small difference in Node versions to install given the upgraded ARM architecture – see notes later).
  • An MQTT broker installed on the Raspberry Pi. See the section “Install Mosquitto on Your Pi” in my OpenHAB Guide part 2 OpenHAB Beginner's Guide Part 2: ZWave, MQTT, Rules and Charting OpenHAB Beginner's Guide Part 2: ZWave, MQTT, Rules and Charting OpenHAB, the open source home automation software, far exceeds the capabilities of other home automation systems on the market – but it's not easy to get set up. In fact, it can be downright frustrating. Read More . It doesn’t need to be installed specifically on the Pi – you can even use a cloud based MQTT server, but since we need a Pi for this tutorial anyway, it’s convenient.
  • NodeMCU v2 (Arduino compatible)
  • Neopixel LEDs (I’d recommend 4 pixels for testing, then you can add an external power supply and add as many as you like)

Installing the HomeKit Bridge

We’re going to install a NodeJS application called HAP-NodeJS to the Raspberry Pi: this will form a bridge between HomeKit requests and the Wi-Fi devices. We’ll configure this bridge with one accessory for now, but you can add as many as you like.

Ads by Google

I’m actually installing this onto my existing home server running OpenHAB – I hope to connect the two together at a later date, but for now, know that they can co-exist on the same Raspberry Pi. If you’re doing the same, just in case, make a clone backup of your current Pi SD card Easily Clone Your SD Card For Trouble-free Raspberry Pi Computing Easily Clone Your SD Card For Trouble-free Raspberry Pi Computing Whether you have one SD card or several, one thing that you will need is the ability to back up your cards to avoid the problems that occur when your Raspberry Pi fails to boot. Read More . If everything goes wrong, you can restore to that.

Begin by doing a full upgrade from the Terminal or an SSH session Setting Up Your Raspberry Pi For Headless Use With SSH Setting Up Your Raspberry Pi For Headless Use With SSH The Raspberry Pi can accept SSH commands when connected to a local network (either by Ethernet or Wi-Fi), enabling you to easily set it up. The benefits of SSH go beyond upsetting the daily screening... Read More .

sudo apt-get update
sudo apt-get upgrade

You may need to do those twice if it’s been a while.

Now install a few core packages we’re going to need:

sudo apt-get install npm git-core libnss-mdns libavahi-compat-libdnssd-dev

Next, we’re going to install the latest version of NodeJS. You might be tempted to do this with apt-get, but don’t – that version is really old now and will not work. Instead, visit nodejs.org, browse to the download/release/latest-v5.x.0/ directory, and check what the link for the latest version is. You’re looking for linux-armv7l for Raspberry Pi 2, or linuxarmv6l for the original RPi models. Then, adjusting the URLs and directory names as needed, download and install using the following commands.

wget https://nodejs.org/download/release/latest-v5.x.0/node-v5.5.0-linux-armv7l.tar.gz
tar -xvf node-v5.5.0-linux-armv7l.tar.gz
cd node-v5.5.0-linux-armv7l
sudo cp -R * /usr/local

Confirm by typing

node version

And you should see v5.5 (or whatever the latest was that you downloaded).

Next, we have some Node modules to install.

sudo npm install -g npm
sudo npm install -g node-gyp

In that first command, we’re actually using the Node Package Manager (npm) to install a newer version of itself. Clever!

Now, to download the HomeKit emulator called HAP-NodeJS:

git clone https://github.com/KhaosT/HAP-NodeJS.git
cd HAP-NodeJS
npm rebuild
sudo npm install node-persist
sudo npm install srp

At this point, I ran this error: “#error This version of node/NAN/v8 requires a C++11 compiler“. If that happens to you, install a more recent C++ compiler with the commands:

sudo apt-get install gcc-4.8 g++-4.8
sudo update-alternatives --install/usr/bin/gccgcc/usr/bin/gcc-4.6 20
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.6 20
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50

Now you shouldn’t have a problem. Continue running these commands, one by one:

sudo npm install srp
sudo npm install mdns --unsafe-perm
sudo npm install debug
sudo npm install ed25519 --unsafe-perm
sudo npm install curve25519 --unsafe-perm

That should be everything. Try running the emulator with:

node Core.js

If you get errors saying it can’t find such and such module, just use the sudo npm install command again, and affix the name of whatever module was missing. Assuming all is well, you should see a few warnings, and your HomeKit bridge will be running. This is what success looks like:

hap-nodejs installed

You can see immediately that it’s already created a set of 6 fake devices. We’ll use those as a starting point for our own Wi-Fi light later, but we’ll just use those for now to test. You can also see more debug information if you start the server with:

DEBUG=* node Core.js

Now jump over to an Apple device capable of running Siri. Apple curiously doesn’t provide a stock HomeKit app except to registered developers, so download the free Elgato Eve app, a HomeKit management app which enables you to add (even non-Elgato) devices to your HomeKit network.

The first time you launch the app you’ll need to name your home, go ahead and walk through that. Then select “Add Accessory”. Ignore the message about being close to it!

elgato eve 1

It’ll tell you to look for a unique “HomeKit Setup Code” next. Ignore that, and hit “Add to [name of your home]”.

It’ll also tell you the device isn’t certified. Indeed it isn’t. Go ahead anyway. When you get to the screen asking for an accessory code…

elgato eve 2

Choose to enter the code manually, and type in the following:

031-45-154

This can be found/changed in the Light_accessory.js file, but more on that later. Add this accessory to your default room, call it Fake Light, and keep walking through the dialogs to choose icon etc.

Finally, jump back to the SSH session where you have HAP-NodeJS running. You might already have seen a message saying “Are we on?” – that’s the Elgato app polling for the light status. Open Siri and tell her to “Turn on fake light”, then try turning it off again. Hopefully, you’ll see some debug messages from HAP-NodeJS to show it received the commands.

Are we on? No.
Turning the light on!
Turning the light off!

Fantastic, that’s step one finished. Now we’ll need an actual light, before coming back to configure the bridge again.

Building a Wi-Fi Light

The hardware side of this step is surprisingly simple if we start with just four Neopixels, as we can power those directly from the NodeMCU dev board and its USB connection. If you have a longer strip, don’t worry – we’ve defined this in software, so the rest just won’t turn on.

Connect the red power cable from a Neopixel strand to the VIN pin, blue ground to GND, and the green signal cable to the pin marked D2 on the NodeMCU. Be very careful about polarity: if you mix up the ground and VIN, you’ll send a surge of power through your board, and destroy it in the process.

If your Arduino environment isn’t yet setup to work with ESP8266, go ahead and follow the guide in my ESP8266: Arduino Killer Meet the Arduino Killer: ESP8266 Meet the Arduino Killer: ESP8266 What if I told you a there's an Arduino-compatible dev board with built-in Wi-Fi for less than $10? Well, there is. Read More guide then come back after you’ve confirmed that’s working. Install these additional libraries:

The code we’re using is a modification of Github user Aditya Tannu’s – I’ve removed the unnecessary over-the-air update functionality, added in some HSV functions that were missing, and made it easier to create more lights by only changing a single variable. If you can’t see the code embedded below, you’ll find it at this Gist.

Update the following lines with your own network information, and a unique name for each fixture you create (host).

const char* ssid = "....";
const char* password = "...";
const char* host = "officelight"; 
IPAddress MQTTserver(192, 168, 1, 99);

The IP address of this fixture is automatically obtained through DHCP – it doesn’t matter if it changes, since we’re connecting to the same MQTT server each time.

For now we’re only using 4 Neopixels, but you can increase the number later if you power them from an external source. Upload the code, and let’s test – use your favorite MQTT client to send commands (adjust the host name in the following instructions if you’ve changed it).

  • You can send on to the root officelight channel to turn it on. Send any other value to that channel to turn it off.
  • You can send a number from 0-360 to the officelight/hue to change the color. We’re using the HSV color space, so 0 and 360 are red, 120 is green, and 240 is blue.
  • You send a percentage value for brightness (0-100, don’t include the % symbol).
  • Same for saturation. A value of 100 will be fully saturated (ie, a solid color), and zero will be pure white, regardless of the Hue specified.

Once you’ve confirmed your MQTT-driven lighting fixture is working, move on.

Configuring a New HomeKit Accessory

Switch back to the Raspberry Pi and terminate the HAP-NodeJS app if you haven’t already. Navigate to the /accessories directory. To make this easy, you can directly download code that’s already been paired to the “officelight” fixture by typing in the following:

wget https://gist.githubusercontent.com/jamesabruce/a6607fa9d93e41042fee/raw/12e4fd1d1c2624e7540ba5e17c3e79bc6bdec5fd/Officelight_accessory.js

Essentially, this is a duplicate of the default light accessory, with some variable names changed (again, adapted from Adysan’s work, simplified for ease of use). Here’s what you should know for creating your own custom accessories based on this.

  • All accessories must be named *_accessory.js
  • Change the IP address in the options variable at the top to your MQTT server
  • If you’ve got a different fixture name, search/replace all instances of “officelight” with your unique fixture name. You can do a search/replace in Nano by pressing CTRL and \, typing the term to find, the term to replace, then hit A (meaning all instances). Step through each of these to learn precisely which variables are being updated.
  • Create a unique hexadecimal username for the accessory (light.username = “1B:2B:3C:5D:6E:FF”;)
  • Don’t change the PIN code. It follows a specific format, and unless you know what you’re doing, it won’t be able to pair. There’s no issue with keeping them the same between lights.
  • You can give your fixture a different “Siri name” when adding them to the Elgato Eve app, and edit those at any time so you’re not stuck with your initial choice. There’s no need to edit the configuration files or restart the server.
  • Once you’ve got multiple fixtures, you can use the Elgato Eve app to group them by room, or to create specific scenes consisting of multiple complex actions. Scenes can consist of multiple actions, such as: turn on the office light, dim it to to 25%, make it red, and activate the coffee machine.

You’ll need to add your new accessory through your HomeKit app of choice again.

Finally, we want to run our HAP-NodeJS app whenever the Pi is restarted. Add the following to your etc/rc.local file, right before the exit 0.

sudo node /home/pi/HAP-NodeJS/Core.js < /dev/null &

You can see I’ve combined this with some other commands I already have set to start on boot.

rclocal run node on startup

If this is the first time you’re using rc.local, you may need to set it as executable:

sudo chmod 755 /etc/rc.local

If for some reason you need to run it in debug mode again, you can kill the running Node app with:

killall node

One final step: navigate to the accessories directory, and delete the GarageDoorOpener_accessory.js. At the time of writing this is buggy, and will cause the server to break after a while.

What Will You Control With Siri?

Now that you’ve got the basics down, there’s really no limit to what you can control – if you can code it in Javascript, you can make your own accessory file. There’s so much potential here, I think you’re going to have a lot of fun. Let me know in the comments what you come up with!

  1. Lisergio
    October 25, 2016 at 9:43 pm

    hi again!
    I would like to make some accessory to control blinds, to detect motion and thermostat, all using esp8266 modules. where I can find some tutorial to get it?

  2. Ruben
    October 23, 2016 at 6:29 pm

    I can't upload the sketch to the esp 8266 due to this line:
    PubSubClient client(wclient, MQTTserver);

    Does anyone has a solution for me?

    This was the error it gave me:
    no matching function for call to 'PubSubClient::PubSubClient(WiFiClient&, IPAddress&)'
    PubSubClient client(wclient, MQTTserver);

    • James Bruce
      October 25, 2016 at 12:14 pm

      Are you using the library linked in the article? There's a couple of versions floating around, some of which don't have the needed function.

  3. Jon
    October 13, 2016 at 9:25 am

    Is there any reason to use Hap-NodeJS instead of OpenHAB with OpenHAB-HomeKit-Bridge?

    • James Bruce
      October 13, 2016 at 9:46 am

      Nope. If you're integrating into OpenHAB, that's the best way to go. This was designed as a standalone tutorial.

  4. Dragos
    October 12, 2016 at 4:10 pm

    Hi,
    Can it be integrated with an existing Openhab configuration? I know it can but I don't know how.
    This tutorial could be more interesting if would be a related to your other tutorials already done!
    I have Openhab installed on my Rpi, using an Arduino with a few sensors through Mqtt and a few zwave devices already integrated in OH, including a Logitech Harmony remote so it would be very important to me to keep my configuration but to complete it with HomeKit!
    What do you think about this?
    Thanks.

  5. Peter Moffat
    October 9, 2016 at 1:49 pm

    Thanks for this!

    I've got it it running on multiple Wemos D1 Minis, with the MQTT and HAP-Node.js running on my home server.

    For the life of me however, I can only get them to run individually, i.e. if all the devices using your accessory and sketch are on, none work. They seem to be fine, and then fail to respond after a minute or two.

    I've used your accessory file and replaced all the references to 'óffice' with 'bedroom' or 'kitchen' as appropriate, maintaining case as per your original, along with chaning the host in the sketch to match.

    If I power the units on individually, each works perfectly and responds only to its device in the Home app, but if more than one is on, none of them seem to work, as said above.

    I also have other accessories, a couple of sonoff's controlling mains lights, they are also running similar sketches (though just on/off), and function fine all the time.

    Any idea what I'm doing wrong here?

    • James Bruce
      October 11, 2016 at 9:00 am

      Could you post your code for another accessory to a pastebin or something for us to take a look at? Make sure you've changed the " clientId: 'MakeUseOf Wifi Light' " for each one, otherwise you'll have them all reporting as the same client to the MQTT server.

  6. Peter Moffat
    October 9, 2016 at 1:48 pm

    Thanks for this!

    I've got it it running on multiple Wemos D1 Minis, with the MQTT and HAP-Node.js running on my home server.

    For the life of me however, I can only get them to run individually, i.e. if all the devices using your accessory and sketch are on, none work. They seem to be fine, and then fail to respond after a minute or two.

    I've used your accessory file and replaced all the references to 'office' with 'bedroom' or 'kitchen' as appropriate, maintaining case as per your original, along with changing the host in the sketch to match.

    If I power the units on individually, each works perfectly and responds only to its device in the Home app, but if more than one is on, none of them seem to work, as said above.

    I also have other accessories, a couple of Itead Sonoff's controlling mains lights, they are also running similar sketches (though just on/off), and function fine all the time.

    Any idea what I'm doing wrong here?

  7. Lisergio
    October 6, 2016 at 11:30 am

    finally, everything works perfect.
    I modified the code esp8266, so only turn a relay.

    It would be possible to send data from the esp8266 to the homekit bridge to read the temperature of a sensor DHT11, and make a thermostat?

    thanks again for all!!

  8. Simone
    October 5, 2016 at 3:23 pm

    There is a bug in the code, everything works perfectly except the brightness.

    to explain better. the brightness setting is not saved after power off.

    so if you set the brightness to 25% (for example) and turn off the lights, the next time you turn it on it always comes back to 100%,
    even if your phone still displays the previous setting.

  9. Lisergio
    October 4, 2016 at 8:40 pm

    is possible, make the wifi-lamp, using a esp8266-01.. to connect a simple led, or relay module??
    i compile the sketch using 1.6.4 version , but get some errors...

    Arduino:1.6.4 (Mac OS X), Placa:"Generic ESP8266 Module, Serial, 80 MHz, 40MHz, DIO, 115200, 512K (64K SPIFFS), ck, Disabled, None"

    wifi_homekit_esp_8266:24: error: no matching function for call to 'PubSubClient::PubSubClient(WiFiClient&, IPAddress&)'

    thanks again!

    • James Bruce
      October 5, 2016 at 8:05 am

      Sounds like you're using the wrong MQTT library. Did you download the one mentioned in the article?

      • Lisergio
        October 5, 2016 at 5:20 pm

        thanks...
        i download the pubsubclient library.. but was corrupt, I've downloaded again and now works correctly...

  10. Lisergio
    October 4, 2016 at 8:33 pm

    WORKS!!!

    i need to install another packages...

    sudo npm install curve25519-n

    sudo npm install ip

  11. Lisergio
    October 3, 2016 at 9:34 pm

    when execute , node Core.js , return this error:

    module.js:457
    throw err;
    ^

    Error: Cannot find module '/usr/lib/node_modules/hap-nodejs/node_modules/mdns/Core.js'
    at Function.Module._resolveFilename (module.js:455:15)
    at Function.Module._load (module.js:403:25)
    at Module.runMain (module.js:590:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:509:3

    • James Bruce
      October 4, 2016 at 2:07 pm

      Looks like you're missing "mdns". Try "npm install mdns"

  12. orio
    October 2, 2016 at 2:29 am

    Anyone knows if this works with a regular RBG led strip?

    • James Bruce
      October 2, 2016 at 7:53 am

      If you replace the Arduino portion of the code, then yes. That's pretty heavy modification though.

  13. Lisergio
    October 1, 2016 at 3:54 pm

    I took several days trying, and I always have errors in the installation, someone has a image of raspbian, yet Installed?

  14. Lisergio
    September 30, 2016 at 10:24 pm

    Hi! Good job.!

    I try to make the install in RPi2,using jessie-raspbian but have some errors...
    (thanks for help)
    when type "node version " get this error:

    module.js:341
    throw err;
    ^

    Error: Cannot find module '/node-v5.12.0-linux-armv7l/version'
    at Function.Module._resolveFilename (module.js:339:15)
    at Function.Module._load (module.js:290:25)
    at Function.Module.runMain (module.js:447:10)
    at startup (node.js:148:18)
    at node.js:405:3

    and when type "sudo npm install srp"

    get more ...

    > bignum@0.12.5 install /node-v5.12.0-linux-armv7l/HAP-NodeJS/node_modules/bignum
    > node-pre-gyp install --fallback-to-build

    node-pre-gyp ERR! Tried to download: https://rvagg-node.s3-us-west-2.amazonaws.com/bignum/v0.12.5/bignum-v0.12.5-node-v47-linux-arm.tar.gz
    node-pre-gyp ERR! Pre-built binaries not found for bignum@0.12.5 and node@5.12.0 (node-v47 ABI) (falling back to source compile with node-gyp)
    gyp WARN EACCES user "root" does not have permission to access the dev dir "/root/.node-gyp/5.12.0"
    gyp WARN EACCES attempting to reinstall using temporary dev dir "/node-v5.12.0-linux-armv7l/HAP-NodeJS/node_modules/bignum/.node-gyp"
    make: Entering directory '/node-v5.12.0-linux-armv7l/HAP-NodeJS/node_modules/bignum/build'
    make: *** No rule to make target '../.node-gyp/5.12.0/include/node/common.gypi', needed by 'Makefile'. Stop.
    make: Leaving directory '/node-v5.12.0-linux-armv7l/HAP-NodeJS/node_modules/bignum/build'
    gyp ERR! build error
    gyp ERR! stack Error: `make` failed with exit code: 2
    gyp ERR! stack at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:276:23)
    gyp ERR! stack at emitTwo (events.js:100:13)
    gyp ERR! stack at ChildProcess.emit (events.js:185:7)
    gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_proces

  15. Ben Chen
    September 3, 2016 at 7:34 am

    This works great! Thanks for sharing the experience. But should there be a logic level shifter between the D2 pin on NodeMCU and the green signal cable of the NeoPixels? Or as long as it works, there should be no problem with that?

  16. Robert
    August 11, 2016 at 9:05 pm

    There's a line missing before "node Core.js". You need to add
    "npm install mqtt --unsafe-perm"
    Also, the accessories the the ./accessories directory don't update any mqtt status. It took me a while to add the proper statements in my *_accessory files:

    // MQTT Setup
    var mqtt = require('mqtt');
    console.log("Connecting to MQTT broker...");
    var mqtt = require('mqtt');
    var options = {
    port: 1883,
    host: '192.168.2.180',
    clientId: 'OfficeLight'
    };
    var client = mqtt.connect(options);
    console.log("Wifi Light Connected to MQTT broker");

  17. Menno
    March 3, 2016 at 4:08 pm

    Hello James,

    I'm super new to all this and frankly quite a noob (don't own a Raspberry Pi yet, for instance)

    My goal is to control the lights in my house using WiFi, and ideally Siri, without having to buy, say, those ridiculously expensive Hue bulbs. However, I'm a bit overwhelmed by all of the terminologies flying around here. What is the best place for me to start?

    Would love some guidance,
    Kind regards,

    Menno
    (The Netherlands)

  18. Abishek
    February 21, 2016 at 9:48 pm

    This works great if your on your local network at home. How do you get it to work remotely over LTE for example ?

    • James Bruce
      February 22, 2016 at 10:26 am

      As silly as this sounds, you need an Apple TV. This creates the bridge from your home to the outside world that allows you to use HomeKit remotely. There is no alternative to this currently.

      • Abishek
        February 22, 2016 at 7:59 pm

        Thanks

    • Pierre Bodyn
      July 30, 2016 at 11:11 am

      It's works with lte ect. You need a iPad or mac @home .. or a dyndns for your raspberry.

      • Martin
        August 23, 2016 at 9:30 am

        Pierre would you mind explaining how you would get siri to communicate to the RPi with and iPad or Mac at home? Please

        • Pierre Bodyn
          August 23, 2016 at 10:38 am

          iPad with ios10 ->Settings->HomeKit->set @home. Done

        • Pierre Bodyn
          August 23, 2016 at 10:42 am

          Btw iPad & iPhone have to be in the same cloud!

        • James Bruce
          August 23, 2016 at 10:47 am

          iOS 10 isn't out yet, and that option isn't there on latest iOS 9.

Leave a Reply

Your email address will not be published. Required fields are marked *