tsujimotterのノートブック

日曜数学者 tsujimotter の「趣味で数学」実践ノート

Amazon dash ボタンで馬場君に焼きそばパンを買いに行ってもらう

これは馬場君に焼きそばパンを買いに行ってもらうしかない。

そう思ったのでした。

経緯

amazon dash ボタンってありますよね。それがうちに届いたんです。

ボタンを押すと Amazon がダッシュして商品を届けてくれる。まさに Internet of Things (IoT) の世界がやってきたという感じがします。


さて、せっかくボタンが届いたんだから、ハックしたいですよね。

最近では amazon dash を単に「IoT ボタン」として使う技術が紹介されています。
qiita.com


「ボタンを何につなげたら面白いか」と考えたときに、私はこれを思い出しました。

Babascript

Babascript とは、馬場匠見さん橋本翔さんらが開発したプログラミング言語です。通常のプログラミングコードの中に、人間が処理を代行する「人力処理」を記述することができるというもので、人力処理のパートを「馬場君が」実行することから、Babascript の名称がつけられています。

WISS2014 でも発表されており、

「馬場君がすべてやってくれる」

の名言(迷言?)は爆笑を読んだのを覚えています(私もニコ生で見ていた)。原稿はこちら。

Babascript: 人とコンピュータの協調による処理実行環境 - WISS2014
https://www.wiss.org/WISS2014Proceedings/oral/039.pdf

「計算などコンピュータが得意な部分はコンピュータが担当し、創造的な部分は人間が担当すべき」という「人とコンピュータの共創の重要性」を訴える研究で、とても興味深いコンセプトだなと感心しておりました。

以下のページではコードも公開されていて、いつか使ってみたいと思っていました。
github.com


馬場君への指示はワンライナーで以下のようにかけます。

baba -e "焼きそばを買ってきてください"

作ってみた

というわけで、Babascript を amazon dash ボタンと連動させて、押すと馬場君が焼きそばパンを買ってくれるボタンを作ろう、というのが本記事の目的です。

一方で、残念ながら私は馬場君とは知り合いではありません。

見ず知らずの私が、突然馬場君に焼きそばパンを買いに行かせるわけにはいかないので 命令の指示は私宛に送るようにします。


で、できたのがこちら。



やっていることは簡単で、Dash Button for Node というモジュールを使って Amazon dash ボタンの押下イベントを待ち受けて、イベントが発生したら上記の Babascript ワンライナーを実行するだけです。

メイン部分は、以下のようなコードだけで実行できます。

// test.js
// sudo node test.js で実行

const DashButton = require("dash-button"); // モジュール読み込み

const PHY_ADDR = "xx:xx:xx:xx:xx:xx"; // ここでフィジカルアドレスを指定

let button = new DashButton(PHY_ADDR); // ボタンのアドレスを引数に渡してDashButtonクラスを呼び出し

console.log("I'm listening'") // 「がんばってます」を主張

/*
  以下が発火するイベントの指定部。
*/
button.addListener(() => {
   // ワンライナーコマンドを実行
   const exec = require('child_process').exec;
   exec('baba -e "焼きそばパンを買ってきてください"', (err, stdout, stderr) => {
      if (err) { console.log(err); }
      console.log(stdout);
   });

});

上記のコードは、以下のサイトで紹介されていたサンプルコードをほんの少しだけ変えたものです。
qiita.com

作り方

まず、amazon dash ボタンと Mac Book Air を連動する仕組みですが、以下の記事を参考にしました。
qiita.com
qiita.com


結構面白い事をやっているようです。

amazon dash ボタンは、通常は電源がオフになっています。ボタンが押下されると、電源が入り登録されている Wi-Fi を探しに行きます。Wi-Fi に繋ぐ際に、IP アドレスの重複を確認するために "ARP Probe" というパケットをブロードキャストしているとのこと。そのパケットを Mac 側でフックすればいいのですね。Mac側には node.js で書いたサーバを立てて、ARP パケットを待ち受けます。

amazon dash ボタンがネットワークに接続されると、HTTP リクエストがアマゾンに対して送られ、注文処理が行われます。このままではボタンを押すたびに購入されてしまいますが、回避する方法があります。

初期登録の最後に商品とボタンを紐付ける設定が行われますが、そこで×ボタンを押して設定を中断してしまうのです。「セットアップが完了していない」等の警告が出ますが無視してかまいません。

f:id:tsujimotter:20161209135439j:plain:w200

ここで気になるのが、一度設定を中断してしまった amazon dash ボタンはもう通常通り使えないのか、という点です。もちろん再設定することで使えるようになります(安心してハックできますね)。設定画面に「この Dash Button を無効にする」というボタンがあります。少し怖い表現ですが、このボタンを押すと使用可能なボタン一覧から削除されて、再度「新しい Dash Button をセットアップ」から設定可能になります。



続いて、dash button を検知する node サーバのセットアップをしましょう。私は Mac Book Air を使っているので、その環境に合わせた説明となります。

注意してほしいのは、Mac が接続するWi-Fiは dash button に初期設定した Wi-Fi と同じものに接続してください。(私は間違えて g と a が異なる SSID に接続してしまって、つながらないつながらないと焦りました。)

まず,node 6 をインストールします。古いバージョンだと対応していないようです。

Node.js

次にプロジェクトのディレクトリを作って、そこに Dash Buton for Node をインストールします。

$ mkdir node-button
$ cd node-button
$ npm init
$ npm install --save dash-button

上記のステップでエラーが出た人は,インストールされている Python のバージョンに気をつけてください。Pythonは 2 系列でないといけないようなのですが、私の mac には 3.5.11 が入っていてエラーが起きました。

バージョンの異なる Python を同居させて、使い分けたいときは、pyenv が便利です。
qiita.com
qiita.com

pyenv をインストールすると、元々入っていた Python は system として扱われるため、アンインストールの必要はありません。


Pypcap というモジュールも必要かもしれません。pip を使ってインストールしておきます。

pip install --upgrade pip
pip install pypcap


Dash Buton for Node がインストールできたら、package.json の "script" の箇所を以下のように書き換えます。

{
  "scripts": {
    "scan": "dash-button scan"
  }
}

このように変更することで、以下のコマンドで ARP scan が実行できます。

sudo npm run scan

sudo をつけるのを忘れないでください。

dash button を押してみてください。うまくいけば、数秒後(若干ラグがある)にボタンの MAC アドレスが表示されます。私のボタンは ac から始まる MAC アドレスでした。

この MAC アドレスを控えておいて、最初に紹介した test.js のコードに書き込みます。

sudo node test.js

を実行すると、プログラムが実行されボタンを待ち受けます。このコードでは、ボタンに反応して

baba -e "焼きそばパンを買ってきてください"

が実行されます。


Babascriptが動かない!!!

あとは、Babascript をインストールして連動させるだけですね。

インストールは簡単です。

gem install babascript

babascript といいつつ、中身は Ruby で書かれているみたいです。


ためしに,baba -e "テスト" と打ってみると、

$ baba -e "テスト"
テスト
dyld: lazy symbol binding failed: Symbol not found: _clock_gettime
  Referenced from: /Users/tsujijunpei/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/extensions/x86_64-darwin-15/2.2.0-static/eventmachine-1.2.1/rubyeventmachine.bundle (which was built for Mac OS X 10.12)
  Expected in: /usr/lib/libSystem.B.dylib

dyld: Symbol not found: _clock_gettime
  Referenced from: /Users/tsujijunpei/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/extensions/x86_64-darwin-15/2.2.0-static/eventmachine-1.2.1/rubyeventmachine.bundle (which was built for Mac OS X 10.12)
  Expected in: /usr/lib/libSystem.B.dylib

Trace/BPT trap: 5


なんだこのエラー・・・。

このあといろいろ調べてみたのですが、残念ながらうまくいかず。

* * *

仕方ないので、同じ作者の作った tw というツールを使ってお茶を濁すことにします。tw についての情報は以下のページに載っています。

橋本商会 » ターミナルで使うtwitterクライアント作った

インストールは簡単

gem install tw

"hoge" とツイートさせたいときは以下のコマンドでオーケー。便利です。

echo 'hoge' | tw --pipe


tw を実行するスクリプトを書いて baba と名前を付けておきます。

#! /bin/sh

echo "@tsujimotter 焼きそばを買ってきてください" | tw --pipe

そして実行権限をつけておく。

chmod 701 baba

さらに,/usr/local/bin に

ln -s /path/to/baba /usr/local/bin/baba

としてシンボリックリンクを貼っておきます。(/path/to のところには baba の置いてあるディレクトリを指定)

すると,

baba

とコマンドを実行するだけでツイートされます。

ツイッターの仕様上、同じツイートの連続投稿は無視されるようなので、ツイートの後ろに日付などをいれると良いかもしれません。


課題

パケットスキャンの安定性

動画ではさも一発で成功したかのように撮っていますが、これ、かなり安定しません。

何回押しても反応しない。たまにネットワークに繋げ直すと反応することがある。

Dash Button for Node では ARP のブロードキャストパケットを監視しているわけなのですが、キャッシュか何かが働いてしまってうまくキャッチできないのでしょうか。

とりあえず私は「Mac の Wi-Fi の接続先をいったん切り替えてから戻す」という、なんだかよくわからない解決法によってなんとか動かしています。

でもこれじゃあ焼きそばパンがほしいときに、ボタンを押す前にサーバーのネットワークを接続しなおさなければならない。何とかしたいところです。

Babascript との連動

まさかの Babascript が使えない、という非常に残念な結果となりました。

エラーの原因は Ruby のバージョンの問題なのか、はたまたインストール足りないものがあるのか・・・。原因を調べて解決したいです。

通知先のサーバーが落ちているという可能性もあって、問題は根深いかもしれません。


おわりに

Amazon dash ボタンが届いたので、勢いで書きました。いろいろうまくいかないことがありましたが触ってみて楽しかったです。

使ってみてわかったことですが、ハックするにはこのボタンは結構使い勝手が悪いですね。ボタンを押してから反応までのラグがありますし、ボタンを監視するためには何らかのサーバに相当するマシン(ラズベリーパイとか)を常時置かなければなりません。

既に Amazon では IoT ボタンとして Developer 向けのものが売っているみたいですね。日本ではまだ使えないみたいですが、これが使えるようになったら便利かもしれません。HTTPリクエストも直接送れるみたいですし。

AWS IoT ボタン - AWS IoT | AWS


せっかくなのでこの記事をおうちハックアドベントカレンダーに寄稿したいと思ったのですが、今年はもう埋まってしまったとのこと。残念。。。
qiita.com