Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

機材がなくてもHomeKitを体験できる

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

HomeKitの説明

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

[iOS 8] HomeKit 対応アプリを作ろう (2) 開発を始めるための基礎知識

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

HomeKit対応アプリの作成

新規アプリケーションを作成して、プロジェクトからTARGETSを選択して「Capabilities」タブを選択します。
そこから「HomeKit」のスイッチをONにします。
スクリーンショット 2016-10-15 19.22.58.png

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

スクリーンショット 2016-10-15 19.24.56.png

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

HomeKit Accessory Simulator

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

スクリーンショット 2016-10-15 19.27.56.png

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

スクリーンショット 2016-10-15 19.28.36.png

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

スクリーンショット 2016-10-15 19.29.11.png

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

スクリーンショット 2016-10-15 19.29.35.png

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

標準のホームアプリから試してみる

この時点でiOS10標準のホームアプリからシミュレータ上のアクセサリーにアクセスできます(同一ネットワークに存在している場合)。
IMG_2174.PNG

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

IMG_2175.PNG

するとシミュレータに追加したアクセサリが見えます。
これを追加してみると以下のように明るさや色を設定できます。
IMG_2176.PNG

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

Homekitアプリを自作する

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

[iOS 8] HomeKit 対応アプリを作ろう (3) Swift で54行で試せる HomeKit のアクセサリーブラウザの実装方法

上記サンプルで使われている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)
                    })
                }
            }
        }
    }
}

アクセサリーは複数のサービスを持てるので1つずつ取り出してチェックしています。
目的のサービスかどうかはHMServiceのserviceTypeで見ていきます。
サービスタイプはHMServiceTypes.hに定義されています。
ここではLighbulbを探しています。
各サービスには参照可能な設定値があり、characteristicsに複数格納されています。
こちらも1つずつ取り出して目的の明るさを表す値を探します。
目的の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デベロッパガイド

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away