RaspberryPiでスマートホーム 〜MQTTで指令を受ける〜

前回RaspberryPiとUSB赤外線リモコンアドバンスを使ってエアコンと照明をラズパイからコントロールできるようになりました。

ただ現状ではラズパイ上でコマンドを叩かないと操作できません。cronで決められた時間に決められた操作をするだけならそれでもいいんですけど、自分で好きな時に好きな操作をするには不便です。

そこでよそから指令を投げてその指令を実行するようにします。

MQTT

まずはラズパイが指示を受けられる体制を整えようと思います。その指示のやりとりにはMQTTを使うことにしました。

MQTTとは…

要はコンピューター同士がコミュニケーションするための仕組みだそうです。メッセージを中継してくれるブローカー(サーバー)に接続してどのトピック(チャンネルのようなもの)に送信するのか(パブリッシュ)、どのトピックから受信するのか(サブスクライブ)、をブローカーに伝えます。

このMQTTを使う場合どこかにメッセージを中継してくれるブローカーが必要です。家の中だけならラズパイにそのブローカーの役割をやらせてもいいんですが、せっかくなら外からも操作できると便利です。

AWS IoT

なのでAmazonのAWSを使うことにしました。

AWSのサービスの中にAWS IoTというのがあり、これがMQTTのブローカーとしてメッセージの中継をしてくれます。

AWSを使うにはあらかじめアカウントを作成しておく必要があります。アカウント作成の説明は省略しますが、アカウント作成してIAMでユーザー作成して…といったお決まりの約束をあらかじめ済ましておきます。

AWS IoTは有料でメッセージ件数で課金されます。でもアカウント作成後1年間は毎月25万件のメッセージまでは無料枠で使えます。無料枠がなくなっても100万件のメッセージで$8ですので1$=115円で計算すると月に1万件で9.2円、そんなにエアコンつけたり消したりしないので個人的には問題なし、ということでAWSにしました。

インターネット上には無料のMQTTブローカーもあるようなのでAWSが嫌ならそれらを使ってもいいと思います。

ラズパイを登録

AWSにログインしたらAWS IoTのページに行き、ラズパイを登録します。

ポリシーを作成

まず、このラズパイはAWS上で何をすることが許可されているのか、を指定するポリシーを作成します。

画面見にくいですが

  • 名前→RaspberryPiPolicy
  • アクション→iot:*
  • リソースARN→*

と入力しています。

安直にiot関係は全て操作できるように指定しています。名前は何でも構いません。

ラズパイを登録

次にラズパイを登録します。

名前を入力します。何でも構いませんがここでは”RaspberryPi”としています。

次に証明書を作成します。何を証明するのかというと、この証明書をラズパイ側に置くことで、AWSに対してこれは確かに私が登録したラズパイですということを証明します。

前回作業したのと同じディレクトリで今回も作業するので、そこにこれら作成した証明書、プライベートキー、パブリックキー、あとルートCAをダウンロードしてコピーしておきます。それぞれ

  • ルートCA…VeriSign.pem
  • 証明書…certificate.pem.crt
  • プライベートキー…private.key
  • パブリックキー…public.key

という名前で保存しました。

そして忘れずに”有効化”して”ポリシーのアタッチ”に進みます。

最後に先ほど作成したポリシーをアタッチして登録完了です。

接続する

次にブローカーに接続してサブスクライブするスクリプトを作成します。Pythonで作成しました。

AWSに接続して繋がったら”homeapp/to”というトピックをサブクライブするスクリプトです。私は”homeapp.py”という名前で作成しました。

トピック名ですがラズパイを基点に”homeapp/to”はラズパイへの送信、”homeapp/from”はラズパイからの送信に使おうと思ってます。今回は”homeapp/from”は使いませんけど。

(endpoint)はAWSで自分のendpointを確認してそれに置き換えます。

paho mqttというコンポーネントを使用していますので実行する前に

pip install paho

等であらかじめインストールしておきます。

python homeapp.py

で実行します。スクリプトの最後で”loop_forever()”してるのでプロンプトには帰ってきません。ずっと受信し続けます。

MQTTでJSONのメッセージを受信したら各パラメータを取り出し、前回作成したir.shコマンドを呼び出してリモコンを操作します。

テスト

AWSのサイト上のテスト用のページからMQTTのトピックに接続してテストします。

topicには”homeapp/to”、JSONは以下のように入力して”トピックに発行”を押します。

ライトが付きました!

これでMQTTを使って指示を待ち受ける準備ができました。JSON形式の指示をMQTTで送信することができればどのデバイスからも部屋の電気やエアコンを操作できるようになりました。

実運用のためには

このスクリプトが起動し続けてないと当然受信できませんので

nohup python homeapp.py &

等でバックグラウンドで動かし続けておく必要があります。

デーモン化しておくとよりよいかと思います。”python スクリプト デーモン化”で検索すると参考になるページが引っかかります。

エラー処理してないのでメッセージが予期した内容と違うと落ちます。必要ならtryで補足して無視する、ログを吐く、等行ってください。前述のnohupコマンドで起動した場合は出力が同じディレクトリのnohup.outというテキストに書き込まれるので例えばMQTT受信時にでもログとしてprint()してやってもいいと思います。

あとMQTTにはQoSで品質が定められています。

  • QoS0…とりあえず1回投げる。届こうが届くまいが知らない。
  • QoS1…最低1回は届く。2回以上届くかもしれない。
  • QoS2…確実に1回届ける。

AWS IoTはQoS0,1なので同じメッセージが何回か来る可能性があります。つまり同じメッセージが2回くると2回実行されてしまいます。JSONにシリアル番号などを付加しておいて既に実行した番号なら無視する、といった処理も場合によっては必要かもしれません。

送信はどうする?

受信はできるようになりました。でも毎回AWSのテストツールからJSONで指示を組み立てて送信するのも面倒なので、次は送信側を作らないといけないですね。PCやスマホ等いろいろなものから送信できると便利です。

どうやらJavascriptでMQTTのメッセージが送れるようです。HtmlとJavaScriptならブラウザされあればどの端末からでも送信できて便利そうですね。ちょっとそちらを検討してみます。

追記:
作りました。