お金をかけずにHomeKitアプリ開発体験

#機材がなくてもHomeKitを体験できる
iOS10からホームアプリも標準で搭載されるようになりましたが、日本で購入できるHomeKit対応製品は限られているうえに安くもありません。
ちょっと体験してみるだけならシミュレータを使って出来るので感触をつかむのに便利です。

##HomeKitの説明
HomeKitにはホームやルームといった概念があります。
概念的な説明はクラスメソッドさんのブログが親切なのでご参照ください。

[[iOS 8] HomeKit 対応アプリを作ろう (2) 開発を始めるための基礎知識](http://dev.classmethod.jp/smartphone/ios-8-homekit-basic/)

本記事では実装を進めてみます。
環境はXCode8、iOS10を想定しています。

##HomeKit対応アプリの作成
新規アプリケーションを作成して、プロジェクトからTARGETSを選択して「Capabilities」タブを選択します。
そこから「HomeKit」のスイッチをONにします。
![スクリーンショット 2016-10-15 19.22.58.png](https://qiita-image-store.s3.amazonaws.com/0/143909/6ccaffa0-8442-8c79-9326-261033cfc002.png)

すると下の部分に「Download HomeKit Simulator...」というボタンが出て来るのでクリックします。

![スクリーンショット 2016-10-15 19.24.56.png](https://qiita-image-store.s3.amazonaws.com/0/143909/cc677d28-3f66-c77e-d43b-80449d972256.png)

するとダウンロードページに飛ぶので、「Additional Tools for Xcode8」というものをダウンロードします。ダウンロードしたdmgファイルをダブルクリックして「Hardware」の下にいる「HomeKit Accessory Simulator」をアプリケーションディレクトリにドラッグアンドドロップします。

##HomeKit Accessory Simulator

それでは早速HomeKit Accessory Simulatorを起動させてみましょう。

![スクリーンショット 2016-10-15 19.27.56.png](https://qiita-image-store.s3.amazonaws.com/0/143909/c26c83eb-16ce-2c4b-07ad-b263327b74bc.png)

起動したら「File」-「New」-「Accessory」と選択して新たなアクセサリーを追加します。

![スクリーンショット 2016-10-15 19.28.36.png](https://qiita-image-store.s3.amazonaws.com/0/143909/dcfc322e-d1d4-f5fc-bee4-6c196c920996.png)

Name、Manufacturer、Modelに適当に入力します。Serial Numberはデフォルトのままで構いません。
Finishをクリックします。
するとアクセサリーが追加され、そのアクセサリーを選択すると右側ペインの下側に「Add Service」というボタンがあるのでこれをクリックします。

![スクリーンショット 2016-10-15 19.29.11.png](https://qiita-image-store.s3.amazonaws.com/0/143909/754324d0-4baa-09a7-3d64-cf8ee086f6e5.png)

アクセサリーはHomeKitに対応した機器そのものを指し、サービスというのはそのアクセサリーが何を提供するかを指します。ライト、ドア、センサーなど様々なものが定義されており（なければカスタムがある）、１つのアクセサリーが複数のサービスを提供する場合もあります（ドアとカメラ、など）。
ここではとりあえず「Lightbulb」を選択します。Nameは適当に入力するかデフォルトのままでいいでしょう。

![スクリーンショット 2016-10-15 19.29.35.png](https://qiita-image-store.s3.amazonaws.com/0/143909/53d3da62-1d1c-0300-9956-7464938ef8c0.png)

選択したサービスに応じたインターフェースが表示されます。

##標準のホームアプリから試してみる
この時点でiOS10標準のホームアプリからシミュレータ上のアクセサリーにアクセスできます（同一ネットワークに存在している場合）。
![IMG_2174.PNG](https://qiita-image-store.s3.amazonaws.com/0/143909/539017d2-b707-eaf3-9eba-f94278b56f28.png)

ホームアプリを起動して「アクセサリを追加」をタップします。

![IMG_2175.PNG](https://qiita-image-store.s3.amazonaws.com/0/143909/4a01d427-0f10-d62c-b4a6-49b553304a34.png)

するとシミュレータに追加したアクセサリが見えます。
これを追加してみると以下のように明るさや色を設定できます。
![IMG_2176.PNG](https://qiita-image-store.s3.amazonaws.com/0/143909/8d46a3aa-a55b-114c-acd3-017d69f6a024.png)

アプリで操作するとシミュレータ上の設定値も連動して変化するのを確認してみましょう。

##Homekitアプリを自作する
まずホームに登録していない状態のアクセサリーをリストアップするプログラムがクラスメソッドさんのブログに載っているので、ご参照ください。

[[iOS 8] HomeKit 対応アプリを作ろう (3) Swift で54行で試せる HomeKit のアクセサリーブラウザの実装方法](http://dev.classmethod.jp/smartphone/iphone/homekit-accessorybrowser/)

上記サンプルで使われているHMAccessoryBrowserの注意点としては「未登録状態のアクセサリーをリストアップする」ということです。先程のホームアプリなどで追加した場合はリストされないので、実験する前には登録を解除しておきましょう。

さて、本記事では先程シミュレータに追加したLightbulbの明るさを設定するアプリをつくってみましょう。
設定値の更新は登録済みのアクセサリーに対してのみ可能なので、ホームアプリでアクセサリーを登録した状態にしておいてください。

##ホームに登録されているアクセサリーの取得
ホームにアクセスするにはHMHomeManagerを使います。

```ViewController.swift
import UIKit
import HomeKit

class ViewController: UIViewController, HMHomeManagerDelegate {
    @IBOutlet weak var acSlider: UISlider! // 明るさ更新用のスライダー
        
    let homeManager = HMHomeManager()
    var home: HMHome?
    var myAccessory: HMAccessory?
```
スライダーはストーリーボードから追加しておいてください。
0〜100の値をとるように設定しておき、valueChangedのアクションも追加しておきましょう。

HMHomeManagerDelegateはホームの情報に変化があった場合に呼ばれるデリゲートです。

```ViewController.swift
override func viewDidLoad() {
        super.viewDidLoad()
        homeManager.delegate = self
}

func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
        home = manager.primaryHome        
        // HomeアプリなどでHomeにアクセサリを追加済みであること
        myAccessory = home?.accessories[0]
        getValue()　　// 現在の値の取得
}
```

HomeManagerインスタンスのprimaryHomeはユーザーが主に利用しているホームを格納しています。
homeManagerDidUpdateHomesが呼ばれた後でないと有効な値が入っていません。
そしてそのhomeのaccessoriesからそのホームに直接登録されているアクセサリーにアクセスできます。
ここでは決め打ちで先頭のアクセサリーを取り出しています。
なお、ホームに部屋を追加して、そこにアクセサリーを登録している場合はホームからroomsで対象の部屋を取り出して、と辿りながらアクセスします。

それでは値を取得しているgetValueを実装しましょう。

```ViewController.swift
func getValue() {
    guard let accessory = myAccessory else {
        return
    }
        
    var brightness = 0
    for service in accessory.services {
        if service.serviceType == HMServiceTypeLightbulb {
            for c in service.characteristics {
                if c.characteristicType == HMCharacteristicTypeBrightness {
                    c.readValue(completionHandler: { [weak self] _ in
                        brightness = c.value as! Int
                        self?.acSlider.value = Float(brightness)
                    })
                }
            }
        }
    }
}
```
アクセサリーは複数のサービスを持てるので１つずつ取り出してチェックしています。
目的のサービスかどうかはHMServiceのserviceTypeで見ていきます。
サービスタイプはHMServiceTypes.hに定義されています。
ここではLighbulbを探しています。
各サービスには参照可能な設定値があり、characteristicsに複数格納されています。
こちらも１つずつ取り出して目的の明るさを表す値を探します。
目的のcharacteristicを見つけたらHMCharacteristicのreadValueメソッドを呼び出してコールバックでvalueから値を取り出します。
readValueを呼ばずにvalueにアクセスしてもnilになっています。

次にスライダーを操作して明るさを操作します。

```ViewController.swift
@IBAction func changedBrightness(_ sender: AnyObject) {
    guard let accessory = myAccessory else {
        return
    }
        
    let value = Int(acSlider.value)
    for service in accessory.services {
        if service.serviceType == HMServiceTypeLightbulb {
            for c in service.characteristics {
                if c.characteristicType == HMCharacteristicTypeBrightness {
                    c.writeValue(value, completionHandler: { error in
                        print(error)
                    })
                }
            }
        }
     }
}
```
目的のcharacteristicを見つけるまではgetValueと同じです。
readValueの代わりにwriteValueを呼び出すだけです。
このアプリでスライダーを操作するとシミュレータ上の「Brightness」のバーと連動して変化します。

##参考
[HomeKitデベロッパガイド](https://developer.apple.com/jp/documentation/HomeKitDeveloperGuide.pdf)