Raspberry Pi Zero で赤外線リモコンを作る

# はじめに
雪が無いのに、東京も寒いですね。まるで冬のようです☃
※ 昨年度まで北海道民だったので、雪がないと冬という実感が湧きません。

さて、朝はみなさん忙しいですよね。
寒くて布団から出られなくてギリギリまで寝てしまい、急いで支度をして家を出るなんて方は少なくないのではないでしょうか。

そんな時、エアコンの電源を切り忘れませんか…？
タイマーで朝つくようにしていると、つけた感覚が無いので特に消し忘れやすいと思います。

そこで、 Raspberry Pi と赤外線 LED、赤外線リモコン受信モジュールを使ってリモコンを作成し、指定した時刻に停止させます。

電子回路には自信はありませんが、 Web のレイヤまで持ってくればこっちのもの。API を実装して最終的には外出先から叩けるようにします。

# ⚠ 免責事項
電子回路については全くの素人ですので、誤りもあるかと思います。見つけた方はコメントからご指摘ください🙏
また、本稿を参考にした事による電子部品の破損など、すべての損害について責任は負えませんので、ご了承ください🙇

# 準備
今回リモコン制作に使う部品です。

- Raspberry Pi (ここでは Zero を使いますがなんでも良いです)
- 赤外線リモコン受信モジュール ([GP1UXC41QS](http://akizukidenshi.com/catalog/g/gI-06487/))
- NPN型トランジスタ ([2SC2120-Y](http://akizukidenshi.com/catalog/g/gI-02732/))
- 赤外線LED ([OSI5FU5111C-40](http://akizukidenshi.com/catalog/g/gI-03261/))
- 抵抗 `10Ω`, `47Ω`, `1kΩ` (`1kΩ` だけ2個必要)
- 電解コンデンサ `47μF`
- ブレッドボード (+ ジャンパーワイヤ)
- Raspberry Pi とブレッドボードが繋げるもの

# 回路図
http://www.digikey.jp/schemeit/project/remocon-R9GQJE02025G/

## 送信部分
![send](https://qiita-image-store.s3.amazonaws.com/0/1804/f1377865-c7db-fcd1-eabe-8d5b0910be0b.png)

3.3V OUT と GPIO25 の間に抵抗と LED を入れても送信できますが、推奨されません。**GPIO には 3.3V 以上の電圧をかけることや 16mA 以上の電流を流すことはできません。Raspberry Pi が故障する原因になります。**
その上、信号を送信していない時も LED が点灯し続けてしまうので、電力の無駄にもなります。

図のようにトランジスタを使ってスイッチング回路を組んでください。LED の数は、リモコンで操作したい電化製品が反応するのであれば1つでも構いません。また、電源は 5V ではなく 3.3V を選んでも問題ありません。

⚠パルスで 1000mA まで流せる LED を採用しているので 抵抗(R1) は 10Ω ですが、他の LED を使う場合は抵抗値に注意してください。また、大きな電流を流す際は抵抗の定格電力にも注意してください。

### LED に流れる電流
1. 順電圧 `1.35V` の LED　が直列に2個並んでいるので `1.35 × 2 = 2.7V`
2. LED と直列に接続された 抵抗(R1) にかかる電圧は `5 - 2.7 = 2.3V`
3. 抵抗(R1) は `10Ω` なので、流れる電流は `2.3 / 10 = 0.23A = 230mA`
4. 抵抗(R1) と直列に接続されている LED にも同じ電流が流れるので、 LED に流れる電流は `230mA`
5. 正確には、トランジスタで電流が制御されているので、**最大`230mA`**

⚠抵抗(R1) では `0.3 × 0.23 ≒ 0.53W` の電力が消費されるので、定格電力が 1W の抵抗を選んでおけば安心でしょう。ただし、今回はパルスなので若干超えても壊れないようです。定格電力が 0.5W の抵抗しか手元にない場合は、代用しても問題ないでしょう。
参考: https://www.akaneohm.com/column/surge/

### トランジスタに流れる電流と LED に流れる電流 (ベース電流とコレクタ電流)
1. ベースエミッタ間電圧が `0.5~0.8V` なので、約`0.7V` とする。
2. トランジスタと直列に接続された 抵抗(R2) に掛かる電圧は `3.3 - 0.7 = 2.6V`
3. 抵抗(R2) は `1kΩ` なので、流れる電流は `2.6 / 1 × 10^3 = 0.0026A = 2.6mA`
4. トランジスタと並列に接続された 抵抗(R3) にはトランジスタと同じ電圧が掛かる。
5. 抵抗(R3) は `1kΩ` なので、流れる電流は `0.7 / 1 × 10^3 = 0.0007A = 0.7mA`
6. トランジスタのベースに流れ込む電流は `2.6 - 0.7 = 1.9mA`
7. 増幅率(hFE) は `160~320` なので、コレクタ電流は `304~608mA`

## 受信部分
![receive](https://qiita-image-store.s3.amazonaws.com/0/1804/08ece33e-f43c-92db-648c-8a2153a0ab3a.png)

図のように 抵抗(R4) と 電解コンデンサ(C1) を入れて、 CR フィルターを実装することが推奨されています。データシートを必ず確認してください。

# 赤外線リモコン受信モジュールの設定と読取

## lirc のインストールと lirc-rpi 有効化
```shell-session
sudo apt install lirc
```

`/boot/config.txt` を開いて、 lirc-rpi を有効化し GPIO のピンを割り当てます。

```
# Uncomment this to enable the lirc-rpi module
#dtoverlay=lirc-rpi
```

↓

```
# Uncomment this to enable the lirc-rpi module
dtoverlay=lirc-rpi,gpio_in_pin=24,gpio_out_pin=25
```

この設定の後、一度再起動が必要です。

⚠上記の設定によって lircd は自動起動するので、 `systemctl enable` 等は不要です。逆に他の方法で自動起動を設定してしまうことで GPIO の割り当てられるピンが変わってしまうなど不具合が起こる事もあり、注意が必要です。

## リモコンの信号を記録する
```shell-session:例
mode2 -d /dev/lirc0 | sed -ue '1d' | tee aircon_on.txt
```

この状態で、何かリモコンのボタンを押すと、画面に次のような数字の羅列が出力されます。

```
pulse 3375
space 1465
pulse 583
space 1027
pulse 552
space 1039
pulse 574
space 1020
pulse 520
space 253
pulse 582
space 203
pulse 550
space 1038
pulse 551
space 1043
pulse 546
space 209
pulse 562
space 1060
```

因みに、先頭1行は不要なので `sed -ue '1d'` の箇所で削ってます。
(信号を受信するまでの長さが入っています)

## 整形して lircd.conf を作成する
受信した信号を整形して `lircd.conf` を作成します。

```shell-session
cat aircon_on.txt | awk '{if(NR % 30) ORS=" "; else ORS="\n"; print $2}' | cat -; echo
```

先程の空白区切り2列に並んでいた2列目の数字だけを抜き出して、30行毎に空白区切りの1行にまとめて出力しています。これをコピーして `lircd.conf` に貼り付けます。

※もし lighting_on_off の行数が偶数で、 `space` で終わっている場合末尾の `space` から始まる行は取り除く必要があります。

`cat -; echo` を入れることで末尾に必ず改行が入ります。(コピペしやすくする為)

```:/etc/lirc/lircd.conf
begin remote

  name            aircon
  flags           RAW_CODES
  eps             30
  aeps            100
  gap             200000
  toggle_bit_mask 0x0

  begin raw_codes
    name on
460 383 496 368 485 376 487 411 454 394 469 25241 3474 1717 450 1244 484 383 483 379 510 351 490 1246 483 376 578 353 418 381
481 385 483 1249 482 378 485 1255 471 1302 430 379 491 1247 499 1226 480 1253 478 1248 486 1242 478 384 487 405 473 1235 477 378
486 382 484 381 484 378 496 370 485 384 482 378 483 379 537 331 481 378 526 1211 480 380 482 1263 495 355 486 378 486 381
482 1245 484 1250 476 388 477 382 489 417 444 384 477 383 485 384 481 394 468 384 479 377 492 381 481 395 475 425 489 344
506 379 446 391 475 379 483 1248 486 1241 486 1304 425 383 481 1291 434 384 484 1250 483 1245 478 34546 3488 1684 477 1248 489 377
484 382 479 405 457 1255 488 373 497 369 478 382 487 380 494 1241 482 377 480 1266 468 1248 480 379 485 1249 481 1244 485 1250
487 1239 480 1263 478 367 484 384 484 1244 484 386 480 385 480 395 465 382 507 356 498 370 485 378 483 380 484 390 484 375
485 376 507 1230 479 380 486 380 484 382 496 364 487 1247 482 378 485 379 487 380 485 382 478 384 483 380 486 391 471 385
479 382 481 384 482 381 482 383 488 383 478 385 484 378 489 374 488 376 487 388 476 379 483 1263 483 368 477 1250 480 381
520 1213 478 384 485 34546 3487 1688 479 1246 482 383 481 382 508 358 484 1255 469 385 485 384 480 391 471 381 482 1252 481 381
478 1251 483 1244 493 403 451 1250 478 1251 477 1249 485 1265 458 1251 483 380 485 381 508 1225 486 378 487 370 485 406 462 380
485 380 482 400 462 392 474 387 476 389 478 381 486 377 489 378 483 385 486 373 484 381 480 386 484 381 484 385 518 1208
487 399 459 382 483 1268 468 386 471 477 387 1249 483 382 505 357 481 1249 480 1253 479 1250 478 383 581 1154 477 385 477 383
485 380 482 383 507 391 459 368 482 386 485 377 511 361 477 382 488 1241 484 1268 485 1221 482 1247 504 362 484 1247 481 381
482 1246 483 1250 482 1246 483 1244 483 1248 479 383 483 384 480 380 486 384 480 384 478 384 481 415 450 383 485 379 484 382
482 385 477 386 481 378 487 1248 486 1243 480 384 482 394 470 390 474 383 482 383 485 381 479 382 480 384 484 384 481 382
482 1250 482 1247 481 407 456 384 480 383 516 349 483 383 504 358 482 385 519 339 494 398 458 389 497 362 482 417 466 362
484 382 520 345 507 358 614 251 484 1243 486 378 486 382 480 408 458 382 481 383 479 1255 479 1247 482 384 479 417 496 334
485 378 480 385 534 329 521 344 487 1247 479 385 478 385 484 379 498 365 482 430 440 379 484 396 468 378 483 387 501 1230
484 1245 476 1256 479 378 484 1248 479 1250 482 1244 481

    name off
466 382 490 374 486 379 497 363 490 380 493 25219 3484 1740 430 1245 509 356 502 361 480 381 483 1307 426 386 476 382 481 382
481 382 488 1251 477 383 481 1246 483 1279 452 378 483 1255 475 1248 482 1248 482 1264 466 1250 475 383 501 365 478 1255 477 380
486 382 484 380 486 377 483 383 480 388 561 299 484 380 487 379 479 382 488 1247 517 345 481 1268 460 411 461 377 483 382
481 1246 484 1249 473 387 483 388 481 388 473 383 487 377 483 382 479 383 485 379 510 364 481 374 485 385 479 381 497 370
480 378 485 386 484 378 493 1242 478 1251 477 1256 474 381 514 1220 477 431 436 1250 506 1225 484 34541 3483 1685 479 1247 482 383
486 389 475 398 482 1234 481 376 487 382 483 380 490 376 481 1259 478 379 477 1292 438 1248 479 383 483 1251 479 1246 482 1250
479 1246 484 1249 479 380 482 387 483 1247 482 378 483 382 493 373 482 383 480 382 487 414 451 388 474 397 466 381 484 385
479 381 481 1254 479 381 495 369 490 396 460 383 483 1258 506 356 475 394 473 402 456 404 464 395 468 383 483 383 497 367
508 355 482 384 480 381 488 378 481 389 477 395 472 393 467 385 482 384 481 381 488 380 483 1248 477 383 488 1244 481 382
481 1248 518 369 461 34548 3486 1685 482 1247 485 389 469 385 484 379 484 1289 480 342 481 383 489 385 472 384 481 1256 474 380
484 1254 476 1245 483 383 480 1250 490 1240 502 1225 485 1266 479 1229 481 380 486 380 484 1247 504 359 489 374 485 379 487 380
483 382 483 377 486 383 482 380 486 381 479 384 507 380 460 383 482 382 483 384 502 363 512 348 507 358 491 379 480 398
464 383 490 371 486 1249 490 371 505 362 484 1247 481 379 487 381 480 1263 469 1249 479 1293 432 382 487 1246 483 382 483 380
499 365 485 380 483 383 482 381 483 385 480 380 523 342 484 392 476 1242 515 1213 483 1251 476 1250 482 402 462 1248 483 388
483 1242 481 1256 493 1226 481 1249 487 1242 481 387 477 383 483 379 486 381 482 378 488 398 466 385 497 364 498 386 463 407
457 383 480 381 488 376 493 1238 482 1251 489 373 494 372 481 382 484 397 463 384 488 377 509 380 456 382 483 384 486 379
484 1246 494 1235 484 433 424 386 484 382 480 384 481 380 486 380 485 396 467 417 446 387 482 390 470 387 481 382 481 381
483 400 506 342 515 349 484 378 486 1247 481 380 483 425 441 383 483 381 513 351 481 1249 483 1251 489 373 481 381 479 384
484 383 483 422 442 385 489 369 493 1239 483 386 475 419 455 375 493 375 477 382 483 400 466 383 483 380 487 1250 480 379
506 1222 479 1249 483 390 472 1252 504 1221 483 1254 481

  end raw_codes

end remote
```

※ファイルの先頭に書かれている `#UNCONFIGURED` があると動かないので必ず消してください。

`/etc/lirc/hardware.conf` の次の箇所を変更します。

```
# Run "lircd --driver=help" for a list of supported drivers.
DRIVER="UNCONFIGURED"
# usually /dev/lirc0 is the correct setting for systems using udev
DEVICE=""
MODULES=""
```

↓

```
# Run "lircd --driver=help" for a list of supported drivers.
DRIVER="default"
# usually /dev/lirc0 is the correct setting for systems using udev
DEVICE="/dev/lirc0"
MODULES="lirc_rpi"
```

lircd を再起動して設定を反映します。

```shell-session
sudo systemctl restart lirc
sudo systemctl status lirc
```

# 赤外線 LED を使って信号の送信
次のコマンドで正しくリモコンのボタンが登録されたか一覧が見れます。

```shell-session
irsend LIST '' ''
irsend LIST aircon ''
```

次に、実際に信号を送出します。

```
irsend SEND_ONCE aircon on
```

もしエアコンなどの受信側が反応しない場合、データ整形に誤りがないか、赤外線 LED は受信機器の方向を向いているか、カメラ等で覗いて赤外線 LED の強度が足りないようであれば、受信部に近づけるなど試してみてください。

### トラブルシューティング
`irsend LIST '' ''` 実行時に次のようなエラーが出た場合以下の項目を確認してみてください。

```
irsend: could not connect to socket
irsend: No such file or directory
```

- `lircd` が正常に起動しているか
- `/etc/lirc/lircd.conf` が正しく設定されているか
- `/etc/lirc/hardware.conf` が正しく設定されているか

#### Tips
リモコンには状態管理をして同じボタンでも異なる信号が送信されるものと、単純にボタンと信号が一対一で対応しているものがあります。

前者は、エアコンのリモコンなどが該当します。信号を読取る際には液晶表示部を確認して、今は何の信号が送られているのか確認した上で記録する必要があります。

後者は、照明器具のリモコンなどが該当します。記録する際は簡単ですが、実際に利用する際は不便なことがあります。
電源ボタンがトグルだった場合、現在点灯しているのか、消灯しているのかはリモコン側からは分からないので、点灯と消灯を切り替えるという操作しかできません。照明器具の場合は、照度センサーを利用することで点灯しているか消灯しているか判断して、既に点灯している場合は何もしないなどの工夫すると良いでしょう。

### 指定した時刻にエアコンを停止させる
`at` を使うので入っていなければ入れてください。

```shell-session
sudo apt install at
```

#### 設定

```
echo "irsend SEND_ONCE aircon off" | at 10:00
at -l
```

たったこれだけで、10時にエアコンが停止します。(タイムゾーンに注意)
`at -l` で登録している job 一覧が確認できます。

毎日指定した時刻に信号を送信したい場合は cron を使うと良いでしょう。

# API の実装
Go で実装したので、クロスコンパイルして Raspberry Pi 上でも動きます。
https://github.com/ww24/lirc-web-api

まだ機能は少ないですが、今後拡張していく予定です。

## インストール
次のワンライナーでインストールから起動まで行います。

```shell-session
curl https://raw.githubusercontent.com/ww24/lirc-web-api/master/install.sh | sh
```

※ systemd が稼働している環境以外では、カレントディレクトリに展開されます。

## 確認
```shell-session
curl http://localhost:3000/api/v1/signals
```

```json
{
  "status":"ok",
  "signals":[
    {
      "remote":"aircon",
      "name":"on"
    },
    {
      "remote":"aircon",
      "name":"off"
    }
  ]
}
```

## 送信方法
```
curl -XPOST http://localhost:3000/api/v1/aircon/on
```

## 簡易クライアント
ブラウザで `http://localhost:3000/` を開くと Web クライアントが開きます。
※ `localhost` の箇所は Raspberry Pi の IP アドレスで置き換えてください。

⚠ 外出先から利用する際は VPN を通すなど、認証を挟むようにしてください。悪意のある第三者に攻撃されて被害を被っても責任は負えません。

# リモコンの活用例
赤外線リモコンで操作するタイプの家電なら基本的に何でも操作できるので、照明器具を操作して朝起きたい時間に点灯させるという使い方もできます。

Hubot を使って Slack 等と連携させても面白いと思います。

# 参考
- [Slack経由で家の外からエアコンをon, offできる装置を、Raspberry Piで作ってみた。（しかも御坂美琴ちゃんが応答してくれる）](http://qiita.com/KAKY/items/55e6c54fa2073cdc0bbe)
- [Umbrella　RaspberryPiでLIRCする(2015/02仕様変更？)](http://wbbwbb.blog83.fc2.com/blog-entry-189.html)
- [Raspberry Piで赤外線リモコンを学習し発信する (r271-635)](http://netlog.jpn.org/r271-635/2014/07/raspberry_pi_ir_remotecontrol.html)
- [赤外線学習リモコン―赤外線信号送信・受信（改） | Feijoa.jp](http://www.feijoa.jp/laboratory/raspberrypi/infrared2/)
- [第22回 Raspberry PiのGPIO概要](https://tool-lab.com/make/raspberrypi-startup-22/)
- [デジタルトランジスタ(デジトラ)の基本的な考え方を教えてください。 | FAQ | ローム 半導体 ROHM](http://www.rohm.co.jp/web/japan/faq_search/-/faq_search/FaqId/234)