家の外からiPhoneでエアコン操作

# 背景

冬は身体も心も寒い。

1人暮らしの寒い家に帰ると、寂寞の情が込み上げて来る。
家だけでも暖かく迎え入れてくれれば、せめて身体は暖かくなるのにな。

ということで、昔から作りたいと思っていたラズベリーパイを使って遠隔でエアコン操作できるシステムを作ることにした。

流行りのLINE BOTとかで操作させようかと思ったけど、
LINEを開く→エアコン操作用のアカウントを探す→文字を打つ
この操作ってめんどくさくね？と思い、エアコン操作するためだけのiPhoneのアプリを作ることにした。

ちなみに、今まではiOSのアプリしか作ったことなく、初めての電子工作です。

# 全体のシステム
少し長くなるので、まずは全体の構想について。

Raspberry PiがWebサーバー走ってる状態で待っている。
↓
iPhoneでPOSTする。
(iPhonetoRaspberry Piは別ネットワークなので、グローバルIPが必要)
↓
Raspberry Pi上のphpでエアコンをつけるスクリプトを実行
↓
iPhoneへレスポンス

# iPhoneのアプリ作成
storyboardを軸として、[RxSwift](https://github.com/ReactiveX/RxSwift)と[APIKit](https://github.com/ishkawa/APIKit)と[SVProgressHUD](https://github.com/SVProgressHUD/SVProgressHUD)を使ってさらっと作成。
そんなに綺麗に作ってないけど、参考程度までに。

[taiking/RemoteController](https://github.com/taiking/RemoteController)

# 購入リスト
秋月電子通商様には感謝です。

- [ラズベリーパイ3 modelB ](http://akizukidenshi.com/catalog/g/gM-11425/)
- [5mm 赤外線LED](https://akizukidenshi.com/catalog/g/gI-03261/)
- [赤外線リモコン受信モジュール](https://akizukidenshi.com/catalog/g/gI-01570/)
- [LED光拡散キャップ](https://akizukidenshi.com/catalog/g/gI-01120/)
- [ブレッドボード](https://akizukidenshi.com/catalog/g/gP-00313/)
- [赤色LED](https://akizukidenshi.com/catalog/g/gI-01318/)
- [HDMIコード](https://akizukidenshi.com/catalog/g/gC-06495/)
- [ジャンパーコード(オス-オス)](https://akizukidenshi.com/catalog/g/gC-05371/)
- [ジャンパーコード(メス-メス)](https://akizukidenshi.com/catalog/g/gP-03476/)
- [抵抗100Ω](https://akizukidenshi.com/catalog/g/gR-25101/)
- [microSD](http://akizukidenshi.com/catalog/g/gS-10256/)

抵抗を買いすぎたけど、まぁいつか使うだろう()

# Raspbianのインストール
[Raspberry Pi 3にRaspbianをインストール(Mac OS X を使用)](http://qiita.com/onlyindreams/items/acc70807b69b43e176bf)を参考にしました。
先人の知恵には頭が上がりません。
ちなみにMacのSDカードスロットは不調が多い。試行錯誤を重ね、SDカードの書き込みロックを5mmほどずらしたらいけた。[^1]

# Raspberry Piの遠隔操作
家にはモニタとなるものがテレビしかないので、非常に見にくくてストレス。
てことで、自分のMacとSSH接続させた時の備忘録。

- Raspberry PiとMacを同じネットワークに接続(私はLANケーブルを直接ラズパイにブッコミました。)
- Raspberry Pi上で以下を行う。

```console. 
> hostname -I # Raspberry PiのローカルIPアドレスを調べる。
> touch /boot/ssh # 2016-11-25以降はデフォルトでSSHが無効になってるので、/boot/にからファイルsshを作成
> sudo reboot # 再起動
```
[参考(raspbianのリリースノート)](http://downloads.raspberrypi.org/raspbian/release_notes.txt)

- Macのターミナルで以下を行う。

``` console. 
> ssh pi@xxx.xxx.xxx.xxxx # xxxはhostname -I の値
```

これだけで接続できる。なんて簡単だ。

# Raspberry Piのセキリュティ設定
グローバルIPを設定して、インターネット上に公開するから最低限のセキュリティーは必要だろうと言うことで設定。
[ラズベリーパイ(B+)のセキュリティ設定まとめ](http://masatolan.com/raspberry-pi/raspberry-pi-security/)

これだけでいけるのか不安だが。。
# LED操作
電子工作のHello WorldといわれるLチカをやってみます。
まずはRaspberry Pi3 modelBのピンの仕様について説明します。

![Pi-GPIO-header.png](https://qiita-image-store.s3.amazonaws.com/0/114688/1b4e0d06-e669-b741-e84a-0a8879860f61.png)
[Embedded Linux Wiki](http://elinux.org/RPi_Low-level_peripherals)より

この画像が表すのは、電源を入れるとオレンジのピンが常に3.3V、赤のピンが5Vを出力する。黒のピンは常にGNDで、GPIOxxはプログラムで制御できるピンとなってる。

### Lピカ
とりあえず、LチカというよりLピカ(LEDがずっとついてる状態)をしてみよう。
回路はこんな感じ。上の画像の左上の四角(Raspberry Piの裏のハンダ付けで唯一四角のところ)の3.3VのピンをLEDのプラスの方に、マイナスの方はGNDにつなげた。
見事に点灯した。感動。

![S__51437570 2.jpg](https://qiita-image-store.s3.amazonaws.com/0/114688/4522acb1-589c-36c5-ff50-bccc41e3e02a.jpeg)

### Lチカ
LEDのプラスの方をGPIO2にした。
そして以下のコードを実行させた。

```console. 
> echo 2 > /sys/class/gpio/export  # /sys/class/gpio/gpio2が作られる
> echo out > /sys/class/gpio/gpio2/direction  # gpio2をoutput用に使う
 
> while :  #以下をくりかえす
do       #
echo 1 > /sys/class/gpio/gpio2/value   # LEDをオンにする(GPIO2の値を１にする)
sleep 0.1   # 0.1秒待つ
echo 0 > /sys/class/gpio/gpio2/value  # LEDをオフにする
sleep 0.1   # 0.1秒待つ
done

# Ctr-cで停止できる
```

見事にチカチカ。感動

# 赤外線操作
見事Hello World的なものができたので、いよいよエアコン操作に入る。長い道のりだ。
### リモコンの仕様

エアコンのリモコンは発する赤外線が複雑だ。同じ温度を1℃あげる操作でも、その時の風量や風向によって発する赤外線は変わってくる[^2]。すべてをの操作を網羅するのは難しい。節電家の私は

- 21℃.風量自動.暖房
- 27℃.風量自動.冷房
- 停止

の3つの操作をできるようにしようと考えた。

### モジュールのインストール
apt-getで赤外線操作のできるモジュールLIRCをインストール
ついでに、apt-getの更新もしとこう。

```console. 
> sudo apt-get update
> sudo apt-get upgrade
> sudo apt-get install lirc
```

### LIRC使用の準備
以下のコマンドで、lircへの入出力に使うGPIO番号を指定できると思いきや失敗した。

```console. 
> sudo modprobe lirc-rpi gpio_out_pin=17 gpio_in_pin=18
```

色々調べてみると、/boot/config.txt に以下の一行を追記すればいけた。

```/boot/config.txt
 ・
 ・  省略
 ・
dtoverlay=lirc-rpi,gpio_out_pin=17,gpio_in_pin=18,gpio_in_pull=up
```

そして再起動。

```console.
> lsmod | grep lirc # lircの存在を確認
lirc_rpi 6422 0
lirc_dev 8110 1 lirc_rpi
rc_core 16220 1 lirc_dev
```
これで、ソフトの部分の設定が完了だ。次は回路を組む。

### 回路作成
先ほど、outをGPIO17にinをGPIO18にセットした。
つまり、赤外線LEDを光らすLEDを繋ぐのはGPIO17、赤外線センサーをGPIO18に繋げばいいということだ。
赤外線センサーには足が3本あるので、下の画像を参考に繋ぐとよい。
![I-01570.jpg](https://qiita-image-store.s3.amazonaws.com/0/114688/b46a4a7d-1796-a2ac-592c-587e4dac63b1.jpeg)


### リモコンの赤外線を受信
いよいよだ。

```
> sudo /etc/init.d/lirc stop #赤外線を受信するにはLIRCを停止させる必要がある。
> mode2 -d /dev/lirc0
```

この状態でセンサーに光をあてると、よくわからん数字がでてくる。こんなかんじ。

```output.
space 16777215
pulse 243
space 551
pulse 292
space 550
pulse 290
　　・
　　・
```
これでセンサーが赤外線を受信できることが確認できた。
次はこれを学習させる。

本来、`irrecord`を使った方が楽なのだが、エアコンのリモコンの点滅時間が長いので、認識してくれなかった。
ちなみにテレビのリモコンを作るときは、`irrecord`を使えたので、参考までに下の方に載せておく。

ということで、エアコンのリモコン作りは地道によくわからない数字を解析する。
まずは以下のファイルを作る。

```parse.rb
lines =  File.open(ARGV[0]).readlines
lines_without_first = lines.slice(1..-1)
puts lines_without_first.map{|line|line.split(" ")[1]}.join(" ")
```
次に赤外線パターンを覚えさせる。

```console. 
> mode2 -d /dev/lirc0 | tee cool
  # 冷房のスイッチを入れる。
  # Ctr-c
> mode2 -d /dev/lirc0 | tee heat
  # 暖房のスイッチを入れる。
  # Ctr-c
> mode2 -d /dev/lirc0 | tee stop
  # 停止のスイッチを入れる。
  # Ctr-c
```

これで赤外線の信号のパターンをファイルに保存することができた。これをparse.rbを使って整形する。
あっ、Rubyのインストールは[これ](http://qiita.com/kon_yu/items/c57e98eb693646ee5766)を参考に。

```console. 
> ruby parse.rb stop
```

先ほどの数字の列を用いいて、/etc/lirc/lircd.confを編集します。

```/etc/lirc/lircd.conf
# Please make this file available to others
# by sending it to <lirc@bartelmus.de>
#
# this config file was automatically generated
# using lirc-0.9.0-pre1(default) on Wed Jan 11 00:00:00 2017
#
# contributed by 
#
# model no. of remote control: 
# devices being controlled by this remote:
#

begin remote

  name  aircon
  flags RAW_CODES
  eps            30
  aeps          100

  gap          200000
  toggle_bit_mask 0x0

      begin raw_codes

      name stop
30505 51258 3191 1831 272 1410 271 571 282 558・・・・・(省略)

      name cool
30800 50975 3432 1611 491 1192 490 351 490 351・・・・・(省略)

      name heat
30725 51047 3412 1634 469 1214 468 373 469 372・・・・・(省略)

      end raw_codes

end remote
```
1行が長すぎるとダメらしいので、大量の数字の部分は80文字くらいで適宜改行してください。

### 赤外線の送信

```console. 
> sudo /etc/init.d/lirc start
> irsend LIST '' ''
irsend: aircon
> irsend LIST aircon ''
irsend: 0000000000000000 stop # ←これがでれば準備OK
irsend: 0000000000000001 cool # ←これがでれば準備OK
irsend: 0000000000000002 heat # ←これがでれば準備OK
```

いよいよ、、、発射！！


```console. 
> irsend SEND_ONCE aircon cool
```

これでエアコンがついたと思います。やったー

# http通信
### アパッチの導入
webサーバーを導入する。

```console. 
> sudo apt-get install apache2
```

### ローカルIPアドレスの固定
Raspberry piがLANを使うとき、初期設定ではローカルIPアドレスが切り替わるので固定させてあげないといけない。(私は切り替わったことがないが一応。。。)
`/etc/dhcpcd.conf`ファイルの末尾に以下のコードを追記


```/etc/dhcpcd.conf
　　・
　　・省略
　　・
interface eth0
static ip_address=***.***.**.**/24 ## **はRaspberry PiのローカルIPアドレス
static routers=***.***.**.**
static domain_name_servers=***.***.**.**
```
気をつけないのがいけないのが、ip_adressとroutersが同じだとダメなことだ。私はこれで2時間無駄にした。routersとdomain_name_serversは同じでも問題ない。

設定をreload

```console. 
> sudo /etc/init.d/dhcpcd reload
```

### ポート開放
だいたいのWi-Fiの初期設定はポートを開放していないので、開放してあげないと外部からの通信をうけつけることができない。なので、まずはルーター側でポート開放してあげないといけない。

私はソフトバンク光を使っている。まずはそのWi-Fiにつなぎ、http://172.16.255.254 にアクセスし、設定画面に行く。[^3]

「ルーター機能の設定」→「ポート転送設定」
転送先IPアドレスはRaspberry PiのローカルIPアドレスを指定。
有効にするのは忘れずに。設定できたら保存して再起動が必要になる。
<img width="1280" alt="screen.png" src="https://qiita-image-store.s3.amazonaws.com/0/114688/a2cc4b44-fd21-0a42-ccd0-95bc1a4ec250.png">

そして、外部からアクセスするためのIPアドレス、いわゆるグローバルIPアドレスは「設定/接続情報」→「WAN側IPアドレス」で確認できる。このIPアドレスをBaseRequest.swiftのbaseURLの返り値にする。

### エアコン操作の実行ファイルを作る。
Apacheの設定がちょっと面倒だったので、`/var/www/html/`配下にファイルを作った。こんなんしていいんかな。。以下の二つのファイルを作成。

```/var/www/html/controller.sh
sudo /etc/init.d/lirc start # lircの起動。
irsend SEND_ONCE aircon $1 # $1は実行時の引数が格納されている。今回はstop, cool or heat
```


```/var/www/html/index.php
<?php
  $method = $_SERVER["REQUEST_METHOD"];  # httpMethodを取得
  header('Content-type: application/json');   # APIKitでパースできるのはJsonはので、responseをjsonに指定

  # POST以外ならエラー
  if ($method != "POST") {
    $response = array("error" => array("message" => "Request by POST"));
    echo json_encode($response);
    return;   
  }

  # iOSからはjsonでPostのbodyが来るので、$_POST["value"]ではダメ
  $json_string = file_get_contents('php://input');
  $json_obj = json_decode($json_string);
  $value = $json_obj->value;

  if ($value == "stop" || $value == "heat" || $value == "cool") {
    $output = shell_exec('sh controller.sh ' . $value);
    $response = array("success" => array("status" => $value));
    echo json_encode($response);
  } else {
    $response = array("error" => array("message" => "Parameter is invalid."));
    echo json_encode($response);
  }
```
phpでjsonのbodyを取得するのにかなり苦戦した。[^4]
status codeとかは全く考えていないのでご了承ください。

これでアプリ上でボタンを押すとエアコンがつくはず！！
注意しないといけないのが、iPhoneとRaspberry Piが同じネットワークに繋がっていると動作できないのでご注意を。逆に言うと、別のネットーワークに繋がってないといけないので、外からでもエアコンの停止などができる！


# (補足)irrecordを使ったリモコン受信

エアコンのリモコンでは使えなかったので、テレビで実験したところいけたので、参考までに載せておく。

```console. 
> irrecord -n -d /dev/lirc0 ~/tv.conf
irrecord -  application for recording IR-codes for usage with lirc
 ・
 ・  省略
 ・
Press RETURN to continue. 
(エンターキーを押す)
 ・
 ・  省略
 ・
Press RETURN now to start recording.(再びエンターキーを押す)
...................................................(リモコンのあらゆる種類のボタンを適当に押す)
Found const length: 107586
Please keep on pressing buttons like described above.
...................................................(リモコンのあらゆる種類のボタンを適当に押す)
Space/pulse encoded remote control found.
 ・
 ・  省略
 ・
Please enter the name for the next button (press <ENTER> to finish recording)
on(←これから登録するボタンの名前)F

Now hold down button "on".
(センサーに向けてボタンを押す)
 ・
 ・  以降これを繰り返す。
 ・  省略
 ・



No toggle bit mask found.
Successfully written config file.
```
これで、~/tv.confが作成された。
~/tv.confの中身を、/etc/lirc/lircd.confにコピーする。

あとは、エアコンの赤外線送信と同じ流れ。

# 感想
エアコンのおかげで身体は暖かくなったが、心は暖かくはならなかった。
そうこうしているうちに、もうすぐ夏になる。身体だけが暖かくなっていく。

# 参考サイト
[^1]: [MacBook ProのSDカードスロットって書き込みロックがかかる不具合あるっぽい？](http://kanonji.info/blog/2013/11/26/macbook-pro%E3%81%AEsd%E3%82%AB%E3%83%BC%E3%83%89%E3%82%B9%E3%83%AD%E3%83%83%E3%83%88%E3%81%A3%E3%81%A6%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BF%E3%83%AD%E3%83%83%E3%82%AF%E3%81%8C%E3%81%8B%E3%81%8B/)
[^2]: [Raspberry Pi上のLIRCでエアコンを操作する](http://raspibb2.blogspot.jp/2016/06/raspberry-pilirc.html)
[^3]: [光BBユニット（E-WMTA2.3）](http://ybb.softbank.jp/support/connect/hikari/router/bbu23-menu.html)
[^4]: [PHPでHTTP POSTされたJSON本文のbodyを受け取る方法](http://takuya-1st.hatenablog.jp/entry/2013/07/19/221203)