SiriでArduinoを操作する

TL;DR (目次も兼ねる)

  • SiriでArduinoを操作する
  • しかしSiriとArduinoを直接結ぶのは困難
  • そこでSiri-Arduino間にRaspberry Piを仲介人として置く
  • Raspberry Pi上ではHomebridge(Node.jsベース)を走らせる
  • HomebridgeがSiriのコマンドを扱いやすい通信に変えてくれる
  • Homebridgeはプラグイン(npmよりインストール可能)により種種の通信へ対応できる
  • 今回はRPiとArduino間をHTTPで通信させる
  • Arduinoのスケッチはここのものを使う(少し変更を加える).
  • おまけはHomebridgeのDaemon化

iOSのSiriでArduinoに取り付けられたLED(以後Lightと呼ぶ)を操作してみたいと思い立った. 調べてみたところ,どうやらHomeKit経由で操作すると良いようだ. HomeKitは家電を管理/制御するためのiOS向けフレームワーク(データベースでもある). HomeKitならばSiriによる家電制御も可能であることから,ArduinoをHomeKitに準拠した家電として認識させることが出来れば勝ちとなる. しかしAppleはHomeKitの仕様をオープンには公開していない. そこで今回は非公式ながらもHomeKitを忠実に実装したHomebridgeと呼ばれるAPIを利用し,iOSとArduinoの仲介人になってもらう. ArchLinuxをインストールしたRaspberry Pi Model B+(以後RPi)があるので,HomebridgeはこのRPi上で動かすことにした(ArchLinuxのインストール方法はここを参照).
iPhoneが家電を制御する時に出す信号を"HomeKit"と記したものが上の接続図. HomeKit信号はLANを通ってRPiに入る. RPiで走っているHomebridgeサーバーが信号の意味を解釈して,それに対応する処理を行う. 今回は同LANに繋がる機器(今回はArduino)へHTTPリクエストを送るようセットアップする. これはHomebridgeのプラグインの一である"homebridge-http"により実現できる. 送り先はIPアドレスで指定する. ArduinoはEthernetシールドを追加することでWebサーバーとして機能するので,RPi-Arduino間はHTTP通信とした. Homebridgeのプラグインは種種あるのでArduino以外の機器とでも比較的簡単に通信させることが出来る. 例えばスマートTVへXMLを送信することが出来るので,LAN経由の操作が出来たり,Siriのコマンドに対応したシェルスクリプトをRPi上で実行させることも出来る. もちろんRPiのGPIOを操作することも意味する. これらはnpm(Node.js Package Manager)よりプラグインとして提供されているので好みのプラグインをインストールすることでお望みの通信を実現できる. 可能性は大きい. さて,概念の説明はこのくらいにして実際にセットアップをして行こう. まずはRPiを起動させよう. 私は手元のMacからSSH接続でRPiをセットアップする. ssh ユーザー名@ホスト名.local パスワードを入力してログインしよう. まずはパッケージの更新から. sudo pacman -Syu 次にC++コンパイラ(C++14対応のもの)とPython2をインストールする. sudo pacman -S clang python2 インストールを終えたら次のコマンドを入力して確認. g++ -v 出力最後の行にgcc version 6.1.1 ...などと表示されればOK. 続けてgitとmake,avahiもインストールしよう. sudo pacman -S git make avahi これで準備は完了. お次はHomebridgeのベースであるNode.jsとNode.jsのパッケージマネージャーであるnpmをインストール. sudo pacman -S nodejs npm
上の方法でNode.jsがインストール出来ない場合は次の方法を試そう参考元. wget https://nodejs.org/dist/v6.2.2/node-v6.2.2-linux-armv6l.tar.gz tar -xvf node-v6.2.2-linux-armv6l.tar.gz cd node-v6.2.2-linux-armv6l sudo cp -R * /usr/local/ RPi2のモデルBとRPi3の場合はarmv6lの部分をarmv7lへ変更する.
node -v npm -v どちらもv6.2.2などのようにバージョンが表示されればNode.jsとnpmのインストール完了. 次はHomebridge本体とHTTP通信を行うためのプラグインをインストールする(EACCESエラーが出る場合は次の記録を参照: npmでパッケージをインストールする). npm update -g npm npm install -g homebridge --unsafe-perm npm install -g homebridge-http 最後はHomebridgeの設定ファイルを用意,編集する. cd /usr/local/lib/node_module/homebridge cp config-sample.json ~/.homebridge/config.json nano -w ~/.homebridge/config.json 次のように編集する.

~/.homebridge/config.json

{
    "bridge": {
        "name": "Homebridge",
        "username": "CC:22:3D:E3:CE:30",
        "port": 51826,
        "pin": "031-45-154"
    },
    
    "description": "This is an example configuration file with one fake accessory and one fake platform. You can use this as a template for creating your own configuration file containing devices you actually own.",
    
    "accessories": [
        {
            "accessory": "Http",
            "name": "Light",
            "switchHandling": "yes",
            "http_method": "GET",
            "on_url": "http://192.168.11.5?9=ON",
            "off_url": "http://192.168.11.5?9=OFF",
            "status_url": "http://192.168.11.5",
            "service": "Light",
            "brightnessHandling": "",
            "brightness_url": "",
            "brightnesslvl_url": "",
            "sendimmediately": "",
            "username": "",
            "password": ""
        }
    ],
    
    "platforms": []
}
bridgeのpinはiOSデバイスとペアリングする時に入力するPIN番号. デフォルト値で問題無いが,気になる方は任意の数字へ変更しよう. accessoriesの中にはプラグインの設定を入力して行く. プラグインごとに設定例があるためそれを参考にする(今回はhomebridge-httpというプラグインなのでこちらを参考にした). on_url,off_url,status_urlにあるIPアドレスはArduinoのIPアドレスと合わせる. Ctrl+Xを押し,yを押したらEnterで保存. これで"Light"(ArduinoにつながったLEDを想定)という名前のアクセサリが追加される. Siriに"Turn on the Light(Lightをオンにして)"と言うとon_urlへHTTPリクエストが送られ,"Turn off the Light(Lightをオフにして)"と言えばoff_urlをリクエストする. 設定ファイルに間違いが無ければ次のコマンドでHomebridgeを立ち上げよう. homebridge 数行の*** WARNING ***が表示されるが無視して問題ない. 枠で囲われた8桁の数字がPINコードになる(設定ファイルの6行目で設定した値).
Sep 11 11:44:00 RPi homebridge[1638]: Scan this code with your HomeKit App on your iOS device to pair with Homebridge:
Sep 11 11:44:00 RPi homebridge[1638]:
Sep 11 11:44:00 RPi homebridge[1638]:     ┌────────────┐
Sep 11 11:44:00 RPi homebridge[1638]:     │ 031-45-154 │
Sep 11 11:44:00 RPi homebridge[1638]:     └────────────┘
Sep 11 11:44:00 RPi homebridge[1638]:
Sep 11 11:44:00 RPi homebridge[1638]: [9/11/2016, 11:44:00 AM] Homebridge is running on port 51826.
このPINコードをiOSのHomeアプリに入力することでペアリングが完了する.

iOSデバイス上でHomeアプリを立ち上げたら"Add Accessory(アクセサリーの追加)"をタップ. 同一LAN上にあるHomebridgeサーバー(RPi)が表示されるのでそれをタップ. Homebridge自体が非公式APIなので認証されていない旨のアラートが出るが"Add Anyway(追加)"を選択する. ここでPINコードの入力を行う. カメラを使った文字認識も使えるが,相手がディスプレイなので上手く認識されない可能性があるため"Enter Code Manually(手動でコードを入力)"をタップ. 8桁のPINコードを入力し,合っていればペアリングは完了する. 追加したアクセサリ(Homebridge)の詳細が表示されるがデフォルトで"Next(次へ)". 続いてLight(homebridge-httpプラグイン)が表示されるのでデフォルトのまま"Done(完了)"をタップ. 以上でHomeKitサイドの設定は完了. 後はHomebridgeとArduino間の通信を上手くやれば良い.


HomeアプリでLightをオンにするとhttp://192.168.11.5?9=ONへアクセスされるようになった. Webサーバーとして動作しているArduino(IPアドレスは192.168.11.5とする)がこれの意味を解釈し,指定されたピンの状態を変えられれば良い. これには以前ここでつくったスケッチがそのまま使える. スケッチ内のIPアドレスをHomebridgeで設定したものに合わせよう. このスケッチではGETメソッドのキーと値により対応するピンの状態を変更させる. ?9=ONは9番ピンをHIGHに,?9=OFFは9番ピンをLOWにする. 今回はsendBackHttpResponse()に変更を加え,ピンの状態をHomeアプリから確認出来るようにしよう.

LED_RemoteController.ino

void sendBackHttpResponse(EthernetClient client)
{
  // HTTPヘッダ
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html; charset=UTF-8");
  client.println("Connection: close");
  client.println();
  
  // ペイロード
  int pinState = digitalRead(ledPin);
  client.println(pinState);
}
HTTPレスポンスとして10を送ることによりhomebridge-httpは通信先の状態がONかOFFかを判断出来る(status_urlはこの判断を行うためのアドレス). これでArduinoにつながったLEDの状態を返してやればHomeアプリで確認出来るようになる寸法. ArduinoとRPiとiOSデバイスが同一LAN上にあることを確認したらSiriを立ち上げて一言"Turn on the Light(Lightをオンにして)". Siriの信号がRPi上のHomebridgeへ届き,HomebridgeがLightという名前のアクセサリーに対応した処理を行い(指定のURLにアクセスし),ArduinoはHTTPアクセスを受け取ってピンの状態を変化させる. 夢がかなった.
もちろんHomeアプリやコントロールセンターの3ページ目からも操作可能.
HomeアプリのスイッチをタップでLEDを点灯/消灯
スイッチをプレスすると大きなスライドスイッチが現れる
コントロールセンターの3ページ目からも同様の操作が可能

RPiの電源ONでHomebridgeを走らせる

停電や障害が発生してRPiが再起動した場合,今のままではHomebridgeは勝手に起動してくれない. 次の手順でHomebridgeをDaemon化すればHomebridgeは勝手に起動するようになるので稼働率がだいぶ高まる. 参考元はこちら. 以後"ユーザー名"とあるところはログイン中のユーザー名に置き換えよう. 大まかな手順は次の通り.
  1. /var/内にhomebridgeフォルダを作成
  2. homebridge設定ファイルを上フォルダ内へコピー
  3. /etc/default/内に設定ファイルの在り処を書く
  4. /etc/systemd/system/内にhomebridgeをサービスとして設定
  5. homebridgeサービスを起動して状態を確認
まずはお引っ越し先のフォルダ/var/homebridgeをつくって,そこへ設定ファイルを移行する. sudo mkdir /var/homebridge sudo chown ユーザー名 /var/homebridge/ cp ~/.homebridge/config.json /var/homebridge/ sudo nano -w /etc/default/homebridge 最後のコマンドは手順3にあたる. ここには次の内容を書き込む.

/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=*
3行目だけ書けば動くが,一応全部書いておこう. これは例えるならば住所変更手続を行ったようなもの. Homebridgeの設定ファイル(config.json)の在り処を書き記しておくのだ. 続いてHomebridgeをサービスとして設定しよう. sudo nano /etc/systemd/system/homebridge.service 次の内容を書き込む.

homebridge.service

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

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

[Install]
WantedBy=multi-user.target
これで自動起動するサービス,すなわちHomebridgeについて設定することが出来た. 後は次のコマンドでサービスを有効化し起動させれば良い. sudo systemctl daemon-reload sudo systemctl enable homebridge sudo systemctl start homebridge 以後,Homebridgeの設定を変更するには/var/homebridge/config.jsonを編集すれば良い. 編集後は次のコマンドでサービスを再起動して設定を適用する. sudo systemctl restart homebridge 次のコマンドでサービスの状態を知ることが出来る. systemctl status homebridge Homebridgeが出力するログは次のコマンドで読むことができる. journalctl -f -u homebridge ログから抜けるにはCtrl+Cを押す. これで各機能(アクセサリ)が正常に動作しているようならばホームディレクトリ下にある.homebridgeフォルダを削除してしまっても構わない. rm -r ~/.homebridge 思い出として残しておいても良いかもしれないが.

再追加するときHomeアプリでHomebridgeが見つからない場合は...

都合により再度HomeアプリにHomebridgeを追加する際,Homebridgeが見つからない場合がある. その場合は/var/homebridge/persist/を削除すると上手く行く. rm -R /var/homebridge/persist/ sudo systemctl restart homebridge もう一度Homeアプリの"Add Accessory"をタップすればHomebridgeが表示されるようになるはず.
次の記録: Siriで赤外線リモコン操作を実現する
8582955794482166987 http://www.storange.jp/2016/09/siriarduino.html http://www.storange.jp/2016/09/siriarduino.html SiriでArduinoを操作する 2016-09-13T20:06:00+09:00 http://www.storange.jp/2016/09/siriarduino.html Hideyuki Tabata 200 200 72 72