RaspberryPi3とhomekitとwebIOPiで家電操作する

# はじめに

RaspberryPi3を使ってIR信号(赤外線信号)を送信して家電を制御するためにしたことをメモ。
本当はIRKitがあれば簡単にできる([記事](http://qiita.com/FePlus/items/4b863de7af8fbdee4d61))。しかし現在買現在買うことができず、[後継機](http://nature.global/remo-jp/)はあるようだがすぐには手に入れることができなさそうなので、、ラズパイのGPIOからIR送信する。（こっちは低コストですから (´；ω；｀)ﾌﾞﾜｯ

やりたいことはスマホやPCからラズパイにIR送信のリクエストを送り、GPIOからIR送信することで家電を制御できるようにする。


## 必要なもの

最低限必要なものは、ラズパイ・[赤外線受信モジュール](http://akizukidenshi.com/catalog/g/gI-00622/)・[赤外線LED](http://akizukidenshi.com/catalog/g/gI-03261/)。
一応、赤外線送信を強くするためトランジスタを使った回路にしているが、受光器に直接向けるのならば問題ないと思う。ただ、エアコンや照明のような少し距離があるものだと、シンプルな回路だと光量が弱く届かないかもしれないので注意が必要。

## 構成とリクエストについて

リクエストは、iOS/Androidとプラットフォームを選ばず操作したいのでREST Apiでできるようにする。
また、iOS限定だが、せっかくiOS10がリリースされ、公式にhomeアプリがプリインストールされたので[homebridge](https://github.com/nfarina/homebridge)も導入してラズパイをhomekit製品としてiPhoneから操作できるようにもする。

ものすごく大まかな構成

<img width="716" alt="スクリーンショット 2016-11-03 22.54.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/77816/bf17f293-9ffb-08f8-8050-c61c1ef82964.png">


# 実践

## IR解析してIR送信する

[LIRC](http://www.lirc.org/)を使ってリモコンキーの解析、送信をする。
LIRCはリモコンキーのデコードや送信をコンフィグやコマンドラインなどを行うことができるLinuxのパッケージ。
### LIRCのinstallとsetup

#### install

パッケージからインストール

```
$ sudo apt-get install -y lirc
```

#### ハードウェア設定

`/etc/lirc/hardware.conf` にデーモン起動時の引数・デバイス・モジュールを指定する。
詳しくは公式の[option](http://www.lirc.org/html/lircd.html)項目を参照してください。

※ `sudo` コマンドで編集します

```ini:/etc/lirc/hardware.conf
LIRCD_ARGS="--uinput"
DRIVER="default"
DEVICE="/dev/lirc0"
MODULES="lirc_rpi"
```

#### カーネルモジュール・GPIOを設定

ラズパイのブートコンフィグ(`/boot/config.txt`)にモジュールと使用するGPIOを追記する。
`dtoverlay`を使ってデバイスツリーにモジュール(`lirc-rpi`)を追加、そしてGPIOの設定。
ここではIR送信をGOIO17、受信をGPIO18としている。

※ `sudo` コマンドで編集

```ini:/boot/config.txt
# Uncomment this to enable the lirc-rpi module
dtoverlay=lirc-rpi,gpio_out_pin=17,gpio_in_pin=18,gpio_in_pull=up
```

#### 確認する

再起動して正常にドライバが起動しているか確認する。
`lirc_rpi` はラズパイのデバイスドライバで、[ソース](https://github.com/raspberrypi/linux/blob/rpi-3.10.y/drivers/staging/media/lirc/lirc_rpi.c)をから、 `lirc_rpi` は `lirc_dev` をロードして使っている。

```bash
# 再起動
$ sudo reboot
    :
# 起動できているかdmesgで確認する
$ dmesg | grep lirc
[    4.077720] lirc_dev: IR Remote Control driver registered, major 245
[    4.117482] lirc_rpi: module is from the staging directory, the quality is unknown, you have been warned.
[    5.070398] lirc_rpi: auto-detected active low receiver on GPIO pin 18
[    5.070709] lirc_rpi lirc_rpi: lirc_dev: driver lirc_rpi registered at minor = 0
[    5.070719] lirc_rpi: driver registered!
[    8.883938] input: lircd as /devices/virtual/input/input0

# ドライバの確認
$ lsmod | grep lirc
lirc_rpi                6478  0
lirc_dev                8310  1 lirc_rpi
rc_core                16468  1 lirc_dev
```

### IRコマンドを解析してconfigを作成する

送信したいリモコンコードを解析してconfファイルを作成する。


#### IR受信用の回路を組む

入力ピンとして設定した `GOIO18` にIRレシーバーを接続。IR受信モジュールの正面左から5V・GRD・GPIO18。

![ir_receive.png](https://qiita-image-store.s3.amazonaws.com/0/77816/0d2cf915-17c8-a93f-537b-295410337f14.png)


#### IR受信が有効化どうか確認する

[`mode2`](http://www.lirc.org/html/mode2.html) コマンドを使って待受状態にする。テレビのリモコンなどをレシーバーに向けて送信してみて数字の羅列が流れればOK。

```bash
# lircデーモンを停止
$ sudo /etc/init.d/lircd stop

# IR受信信号を表示
$ mode2 -d /dev/lirc0
    # 何かリモコンコードを送信してみて以下のような出力がでれば受信できています
    # (待機時は何も出力されない)
        pulse 573
        space 1639
            :
```

#### configファイルを作成

リモコン操作したい機器のコンフィグファイルを作成する。


コンフィグファイルの作成作業は、リモコンごとに行う。
例えば、エアコン・テレビ・コンポ、と3つのリモコンのコンフィグを作りたいならば3回行う。そして3つのコンフィグファイルを一つのコンフィグファイルにまとめる。このまとめたファイルが最終的なコンフィグファイルとなる。

##### リモコンのconfigファイル作成

[`irrecord`](http://www.lirc.org/html/irrecord.html) コマンドを実行してコメントに従ってconfigファイルを作成する。

```bash
$ irrecord -n -d /dev/lirc0 ./tv.conf
    # Enter二回押して登録開始
    Press RETURN now to start recording.
        # ボタンを押し続けたりする
    Please enter the name for the next button (press <ENTER> to finish recording)
        # ここで登録するコマンド名を入力
        # そしてリモコンで登録したいコマンドを押して受信させる
            :
        # 繰り返す
    Please enter the name for the next button (press <ENTER> to finish recording)
        # 終わりはそのままEnter
```

##### configファイルの編集

読み込みでエラーになるようなので、`name` を**空白なしの文字列**に変更する。

```bash
$ vim ./tv.conf
    # コメントは消してもいいと思う
    begin remote
    name tv     # ここの名前を空白なしの文字列に変更する
        :
    end remote
```

##### configファイルをコピーする

作成したconfigファイルを `/etc/lirc/lircd.conf` にマージ。もし他のリモコンを作りたい場合は `irrecord` コマンドからの作業を繰り返す。

```bash
$ sudo su
# テレビのリモコンをマージ
% cat ./tv.conf >> /etc/lirc/lircd.conf
# 照明のリモコンをマージ
% cat ./room_right.conf >> /etc/lirc/lircd.conf
    :
% exit
# 再読込
$ sudo /etc/init.d/lirc restart
```

#### 登録したリモコンコードを確認してみる

[`irw`](http://www.lirc.org/html/irw.html) を実行して、登録したリモコンをレシーバに向かって送信してみる。
正常に登録されている場合は登録した内容が出力される。もしうまく行かなければ、 `lirc` のりスタートなどしてみてください。

```bash
$ irw
    # 登録したリモコンをレシーバに向かって送信する
    0000000000000xxx 00 power tv
```

### IR送信してみる

送信は [`irsend`](http://www.lirc.org/html/irsend.html) コマンド。

#### 送信用の回路を組む

送信する赤外線LEDを強化するためにトランジスタで増幅した回路で、少しは強化されているはず。。
もしトランジスタなどない場合はGPIOとGRDにつなげるだけか、[拡散キャップ](http://akizukidenshi.com/catalog/c/c5cap/)つけるでもいいと思う。

![ir_send.png](https://qiita-image-store.s3.amazonaws.com/0/77816/9e4b828e-1721-c064-a576-c51861f91c3c.png)


#### 登録してあるリモコンコードを表示

まずは、先程作成したコンフィグファイルから、登録できているか確認してみる。

```bash
# 登録してあるリスト表示 1
$ irsend list "" ""
    irsend: tv
    irsend: room_light
# 登録してあるリスト表示 2 (更に詳細)
$ irsend list tv ""
    irsend: 00000000000048b7 power
    irsend: 00000000000058a7 vol-up
        :
```

#### 送信する

コマンドを実行でIRコードが送信される。 しっかりと送れていれば電源やチャンネルなど変えることができるはず。復数連続で送らなければ操作できないデバイスもあるので、その場合は `for` 分など使って繰り返し送信する必要があるかも。

```bash
# 一回送信
$ irsend send_once tv power

# 複数回送信してみる
$ for i in {0..5}; do irsend send_once tv vol-up; echo $i; done;
```

## WebIOPiを使いWeb経由でIR送信できるようにする

Web経由でのスクリプト操作をするために、REST APiやHTTPサーバを簡単に構築できるWebIOPiを導入する。

### WebIOPiの構築

**Python3**必須。それとRasoberryPi2,3の場合、パッチを当てる。(ボードの種類が変わり、GPIOの配置など異なるため)

#### python3 install

python3をインストール済みの場合はスキップしてください。

- install

```bash
$ sudo apt-get install python3-dev python3-pip
```

- python link

```bash
$ which python
    /usr/bin/python
$ cd /usr/bin/
$ sudo unlink python
$ sudo ln -s python3.4 python
# check
$ python -V
    Python 3.4.2
```

#### WebIOPi install

ここからWebIOPiのインストール作業。

##### 本体のdownload

```bash
$ mkdir ~/webIOPi
$ wget http://sourceforge.net/projects/webiopi/files/WebIOPi-0.7.1.tar.gz
$ tar -zxvf WebIOPi-0.7.1.tar.gz
```
##### パッチをあてる

オリジナルのWebIOPiは初代ラズパイ用なのでボード型番、GPIO配列が異なるので、そのままだと動作しない。そこでRaspberryPi2,3用に修正パッチをあてる必要がある。(https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98981)

```bash
# patchをclone
$ cd ~
$ git clone https://github.com/acrobotic/Ai_Demos_RPi
# patchをあてる
$ cd ./WebIOPi-0.7.1
$ patch -p0 -i ../Ai_Demos_RPi/demos/gpio/webiopi_raspberry_pi_2_cpu_support.patch
$ patch -p0 -i ../Ai_Demos_RPi/demos/gpio/webiopi_raspberry_pi_2_gpio_40_pin.patch
$ patch -p0 -i ../Ai_Demos_RPi/demos/gpio/webiopi_raspberry_pi_2_gpio_mapping.patch
```

##### install

パッチをあてた後に、`setup.sh` でインストール。

```bash
$ sudo ./setup.sh
    Do you want to access WebIOPi over Internet? [y/n] n # for Waves : 特に今は必要ない
    # Raspberry-pi 再起動
```


#### 自動起動設定

自動起動するため、SystemServiceに登録する。

```bash
# 登録
sudo systemctl enable webiopi.service

# start / stop
sudo systemctl start  webiopi.service
sudo systemctl stop   webiopi.service
```

起動と停止、再起動は他のサービスと同じ。

```bash
$ sudo service webiopi start    # 起動
$ sudo service webiopi stop     # 停止
$ sudo service webiopi restart  # 再起動
```

debug modeで動作したい場合は `-d` で直接起動するとログなどがコンソールに出力される。

```bash
$ sudo webiopi -c /etc/webiopi/config -d
```

##### HTTPサーバにアクセスする

`http://<raspberry pi3 address>:8000` でアクセスでる。ログインのユーザとパスワードは `webiopi` / `raspberry` 。
リスト一番上の `GPIO Header` にアクセスして、LEDなどを繋いでGPIOを操作することができるか確認してみる。

![スクリーンショット 2016-10-26 22.39.10.png](https://qiita-image-store.s3.amazonaws.com/0/77816/3de7496b-290b-baac-a8d6-9af405953064.png)


Password認証を無効にしたい場合は `/etc/webiopi/config` を以下のように編集することで可能。

```bash
$ sudo vim /etc/webiopi/config
    passwd-file = /etc/webiopi/passwd
    ↓  # コメントアウトする
    #passwd-file = /etc/webiopi/passwd
```

##### REST Apiを使ってみる

[色々](http://webiopi.trouch.com/RESTAPI.html )とあるが、基本的なON/OFFを試してみる。(LEDなどをつなげて確認してみるとわかりやすい)

```bash
# on
curl -X POST <raspberry pi address>:8000/GPIO/27/value/1
# off
curl -X POST <raspberry pi address>:8000/GPIO/27/value/0
```

### WebIOpi スクリプト

IR送信するPythonスクリプトを作成して、REST Api経由で実行できるようにする。

#### scriptファイルの作成

適当な場所にスクリプトファイルを作成。種類・コマンド・送信回数を引数として、先程設定した `irsend` コマンドを実行しするだけのシンプルなスクリプト。IR送信は基本的にレスポンスはない投げっぱなしなので、戻り値は何でもよくて、ここでは `OK` としている。
[公式のサンプル](http://webiopi.trouch.com/Tutorial_Basis.html#python-script)参考にしているが、GPIO操作を直接しないので `setup()` や `loop()` は書いてない。

```python:script.py
import webiopi
import os

@webiopi.macro
def sendIr(kind, command, count="1"):
    for _ in range(int(count)):
        os.system("irsend send_once " + kind + " " + command)
    return "OK"
```

#### scriptファイルの設定

`/etc/webiopi/config` に先ほど作成したスクリプトファイルを指定する。

```ini:/etc/webiopi/config
[SCRIPTS]
# Load custom scripts syntax :
# name = sourcefile
#   each sourcefile may have setup, loop and destroy functions and macros
myscript = <your project dir>/webIOPi/project/script.py
```

#### REST Apiからscriptを実行してみる

`curl` コマンドで確認。scriptはPOSTリクエスト。 (http://webiopi.trouch.com/RESTAPI.html#call-a-macro-on-the-server)

```bash
$ curl -X POST <raspberry pi address>:8000/macros/sendIr/tv,power,1
    OK
```

### Webページからもスクリプト実行できるようにする

先ほど作成したスクリプトをWebページからも実行してみる。

#### htmlファイルの作成

ここも[公式のサンプルを参考](http://webiopi.trouch.com/Tutorial_Basis.html#python-script)にしている。

```html:index.html
<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="/webiopi.js"></script>
    <script>
    webiopi().ready(function(){
        // webiopiとjqueryの読み込みをする
        $("send_ir").click(function(){
            // callback object
            var callback = function(macro, args, response) {
                // do nothing
            }
            // 引数は配列。これはサンプルのためハードコード。
            var args = ["kenwood", "power", "3"];
            // method name, args, callback
            //   - callbackが必要ないならnullでも良い
            webiopi().callMacro("sendIr", args, callbcak);
        });
    });
    </script>
    <title>sendir</title>
</head>
<body>
    <p id="send_ir">send ir test</p>
</body>
</html>
```

#### htmlファイルの設定

スクリプトファイル同様、htmlファイルがある**ディレクトリ**を指定する。


```ini:/etc/webiopi/config
[HTTP]
    :
doc-root = <your project dir>/webIOPi/project
```

#### アクセスしてスクリプトを実行してみる

`http://<raspberry pi address>:8000` にアクセスすると先ほど作成した `index.html` が表示されるはず。さらに `send ir test` をクリックするとIR送信スクリプトが実行される。ログなどを仕込みながら確認してみてください。

![スクリーンショット 2016-10-26 22.37.37.png](https://qiita-image-store.s3.amazonaws.com/0/77816/0ad6d5c7-9ab3-1572-0391-83d2063b385c.png)

ここまでくれば、リモコンコード送信するボタンを追加していけばブラウザから家電を操作することができる。


## iOSホームアプリから制御する

[homebridge](https://github.com/nfarina/homebridge)を使ってラズパイをHomeKit製品としてiOS製品に認識させ、ホームアプリ(iOS10から追加されたアップルの公式アプリ)に登録してIR送信リクエストを行えるようにする。

### homebridgeの構築

homebridgeの構築には、local dnsの `avahi`、 `nodejs` が必要。

#### avahi install

avahiはローカルでホスト名のアクセスを可能とさせるDNSのようなもで、AppleのBonjour同様、導入するとローカルネットワーク内でホスト名でアクセスすることができる。

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

#### nodejs install

すでに導入している場合はスキップしてください。ここでは `v6.6.0` をインストールする。

- install

```bash
$ sudo apt-get install -y nodejs npm
```

- インストールされた場所にパスが通るように修正

```bash
$ sudo npm cache clean
# n はバージョン管理ツール
$ sudo npm install n -g
    /usr/local/bin/n -> /usr/local/lib/node_modules/n/bin/n
    n@2.1.4 /usr/local/lib/node_modules/n
$ sudo n stable
    install : node-v6.6.0
        mkdir : /usr/local/n/versions/node/6.6.0
        fetch : https://nodejs.org/dist/v6.6.0/node-v6.6.0-linux-armv7l.tar.gz
    ######################################################################## 100.0%
    installed : v6.6.0
#version確認
$ node -v
    v6.6.0
```

#### homebridge install

homebridge本体と、HTTPリクエストさせるプラグインをインストールする。多くのプラグインがあるので、[npnjs](https://www.npmjs.com/search?q=homebridge-plugin)で探して試すのも面白いかも。

```bash
$ sudo npm install -g homebridge
$ sudo npm install -g homebridge-http   # https://github.com/rudders/homebridge-http
```

#### configファイルの作成

コンフィグにあるリストがホームアプリが認識する操作リスト(アクセサリ)となる。json形式で、デフォルトはホームディレクトリ直下の `~/.homebridge/config.json` となっている。
このファイルに先程構築したREST Apiをコマンドごとに追加していく。以下コンフィグファイルの説明。

- `username` はラズパイのMACアドレスなので `ifconfig` などで調べて追加する。
- 追加したいコマンドを `accessories` の配列に追加する。
- `service` は[ソース](https://github.com/rudders/homebridge-http/blob/master/index.js)から `Switch` か `Light` のようだが、それで挙動が変わる感じはなかったのでどちらでもいいと思う。
- `status_url` ホームアプリ起動時や、送信後などにステータス取得するためのURL。IR送信は投げっぱなしで、ステータスなど無いのがほとんどなので、常にOFFでもいいと思う。ここでは一応GPIOの値を取るようにしている。
- `on_url` / `off_url` はどちらも同じで、IR送信のREST Apiを自身のWebIOPiのアドレス (`http://localhost:8000`)にリクエスト指定する。

```json:config.json
{
    "bridge":
    {
        "name": "Homebridge",
        "username": "B8:27:XX:XX:XX:XX",
        "port": 51826,
        "pin": "031-45-154"
    },

    "accessories": [
        {   "accessory" : "Http", "http_method": "POST",
            "searvice":"Switch",
            "status_url":  "http://localhost:8000/GPIO/17/value", "switchHandling": "yes",
            "name"      : "コンポ電源",
            "on_url"    : "http://localhost:8000/macros/sendIr/kenwood,power",
            "off_url"   : "http://localhost:8000/macros/sendIr/kenwood,power"
        },
            :
            :
    ]
}
```

### 自動起動設定する

[方法](https://github.com/nfarina/homebridge/wiki/Running-HomeBridge-on-a-Raspberry-Pi#running-homebridge-on-boot-etcrclocal)はいくつもあるようだが、`init.d` に起動スクリプトを追加することにする。

#### 起動スクリプトの作成

templateからスクリプトを作成して、serviceとして登録する。

```bash
# templateをダウンロード
$ sudo curl https://raw.githubusercontent.com/fhd/init-script-template/master/template /etc/init.d/homebridge
# 編集
$ sudo vim /etc/init.d/homebridge
        :
    dir=<your home directry>
    cmd="DEBUG=* /usr/local/bin/homebridge"
    user=<your name>
        :
```

#### 権限設定して登録

```bash
$ sudo chmod 755 /etc/init.d/homebridge
$ sudo update-rc.d homebridge defaults
# 再起動
$ sudo reboot
```

#### 起動できているか確認

ログを確認してみる。起動が成功すると最後にPINコードが表示される。これはホームアプリ登録時に必要となる。(`~/.homebridge/config.json` に記載されている)

```bash
$ cat /var/log/homebridge.log
    :
    [10/26/2016, 11:52:01 PM] [TV-up] Initializing Http accessory...
    [10/26/2016, 11:52:01 PM] [TV-down] Initializing Http accessory...
    [10/26/2016, 11:52:01 PM] [TV-mute] Initializing Http accessory...
    Scan this code with your HomeKit App on your iOS device to pair with Homebridge:

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

    [10/26/2016, 11:52:01 PM] Homebridge is running on port 51826.
```


### ホームアプリに登録して操作してみる

ホームアプリを起動して `アクセサリを追加` をタップ
![スクリーンショット 2016-11-03 21.00.47.png](https://qiita-image-store.s3.amazonaws.com/0/77816/f78ec394-c1c5-c2b9-708b-8eb14a5fd355.png)![スクリーンショット 2016-11-03 20.52.30.png](https://qiita-image-store.s3.amazonaws.com/0/77816/7555d5eb-f47f-bc10-6615-ba9cba3a4387.png)

同一ネットワークで起動できているなら `Homebridge` が出現するはずなのでタップ。 `このまま追加` でコード入力へ。。 (ターミナルの画面だと正常にスキャンできないので `コードを手動で入力` をタップして直接入力がおすすめ)
![スクリーンショット 2016-11-03 20.53.26.png](https://qiita-image-store.s3.amazonaws.com/0/77816/5039e06d-785b-1d0f-387b-28b92fd1d0b7.png)![スクリーンショット 2016-11-03 20.54.03.png](https://qiita-image-store.s3.amazonaws.com/0/77816/daeafb29-61ea-c923-a524-a8a671ff8dfb.png)

認識するためにコードを入力する

![スクリーンショット 2016-11-03 20.56.36.png](https://qiita-image-store.s3.amazonaws.com/0/77816/54cd30ad-3b50-7650-a0d4-e6ac94a092ec.png)

`config.json` のアクセサリが追加される。 アクセサリの `よく使う項目に含める` を有効にするとコントロールセンターからアクセスできる。

![スクリーンショット 2016-11-03 20.57.22.png](https://qiita-image-store.s3.amazonaws.com/0/77816/e680f5f3-c7d6-68d2-8f86-73a310314017.png)![スクリーンショット 2016-11-03 21.16.14.png](https://qiita-image-store.s3.amazonaws.com/0/77816/5fe67401-f290-3375-afd8-0a79ee4f965e.png)

これでiPhoneにHomeKit製品として認識させることができた。ただし、試したところ認識できるのは一台のみで、他のiPhoneで認識することはできず、1対1のようだ。

# おしまい

今は赤外線LEDをスターウォーズのBB-2に仕込んでテレビの操作ができるようにしています。iPhoneはHomeKit経由で、AndroidはWebブラウザ経由でテレビやコンポを操作しています。Webは[Bootstrap](http://getbootstrap.com/)などで簡単にレスポンシブデザインなページができるのでセンスがなくても何とかなりました。
自分でがっつりコードを書かなくても様々なライブラリの組み合わせで実用性のあるものを作れるのは楽しいですね。最近はESP8266にハマりだしたので、それらを使った複数部屋へのリモコンネットワーク構築を考えています。

<img width="428" alt="スクリーンショット 2016-11-03 23.18.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/77816/3a655a60-fbb6-048f-b548-51efe7b7b5f9.png">