RaspberryPiでも消臭力してみた
毎回、ダメなパターンのエントリですが、今回はそれに輪をかけて駄目なタイトルになっています。
最近、Amazon Dash Buttonを使ってみたくなったので購入を考えていました。ただ、本体にくっついているデザイン面が日用品ばかりで今ひとつ気が乗らず、購入までには至りませんでいた。この時点で正当な使い方は考えておらず、ネット情報でAmazon Dash Buttonを押してWebHookを行ったりできるネタがあったので、自分でもぜひやってみようと思っていました。
あとでネットの情報を読んでいてわかったこととしては、構造それなりなのに500円と安価で、少し溜まったAmazonポイントで購入できるのもいいなと思っています。実質はものを買えば500円割引になるので、そっちのほうがオトクなんですけど。
中身の詳しい内容は以下が詳しかったです。
1週間ほど考えて、やっと購入するものを決定しました。
ムーニーと迷っての購入です。決しておむつプレイが好きなわけではないのであしからず。
ネット情報ではDasherというnode.jsのモジュールを使っている情報が多かったのですが、これは以下のnode-dash-buttonの処理をWebhookに特化したラッパーのようですので、自分はRaspberryPiのコマンドなどを実行したかったので、オリジナルのものを使うことにしました。
IFFTとかSlackへなにかを行うのであればDasherのほうが便利です。
node-dash-buttonをインストールする
上記のリンクからreadme.mdのInstallation Instructions節で方法が書かれています。
# dependancy on libpcap for reading packets
$ sudo apt-get install libpcap-dev
$ npm install node-dash-button
これでいいようです。…が。
自分の環境では少し気になっていることがありました。そもそもnode.jsはデフォルトのRasbianではバージョンが古いため、nvmをインストールすることでバージョンを上げていました。デフォルトのバージョンではnode-dash-button
は動作しないようです。
ユーザからはこれで問題はありません。
しかし、インストール時に使用しているlibpcap-dev
は、管理者権限でないとこれを使用したプログラムは動作しません。(sudo
をつける必要があるということです。)sudoで呼び出されるnode.jsはnvmでインストールしたバージョンのものは適応されず、デフォルトのものが呼び出されてしまいます。(pathなどの環境が異なるので致し方ないのですが)
そこで、根本的にはバージョンアップをすることにしました。 Dasherのreadme.mdに
note Raspberry Pi users may need to update node arm which will automatically remove nodejs-legacy. Credit @legotheboss
なる記載があり以下のコマンドでnodeを比較的新しいバージョンに変更できます。
$ wget http://node-arm.herokuapp.com/node_latest_armhf.deb $ sudo dpkg -i node_latest_armhf.deb $ $ node -v v4.2.1
これで、比較的新しいnode.jsが準備でき(node.jsは2017/02/18現在v6.9.5まで来ているようですので気休めなのかもしれませんが、デフォルトのバージョンよりはいいと思います)、node-dash-buttonの利用ができるようになりました。 あとはnode-dash-buttonをインストールする処理を行うことになります。
$ sudo apt-get install libpcap-dev $ npm install node-dash-button
これでOKです。
DashButtonの設定を行う
以下のページのボタンセットアップ節を見てください。このページが分かりやすかったと思います。
具体的には、Dash ButtonのWi-Fi設定を行った後に、ボタン押下時に注文する商品を選択する画面でキャンセルしましょう。(商品との紐付けをしないようにする点) 商品と紐付けさえ行わなければ基本的には注文はされません。(buttonを押すとエラーが発生し、白色のLEDの点滅後に赤いLEDが点灯します。)
後はnode-dash-button
の設定と実行になります。
node-dash-button
の設定
node-dash-buttonはarpパケットを受け取ってその中にあるMACアドレスを判別して処理を行うので、入手したDashButtonが通信するときに使うMACアドレスを取得する必要があります。node-dash-button
にはそのMACアドレスを取得するプログラムも含まれています。(Dasherモジュールにもこのプログラムが含まれています。)
$ cd node_modules/node-dash-button $ sudo node .bin/findbutton Watching for arp & udp requests on your local network, please try to press your dash now Dash buttons should appear as manufactured by 'Amazon Technologies Inc.' Possible dash hardware address detected: XX:XX:XX:XX:XX:XX Manufacturer: Amazon Technologies Inc. Protocol: udp Possible dash hardware address detected: XX:XX:XX:XX:XX:XX Manufacturer: Amazon Technologies Inc. Protocol: arp
実行後にボタンを押してください。Amazon Technologies Inc.のベンダネームとしてXX:XX:XX:XX:XX:XX
というような形でMACアドレスが取得されます。(MACアドレスは伏せ字にしていますので、適宜読み替えてください。)
このMACアドレスをトリガーにして処理を実行するすることになります。
node-dash-button
の実行
node-dasu-button
モジュールをインストールしたディレクトリで以下のようなスクリプトを作成します。
var dash_button = require('node-dash-button'); var dash = dash_button("XX:XX:XX:XX:XX:XX", null, null, 'all'); //address from step above dash.on("detected", function (){ console.log("omg found"); });
MACアドレスの入ったarpパケットを検出するとdetected
イベントを検出して処理を実行します。このスクリプトの場合にはconsole.log("omg found");
の処理が実行されます。この処理を別のものにすることで、buttonを押すと色々な処理が行える様になります。
node-dash-button
で検出した際にコマンドを実行する
node.jsからシェルコマンドを実行する方法としては以下を参考にしました。
sudo環境での実行なのでpathが心配だったのですが、特に問題はなかったみたいです。
例えば実行するディレクトリのファイルを取得するls
コマンドを実行するには以下のように記述します。
const execSync = require('child_process').execSync; const result = execSync('ls -la ./').toString(); console.log(result);
node.jsは非同期実行なので同期的な実行にしたほうがわかりやすくなるかなとは思いますのでこちらを使用しました。
スクリプト名をnode dash-button_shell.js
した場合
const dash_button = require('node-dash-button'); const execSync = require('child_process').execSync; var dash = dash_button("XX:XX:XX:XX:XX:XX", null, null, 'all'); //address from step above dash.on("detected", function (){ var result = execSync('ls -la ./').toString(); console.log(result); });
このようになります。これを実行すると
$ sudo node dash-button_shell.js omg found 合計 656 drwxr-xr-x 3 pi pi 4096 2月 15 09:40 . drwxr-xr-x 45 pi pi 4096 2月 20 23:33 .. -rw-r--r-- 1 pi pi 204 2月 15 01:10 dash-button.js -rw-r--r-- 1 pi pi 341 2月 15 09:40 dash-button_play.js -rw-r--r-- 1 pi pi 336 2月 15 09:23 dash-button_shell.js -rw-r--r-- 1 pi pi 348 2月 15 09:32 dash-button_talk.js -rwxr--r-- 1 pi pi 503 2月 15 09:27 jtalk.sh drwxr-xr-x 4 pi pi 4096 2月 15 01:05 node_modules -rwxr--r-- 1 pi pi 635436 2月 8 23:00 riki.wav
うまくカレントディレクトリのファイル一覧を取得できています。気にしていた実行pathの問題も問題はなさそうです。
node-dash-button
でボタンを押したら【消臭力】の音声ファイルを鳴らす。
音声を鳴らすコマンドはaplay
で行えるので今回は慣らしたい音声ファイルriki.wav
として鳴らしてみます。
const dash_button = require('node-dash-button'); const execSync = require('child_process').execSync; var dash = dash_button("XX:XX:XX:XX:XX:XX", null, null, 'all'); dash.on("detected", function (){ var result = execSync('aplay riki.wav').toString(); });
これでOKです! 「しょ~しゅ~りき~♪」どこでもミゲルくんが歌ってくれる・・・素敵です!
node-dash-button
で検出した際に音声合成で言葉を話す
以前、Open JTalkを使いましたので、今回もそこで作成したshを使用することにします。
今回使用するシェルスクリプトは以下のようなものです。(ファイル名はjtalk.sh
)
#!/bin/bash #HTSVOICE=/usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice HTSVOICE=/usr/share/hts-voice/mei/mei_normal.htsvoice voice=`tempfile` option="-m $HTSVOICE \ -s 16000 \ -p 100 \ -a 0.03 \ -u 0.0 \ -jm 1.0 \ -jf 1.0 \ -x /var/lib/mecab/dic/open-jtalk/naist-jdic \ -ow $voice" if [ -z "$1" ] ; then open_jtalk $option else if [ -f "$1" ] ; then open_jtalk $option $1 else echo "$1" | open_jtalk $option fi fi aplay -q $voice rm $voice
node.jsからこのスクリプトを呼び出すことになるので以下のようなスクリプトを記述します。
const dash_button = require('node-dash-button'); const execSync = require('child_process').execSync; var dash = dash_button("XX:XX:XX:XX:XX:XX", null, null, 'all'); dash.on("detected", function (){ console.log("omg found"); var result = execSync('./jtalk.sh \'こんにちは\''); });
ボタン一つで話したい音声が話せます。す・て・き(うっとり)
蛇足
今回はnode.jsを使用していましたが、通信時のarpパケットさえ捉えられればよいのでtcpdumpでも同様の処理を行えます。というか両者ともlibpcapを使っているのであれば同様なことが可能です。
まずは、libpcapを使用するtcpdumpをインストールします。
$ sudo apt-get install tcpdump
インストールが終わったら以下のようなスクリプトを作成します。
ファイル名はbutton.sh
としました。
#!/bin/bash tcpdump -i wlan0 -e | while read line do if [[ $line = *XX:XX:XX:XX:XX:XX*ethertype\ ARP* ]]; then echo "button pressed" fi done
XX:XX:XX:XX:XX:XX
はDashボタンのMACアドレスを設定してください。
このシェルスクリプトは指定されたMACアドレスのパケットを受信したら標準出力にbutton pressed
という表示を行うものになります。
実行は以下のように行います。(ファイルの編集が終わったらchmodで実行権限を与えてください。)
$ sudo ./button.sh tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes button pressed ^C74 packets captured 75 packets received by filter 0 packets dropped by kernel
(Ctrl-Cで処理を中断していますので一回となっていますが、基本は無限ループになります。)
おわりに
無事に同一のWi-Fiエリアであれば、ミゲルくんが歌ってくれる素敵な家になりました。それにしても、Amazon Dash Buttonはこんな価格で出してもいいもんなんでしょうか?
難点を上げるとしては、ボタンを押してからARPパケットの送出するまでの反応が遅いかなと思います。まあ、値段からみれば十分問題のない範囲ですけどね。
あとで動画を追加する予定です。