Raspberry PiとSiriで家電の音声制御 後編 Siriでの家電制御

前回までで、Siriの制御対象の機器の準備はできたので、あとはRaspberry PiをHomeKit機器として認識させるための作業になります。

siri-raspberry-3

この部分ですね。

あ、この工作やってる頃にちょうどWWDC (2016)があってSiriのサードパーティ開放の話が出たりしたみたいですが、この工作では別にiOSアプリとかを作るわけではないので、全然関係ありません。

 

ではでは早速、ミドルウェアの設定をしていきます。ベースにさせていただくのは以下の記事です。

このあたりを見比べながら進めていきたいと思います。

まずはRaspberry Piのベースのアップデートをしておきます。

$ sudo apt-get update
$ sudo apt-get upgrade

続いて、Node.jsのインストールです。こちらに記載のRaspberry Pi 2 Model B向けの操作をそのまま実行していきます。

$ wget https://nodejs.org/dist/v4.0.0/node-v4.0.0-linux-armv7l.tar.gz 
$ tar -xvf node-v4.0.0-linux-armv7l.tar.gz 
$ cd node-v4.0.0-linux-armv7l
$ sudo cp -R * /usr/local/
$ node -v
v4.0.0
$ npm -v
2.14.2

それから、avahi絡みのライブラリをインストールします。

$ sudo apt-get install libavahi-compat-libdnssd-dev

これで前準備は完了。いよいよHomebridgeの導入です。

$ sudo npm install -g homebridge

まずこれでHomebridge本体のインストールは完了。続いて、HTTPリクエストを投げてくれるプラグインを突っ込みます。

$ sudo npm install -g homebridge-readablehttp

これで必要なものは全て揃ったはず。とりあえず実行してみます。

$ homebridge
*** WARNING *** The program 'node' uses the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node>
*** WARNING *** The program 'node' called 'DNSServiceRegister()' which is not supported (or only supported partially) in the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node&f=DNSServiceRegister>
[5/28/2016, 3:11:01 PM] Loaded plugin: homebridge-readablehttp
[5/28/2016, 3:11:01 PM] Registering accessory 'homebridge-readablehttp.Http'
[5/28/2016, 3:11:01 PM] ---
Scan this code with your HomeKit App on your iOS device to pair with Homebridge:

    ┌────────────┐     
    │ 031-45-154 │     
    └────────────┘     

[5/28/2016, 3:11:01 PM] Homebridge is running on port 51826.

なんか登録用の数字が表示されているので、おそらく動作自体はOKでしょう。あとは前に作成したWeb APIを叩いてくれるように設定していけばよさそうです。

設定ファイルはホームディレクトリ直下の”.homebridge”の直下に、”config.json”の名前で作ります。自分の場合は”/home/pi/.homebridge/config.json”。作成場所はおそらくプラグインに依らず共通です。

とりあえず、自分はこんな感じで設定ファイルを作ってみました。

{
    "bridge": {
        "name": "RaspiBridge",
        "username": "E1:95:53:70:DE:C6",
        "port": 51826,
        "pin": "031-45-204"
    },

    "description": "HomeBridge HTTP Status Control",

    "accessories": [
      {
        "accessory":       "Http",
        "service":         "Light",
        "name":            "でんき",
        "username":        "",
        "password":        "",
        "sendimmediately": "",
        "http_method":     "GET",
        "on_url":          "http://192.168.24.204:10080/appliances/myhome?room=room_t&device=light&function=power&parameter=on",
        "on_body":         "",
        "off_url":         "http://192.168.24.204:10080/appliances/myhome?room=room_t&device=light&function=power&parameter=off",
        "off_body":        "",
        "read_url":        "",
        "brightnessHandling": "no",
        "http_brightness_method": "",
        "brightness_url": ""
       }
    ]
}

“bridge”の所はどのプラグインを使っても共通で設定する項目です。あとでiOSアプリを使ってこのRaspberry Piを探して登録することになるのですが、ここの”name”で設定した値で発見されることになります。”username”はMACアドレス形式ならよいみたいなので、自分のRaspberry PiのMACアドレスにしています(上のは実際とちょっと変えてます)。”port”はいじらずで、”pin”はこの形式で好きな数字を入れます。あとでペアリングに使います。

“description”はサンプルそのままです。

“accessories”からはプラグインごとに設定項目が変わります。最初はhomebridge-readablehttpsample-config.jsonだけ見て設定しようとしたのですが、どういうプロパティがあってどのプロパティを設定すれば良いのかよくわからなくて、結局ソースも見ることになってしまいました。

その結果、今回の自分の実装には関係なさそうなプロパティでもとりあえず何かしら値を入れとかなきゃいけないっぽかったので、そういうものについては空文字に設定しています。

ここで重要なのは”on_url”と”off_url”で、ここに前回作成したWeb APIのURLを記入します。今回はシンプルにGETメソッドで動くようにしているので、”http_method”もそれに合わせて”GET”にしています。見た感じ、”POST”もいけそうですね。

これで設定ファイルの準備はOKです。改めてhomebridgeを起動させます。

$ homebridge
*** WARNING *** The program 'node' uses the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node>
*** WARNING *** The program 'node' called 'DNSServiceRegister()' which is not supported (or only supported partially) in the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node&f=DNSServiceRegister>
[5/28/2016, 4:35:42 PM] Loaded plugin: homebridge-readablehttp
[5/28/2016, 4:35:42 PM] Registering accessory 'homebridge-readablehttp.Http'
[5/28/2016, 4:35:42 PM] ---
[5/28/2016, 4:35:42 PM] Loaded config.json with 1 accessories and 0 platforms.
[5/28/2016, 4:35:42 PM] ---
[5/28/2016, 4:35:42 PM] Loading 1 accessories...
[5/28/2016, 4:35:42 PM] [でんき] Initializing Http accessory...
Scan this code with your HomeKit App on your iOS device to pair with Homebridge:

    ┌────────────┐     
    │ 031-45-204 │     
    └────────────┘     

[5/28/2016, 4:35:42 PM] Homebridge is running on port 51826.

アクセサリとして「でんき」が登録されて、PIN番号も変更したものに変わっています。

 

以上でRaspberry Pi本体の方の設定は終了で、ここからはiOSアプリの方の設定です。HomeKitに対応したアプリが必要なので、とりあえずInsteon+というアプリを落としてきます。

insteon-1

初回登録が済んだらこの画面になるので、”Home”をタッチ。

insteon-2

右上の”+”をタッチ。

insteon-3

“Add a Device”をタッチ。

insteon-4

HomeKit対応機器を探し始めます。ここで、iPhoneとRaspberry Piが同じローカルネットに接続されていれば、先ほどconfig.jsonのbridge.nameに記載したデバイスが見つかるハズ。

insteon-5

自作ゆえに当然なので、”このまま追加”をタッチ。

insteon-6

“コードを手動で入力”をタッチして、先ほど自分で設定したPINを入力すれば登録完了です。

insteon-7

“All Room”の中に”All Device”があり、さらにそれをタッチすると…

insteon-8

おお、ちゃんと「でんき」が登録されています!

ではいよいよ、Siriに話しかけてみます。「でんき消して!」

insteon-9

消えました。成功!

insteon-10

つけるのもバッチリ。よしよし。

実際に動いている様子はこちらです↓

「Hey Siri!」が気だるい感じになっているのは、普段自分が寝る前のテンションに反応してくれるように認識を調整していて、それに合わせるように喋っているからです。それ以外の言葉もなんだかモゴモゴしていますが、それでもSiriは正確に認識してくれます。

 

ちなみに今回使ったHomeKitアプリのInsteron+、アイコンとかも細かく編集できるようになっていまして、

insteon-11

 

電球だけでもこんなに色々あります。

insteon-12

こんな感じに変えてみました。

insteon-13

それから上記画面の”SIRI CONTROL”を変更すれば、Siriに認識させる呼び名も変えられるようです。

 

シーン別の家電制御設定というのもできるようになっています。

insteon-14

編集画面で”Edit Scene”をタッチ。

insteon-15

 

すると、デフォルトで用意されているシーン名が出てきます。ここでは”おやすみ”を設定したいと思います。

insteon-16

下の方の”Add to this Scene”をタッチ。

insteon-17

「でんき」を選択。

insteon-18

「でんき」が追加されているので、これをタッチすると、

insteon-19

どの動作にするかの選択になるので、”OFF”を選びます。

 

これで準備OK。では、Siriに話しかけてみます。「おやすみ!」

insteon-20

すると、まず通常のSiriの通常の応答が優先されますが、その下に”おやすみシーン”が表示されます。これをタッチすると、

insteon-21

という返事があり、部屋の電気を消してくれました。「おやすみ!」の一発で電気を消してくれたら嬉しかったのですが、これはまあしょうがないですね。ダイレクトに「でんき消して」と言えば済みますし。

 

さて、期待通りのものができたので満足しているのですが、最後の仕上げが残っています。Raspberry Piが再起動した時に、自動的にHomebridgeが起動するようにしておきたいと思います。

こちらを見るとやり方が2つ(init.dを使うものとsystemdを使うもの)があるようなのですが、どっちにしろよくわからないので、ここでは後者のやり方で試したいと思います。

後者の詳しいやり方は以下に記載されているので、多少コマンドを補いながら試していきます。

$ sudo useradd --system homebridge
$ sudo mkdir /var/homebridge
$ sudo cp /home/pi/.homebridge/config.json /var/homebridge/.
$ sudo chown -R homebridge:homebridge /var/homebridge

ここまで設定したら、以下の内容で二つのファイルを作成します。

$ sudo vim /etc/default/homebridge

# Defaults / Configuration options for homebridge
# The following settings tells homebridge where to find the config.json file and where to persist the data (i.e. pairing and others)
HOMEBRIDGE_OPTS=-U /var/homebridge

# If you uncomment the following line, homebridge will log more 
# You can display this via systemd's journalctl: journalctl -f -u homebridge
# DEBUG=*
$ sudo vim /etc/systemd/system/homebridge.service

[Unit]
Description=Node.js HomeKit Server 
After=syslog.target

[Service]
Type=simple
User=homebridge
EnvironmentFile=/etc/default/homebridge
ExecStart=/usr/local/bin/homebridge $HOMEBRIDGE_OPTS
Restart=on-failure
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target

できたら、以下を実行します。

$ sudo systemctl daemon-reload
$ sudo systemctl enable homebridge
$ sudo systemctl start homebridge

ここまでやったら、Raspberry Piを再起動します。そのあと、再度ログインしてから、以下のコマンドで状態を確認します。

$ sudo journalctl -u homebridge
-- Logs begin at Sat 2016-05-28 19:05:57 JST, end at Sat 2016-05-28 19:07:20 JST. --
May 28 19:06:00 raspberrypi systemd[1]: Starting Node.js HomeKit Server...
May 28 19:06:00 raspberrypi systemd[1]: Started Node.js HomeKit Server.
May 28 19:06:04 raspberrypi homebridge[385]: *** WARNING *** The program 'node' uses the Apple Bonjour compatibility layer of Avahi
May 28 19:06:04 raspberrypi node[385]: *** WARNING *** The program 'node' uses the Apple Bonjour compatibility layer of Avahi.
May 28 19:06:04 raspberrypi node[385]: *** WARNING *** Please fix your application to use the native API of Avahi!
May 28 19:06:04 raspberrypi node[385]: *** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node
May 28 19:06:04 raspberrypi node[385]: *** WARNING *** The program 'node' called 'DNSServiceRegister()' which is not supported (or 
May 28 19:06:04 raspberrypi node[385]: *** WARNING *** Please fix your application to use the native API of Avahi!
May 28 19:06:04 raspberrypi node[385]: *** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node
May 28 19:06:04 raspberrypi homebridge[385]: *** WARNING *** Please fix your application to use the native API of Avahi!
May 28 19:06:04 raspberrypi homebridge[385]: *** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&
May 28 19:06:04 raspberrypi homebridge[385]: *** WARNING *** The program 'node' called 'DNSServiceRegister()' which is not supporte
May 28 19:06:04 raspberrypi homebridge[385]: *** WARNING *** Please fix your application to use the native API of Avahi!
May 28 19:06:04 raspberrypi homebridge[385]: *** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&
May 28 19:06:08 raspberrypi homebridge[385]: [5/28/2016, 7:06:08 PM] Loaded plugin: homebridge-readablehttp
May 28 19:06:08 raspberrypi homebridge[385]: [5/28/2016, 7:06:08 PM] Registering accessory 'homebridge-readablehttp.Http'
May 28 19:06:08 raspberrypi homebridge[385]: [5/28/2016, 7:06:08 PM] ---
May 28 19:06:08 raspberrypi homebridge[385]: [5/28/2016, 7:06:08 PM] Loaded config.json with 1 accessories and 0 platforms.
May 28 19:06:08 raspberrypi homebridge[385]: [5/28/2016, 7:06:08 PM] ---
May 28 19:06:08 raspberrypi homebridge[385]: [5/28/2016, 7:06:08 PM] Loading 1 accessories...
May 28 19:06:08 raspberrypi homebridge[385]: [5/28/2016, 7:06:08 PM] [でんき] Initializing Http accessory...
May 28 19:06:08 raspberrypi homebridge[385]: Scan this code with your HomeKit App on your iOS device to pair with Homebridge:
May 28 19:06:08 raspberrypi homebridge[385]:                        
May 28 19:06:08 raspberrypi homebridge[385]:     ┌────────────┐     
May 28 19:06:08 raspberrypi homebridge[385]:     │ 031-45-204 │     
May 28 19:06:08 raspberrypi homebridge[385]:     └────────────┘     
May 28 19:06:08 raspberrypi homebridge[385]:                        
May 28 19:06:08 raspberrypi homebridge[385]: [5/28/2016, 7:06:08 PM] Homebridge is running on port 51826.

上記のように表示されていればOKです。上記のようになっていなくて、

$ sudo journalctl -u homebridge
-- Logs begin at Sat 2016-05-28 18:57:48 JST, end at Sat 2016-05-28 18:58:51 JST. --
May 28 18:57:52 raspberrypi systemd[1]: Starting Node.js HomeKit Server...
May 28 18:57:52 raspberrypi systemd[1]: Started Node.js HomeKit Server.
May 28 18:57:52 raspberrypi systemd[1]: homebridge.service: main process exited, code=exited, status=203/EXEC
May 28 18:57:52 raspberrypi systemd[1]: Unit homebridge.service entered failed state.
May 28 18:58:03 raspberrypi systemd[1]: homebridge.service holdoff time over, scheduling restart.
May 28 18:58:03 raspberrypi systemd[1]: Stopping Node.js HomeKit Server...
May 28 18:58:03 raspberrypi systemd[1]: Starting Node.js HomeKit Server...
May 28 18:58:03 raspberrypi systemd[1]: Started Node.js HomeKit Server.
May 28 18:58:03 raspberrypi systemd[1]: homebridge.service: main process exited, code=exited, status=203/EXEC
May 28 18:58:03 raspberrypi systemd[1]: Unit homebridge.service entered failed state.

のように表示されている場合は、”/etc/systemd/system/homebridge.service”の

ExecStart=/usr/local/bin/homebridge $HOMEBRIDGE_OPTS

の部分をチェックしてみてください。本家のスクリプトと少しだけパスが違います。

 

さて、これで再起動しても自動的に立ち上がるようにはなったハズなのですが、なぜかInsteon+がRaspberry Piを見つけてくれなくなってしまいました。しょうがないので一度デバイス登録を削除したりアプリを再インストールしてもう一度登録し直して事なきを得ましたが、この辺りの挙動はまだよくわかりません。

 

ともあれ、とりあえず当初の目標は達成できました。さすがSiriというか、音声の認識をミスることがほとんどないので、すこぶる快適に音声制御できます。認識した後はHTTPリクエストを投げるだけなので、今回はローカルホストの Webサーバにリクエストを投げる形でしたが、とりあえずGETかPOSTで制御できるものならなんでも操作できそうです。

この音声制御、自分としてはなかなか満足いくものになったので、奥様に「これどうよ?」と感想を聞いたら、「あってもなくてもいい」という実に素直な返事が返ってきました。うーん、まあ、そうかもしれません。言ってしまえば、リモコンでON/OFFする手間を省いているだけなので。

とはいえ、この仕組みを作って以来、私自身は自分の部屋の中で1回もリモコンを触らなくなったので、作者本人としては結構便利に使っていたりします。