Androidのメモとか

ポキオの日記です。今日も遅延してない。

ESP8266でHTTP GETするならWiFiClientじゃなくてHTTPClientのほうが良い

何言ってるか分からないと思いますが。

ESP8266

いろいろ困ったちゃんだったWiFiClient

relativelayout.hatenablog.com

ESP8266触る上で、やっぱりやりたくなるのがHTTP GET。以前、京急の運行情報のページをHTTP GETする際に使っていたのがWiFiClient。別に意識していたわけではなく、たまたまサンプルコードがWiFiClientだったので、それを使っていました。

しかし、一つ問題があって、GETするPayloadが長すぎると途中で途切れてしまう問題。これが厄介で、ワークアラウンドとしてRangeを指定してGETするPayloadを小さく、特定の部分だけ返してもらうようなRequestを投げるようにしていました。

便利で、デキる子、HTTPClient

たまたまネットを見ていたら、HTTPClientなるものを見つけ、なんとなく使ってみたらいい感じでした。インスタンスの初期化も簡単だし、とにかくRequestのHeaderも特に記載しなくてもGETできるので素敵です。

とりあえず、コードで書いてみました。

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

char ssid[] = "XXXXXXXX";
char password[] = "YYYYYYYY";

void setup() {
  Serial.begin(115200);
  Serial.println("");

  connectWifi();

  String result1 = getPageSource1("http://unkou.keikyu.co.jp/");
  Serial.println(result1);

  String result2 = getPageSource2("unkou.keikyu.co.jp");
  Serial.println(result2);

  disconnectWifi();
}

void loop() {

}

void connectWifi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }

  Serial.println("connected!");
}

void disconnectWifi() {
  WiFi.disconnect();
  Serial.println("disconnected!");
}

String getPageSource1(char host[]) {
  HTTPClient http;

  http.begin(host);
  int httpCode = http.GET();

  String result = "";

  if (httpCode < 0) {
    result = http.errorToString(httpCode);
  } else if (http.getSize() < 0) {
    result =  "size is invalid";
  } else {
    result = http.getString();
  }

  http.end();
  return result;
}

String getPageSource2(char host[]) {
  WiFiClient client;

  if ( !client.connect(host, 80) ) {
    return String("");
  }

  client.print(String("GET ") + "/" +
               " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
  client.println();

  delay(1000);

  String body = "";

  while (client.available()) {
    body += client.readStringUntil('\r');
  }

  return body;
}

getPageSource1()はHTTPClientでGETし、getPageSource2()はWiFiClientで京急の運行情報を取得するコードにしてみました。

WiFiClientで取得してみる

シリアルモニタを見てみる。

ESP8266

最初はいい感じに取得できているが・・・

ESP8266

なぜか、最後は尻切れになって終了。 HTMLのHeaderが終わった直後くらいで切れているので、データとしてはあまり取得できていません。

HTTPClientで取得してみる

やっぱりHTTPClientですね。

ESP8266

ResponseのHeaderは見ることはできないものの、いい感じに取得できています。

ESP8266

そして、HTMLも最後の</html>まで取得できています。ちょっとHTTPClient、いい感じなので当面こちらを使ってみようと思います。

Raspberry PiのVNCのパスワードを忘れたので変更する

やっちまった。

パスワードの保存場所

~/.vnc/passwd

ただし、暗号化されているためファイルを開いても読めません。

vncpasswdコマンド

こんなコマンドが有るんですね。

raspberry pi vncpasswd

vncpasswdで、引数に先程のファイルを渡して実行するとVNCのパスワードを変更できます。

$ vncpasswd ~/.vnc/passwd

tightvncserverで設定した古いパスワードを聞かれること無く、新しいパスワードに変更できました。

Android ThingsのPreview版をRaspberry Pi用に焼いてみた

取り急ぎ、SD作成〜起動まで。

Android Thingsとは

こちらをご参照のこと。

developer.android.com

jp.techcrunch.com

Preview版のダウンロード

下記サイトから、RPi用のイメージをダウンロード。 およそ268MBのZIPファイルです。

developer.android.com

Mac標準の解凍アプリだと正しく回答できなかったため、The Unarchiverで解凍。

Preview版を焼き焼き

MacBook Airで作成しました。 まず、Micro SDをMacBook Airに刺す。(8GB以上)

とりあえず、Micro SDのDisk番号を下記コマンドで探す。

$ diskutil list

すると、こんな感じでDiskの番号がわかる。

/dev/disk2
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *7.7 GB     disk2
   1:                 DOS_FAT_32 UNTITLED                7.7 GB     disk2s1

2番ということがわかったので、まずはアンマウント。

$ diskutil unmountDisk /dev/disk2

そんでもって、先程解答したイメージを焼いていきます。

$ sudo dd bs=1m if= path/to/iot_rpi3.img  of=/dev/disk2

これが結構時間がかかりました。

4352+0 records in
4352+0 records out
4563402752 bytes transferred in 4306.709407 secs (1059603 bytes/sec)

4300秒。1.2時間であります。 なにか設定間違えたかな・・・?

起動

Raspberry PiにMicro SDを刺して起動します。 一応、HDMIはテレビに繋ぎます。

Raspberry Pi 3 MODEL B

Raspberry Pi 3 MODEL B

  • 発売日: 2016/05/31
  • メディア: Personal Computers

最初、文字がちょこっとだけ流れて、その後Android ThingsのBOOT画面になります。

Android Things

その後、無事に起動。 特に何もできない様子。

アプリ書きますか・・・。

Amazon Dashボタンのハックにおける期待と落胆(Bluetooth編)

Amazon Dash Button

前回はWi-Fi周りを色々検証してみました。

relativelayout.hatenablog.com

今回はBluetoothを覗いてみました

BluetoothSnifferなんて持ってないので、Amazonアプリが入っている端末で開発者向けオプションを有効にして、Bluetooth HCIスヌープログを有効にするにチェックをいれてBluetoothのパケットをキャプチャしてみた。

Amazon Dash Button

キャプチャ方法は以下の通り。

http://relativelayout.hatenablog.com/entry/2016/06/02/204600relativelayout.hatenablog.com

たしかにAmazon Dash Buttonと通信している

Amazon Dash Button

特にスマホAmazon Dash ButtonへのWriteをよく見てみると、初っ端にすごい大きなPayloadをAmazon Dash Buttonに送っている。しかもPrepare Writeで小分けにして。

{"publicKey":"-----BEGIN PUBLIC KEY-----\n(長い英数字)\n(長い英数字)\n-----END PUBLIC KEY-----\n","scheme":0}

うーん、これは鍵っぽいですね(真顔) その後にスマホからWriteしているデータも、全くよくわからないPayloadなので、完全に暗号化されているようです。まぁ、平文では送りませんよね・・・。Bluetoothで送っているデータを書き換えられても、ちょっと実装はダルそうです。

というわけで

結局、Amazon Dash ButtonのHackはARP Probeの監視しか無いんでしょうか・・・。

Amazon Dashボタンのハックにおける期待と落胆(Wi-Fi編)

これ買いました

Amazon Dash

巷で流行りのAmazon Dashボタン。

[asin:B01L2WOS0W:detail]

買ったばかりですが、このボタンをどうにか改造して、他の用途に使えないかの検証をしてみました。

まずはセットアップ

Amazon Dash

セットアップはスマホAmazonアプリから行う模様。位置情報のパーミッションが求められるということは、Wi-FiBluetooth/BLEのスキャンを行っていると思われる。その後、家のAPのSSID/PW入力画面と、商品選択画面が続く。

github.com

上記のサイトのように、SSID/PWの設定が終わり、すぐにセットアップを中断すれば、Amazon Dashボタンに接続先の情報が書き込まれるが、ボタンを押したときに注文される商品の設定がされていない状態のため、どんなにAmazon Dashのボタンを押しても商品は注文されない。

Amazon Dashボタンをハックするには

そもそもAmazon Dashボタンは、ボタンが押されてから設定済みのAPに接続して、特定のURLに何かしらの情報をPOSTして、注文をしていると思われる。ただし、Amazon Dashボタンのハック方法は、上記のDasherを含めて、ネット上の情報を見る限り少しトリッキーである。

Amazon DashボタンがAPに接続した後に、ネットワーク上にBroadcastされるAPR Probeを監視して、そのBroadcastがAmazon Dashボタン(のMACアドレス)から行われたものかどうかを判断するもの。もしAmazon Dashボタンが押されたと検知されたら、他のタスク(例えばIFTTTのトリガーとか)を実行するものである。

Amazon Dash

MacBookからtcpdumpコマンドを走らせて、Wiresharkでパケットを解析してみた。たしかにARPプローブを発見できる。したがって、Amazon Dashボタンをハックするには、以下のことが言えそうである。

  • Amazon Dashボタンのハックは、AP接続後にBroadcastされるARP Probeを監視するのが一般的
  • 逆に言えば、Amazon Dashボタンが接続してくるネットワーク上で、常にARP Probeを監視するスクリプト・マシンが必要になってくる
  • 一方で、Amazon Dashボタンからの購入時、Amazonアプリがネットワーク上に存在しなくても注文ができた
  • AmazonアプリはARP Probeの監視をしておらず、注文自体はAmazon Dashボタン単体で完結しているっぽい

Amazon Dashボタンは非常に安価でDIY魂に火をつける一方で、従来のハック方法では、Amazon Dashボタン押下の監視役が必要となるので、若干面倒である。BLEの通信で授受している情報で抜け穴があれば、なんとかなりそうだが・・・。希望としては、HTTP POSTのURLと、POSTしている内容を変更できたら本当に嬉しいんだけどなぁ・・・。

ESP8266でIFTTT Makerチャネル向けの物理ボタンを作る

まずはIFTTTの物理ボタンを作る

こんな感じ。

IFTTT 物理ボタン

基盤の裏側には皆さんおなじみのESP8266ボードがあります。

ESP8266

スライドスイッチは、USBオスからの5V給電のON/OFFができ、USBの5VとGNDは、ESP8266ボードの5VとGNDにつながっています。

プッシュボタンはESP8266のGNDとGPIO0(Pull-up)につながっていて、ボタン押下をトリガーに、プログラムを走らせることを目論んでます。

IFTTT 物理ボタン

USBオスはめんどくさいので既製品を使います。

サンハヤト USB用変換基板 CK-41

サンハヤト USB用変換基板 CK-41

  • メディア: Tools & Hardware

はんだ付けは苦手なので、テキトーにやっていきます。

プログラム部分を書いていく

今回は試しに、ボタンを押すとTwitterで「#ponponpain」とつぶやくガジェットを作ってみます。

#include <ESP8266WiFi.h>

char ssid[] = "SSID";
char password[] = "PASSWORD";

int button = 0; // GPIO 0(PULL-UPを使う)

WiFiClient wifiClient;

char host[] = "maker.ifttt.com";
char url[] = "/trigger/(IFTTTのトリガー名)/with/key/(IFTTTのKEY)";
int port = 80;

void setup() {
  pinMode(button, INPUT_PULLUP);

  Serial.begin(115200);
  Serial.println("");

  // 接続処理
  connectWifi();
  initializeHttpClient();
}

void loop() {
  // 本当は割り込み処理で実装したかったが、Watchdogの例外が起こってしまい断念
  if (digitalRead(button) == LOW) {
    // PONPONPAINを叫ぶ
    ponponpain();
    
    // 立て続けにPOSTができなかったため、ここで一旦切断
    wifiClient.stop();
    initializeHttpClient();
  } else {
    delay(100);
  }
}

void connectWifi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }

  Serial.println("connected!");
  Serial.println(WiFi.localIP());
}

void initializeHttpClient() {
  if (!wifiClient.connect(host, port)) {
    Serial.println("connection failed");
    Serial.print("client status : ");
    Serial.println(wifiClient.status());
    Serial.print("client connected : ");
    Serial.println(wifiClient.connected());
  } else {
    Serial.println("connection success");
  }
}

// PONPONPAINを叫ぶ
void ponponpain() {
  WiFiClient wifiClient;
  String json = "{\"value1\":\"#ponponpain\"}";


  if (!wifiClient.connect(host, port)) {
    Serial.println("connection failed");
    return;
  }

  Serial.println("http post...");
  wifiClient.println(String("POST ")  + url + " HTTP/1.1");
  wifiClient.println(String("Host: ") + host);
  wifiClient.println("Cache-Control: no-cache");
  wifiClient.println("Content-Type: application/JSON");
  wifiClient.print("Content-Length: ");
  wifiClient.println(json.length());
  wifiClient.println();
  wifiClient.println(json);
}

こんな感じ。相変わらずクソコードです。

IFTTTで設定

IFTTTのMakerチャネルで、イベント(今回はponponpainという名前)を作成して、そこにHTTP-POSTされた値を、そのままTwitterに投稿するレシピを作成。

いざponponpain

今回、USBオスからの給電に対応したため、モバイルバッテリーに直挿ししても使えます。

ESP8266 IFTTT トリガー

ボタンを押して、しばらくすると・・・

こんな感じで、世界中にponponpainを伝えることができました。

【第2類医薬品】ストッパ下痢止めEX 12錠

【第2類医薬品】ストッパ下痢止めEX 12錠

  • 発売日: 2017/07/01
  • メディア: ヘルスケア&ケア用品

IoT縛りの勉強会! IoTLT vol.20 @ ウフルで登壇してきました

IoTLTとは

iotlt.connpass.com

weekly.ascii.jp

国内最大級のIoTに関するライトニングトーク大会。先月に引き続き登壇してきました。運営の方々やウフルの皆さん、ありがとうございました。

会場に向かう

ウフルさんのオフィスは虎ノ門(!)にあり、最寄り駅が神谷町とのこと。職場の品川からは直線距離は近いもののアクセスがちょっと悪いので、都バスで品川→飯倉片町まで行ってそこから散歩することに。

神谷町

東京タワー、こんにちは。半分観光気分で、写真を撮りまくりました。完全にお上りさんです。

神谷町

飯倉片町から神谷町までは、大使館的な建物が多く、セキュリティレベルが高そうな雰囲気でした。なんか機動隊が乗ってそうなクルマばかりだし、おまわりさん大杉でビビるぜ。

ウフル

そんなこんなで、ウフルさんオフィス到着。エントランスからしてシャレオツなんですが…

ウフル

中も超絶シャレオツでチビリそうです。

いざ発表

www.instagram.com

いままでコソコソ実装してきた、家での消費電力(電流)をESP8266ボードで測定してクラウドにアップロードする話です。

割りとオーディエンスが静かだったので焦りましたが(笑)、ツイッター上では盛り上がってました。

speakerdeck.com

資料はこちらです、ご査収下さい。

懇親会・反省点

懇親会では沢山の方々とお話することができました。

ウフル

  • 結局「電源をどうするのか」という問題は共通の課題
  • クランプ電流センサーへの問い合わせが多かった

1灯2差ソケット+コンセント2個 E26用 [品番]04-7605

1灯2差ソケット+コンセント2個 E26用 [品番]04-7605

  • 発売日: 2006/07/21
  • メディア: Tools & Hardware

  • これを使えば、電球のソケットからコンセントが取れるとの情報を頂きました
  • 今はGoogleスプレッドシートに出力しているが、マカレルのサービスならグラフ化も簡単で無料っぽいので使ってみたい

などなど、色々アドバイスを頂きました。個人的には、一応Androidモバイルアプリエンジニアなので、それと組み合わせた何かを作ってみたいなぁと思っていますが…。おいおい何か作ってみようとおもいます。

Raspberry Pi 3 Model B (Element14)

「Androidのメモとか」は、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、Amazonアソシエイト・プログラムの参加者です。

このブログは個人的なメモ書きであったり、考えを書く場所であります。執筆者の所属する団体や企業のコメントや意向とは無関係であります。また、このブログは必ずしも正しいことが書かれているとは限らず、誤字脱字や意図せず誤った情報を載せる場合がありえます。それが原因で読者が不利益を被ったとしても、執筆者はいかなる責任も負いません。ありがとうございます。