3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

DENSOAdvent Calendar 2021

Day 20

AppleHomeKitでデバイスを動作させるために、homebridge用のデバイスをtypescriptで書く

Last updated at Posted at 2021-12-19

AppleHomeKitとは

ここに紹介されているように、Appleが提供するスマートホームを提供するためのプラットフォーム。他社製品(google, alexa)と異なり、ローカルネットワークで動くためインターネットに接続できない環境でも動作する。そのカラクリはローカルネットワークにiPadかAppleTVなどのデータハブが存在し、ハブ経由で通信が実行されることだ。つまり、インターネットに接続できていたとしても、ハブとして動いているデバイスが動作していなければ、AppleHomeKitを使用したスマートホームは生命線を絶たれた状態になるので、全くもってスマートホームは動作しなくなる。

HomeBridgeとは

AppleHomeKitに対応しているデバイスは非常に少ない。大きな原因はAppleの認定制度にある。AppleにはMFiというAppleのエコシステムに乗っかるための認定制度があり、ここに適応できないと大々的にAppleHomeKit適用と製品に書けない。こちらにはAppleの厳しい審査があり、費用がかかり、高頻度のアップデートがあり、筆者のような趣味でスマートホームを楽しむものには大きな壁となる。
そこで出てくるのがHomeBridgeと呼ばれるMFiを経由しないでも、適当なIDを用いるだけで、AppleHomeKit傘下にデバイスを登録できるツールだ。詳細はインターネットで調べれば沢山情報を得られるはずだ。なぜかhomebridge用のデバイスを立ち上げる記事は多かったが、デバイスの動きをコーディングする記事が見当たらなかったので、本記事では簡単な実装を示そうと思う。

HomeBridge API

基本はここにあるAPIを利用していく。

具体例:「部屋の温度と湿度を返すデバイスをAppleHomeKitで立てる」

AppleHomeKitで温度と湿度を返すデバイスを作成する。raspberry pi zeroにI2Cで接続したBME280の温度と湿度の値を返すWebサービスを立ち上げ、Appleのhomeアプリからそのwebサービスを読みに行きiPhone上に表示させる。以下が実際のコードです。

全体像

  • デバイスの種類(テレビ、モーションセンサーなどを)選ぶ。サポートされているものはここに書かれている。
  • Platform pluginかAccessory pluginかを選ぶ。
  • テンプレートを参照しながら、コーディングする。

デバイスの種類を選ぶ

今回は温度と湿度の値を表示させる。したがって、温度センサー湿度センサーを選択する。

Platform pluginかAccessory pluginかを選ぶ

Accessory pluginとはデバイス一つと考えてもらって差し支えないです。Platform pluginはAccessory pluginを複数抱えるプラグインです。具体例を出すと、Phillips HueのようにGatewayの下に照明や人感センサーのような複数のデバイスを一つのpluginで管理したい場合はPlatform pluginを選択します。今回は複数のデバイスではなくて、BME280を繋いだraspberry pi zeroからセンサー値を取り出すだけなので、Accessoryとする。

テンプレートを参照しながら、コーディングする

configファイル

configファイルは以下の様になっています。動作に関係するところは、温度はtemperatureにあるhostを見に行き、湿度はhumidityにあるhostを見に行くようにします。他は適宜必要なメタデータになります。

     "accessories":[
            {
                "accessory": "Bme280SensorAccessory",
                "name": "Bme280SensorAccessory",
                "temperature":{
                    "name":"temperature",
                    "host":"http://192.168.1.140:8088/bme280/temp"
                },
                "humidity":{
                    "name":"humidity", 
                    "host":"http://192.168.1.140:8088/bme280/humid"
                },
                "manufacturer": "Bosch",
                "model": "BME280",
                "serialnumber": "00000001"
            }
     ]

メタデータ

新しいaccessoryの製造元、シリアル番号、モデルを与えます。ホームアプリでいう以下に相当する箇所です。

ここではconfigファイルから取得した値をAccessoryInformationのsetCharacteristicを利用して渡しています。

this.informationService = new hap.Service.AccessoryInformation()
    .setCharacteristic(hap.Characteristic.Manufacturer, config.manufacturer)
    .setCharacteristic(hap.Characteristic.SerialNumber, config.serialnumber)
    .setCharacteristic(hap.Characteristic.Model, config.model);

accessoryが提供するサービスの記述

accessoryが提供するサービスを定義し、それらに対してgetCharctersticされたときのhandlerを渡します。ここでは温度と湿度というサービスを定義し、それぞれの温度や湿度を返すメソッドを渡しています。

// create a new Temperature Sensor service
this.temperatureService = new hap.Service.TemperatureSensor(this.tempname);
this.HumidityService = new hap.Service.HumiditySensor(this.humidname);

// create handlers for required characteristics
this.temperatureService.getCharacteristic(api.hap.Characteristic.CurrentTemperature)
  .on('get', this.handleCurrentTemperatureGet.bind(this));
this.HumidityService.getCharacteristic(api.hap.Characteristic.CurrentRelativeHumidity)
  .on('get', this.handleCurrentHumidityGet.bind(this));

温度のhandlerは以下の様になっています。callback関数を渡しそのcallbackに温度を詰め込みます。callback関数にはnullを渡していますが、これはnullを渡せば成功、Errorを渡すと失敗となります。(この例ではcatchしてもログ出すだけで、適切にエラー処理していないですが。。。)  
ここでのcallbackの処理はconfigから与えたtempHostというURLをaxiosでGETして、そのresponseのJSONの中からvalueというキーの値を取得しています。

    handleCurrentTemperatureGet(callback: CharacteristicGetCallback) {
      this.log.debug('Triggered GET CurrentTemperature');
      let currentValue: number = 0;
      // set this to a valid value for CurrentTemperature
      axiosGet(this.temphost)
      .then(data => {
        this.log.debug(data);
        currentValue = data.value;
        callback(null, currentValue);
      })
      .catch(err => {
        this.log.error(err);
      });

    }

あとは、typescriptをコンパイルして、homebridgeの適当な箇所に配置すれば動作します。その辺りはサーチエンジンを検索すると色々情報が出てくるので探してみてください。

本記事をきっかけに、Homebridgeデバイスを自分で作成し、家の色々なものを自動化して楽しんでみていただければ幸いです!!

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?