Google HomeとRaspberry PiのNode-REDで赤外線リモコンのコントロールをする

Flow
赤外線学習リモコンADRSIRで遊んでいます。Raspberry Pi用のリモコンです。
今回はGoogle Homeの音声コマンドで赤外線コードを送信しスマートホームごっこをしてみます。検索すると多くの例がありますので、この記事ではNode-REDを使って差別化してみます。


前回まででRaspberry Piの赤外線リモコン ADRSIRを動かす事ができるようになりました。
関連記事:
Raspberry Pi用赤外線学習リモコン基板「ADRSIR」を動かしてみる
ADRSIRのコマンドラインツール IR-remocon02-commandline.pyを使ってみる

これでGoogle Homeから赤外線リモコンを動かし家にある家電をコントロールする準備ができました。スマートホームもどきを試してみます。



Google Homeを使った赤外線リモート制御の方法は既に多くの方が紹介してくれています。
音声からリモコンまでの経路は、
【Google Home】→【IFTTT】→【自宅サーバ】→【Raspberry Pi】→【赤外線リモコン】
というのがお手軽なようです。
説明は他のサイト様にたくさんあるようなので省いてしまいます。
IFTTTのWebhooksというサービスを使うと自宅サーバーへ簡単にリクエストを送る事ができるのが肝です。

ここの自宅サーバーにあたる部分をどうやって作るかが一番の問題となります。せっかくRaspberry Piを使うので自宅サーバーの部分もRaspberry Piに任せたいです。
Raspberry PiにGoogle Assistantをインストールして動かす記事も見かけます。Google Assistantも面白そうですがGoogle Homeがあるので同じようなものを動かす気にはなりません。SDカードの容量も使いそうだし。
同じことをやっても記事の価値が出ないのであまり見かけない方法を試してみます。

最新のRaspbianには最初からNode-REDが入っています。という事はNode.jsが簡単に使える環境が出来上がっている事になります。
Node.jsでは簡単にWEBアプリケーション作ることができますが、Node-REDはGUI画面でノード間のデータの流れを作る事ができさらに簡単になります。それにNode-REDが動いている時点でWEBサーバーが動いているのです。

このNode-REDを使ってIFTTTからリクエストを受けて赤外線リモコンを動かしてみます。Node-REDなんてADRSIRを買ってサンプルプログラムを見るまで知らなかったのですが…
日曜日を丸一日使って何となく動くものができたので紹介してみます。

Node-REDをRaspberry Piで動かす

最初にNode-REDを動かさないと話が進みません。そもそもNode-REDって何?という状態から始めました。
Raspberry Piを最新のRaspbianで動かします。
メニュー→プログラミング→Node-RED で動かします。
Node-REDの起動

動かすとターミナル画面が出ます。それだけです。GUI画面がでるのか?と待ち構えていると肩透かしです。表示されたターミナル画面を良く見ると何やらURLが表示されているのに気づくでしょう。Node-REDはブラウザで動くのです。

ブラウザで"http://127.0.0.1:1880/"を開くと画面が表示されます。Raspberry Piをネットにつないでいるならパソコンのブラウザでも開く事ができます。というかつないで下さい。話が進みません。
パソコンからなら"http://ラズパイのIPアドレス:1880/"を開きます。
こんな画面が表示されるでしょう。
Node-RED画面

ブラウザで開けるという事は既にWEBサーバが動いています。編集用のURLを表示している事になります。
そして、この画面でWEBサービスを作るとサブフォルダの名前を設定できます。例えば静的なHTMLページをtestというサブフォルダで作ると"http://ラズパイのIPアドレス:1880/test"で表示できます。
さらっと書いてますがこの事がわかるまでに3時間かかってますから! Linux文化圏は肝心なことがどこにも書いてない! いや書いてあるんでしょうが誰も説明してくれない。

Node-REDは少し変わったプログラム言語です。データドリブン型言語でしょうか。
マルチメディア関係のプログラムを知っている方ならばグラフを作るのと同じような感じです。
データが来たら処理が始まりデータが流れていきます。データが来たノードの処理が実行されます。処理は基本的にデータの加工になります。

Node-REDでPOSTを処理する

IFTTTのWebhooksサービスでは外部のサーバーへPOSTでデータを送る事ができます。Google Homeが認識した音声コマンドに対応するデータをPOSTで自宅サーバへ送ってもらえば、後は赤外線リモコンを光らせるだけです。

Node-REDでPOSTされたデータの流れ(flow)を作っていきます。
http入力ノードを配置してメソッドをPOSTにしPOSTを受けられるようにします。URLは"/ifttt"とします。IFTTTのWebhooksサービスから"http://自宅のIPアドレス:1880/ifttt"へjsonデータをポストすると、http入力ノードのflowにjsonデータが入ります。

Webhooksサービスからのjsonデータをどのようにするかを考えます。
Google Homeへの命令と赤外線リモコンの送信コードは1対1に対応するでしょう。赤外線コードはADRSIRの IR-remocon02-commandline.pyを使って送信します。赤外線コードを引数にするのですが赤外線コード文字列は長いので赤外線コードはファイルに保存しておきます。一つのファイルに一つの赤外線コードを入れておきます。Webhooksサービスからはファイル名を送ってもらうのが楽そうです。
そこでjsonデータは次の様にします。
{"FileName":"ファイル名"}

赤外線コード送信用スクリプト

IR-remocon02-commandline.py をexecノードを使って動かし赤外線を光らせます。execノードでPythonを動かすとデバッグが大変だったのでシェルスクリプトをかませました。
ADRSIR関連のファイルは"/home/pi/Downloads/ADRSIR"に置いてあるとします。
”File2IR.sh”という名前でファイルを作り次のコードを入れ実行許可を付与してください。
#! /bin/bash

IRPATH=/home/pi/Downloads/ADRSIR
cd $IRPATH
CODEFILE=`basename $1`
CODEFULLPATH=$IRPATH/IRCODEs/$CODEFILE

if [ -e $CODEFULLPATH ]; then
  echo --$CODEFILE--
  python IR-remocon02-commandline.py t `head -n 1 $CODEFULLPATH`
else
  echo $CODEFILE :file not found. >&2
  exit 1
fi

exit 0
少し説明します。
File2IR.shは引数にファイル名を一つ与えて動かします。赤外線コードの書かれたテキストファイル名を指定してください。
IR-remocon02-commandline.pyは赤外線コードそのものを引数に与えます。少し不便なのでファイル名で動くようにしています。catでファイルを展開して引数にしています。改行を含むとcatでは引数にならないのでheadで1行目だけを表示します。
webからデータを受けるのでどんなファイルでも開いてしまうのは危険です。そこで"/home/pi/Downloads/ADRSIR/IRCODEs"フォルダにあるファイルだけに制限しています。赤外線コードを書いたファイルは"/home/pi/Downloads/ADRSIR/IRCODEs"に置いてください。

Node-REDのexecノードではflowデータを引数にして"File2IR.sh"を実行します。

複数行に赤外線コードがあると連続して赤外線コードを送るように改造するとより便利かもしれません。
関連記事:Raspberry Piの赤外線リモコンADRSIRで連続して赤外線コードを送信するシェルスクリプトを作りました

msg.payloadの加工

POSTされたjsonデータはmsg.payloadに入っています。
これをexecノードの引数で使おうとしていたのですがうまく動きませんでした。json形式のまま引数になってしまうようでした。
そこで、事前に文字列に変換します。functionノードでFileNameを文字列に変換します。
msg.payload = msg.payload.FileName.toString();
return msg;

Flow

以上のFlowを作りました。
IFTTT POST FLow

[{"id":"8adf7a49.d847f8","type":"http in","z":"a1d272a5.22364","name":"","url":"/ifttt","method":"post","upload":false,"swaggerDoc":"","x":80,"y":40,"wires":[["5f94b553.42f60c","fedcbab2.0bc228","4624c35.518a03c"]]},{"id":"5f94b553.42f60c","type":"http response","z":"a1d272a5.22364","name":"","statusCode":"","headers":{},"x":290,"y":40,"wires":[]},{"id":"6d832cdc.22a8e4","type":"exec","z":"a1d272a5.22364","command":"/home/pi/Downloads/ADRSIR/File2IR.sh","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":320,"y":220,"wires":[["d9bc477c.34b388"],["d9bc477c.34b388"],["d9bc477c.34b388"]]},{"id":"d9bc477c.34b388","type":"debug","z":"a1d272a5.22364","name":"","active":true,"console":"false","complete":"false","x":570,"y":220,"wires":[]},{"id":"fedcbab2.0bc228","type":"debug","z":"a1d272a5.22364","name":"","active":true,"console":"false","complete":"false","x":310,"y":80,"wires":[]},{"id":"4624c35.518a03c","type":"function","z":"a1d272a5.22364","name":"FileName as String","func":"\nmsg.payload = msg.payload.FileName.toString();\nreturn msg;","outputs":1,"noerr":0,"x":150,"y":120,"wires":[["6d832cdc.22a8e4"]]}]
上のテキストをコピーして、Node-REDの"読み込み"→"クリップボード"で読み込んでください。

デプロイ

FlowができたらNode-REDの画面で”デプロイ”をクリックすると公開されます。公開すると"http://ラズパイのIPアドレス:1880/ifttt"というURLへPOSTする事ができます。このURLをブラウザで開いてもGETメソッドを作っていないのでエラーが表示されるでしょう。

Raspberry Piの公開

ローカルネットワークのままではIFTTTから使う事ができません。Raspberry PiをWANへ公開しなくてはなりません。

パスワードの設定

公開する前に必ずやっておく事が一つあります。それはNode-REDの編集画面にパスワードを設定する事です。ブラウザでNode-REDのFlowを編集していました。このままWANへ公開すると誰でもFlowを編集できる事になります。

次のページを参考にパスワードを設定してください。
https://nodered.jp/docs/security Node-RED User Group Japan

パスワードをbcryptでハッシュ化するのですがRaspberry Piにbcryptを入れる事ができませんでした。どうするんだろう? あきらめて他のパソコンでやりました。
【2018/01/27追記 ハッシュ化できました
関連記事:一番初めにRaspberry PiでNode-REDを使うときにやっておくこと 】

パスワードをかけたらWANへ公開します。

WANへの公開

公開方法をここでは説明できません。環境により千差万別です。
我が家ではルータにダイナミックDNS機能があるのでアドレスはそれを使っています。
ルータのポートフォワーディングを使い、例えば外部からポート80へリクエストがあったらRaspberry Piのポート1880へ転送する設定をします。

IFTTTでアプレットを作る

後はIFTTTでアプレットを作るだけです。IFTTTのアカウントの作り方などは他のサイト様にお任せですので説明いたしません。
Google AssistantサービスでトリガしWebhooksサービスでデータを送る方法になります。
トリガの設定は他のサイトで紹介されている方法と同じですのでここでは説明しません。Webhooksサービスの部分だけを説明します。

特定の文句を認識したらWebhooksサービスで文句に対応した赤外線コードの入ったファイル名をPOSTすれば良いのです。
Webhooks設定
URLには
"http://自宅ラズパイの公開IPアドレス:公開ポート番号/ifttt"
を設定します。
メソッドはPOST、Content Typeはjsonを選びます。
Bodyには
{"FileName":"ファイル名"}
と書きます。ファイル名は赤外線コードのファイル名に置き換えてください。例えばテレビの電源を入れる赤外線コードを入れたファイルに"TV-ON.dat"と名前を付けて"/home/pi/Downloads/ADRSIR/IRCODEs"フォルダに保存します。{"FileName":"TV-ON.dat"}とすればTV-ON.datの赤外線コードが送信されます。

後は他の赤外線コードに対応するアプレットを複数つくりそれぞれファイル名だけを変えればいくつでも赤外線コードを送信できます。
リモコンの種類を増やしてもNode-REDのFlowを変更する必要はありません。アプレットと赤外線コードのファイルを作るだけで対応できます。

まとめ

Node-REDの使い方がわからず動かすのに丸一日かかってしまいました。
これでやっとGoogle Homeで家のテレビやエアコンをコントロールする事ができるようになりました。

実際に音声で家電を操作しようとしないですよね・・・登録した文句を忘れて”お役に立てそうにありません”ばかり言われるし、コントロールするものを増やすとフレーズを忘れるし、フレーズを考えるのも一苦労です。

Node-REDでPOSTを受ける例を見かけないので試してみました。平文でファイル名を送るのがセキュリティ的に気になります。httpsにしたいですね。execノードは使い方によってはとても危険そうです。

音声で家電を動かそうと思うと失望してしまいますがIoTのお勉強だと思うととても良い題材です。おかげでNode-REDでWEBサービスを作る方法がわかりました。IFTTTと組み合わせればいろいろなサービスを簡単に使えます。
赤外線コードのファイルが無いなどデバッグ情報をGoogle Homeでしゃべらせるなんて事も簡単にできそうです。

関連記事:
Node-REDでGoogle Homeにテキストをしゃべらせる


コメント

最近のコメント

Threaded Recent Comments will be here.