本記事について
ESP8266という、WiFi通信ができるArduino互換のマイコンがあります。
それを用いて、Amazon Dash Buttonのボタンプッシュを検知する方法です。
WiFiアクセスポイント不要。ESP8266のみでボタンプッシュを検知できます。
Amazon Dash Button ハックの仕組み
Amazon Dash Button ハックの仕組みについておさらいしておきます。
仕組みについては Amazon Dash ButtonをただのIoTボタンとして使う に詳しく書いてあります。
改めて説明すると、Amazon Dash Buttonは、ボタンが押されると、電源が入り、WiFiに接続し、インターネットを介してAmazonのサーバーにアクセスし、実際の注文を行います。
しかし、注文に絡むデバイスのため、本当にハックするのは難しく、改造等は行わないで、Amazon Dash ButtonがWiFiに接続したのを検知して、ボタンがプッシュされたとみなす、間接的なハックを行います。
ボタンを押すとAmazon Dash ButtonがWiFiに接続するようにするには、Amazon Dash ButtonにWiFiのアクセスポイント情報が登録されている必要があります。
そして、その登録のために、注文商品選択直前までAmazon Dash Buttonのセットアップを進め、そこでセットアップを中断しておきます。
そこまでセットアップが進んでいると、WiFiアクセスポイントの登録は完了していて、以後は、ボタンを押すとWiFiアクセスポイントに接続するようになります。
WiFi接続検知の方法
WiFi接続検知の方法は2つあります。
1つ目
Amazon Dash ButtonはWiFiへ接続の際、IPアドレス取得のため、まず自分のMACアドレスをネットワークにブロードキャストします。その仕組を利用して、ボタン検出する側の機器が同じWiFiネットワークに接続しておき、Amazon Dash ButtonのMACアドレスが配信されるのをウォッチして検出する方法です。
2つ目
ボタン検出する側の機器自らがWiFiのアクセスポイントとなり、Amazon Dash Buttonに登録アクセスポイントして登録する方法です。そして、Amazon Dash Buttonから、自らのアクセスポイントへのコネクションを検出します。
手順がシンプルなので、多くのハックは1つ目の方法を用いています。
しかし、1つ目の場合、常時別途WiFiアクセスポイントを用意する必要があり、ESP8266とAmazon Dash Buttonだけで動かすことができません。
WiFi環境が無い状況でも動作できるよう、ここでは2つ目の方法を用いました。
手順
ESP8266をアクセスポイントとして登録
ESP8266はWiFiを受けて、WiFi発信することができるので、仕様上はWiFiからWiFiへの中継ポイント、つまりNATになることができます。
しかし、ESP8266でNAT(NAPT)でWi-Fiを中継する に記載されているように、ESP8266のライブラリではその機能をOFFにされているため、一旦ライブラリを修正してその機能をONにしてライブラリを再コンパイルし、そのライブラリを使ってNATを実装し可動する必要があります。
そして、ESP8266をNATとして可動させ、Amazon Dash ButtonをそのNATを介してセットアップして、ESP8266をAmazon Dash Buttonに登録する必要があります。
幸い、A full functional WiFi Repeater にESP8266をNATにするソースとバイナリがありますので、今回はそのバイナリをインストールして使用しました。
NATインストール
詳細は A full functional WiFi Repeater の「Building and Flashing」に記載されています。
- ダウンロード
A full functional WiFi Repeater で[Clone or download]-[Download ZIP]して解凍 - ソフトインストール
https://www.espressif.com/en/support/download/other-tools からバイナリ書き込みツール「Flash Download Tools」をダウンロードしてインストール - バイナリロード
解凍したファイルの「firmware」にバイナリ「0x00000.bin」「0x10000.bin」があるのでそれを「Flash Download Tools」を使って書き込みます。
(製品によってESP8266のFLASH SIZEが異なるので、使っているESP8266に合わせます)
NATセットアップ
- ESP8266セットアップ
起動するとNATになっているので 詳細は A full functional WiFi Repeater の「Basic Web Config Interface」に従って、ブラウザでアクセスして設定します。
(ここではデフォルトの設定を用いました) - Amazon Dash Buttonセットアップ
上記で設定したESP8266のアクセスポイントにAmazon Dash Buttonがアクセスするようにして、Amazon Dash Buttonのハックにあるのと同様の、商品選択直前までのセットアップを行います。
ボタン検知プログラム
ESP8266のアクセスポイント(SSIDとパスワード)がAmazon Dash Buttonに登録されましたので、後はボタン検知のESP8266のプログラムを書いて転送し実行するだけです。
サンプルプログラムは下記になります。
- Amazon Dash ButtonがESP8266のアクセスポイントに接続すると、
onStationConnected()
コールバック関数が呼ばれますので、これをもってボタンプッシュ検知としています - DNSサーバーは必須ではないのですが、あった方がAmazon Dash Buttonがリトライをあきらめるのが早い(次のボタン検知可能までの間隔が短くなる)ようなので入れてあります
#include <ESP8266WiFi.h>
#include <DNSServer.h>
const char *ssid = "xxxx";
const char *password = "xxxxxxxxxx";
const byte dns_port = 53;
IPAddress apIP(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0);
DNSServer dnsServer;
WiFiEventHandler stationConnectedHandler;
byte bConnection = 0;
int push_count= 0;
int send_frame = 0;
const int max_send_frame = 200000;
byte pin_a = 16;
byte pin_b = 14;
void setup() {
delay(1000);
Serial.begin(115200);
Serial.println();
Serial.println("Configuring access point...");
WiFi.softAPConfig(apIP, apIP, subnet);
WiFi.softAP(ssid, password);
stationConnectedHandler = WiFi.onSoftAPModeStationConnected(&onStationConnected);
IPAddress myIP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(myIP);
dnsServer.start(dns_port, "*", apIP);
pinMode(pin_a, OUTPUT);
pinMode(pin_b, OUTPUT);
digitalWrite(pin_a, LOW);
digitalWrite(pin_b, LOW);
}
void onStationConnected(const WiFiEventSoftAPModeStationConnected& evt) {
bConnection = 1;
send_frame = 0;
++push_count;
Serial.print("Station connected: ");
Serial.print(macToString(evt.mac) + " -> ");
Serial.println(push_count);
digitalWrite(pin_a, HIGH);
digitalWrite(pin_b, HIGH);
Serial.println("pin HIGH");
}
void pinOut(){
if(bConnection){
if(send_frame<max_send_frame){
++send_frame;
} else {
bConnection = 0;
digitalWrite(pin_a, LOW);
digitalWrite(pin_b, LOW);
Serial.println("pin LOW");
}
}
}
void loop() {
dnsServer.processNextRequest();
pinOut();
}
String macToString(const unsigned char* mac) {
char buf[20];
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(buf);
}
最後に
WiFiアクセスポイント不要で、ESP8266だけでボタン検知できるようになるので、屋外等、任意の場所へと、Amazon Dash Button の活用フィールドが広がります。