Amazon Dash ButtonとRaspberry Piで安くなったら自動購入するおうちハック

## 作ったもの
Amazon Dash Buttonが発売され色々な方がハックしていますが、このデバイスの弱点はボタンを押すというシンプルなUIであるため金額がわからないこと、、、

Amazonの値段は頻繁に変わるので、できるだけお安く買いたいですよね？
そこでAmazon Dash Buttonを物理ハックして、指定した金額まで値段が下がったら自動で購入してくれるデバイスを作成してみました。

![タイトルなし.gif](https://qiita-image-store.s3.amazonaws.com/0/7132/35edaf32-f242-5b51-663c-167667a627d9.gif)

## 材料
| 名前 | 部品 | 値段 |
|:--|:--|:--|
| Amazon Dash Button | [![image](https://qiita-image-store.s3.amazonaws.com/0/7132/f83217d4-d786-e7fa-e39b-f9aabe957f5d.png)](http://amzn.to/2hV4kC3) | ¥500 |
| Raspberry Pi 3 | [![image](https://qiita-image-store.s3.amazonaws.com/0/7132/4f722d1e-4989-903b-51b1-f7afa100969f.png)](https://amzn.to/2Vtse9f) | ¥4,800 |
| マイクロサーボ SG92G | <a href="http://akizukidenshi.com/catalog/g/gM-08914/" target="_blank"><img src="https://qiita-image-store.s3.amazonaws.com/0/7132/9ab41fa3-6d29-db86-ded1-ef2d2c165bbb.png" width="150" ></a> | ¥500 |
| Arduino Uno | [![image](https://qiita-image-store.s3.amazonaws.com/0/7132/d937b5de-2448-7b42-58ef-0cf7f5233cef.png)](https://amzn.to/2XCaknf) | ¥3,240 |

とりあえずサーボモーターとAmazon Dash Buttonは結束バンドで固定しています。

## Arduinoでサーボモーターを動かす
Raspberry PiのGPIOに接続するための部材が足りなかったので、少々面倒くさいですがArduino経由でサーボモーターを操作するようにしました。
ちゃんと準備していればArduinoは不要です。

シリアル通信で`A`を受信したときにサーボモーターを少し動かしAmazon Dash Buttonを押すようにしています。

```c
#include <Servo.h> 
const int pin = 8;
Servo myservo;

void setup() {
  myservo.attach(pin);
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    byte res = Serial.read();
    if (res == 'A') {
      myservo.write(20);
      delay(500);
    }
  } else {
    int val = myservo.read();
    if (val != 0) {
      myservo.write(0);
    }
  }
}
```

実際にArduino IDEのシリアルモニタから`A`を送信してみると
こんなかんじでサーボモーターが動作します

![タイトルなし.gif](https://qiita-image-store.s3.amazonaws.com/0/7132/54019fbb-1605-3a1a-c3de-a2136601b843.gif)


## Raspberry PiとArduinoでシリアル通信する
Raspberry PiとArduinoをUSBケーブルで接続し、シリアル通信経由でサーボモーターを操作する手順です。

### pipで[pyserial](https://github.com/pyserial/pyserial)をインストール
まずはRaspberry Pi側の下準備必要なライブラリーをインストールします

```bash
$ sudo apt-get install python-pip
$ sudo pip install pyserial
```

### `dmesg`でArduinoのデバイス名を確認
Raspberry PiとArduinoをUSBケーブルで接続し、接続を確認します。
コマンドを打つとわらわらと表示されますが`Arduino`って表示されているあたりで`ttyACM0`というデバイス名で接続されていることが確認できます。

```bash
$ dmesg
[ 3401.469507] usb 1-1.5: new full-speed USB device number 4 using dwc_otg
[ 3401.583400] usb 1-1.5: New USB device found, idVendor=2341, idProduct=0043
[ 3401.583420] usb 1-1.5: New USB device strings: Mfr=1, Product=2, SerialNumber=220
[ 3401.583433] usb 1-1.5: Manufacturer: Arduino (www.arduino.cc)
[ 3401.583446] usb 1-1.5: SerialNumber: 554313134383513061F0
[ 3401.601770] cdc_acm 1-1.5:1.0: ttyACM0: USB ACM device
```

### シリアル通信してみる
`serial.Serial`には先程取得したデバイス名や、Arduinoで指定した値を設定します。

```py:dashpush.py
import serial
import time

ser = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(3)
ser.write(b'A')
ser.close()
```

動かしてみる

```bash
$ sudo python dashpush.py
```

すべてを接続した状態でサーボモーターが動作すれば準備完了です

## 商品が安いかどうかを判定する
[Amazon Product Advertising API](https://affiliate.amazon.co.jp/gp/advertising/api/detail/main.html)を使い商品の値段を取得し、
設定した金額より安かった場合ボタンを押し購入するように作っていきます。

### ASINを取得
Amazon Dash Buttonに設定している商品のASINを取得します。
ページの商品の情報にあるのでコピペ

この[サントリー 天然水
![image](https://qiita-image-store.s3.amazonaws.com/0/7132/5d4fb748-5fc3-cebb-b773-de5493498274.png)](http://amzn.to/2hMBLDM)
の場合`B0043TXMWM`となります。


### ライブラリーのインストール
pipで[bottlenose](https://github.com/lionheart/bottlenose)と[BeautifulSoup](https://www.crummy.com/software/BeautifulSoup/)をインストールします

```bash
$ sudo pip install bottlenose
$ sudo pip install BeautifulSoup
```


### 商品情報を取得して購入する

`bottlenose`で取得したAmazonの商品情報のXMLを`BeautifulSoup`でパースし、
水の値段が1200円未満だったら、先程のシリアル通信を投げ購入します。

```py:dashpush.py
import serial
import time
from bottlenose import api
from BeautifulSoup import BeautifulStoneSoup

AMAZON_ACCESS_KEY_ID = "xxxxxxxxxx"
AMAZON_SECRET_KEY = "xxxxxxxxxx"
AMAZON_ASSOC_TAG = "corelar-22"
ASIN = "B0043TXMWM"
PURCHASE_PRICE = 1200

# get api
amazon = api.Amazon(AMAZON_ACCESS_KEY_ID, AMAZON_SECRET_KEY, AMAZON_ASSOC_TAG, Region="JP")
res = amazon.ItemLookup(ItemId=ASIN, ResponseGroup="Offers")

# xml parse
soup = BeautifulStoneSoup(res)
price = soup.find("item").find("offer").find("price").find("amount").text

# push button
if int(price) < PURCHASE_PRICE:
    ser = serial.Serial('/dev/ttyACM0', 9600)
    time.sleep(3)
    ser.write(b'A')
    ser.close()
```

購入できました。
<img width="375" alt="IMG_1108.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/7132/dd306bfb-dca3-85ce-a51f-05083caa82c3.png">


## スマホで購入を制御
このままでは、在庫状況に関係なく常に無限購入するようになってしまうため。
スマホから購入する商品の金額の閾値を変更できるようにします。

たとえば
- 必ず購入する（10000円に設定）
- 1200円未満なら購入する（1200円に設定）
- 購入しない（0円に設定）

AWS Lambda上でAPIを作り、この金額をiOSアプリから更新して、Raspberry Piから読み込めるように作っておけば連続で購入される心配はないです。
ボタンが押されたら`Raspberry Pi`から0円指定に戻すだけ。

商品の値段を逐一トラッキングして**ここ１ヶ月で一番安くなったら購入！**みたいなこともできる

## cronに設定して定期実行
今回は30分に１度チェックするようにしました。

```bash
$ crontab -e
```

raspbianの場合初回起動時にエディタの選択画面が表示されるんだけど、
読まずに適当にエンター押したら`nano`が選択されて詰みかけた
`select-editor`コマンドを打つとvimで選択しなおせる

```text:crontab
*/30 * * * * sudo python dashpush.py > /dev/null 2>&1
```

あとは放置・・・

## おわり
Advent Calendarぎりぎり間に合った・・・。
これまで購入APIが存在しなかったんですが、やっと購入できるようになって嬉しい。

前に[ポケモンGOプラスをいじった](http://qiita.com/narikei/items/26fd8aab831e30446038)ときの応用でしたが、これは完全に放置デバイスになった

[AWS Greengrass](https://aws.amazon.com/jp/greengrass/)や[AWS IoT ボタン](https://aws.amazon.com/jp/iotbutton/)とかAmazonが力を入れてきているし、
やっとRaspberry Pi Zeroも来年には国内で販売されるっていうし、
はやく日本に正式版きてほしいですね。