IoT under iOS control. Part 1.

In iOS 10 Apple added a new app - Home. Apple.com says about this app:

With the new Home app, you can securely control all your HomeKit accessories from your favorite iOS device. Have your iPhone turn off the lights. See who’s at the front door from your iPad. And even control things remotely with the help of Apple TV. The Home app makes all your connected devices work harder — and smarter — for you.

After reading this I decided to get into it and find out how it works. So, I created my own iOT device which will be controlled by iOS. In the following series of the articles, I will show how to make it work.

First of all, Home App is made by using Apple’s HomeKit Framework, which you can implement in your own app.

So, what HomeKit is for:

  1. It allows accessories to talk to each other
  2. You can configure and control your accessories
  3. Accessories control by using Siri
  4. iCloud synchronization

What do you need to create your IoT under iOS control?

In my example, I will use Led(Lightbulb), Temp sensor and Relay to control Coffee Machine.

In order to create custom accessory which doesn’t have “works with Apple HomeKit” label and be discoverable by HomeKit, it’s necessary to implement HomeKit Accessory Protocol(HAP). To get access to Apple’s HAP you need to be a part of MFi program. Since we are not, we need to use some third party implementations. I will use library written in GO to write protocols for all of our accessories. So let’s get started with some coding!

All code listed below you can find here.

Getting Started:

  1. Install GO
  2. Setup GO workspace
  3. Create and go to your project directory:
cd $GOPATH/src 
mkdir HomeKitDemo
cd HomeKitDemo
vim lightbulb.go // or use the editor you like

Import libraries:

package main
import (
"fmt"
"github.com/brutella/hc"
"github.com/brutella/hc/accessory"
"io/ioutil"
"log"
"net/http"
)

Let’s describe lightbulb with providing some infromation about it:

func main() {
// here you provide all infromation about your IoT
lightBulbInfo := accessory.Info{
Name: "Lightbulb",
Manufacturer: "Vlad Somov",
SerialNumber: "12345678",
Model: "1",
}
}

Create a lighbulb from given information:

acc := accessory.NewLightbulb(lightBulbInfo)

Create a transport to provide accessory over IP with Pin to pair with our lightbulb:

bulb, err := hc.NewIPTransport(hc.Config{Pin: "YOUR_PIN_HERE_SHOULD_CONTAIN_8_DIGITS"}, acc.Accessory)
if err != nil {
log.Fatal(err)
}

Furthermore, every accessory has different characteristics. For example, lightbulb has:

  1. Power State (On/Off)
  2. Brightness
  3. Hue
  4. Saturation

Add a callback function to be able to monitor power state changes:

acc.Lightbulb.On.OnValueRemoteUpdate(func(on bool) {
if on == true {
log.Println("Turn Light On")
} else {
log.Println("Turn Light Off")
}
})

Describe what to do onTermination:

hc.OnTermination(func() {
bulb.Stop()
})

Start bulb:

bulb.Start()

Let’s try if our accessory protocol is working :)

Download the required package along with its dependencies:

go get github.com/brutella/hc

Run your code by following command:

go run lightbulb.go
If everthing is ok, you will see something like this.

Test if our iOS device sees lightbulb:

  1. Open Home App.
  2. Add Home and Room if you open this app first time.
  3. Click on Add Accessory Button
  4. If everything is ok, your Lightbulb will be discoverable.
  5. You can use QRcode or enter code manually to add lighbulb. We will enter code manually by using pin from the following code:
bulb, err := hc.NewIPTransport(hc.Config{Pin: "YOUR_PIN_HERE_SHOULD_CONTAIN_8_DIGITS"}, acc.Accessory)

If the pin is correct you should see:

If you tap on it, you should see that lightbulb changes its state in your terminal:


Now let’s create function which will send GET request with params about device state to our future real lightbulb.

var rootURL = "HERE_WILL_BE_YOUR_IoT_DEVICE_IP_ADDRESS"
func sendRequestToLighbulb(value int) {
// digital/5 means that you will be sending on\off (1 or 0) state to the 5th pin
resp, err := http.Get(fmt.Sprintf("%s/digital/5/%v", rootURL, value))
    if err != nil {
log.Println("Error:", err)
}
    defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
log.Println("Response:", string(body))
}

Create functions which will handle changing state of our lightbulb:

func turnLightOn() {
log.Println("Turn Light On")
sendRequestToLighbulb(1)
}
func turnLightOff() {
log.Println("Turn Light Off")
sendRequestToLighbulb(0)
}

In OnValueRemoteUpdate() call our functions depend on power state:

acc.Lightbulb.On.OnValueRemoteUpdate(func(on bool) {
if on == true {
turnLightOn()
} else {
turnLightOff()
}
})

So far, that is all you need to make your future accessory to implement the HAP. This code and even more you can find in my repository.

This is the first part of iOT under iOS control. Next, in the Part 2, I will tell you about “How to build your iOT device with a REST api”.

So, I hope you will like it ;)

Got any questions?

Please feel free to contact me by: vlad.somov@icloud.com