31 July 2015

DIY HomeKit Accessory

This is a short introduction to HomeKit accessories. More specifically, I will show how to develop your own HomeKit bridge and deploy it on a Raspberry Pi.

Overview

A HomeKit bridge is a program running on a computer. It receives commands from a client (e.g. iOS app), process it and controls something in your house. For example a light bulb HomeKit bridge receives a command to turn on the light. The bridge doesn’t know when it will receive commands and therefore the program has to run all the time. Those kinds of programs are called daemons, because they run all the time in the background. We have to make sure that our little daemon is very cpu, power and memory efficient. It should run for years without a restart.

The commands, which are received by the bridge, are defined in the HomeKit Accessory Protocol (HAP). This protocol defines how the connection is established, and what kind of information the devices can send to each other. The protocol documentation is only available to MFi members. The rest of us can use HomeControl, which is an implementation of the protocol in Go.

Components

In our example, we have a HomeKit daemon running on a Raspberry Pi, which communicates with an HomeKit iOS app using the HAP. The daemon also communicates with the light bulb. How this is done depends on the kind of light bulb you have. If the light bulb does not support any specific communication protocol, you could simply turn the power supply on and off.

HomeKit Components

Implementation

Lets implement a light bulb HomeKit bridge using HomeControl. Create a new Go file named hklightd.go. We assume that there are two methods turnLightOn() and turnLightOff() to turn the light on and off. First we create a light bulb accessory object and give it the name Personal Light Bulb.

info := model.Info{
    Name: "Personal Light Bulb",
    Manufacturer: "Matthias",
}

light := accessory.NewLightBulb(info)

When the iOS app sends a command to turn the light on or off, HomeControl receives and processes the command, and updates the power state of the light. We use the OnStateChanged(func(bool)) method to register a callback to get notified when this happens.

light.OnStateChanged( func(on bool) {
    if on == true {
        turnLightOn()
    } else {
        turnLightOff()
    }
})

Then we make the accessory available over IP using the pin 32191123.

t, _ := hap.NewIPTransport("32191123", light.Accessory)
t.Start()

Deployment

Our HomeKit bridge will be deployed on a Raspberry Pi 2 running Linux. We compile our program for the Linux operating system and ARMv5 architecture.

GOOS=linux GOARCH=arm GOARM=5 go build hklightd.go

We use GOARM=5 instead of GOARM=6 to prevent the SIGILL: illegal instruction error because of Go’s floating point issues on ARMv6.

The program has to run all the time and runit makes that easy. runit lets us define services, which should be started automatically. Services will also be restarted, if the process terminated. By default, runit requires a subdirectory in /etc/services; for example /etc/services/hklight. In this directory we move the hklightd executable and create another executable file called run, which looks like this

#!/bin/sh
exec ./hklightd 2>>/var/log/hklightd.log

With exec ./hklightd we execute our daemon, and 2>>/var/log/hklightd.log saves log outputs to /var/log/lightd.log. You can manually start, stop or restart the daemon by calling runsv start hklight, runsv stop hklight or runsv restart hklight.

Our light bulb is now accessible via HomeKit and secured with the pin 32191123. You can pair it with any HomeKit iOS app (e.g. Home.app). The communication is secured using strong encryption used in HAP. Because our accessory supports HomeKit, we get some features for free.

  • Accessory Sharing: You can share your accessory with other iCloud users.
  • Remote Access: Starting with iOS 9, you can remotely control the light bulb from anywhere on the world. Remote access requires that an Apple TV (3rd generation or later) is connected to the same network as the HomeKit accessory.
  • Siri Voice Commands: You can use Siri commands to turn your light on and off.

For more info about those features, checkout the official HomeKit support page.

The HomeKit bridge source code is available on Github.