背景
今年の冬は寒い。
最近新宿のボロアパート(立地だけで選んだ)に引っ越して以来、断熱性のカケラもないくそ寒い家に帰るのが嫌でしょうがなかった。
幸いにして(?)エアコンはあるので、家に入ってから暖房をつけるのだが、暖まるまではそこそこ時間がかかり、その間はコートも脱がず凍えるしかない。
そこで、かねてから欲しいと思っていたインターネット経由でエアコンをon, offできる装置を作ることにした。
電子工作は全くの初心者なので、使うのはとっかかりの簡単そうなRaspberry Piにした。
また、一人の家に帰る寂しさを紛らわせるために、最近エンジニアに人気のチャットツールslackを使った。
slackに「暖房オン」とメッセージを打つと、アニメキャラが「暖房つけといたわよ。べ、別にあんたのためじゃないんだからね//」と言いながら暖房をつけてくれる。夢のようだ。
実装開始時点での私の能力
- 電子工作やったことない
- Raspberry Pi触ったことない
- Linux(CentOS, Ubuntu)はだいたい触ったことある
- Apacheやphp, JavaScriptなどを使ってwebアプリケーションを作ったことがある
- 会社でslackというチャットツールを使っている
つまり、普通のWeb屋さんです。
完成形
1. slackでメッセージ投げる(みことたんが返事してくれる!(/ω\)
2. 家に設置したRaspberry Piが赤外線を発信
3. エアコンが動く!
材料
Amazonで買ったもの
- Raspberry Pi Model B+ (Plus)
-
BUFFALO 無線LAN子機 コンパクトモデル 11n技術・11g/b対応 WLI-UC-GNM
- 無線LAN子機の中では圧倒的に小さくてよい
電子部品専門店で買ったもの(私の場合は秋葉原の秋月電子で買った)
- 5mm赤外線LED OSI5FU5111c-40
- 赤外線リモコン受信モジュール PL-IRM2161-XD1 (2個入)
- LEDキャップ OS-CAP-5MK-1
- 抵抗 (50Ωくらい)
- ブレッドボード
- ジャンパーワイヤー (最低オス・メスそれぞれ5本くらい)
- 普通の赤色LED(通電確認用)
その他、Raspberry Piの初期設定のために必要なもの(既に持ってるかも)
- 電源ケーブル(microUSB)
- usbキーボード
- hdmiケーブル & ディスプレイ
Raspberry Pi(ラズベリーパイ)ってなんや
Linuxを動かすことのできるマイコン(マイクロコンピュータ)です。サイズは下の写真のように小さく、手のひらにのせることができるくらいです。
Linuxで動いてるので、Apacheやphpを入れてサーバとして使うことも簡単です。
また、GPIO(General Purpose Input/Output: 汎用入出力)ピンというものがついており、そこから回路を作って電子工作をすることができます。
...なんて説明されても分かったような分からんような感じなので、実際に遊んでみるのが一番だと思います。
↓のリンク先のページは、電子工作初めての女性社員がRaspberry Piで遊んでみる、という内容の連載記事です。つまずいたところを全て記述しながらゆっくり進んでいってくれるので、とても楽しく読めました。
http://deviceplus.jp/author/maruyamadeviceplus-jp/
OSのインストールなどの基本的なセットアップ作業はこのページを読みながら進めてもらえれば間違いないと思います。
以下は、上記のページ通りにRaspberry Pi用のOS: Raspbianを入れたものとして説明を進めます。
Apache, phpのインストール
RaspbianはDebian系のOSなので、aptを用いてインストールすることができます。
$ sudo apt-get install apache2
$ sudo apt-get install php5
$ sudo update-rc.d apache2 defaults #起動時にapacheが自動で立ち上がるように設定
インストール直後は、/var/www or /var/www/htmlがドキュメントルートとなっています。(Apacheのバージョンによる?)
$ vi /var/www/index.php
hello world from raspberry pi!
<?php echo "phpは正しく動いています。"; #phpが正しく動いてるか確認 ?>
として、index.phpをドキュメントルート上に作り、Apache, phpが正しく動いていれば、curlコマンドで以下のような出力が得られるはずです。
$ curl http://localhost
hello world from raspberry pi!
phpは正しく動いています。
さらに、他のPCからも同じように見えることを確認しましょう。
ifconfigコマンドなどで、Raspberry PiのIPアドレスを調べ、そのIPアドレスをブラウザに打ち込めば、先ほどcurlコマンドを打ったときと同じ内容が表示されるはずです。
(Raspberry Piと異なるネットワークに接続しているPCからアクセスする場合は、パブリックIPアドレスを指定する必要があります。
その場合、ルータの設定で外部から80番ポートへのアクセスを、Raspberry PiのプライベートIPアドレスへポートフォワードしてあげるようにしてください。)
slackから通信を受け取り、LEDを光らせる
まずは記念すべき電子工作第1歩として、slackからメッセージを送り、それに反応してRaspberry Piに繋いだLEDが光る仕組みを作ってみましょう。
LEDの点滅スクリプトを走らせる
まず、Raspberry PiのGPIOピンがどのような仕様なのかを理解するために、以下のページに従って電子回路を組んでみて、LEDライトを点灯させてみましょう。
第9回「ラズベリーパイで電子工作!Lチカ…の前にLピカ!」| Device Plus - デバプラ
このページでは200Ω程度の抵抗を使っていますが、50Ωの抵抗でも大丈夫です(責任は負えません。)どうしても怖い方は、50Ωの抵抗を直列で4つ繋げれば200Ωになるので、そうしてください。
以下は、上記のページに従って「GPIO2」を用いてLEDを点けたり消したりできた状態を想定します。(下の画像の状態)
以下のスクリプトを好きな場所に保存し、実行するとLEDが3回点滅します。
echo 2 > /sys/class/gpio/export #「GPIO2」を使う
sleep 1
echo out > /sys/class/gpio/gpio2/direction #「GPIO2」を出力用に使う
echo 1 > /sys/class/gpio/gpio2/value #点灯
sleep 1 #1秒休む
echo 0 > /sys/class/gpio/gpio2/value #消灯
sleep 1
echo 1 > /sys/class/gpio/gpio2/value
sleep 1
echo 0 > /sys/class/gpio/gpio2/value
sleep 1
echo 1 > /sys/class/gpio/gpio2/value
sleep 1
echo 0 > /sys/class/gpio/gpio2/value
echo 2 > /sys/class/gpio/unexport #「GPIO2」の使用を終了
$ sudo sh blink.sh
httpアクセスを受けると、LEDが点滅する
先ほど作った/var/www/index.phpを以下のように書き換えます。
<?php exec('sudo sh /var/pi/blink.sh'); ?>
LEDを点滅させました!
すると、前と同様にRaspberry PiのIPアドレスへアクセスするとLEDが点滅...すると思いきや、点滅しません。
これは、httpリクエストを受け取ってスクリプトを実行するユーザが、root権限を持っていないためです。
そこで、(セキュリティ的には良くないのですが...)www-dataにパスワードなしでスクリプトをsudoで実行できる権限を与えてあげます。
$ sudo visudo # /etc/sudoers.tmpファイルが開かれる
...
pi ALL=(ALL) NOPASSWD: ALL
www-data ALL=NOPASSWD:/bin/sh #この行を追加
この状態でもう一度Raspberry PiのIPアドレスへアクセスすると、見事LEDが点滅するはずです!
slackからメッセージを受けるとLEDが点滅する
ついにslackとの連携です。
今回は、slackから提供されている「Outgoing WebHooks」というAPIを使います。
このAPIは、特定のチャンネルや特定の文字列を含んだメッセージが送られると、こちらの指定したURLにPOSTアクセスをしてくれるというものです。
しかも、レスポンスでjsonデータを返してやれば、それをslack上のメッセージに表示してくれます。
https://slack.com/services/new
にアクセスし、「Outgoing WebHooks」を選択し、指示に従って設定してください。
POST先のURLは、Raspberry PiのパブリックIPアドレスにすればよいです。
「rpi-led」チャンネルなどを作って、「LED」という文字列で始まるメッセージがそのチャンネルに投下されたときだけ反応するように設定するのがよいと思います。
さて、設定が終わったら、自分の設定した条件に適合するようなメッセージを投下してみましょう。 設定がうまくいっていればLEDが点滅するはず。
Raspberry Piからメッセージの返信をする
「Outgoing WebHooks」APIでは、POSTアクセスのレスポンスに、
{"text":"@message@"}
というjsonデータを返してやると、@message@の部分がslack側に表示されます。
なので、以下のように/var/www/index.phpファイルを書き換えてやりましょう。
<?php exec('sudo sh /var/pi/blink.sh'); ?>
{"text":"LEDを点滅させました!"}
すると、slackからのアクセスでLEDが点滅させると、slack上に「LEDを点滅させました!」というメッセージが表示されます。
エアコンをon, offできるようにする
ここまでで、slackにメッセージを投下することで、Raspberry Pi上のスクリプトやコマンドを実行できるようになりました。
次に、Raspberry Piからエアコンのon, offをできるようにしたいと思います。
そのための大まかな手順は以下の2ステップです。
- 赤外線受光器を用いて、エアコンのリモコンがon, off時にどのようなパターンの赤外線を発信しているのかを覚える。
- 赤外線LEDを用いて、先ほど覚えたパターンを送信する。
電子工作による赤外線リモコンの操作は、電子工作プロの方々がたくさんやられているので(以下のリンク)、ここでは詳しい説明は省いて、実際に私がやった手順に集中して書いていきます。
Umbrella RaspberryPiでLIRCする
Raspberry Pi で赤外線リモコン - 猫ぱーんち!
リモコンが発信している赤外線パターンを覚える
赤外線の受信・発信を行うには、lircというLinuxで赤外線リモコンを受信したり発信したりするソフトウェア環境を用います。
まずはインストール
$ sudo apt-get install lirc
lircへの入出力に使うGPIO番号を指定(下のコマンドでは、入力を24, 出力を25番のピンで行うように設定している)
$ sudo modprobe lirc-rpi gpio_in_pin=24 gpio_out_pin=25
デバイスファイルができているか確認
$ ls -l /dev/lirc*
crw-rw---T 1 root video 249, 0 12月 23 13:23 /dev/lirc0
debugfsで、GPIOのアサインを確認
$ sudo mount -t debugfs debugfs /sys/kernel/debug
$ sudo cat /sys/kernel/debug/gpio
GPIOs 0-53, bcm2708_gpio:
gpio-16 (led0 ) out hi
gpio-24 (lirc_rpi ir/in ) in hi
gpio-25 (lirc_rpi ir/out ) in lo
受信動作の確認
図のように赤外線受光器(型番:PL-IRM2161-XD1)とジャンパーワイヤーを設置し、回路を作成します。
このとき、受光器右側の足が3.3V電源のピン、真ん中の足がGNDのピン、左側の足がlircの入力ピンにささっていることを確認してください。(下の図ではそれぞれ、1(3.3V), 20(GND), 18(GPIO24)番のピン)
$ mode2 -d /dev/lirc0
(リモコンを赤外線受信モジュールに向けて何かボタンを押す)
pulse 399512
space 3458
pulse 1739
space 416
pulse 454
space 412
pulse 1322
space 409
pulse 459
space 409
pulse 459
space 408
pulse 476
space 391
pulse 455
:
受信できていれば、上のように表示される。
赤外線パターンファイルの作成
まず、以下のコマンドでlircdが起動していないことを確認します。
$ sudo /etc/init.d/lirc stop
そして、以下のコマンドを打った後、リモコンを赤外線受光器に向けてボタンを押します。
$ mode2 -d /dev/lirc0 | tee AIRON
(エアコンをonにするボタンを押す → Ctrl+C)
$ mode2 -d /dev/lirc0 | tee AIROFF
(エアコンをoffにするボタンを押す → Ctrl+C)
次に、この赤外線パターンファイルから、赤外線送信ファイルを作ります。
以下のスクリプトを用いて、先ほどのパターンデータを整形します。
lines = File.open(ARGV[0]).readlines #行ごとに配列として読み込み
lines_without_first = lines.slice(1..-1) #先頭の行は不必要なので省く
puts lines_without_first.map{|line|line.split(" ")[1]}.join(" ") #整形して表示
$ ruby parse.rb AIROFF
3458 1739 416 454 412 1322 409 459 409 459 408 476 391 455 431 436 408 465 413 448 407 477 396 453 412 454 413 450 415 1322 409 457 414 455 410 456 411 457 411 455 410 460 411 451 412 1326 410.....
ここで表示された数字の羅列は、先ほどの赤外線パターンファイルの中身の数字部分のみを並べたものです。
また、数字の1番目だけは、リモコンのスイッチを押すまでの時間を表したもので不必要です。
この数字の羅列を用いて、/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 2015
#
# contributed by <% YOUR NAME %>
#
# brand: <% BRAND %>
# model no. of remote control: <% MODEL No. %>
# devices being controlled by this remote: <% DEVICE %>
#
begin remote
name aircon
flags RAW_CODES
eps 30
aeps 100
gap 200000
toggle_bit_mask 0x0
begin raw_codes
name off
3458 1739 416 454 412 1322 409 459 409 459 408 476 391 455 431 436 408
465 413 448 407 477 396 453 412 454 413 450 415 1322 409 457 414 455 410
456 411 457 411 455 410 460 411 451 412 1326 410 1320 411 1330 404 453
......
name on
3465 1733 417 452 414 1322 410 454 411 458 418 445 413 454 421 447 411 496
370 454 429 442 418 445 413 456 416 461 396 1327 408 457 413 454 414 452
412 457 416 449 412 454 412 456 411 1326 409 1325 408 1324 435 431 412 452
......
end raw_codes
end remote
数字の羅列の部分は先ほどのスクリプトで表示された数字の羅列を入れてください。(※1行があまりに長いとうまく動かないらしいので、80文字ごとを目安に改行を入れてください。)
また、<% ... %>で囲まれた部分は自分の情報を入れてください。
赤外線の送信
これで、赤外線送信用のファイルも完成しました。
それではついに赤外線を送信してみましょう!
普通のLEDを光らせたときと同じように回路を組みます。
ただし、先ほどの「GPIO2」とは違い、lircの出力端子である「GPIO25」のところにさすことを間違えないでください。
また、LEDも普通のLEDではなく、今回は赤外線LEDを使います。
lircdの起動
$ sudo /etc/init.d/lirc start
自動で起動したい場合は、update-rc.dで登録します。
$ sudo update-rc.d lirc defaults
リモコンとコマンドの確認
$ irsend LIST '' ''
irsend: aircon
$ irsend LIST aircon ''
irsend: 0000000000000001 off
irsend: 0000000000000002 on
上のように表示されていれば、コマンドは正しく登録されています。
それではついに送信です!
$ irsend SEND_ONCE aircon on
これまでの工程が全てうまくいっていれば、エアコンの電源がつくはずです!
(ただし、以外と赤外線LEDの強度は弱く、1mくらいの距離でしか反応しないかもしれません。)
また、LEDの指向性が強く、向きが正確でないと反応しません。そこで、購入しておいたLEDキャップを赤外線LEDにかぶせてやりましょう。これにより、向きが多少ずれていてもエアコンが反応するようになります。(もちろん赤外線の強度は落ちます。)
slackからのメッセージを受けて、エアコンをon, offする
さあいよいよ大詰めです。
slackからのPOSTリクエストを受けて、上記のirsendコマンドを実行するようにしましょう。
以下のように/var/www/index.phpを編集します。
<?php exec("irsend SEND_ONCE aircon off"); ?>
{"text":"エアコンを消しました!"}
この状態で、slackにメッセージを送ると、エアコンが消え、「エアコンを消しました!」というメッセージがslackに送られます。
ついにやりました!slackにメッセージを送ってエアコンを操作することができました!
後は、メッセージによって実行するコマンドを変えるように書くだけです。
slackのOutgoing WebHooksのTrigger Word(s)に「オン,オフ」と設定します。
そして、index.phpを以下のように編集。
<?php
if (preg_match('/オフ/', $_POST['text'])):
exec("irsend SEND_ONCE aircon off");
echo '{"text":"エアコンを消しました!"}';
elseif (preg_match('/オン/', $_POST['text'])):
exec("irsend SEND_ONCE aircon on");
echo '{"text":"エアコンをつけました!"}';
endif;
これにて完成です!
補足(セキュリティについて)
上記のスクリプトだと、Raspberry PiのIPアドレスを知っている人なら、誰でもエアコンを操作できてしまいます。
Outgoing WebHooksは認証用のtokenを含めた、色々なパラメータを送ってきてくれているので、それを用いて正しいアクセス以外をはじくようにするのがよいでしょう。
最終的な私のindex.phpは以下のようになりました。
<?php
#POSTリクエスト確認用
#ob_start();
#var_dump($_POST);
#$post = ob_get_contents();
#ob_end_clean();
#file_put_contents("/tmp/dump.txt", $post);
$data = array(
"off" => array(
"regex" => "/\Aオフ\z/u",
"operation" => "off",
"text" => ["エアコンのスイッチ切っといたわよ!べ、別にあんたのためじゃないんだからね!", "ほら、エアコン切っておいたわよ。家出る前にちゃんと確認しなさいよね!"]
),
"heater" => array(
"regex" => "/\A暖房オン\z/u",
"operation" => "24hot",
"text" => ["あんたが風邪引かないように、暖房入れておいたわ。感謝しなさい!", "早く帰ってきなさい、暖房入れて待ってるから...//"]
),
"cooler" => array(
"regex" => "/\A冷房オン\z/u",
"operation" => "25cool",
"text" => ["今日もあっついわねー、ほら、冷房かけといたわよ。", "クーラーかけとくわ。帰ってきたら一緒にアイスでも食べましょ!"]
)
);
?>
<?php if ($_POST["token"] != "<YOUR TOKEN>"): ?>
<h2>無効なトークンです</h2>
<?php elseif ($_POST["user_id"] == "USLACKBOT"): ?>
{"text":""}
<?php elseif ($_POST["user_id"] != "<YOUR USER ID>"): ?>
{"text":"この操作は⚪︎⚪︎にしか許されてないの。ゴメンね(>_<)"}
<?php else: ?>
<?php foreach ($data as $k => $v): ?>
<?php if (preg_match($v['regex'], $_POST['text'])): ?>
<?php exec("irsend SEND_ONCE sakai-air " . $v['operation'], $output, $return_var); ?>
<?php if ($return_var === 0): ?>
<?php $t = $v['text']; ?>
{"text":"<?php echo $t[array_rand($t)]; ?>"}
<?php else: ?>
{"text":"エラーが発生したみたい...確認お願いするわね。"}
<?php endif; ?>
<?php endif; ?>
<?php endforeach; ?>
<?php endif; ?>
このphpファイルでは、slackのtokenを認証しているので、slackからのアクセス以外は受け付けません。
また、メッセージを打ったユーザのIDも認証することで、私以外の社員からのメッセージでは、エアコンを操作できないようにしてあります。
補足(みことたんについて)
- 御坂美琴(とある科学の超電磁砲)
- 「このライトノベルがすごい!」女性キャラ部門5年連続1位
- とてもかっこいい
- とてもかわいい
「Outgoings WebHooks」のアバターや名前は、設定画面(Trigger Wordsとか指定した画面)から自由に変更できます。
まとめ
- slackのOutgoing WebHooksを用いてRaspberry PiにPOSTリクエストを送り、エンドポイントにあるphpスクリプトから赤外線送信コマンドを実行する。
- エアコンの赤外線パターンは赤外線受光器とlircを用いて丸暗記し、赤外線LEDから送信する。
- みことたんが反応してくれる。
以上です。
みなさんもよいRaspberry Piライフを!!