HomeKitアクセサリを作ろう


GoでHomeKitアクセサリを作ろう!

HomeKit

AppleのiOSデバイス向けホームオートメーションフレームワーク。

iOSにはHomeアプリというのが提供されていて、 そこからHomeKit対応アクセサリをコントロールすることができます。

HomeKit対応アクセサリは振る舞いの定義がいくつか定義済みです。

  • ランプ
  • スイッチ
  • ファン
  • コンセント
  • ドア開閉検知
  • ドアロック
  • 人モーション検知
  • ドアインターフォン
  • セキュリティカメラ
  • etc.

アクセサリとiOS端末間はHAP(HomeKit Accessory Protocol)と呼ばれるプロトコルで連携を取ります。

Go用HAPライブラリ

https://github.com/brutella/hc

go get github.com/brutella/hc

サンプルも別のリポジトリにありますのでインストールしてみましょう。

go get github.com/brutella/hklight

これで hklight というバイナリが作られますので実行してみましょう。

$ hklight
INFO 2017/10/27 06:27:39 Accessory address is 10.0.1.4:54250

実際の登録の流れ

Homeアプリ起動

アクセサリ追加1

「コードがないか、スキャンできませんか?」をタップします。

アクセサリ追加2

お!アクセサリが見つかった!それをタップしましょう。
(出て来ない場合はHomeKitコードを入力をタップ)

アクセサリ追加3

認定されていない(オレオレ)と出ますが承認しましょう。

アクセサリ追加4

PINコードは「32191123」でハードコードされていますのでそれを入力してください。

アクセサリ追加5

登録中・・・

アクセサリ追加6

登録できました!完了をタップ。

マイホーム画面

ライトバルブアクセサリが表示されました。タップしてみましょう

ライト点灯

ライトバルブが点灯しました。

ターミナルにログがでます。

2017/10/27 06:42:32 Turn Light On

コード解説

package main

import (
	"github.com/brutella/hc"
	"github.com/brutella/hc/accessory"
	"log"
)

func turnLightOn() {
	log.Println("Turn Light On")
}

func turnLightOff() {
	log.Println("Turn Light Off")
}

func main() {
	info := accessory.Info{
		Name:         "Personal Light Bulb",
		Manufacturer: "Matthias",
	}

	acc := accessory.NewLightbulb(info)

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

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

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

	t.Start()
}

アクセサリを作成

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

	acc := accessory.NewLightbulb(info)

アクセサリのイベントハンドラを記述

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

PINコードとアクセサリを指定してIPTransportを作成

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

IPTransport用イベントハンドラを記述

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

アクセサリをLAN内に公開

	t.Start()

hcライブラリに未定義なアクセサリ

パッケージのhc/accessory/配下にhcが用意したアクセサリ実装がありますが、比較的少なめです。

でも、以下のようにHomeKitに定義済みのタイプであれば上記実装を参考に 簡単にラッパークラスは実装できます。 例えばモーションセンサーを作ってみましょう。

// MotionSensor ...
type MotionSensor struct {
	*accessory.Accessory

	MotionSensor *service.MotionSensor
}

// NewMotionSensor returns a Thermometer which implements model.Thermometer.
func NewMotionSensor(info accessory.Info) *MotionSensor {
	acc := MotionSensor{}
	acc.Accessory = accessory.New(info, accessory.TypeSensor)
	acc.MotionSensor = service.NewMotionSensor()
	acc.MotionSensor.MotionDetected.SetValue(false)
	acc.AddService(acc.MotionSensor.Service)

	return &acc
}

センサーの用に定期的に動くタイプはgoroutineで無限ループを組んで監視します

	go func() {
		for {
			d := getMotionDetected()
			log.Println("Motion Detected:", d)
			acc.MotionSensor.MotionDetected.SetValue(d)
			time.Sleep(5 * time.Second)
		}
	}()

HomeKitのオートメーション

HomeKitは家のLAN内にハブ役がいれば、家の外からの制御やオートメーション機能が利用できます。 (ハブ役なしでもLAN内からの制御はできます) ただし、ハブ役になれるのは・・・

  • AppleTV 3rdGen以降(もうすぐ4thGen以降になるかもしれない)
  • iOS10以降のiPad
  • HomePod(この冬発売予定のApple製ホームアシスタント)

これらのみです。

オートメーション機能はIFTTTのような設定画面がHomeアプリに備わっていて、 トリガになる条件を選んで、操作対象を選んでどのように操作するかパラメータを指定します。

トリガには

  • iOSデバイスが家に帰ってきたら
  • iOSデバイスが家を出たら
  • センサに反応があればorNOT
  • ドアが開いたらorNOT

操作対象には

  • 多くの電力操作アクセサリ

といったものが使えます。 でも今回の記事を応用すれば完全なソフトウェアサービスがアクセサリとして登録できるので、 さらにいろんなことを連携させたりできるでしょう。

例えば特定の時間帯にドアが開いたらSlackにwarningメッセージをポストするとか。 PCを起動したり終了したりしたらGoogleカレンダーに起動期間を記録するとか。

もちろん「RaspberryPi Zero W」などにアクセサリソフトウェアを仕込んで リアルなフィジカルコンピューティングをホームオートメーションの一部にすることができます。

まとめ

  • 意外とお手軽にHomeKitアクセサリが作れますよ
  • HomeKitはクラウド側に何も準備がいらないのにリモート制御やオートメーションが作れる
  • 唯一のツラミは家にハブ役(結構お高い)が必要なこと
  • HomePodは他社のものに比べお高いがこの機能があるなら高くないのかも?!
comments powered by Disqus