Amazon Dash Buttonを押すと、LINEに通知されるようにする


## 更新履歴
@Tomonobu3110さんからの温かいご指摘があり、**LINE Notifyを使った通知方法**を最後に載せました。
また、**『LINEに通知させるプログラム』内の ``` amazon.js ```において、一部記述ミスがあったため、訂正しました。**

## はじめに
いろいろとAmazon Dash Buttonに関する記事を見ていて、LINEに通知させることはできないかなという、しょうもない考えを一生懸命記なるべく分かり易く記事に書き起こしました。
なので、間違っていることが多くあるかも知れません。
何かマズいことがあれば、是非教えてください。
（特にNode.js、初めて触りました）


## LINEのPush APIについて
今回はLINEのMessaging APIのPush APIを使用します。
本当は、Push APIは有料なのですが、どうやら開発用のアカウントであれば、友達の上限が50人という条件でPush APIを利用できるみたいです。
なので、今回はこの開発者用のアカウント（Developer Trial）を使います。


## Developer Trialに登録する
登録方法の詳細はqiitaに投稿されている先人の知恵を借りてください。

以下では、登録が完了し、

- Channel Access Token

が表示されているとします。


## Node.jsのセットアップ
今回使用するAmazon Dash Buttonは、Wi-Fiの設定を行う際にARPを送信する仕様となっているようなので、Amazon Dash Buttonを接続するLAN内にサーバを立てて、ARPの監視を行うことによりMACアドレスを取得します。
また、Amazon Dash Buttonを押した際の処理もNode.jsに処理させます。
というわけで、いまものすごく流行りの（自分の他の記事で扱っている）RaspberryPi3でサーバを立てます。
RaspberryPi3のセットアップも先人の知恵を借りてください。
以下では、Node.jsをインストールするところから説明します。
（雑でごめんなんさい）

MACアドレスを検出する際に用いるライブラリ？が必要とするNode.jsのバージョンが6以降なので、nvmをインストールし、そこからバージョン6以上のNode.jsを導入します。

```js:nvmのインストール
$ git clone https://github.com/creationix/nvm.git ~/.nvm
```

```js:バージョンの確認
$ nvm --version
0.31.0
``` 

nvmで利用できるすべてのNode.jsのバージョンを確認します。


```js:Node.jsのバージョン確認
$ nvm ls-remote
    v0.1.14
        ...
        ...
    v7.2.1
```

今回はv7.2.1をインストールします。


```js:v7.2.1のインストール
$ nvm install v7.2.1
```

```js:バージョン確認
$ node -v
v7.2.1
```

と表示されればOKです。
npmは

```js:npmのインストール
$ sudo apt-get install npm
```

でインストールしてください。

```js:バージョン確認
$ npm -v
v3.10.10
```


## dash-buttonの導入
次に以下のページを参考にdash-buttonをnpmでインストールします。

[dash-button](https://www.npmjs.com/package/dash-button)

依存ライブラリのインストール

```js:依存ライブラリのインストール
$ sudo apt-get install libpcap-dev
```

```js:dash-buttonの導入
$ sudo npm install --save dash-button
```

以上の手順が終われば、適当にフォルダを作り以下を実行します。

```js
$ sudo mkdir app
$ cd app
$ sudo npm init
```

initではすべてEnterキーの連打でもOKです。
そして、先ほど初期化したpackage.jsonのファイルを編集します。

```js:package.jsonの編集
{
    "scripts": {
        "scan": "dash-button scan"
    }
}
```

そして、dash-buttonのスクリプトを実行します。

```js:dash-buttonの実行
$ sudo npm run scan
```

これで、Amazon Dash ButtonのMACアドレスが取得できます。
起動している間に次の設定を行います。

## Amazon Dash Buttonの設定
ここでは、Androidの場合のみ簡単に書きます。
まず、Google Play Storeから「Amazonショッピングアプリ」をダウンロードします。
ダウンロードが完了すれば、アプリを起動し、プライム会員のアカウントでログインします。
アプリの左上のメニューアイコンをタップし、「アカウントサービス」をタップします。
タップして、下の方へスクロールしていき、「Dash端末」=>「端末を管理」=>「新しいDash Buttonをセットアップ」をタップしてセットアップを開始します。
おそらく、注文する商品を追加するところで、以下のようにMACアドレスが表示されたら、セットアップを中止します。

```js:sh-button
Scanning for DHCP requests and ARP probes on eth0...
Detected a DHCP requests or ARP probes from xx:xx:xx:xx:xx:xx
Detected a DHCP requests or ARP probes from xx:xx:xx:xx:xx:xx
```

**特に商品を選択する前にセットアップをキャンセルしてください**

以降、このMACアドレスを用います。
これで、Dash Buttonの設定は終わりです。


## LINEに通知するプログラム
この記事では、Buttonの監視はNode.jsで行い、JSONデータのPOSTにはlaravel5を用いて、それぞれの処理を切り分けています。
おそらく、このNode.jsから直接LINEのエンドポイントにjsonをPOSTすればいいと思いますが、今回の構成は別サーバでLaravel5を走らせてAPIサービスを提供していたので、そのアドレス（例：https://xx.exsample.com/v1/abc/amazon ）にGETでアクセスすれば、LINEのエンドポイントにjsonが投げられ、その通知がLINEに来るようにしました。

```js:config.json
{
    "mac_address": "xx:xx:xx:xx:xx:xx"
}
```

```js:amazon.js
'use structs';

var request = require("request");
url = 'https://xx.exsample.com/v1/abc/amazon';
const config = require("./config.json");
const DashButton = require("dash-button");

//button constructor
let button = new DashButton(config.mac_address);

console.log("stand by...");

//button push listener
button.addListener(() => {
  request(url, function (error, response, body) {
  if (!error && response.statusCode == 200) {
    console.log(response.body);
  } else {
    console.log('error: '+ response.statusCode);
  }
  });
});
```

ログで "{}" が返ってくると正常に動作しています。
あと、RaspberryPi3でローカルなサーバにドメイン名でアクセスするには、ご存じかと思いますが、

```js:nano
$ sudo nano /etc/hosts
```

で

```js:/etc/hosts
192.xxx.xx.xx     xx.exsample.com
```

などIPアドレスとホスト名を関連付けないといけません。
**（間違えてもホスト名を間違えてはいけません！誰かと同じでhostsファイルが機能していないと疑って30分ほど時間を無駄にします。）**

### おまけ
本当に簡単な仕様でリファレンス通りのJSONをPOSTしているだけです。
LINEのエンドポイントにjsonを送るソースコード

```php:AmazonController.php
        //To
        $to = 'U7fxxxxxxxxxxxxxxxxxxx';
		//Channel_Access_Token
		$Channel_Access_Token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

		$mes = 'テストメッセージです';

		$response_format = [
		  "type" => "text",
		  "text" => $mes
		];

		$post_data = [
		  "to" => $to,
		  "messages" => [$response_format]
		];

		//post
		$channel = curl_init("https://api.line.me/v2/bot/message/push");
		curl_setopt($channel, CURLOPT_POST, true);
		curl_setopt($channel, CURLOPT_CUSTOMREQUEST, 'POST');
		curl_setopt($channel, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($channel, CURLOPT_POSTFIELDS, json_encode($post_data));
		curl_setopt($channel, CURLOPT_HTTPHEADER, array(
		  'Content-Type: application/json; charset=UTF-8',
		  'Authorization: Bearer ' . $Channel_Access_Token
		));

		$result = curl_exec($channel);
		var_dump($result);
		curl_close($channel);
```

## さいごに
結構簡単にLINEと連携？できて感動しました。
約1800円ほどするプログラム可能なAmazon IoT Buttonを買うよりも500円で買えるAmazon Dash Buttonを買うほうが安上がりでいろいろとできそうな気がします。

## LINE Notifyを使った通知の方法
どうやら、LINE NotifyはWebサービスと連携し、その通知をLINEに流すサービスです。（そうLINE Notifyのページに書いてあります）

[LINE Notify](https://notify-bot.line.me/ja/)

サービスを登録していろいろ弄っているとなんてことでしょう。
Messaging APIを使うよりもはるかに簡単に通知できることが分かりました。
（Messaging APIならChannel_Access_TokenとかChannel_Secretとかで送信元とか署名確認とかしないといけない）
LINE Notifyはアクセストークンだけで関連付けられたユーザやグループに通知できるようです。
以下がプログラムです。

```js:amazon_new.js
'use structs';

var request = require("request");
const DashButton = require("dash-button");
const config = require("./config.json");

//button constructor
let button = new DashButton(config.mac_address);

console.log("stand by...");

//button push listener
button.addListener(() => {
  var exec = require('child_process').exec;
  exec("curl -X POST -H 'Authorization: Bearer [アクセストークン]' -F 'message=amazon dash button' https://notify-api.line.me/api/notify",
  function(error, stdout, stderr) {
    if(stdout) {
      console.log(stdout);
    }
    if(stderr) {
      console.log(stderr);
    }
    if(error !== null) {
      comsole.log("exec error: " + error);
    }
  });
});
```

@Tomonobu3110さんに教えていただいた内容に少し毛が生えた程度ですが、リクエストの結果を表示させるようにしました。

ちゃんとLINEに通知が送られるとその結果は以下のようになりました。

```js:結果
stand by...
{"status":200,"message":"ok"}
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   194    0    29  100   165     95    542 --:--:-- --:--:-- --:--:--   544
```

ちゃんと200が返ってきてます。
これだけ簡単に通知できれば、いろんなことに応用できそうです。