ESP8266 (ESP-WROOM-02) でバスの到着を知る「バスどこメーター」を作る(前編)

## 概要
ESP8266 (ESP-WROOM-02) でバスの到着を知ることができる装置を作る

## はじめに

以前、Qiitaで「<a href="http://qiita.com/kazunori279/items/7dbbb525ab0cf6d5d9b5" target="_blank">cloudBitとIFTTTで「おとうさんいまどこメーター」を作る</a>」という記事を読んだ。素晴らしい着想だ。

当時は全く、手も足も出なかったが、今ならできる気がする。そう、WROOM02 なら。

アイデアをそのまま繰り返しても面白くないので、自分なりに考えた。

そうだ、朝の慌ただしい時間帯に、最寄りのバス停に、あとどれ位でバスが来るかをサクッと確認できるメーターを作ろう！
スマフォから「東急バスナビ」で確認できるが、いちいち見てられないので。

「東急バスナビ」は、東急バスが提供する、このようなサービスです。→ <a href="http://tokyu.bus-location.jp/blsys/navis?VID=top&EID=spn&PRM=&RID=&SCT=" target="_blank">東急バスナビ</a>


機械的なサービスの利用について事前に問合せたのですが、そういったサービスは無いそうです。

```
担当部署へこの件に関しまして確認いたしましたところ、一般的なブラウザによる閲覧を想定しており、
それ以外の用途による質問についてはお答えしかねます。との回答がございました。
```

今回は営利目的ではない個人的な利用なので、ちょっとグレーですが、使わせてもらうことにします。(自己責任で)
もし問題あれば連絡ください。

## アーキテクチャ
全体のアーキテクチャは以下のようになります。
ここは得意の AWS で、サーバレス な構成にします。

![スクリーンショット 2016-02-11 20.40.07.png](https://qiita-image-store.s3.amazonaws.com/0/69410/0caa4fdd-6ffc-4265-53b3-c28e6ba679a0.png)


## サーバサイド

AWS APIGateway + Lambda をつかって、サーバサイドの処理を実装します。

 - バス会社からの「バスなび」情報(HTML)をパースして、必要な部分だけをjsonにして返すフィルタの役割になります。
 - Lambda は、リクエストがあるときだけ起動する、サーバレスなアーキテクチャ。


 - APIGateway と Lambda については、「<a href="http://qiita.com/exabugs/items/e868df55333d0805acb2" target="_blank">AWS Lambda を使って Slack ボット (命名: Lambot [ランボー]) を低予算で作ろうじゃないか</a>」を参照して下さい。
 - WROOM02 からの https通信では **TLSv1.1** しかできませんが、APIGateway が **TLSv1.2** を強要するため、しかたなく CloudFront を被せます。
しかし、WROOM02 で SSL (WiFiClientSecure) がうまく動かなかったため、結局、CloudFront で HTTP <-> HTTPS の変換をして、WROOM02 は HTTP で通信するようにします。
 - npm ライブラリ ( request、cheerio ) を使用している。Lambda に登録するには node_modules にインストール後、全体を zip でまとめてアップロードする必要があります。


### Lambda
Lambda 関数は以下。

```js
var request = require("request");
var cheerio = require("cheerio");

exports.handler = function (event, context) {

  var options = {
    uri: 'http://tokyu.bus-location.jp/blsys/navis',
    form: {
      VID: "rsc",
      EID: "rd",
      SCT: 2,
      DSMK: event.DSMK,
      ASMK: event.ASMK
    }
  };

  function trim(node) {
    return node.text().replace(/[\r\n\t]/g, "");
  }

  request.post(options,
    function (error, response, body) {
      if (event.test) {
        body = require('fs').readFileSync('check.html', 'utf-8');
      }
      var $ = cheerio.load(body);
      var pos = [];
      $(".approach tbody tr").each(function () {
        var tr = $(this);
        if (tr.hasClass("stopline")) {
          pos.push([]);
        }
        if (tr.hasClass("busline") && pos.length) {
          tr.children(".colmsg").each(function () {
            $(this).children("div").each(function () {
              var waittm = $(this).children(".waittm").remove();
              var item = {
                route: trim($(this)),
                wait: parseInt(trim(waittm))
              };
              pos[pos.length - 1].push(item);
            });
          });
        }
      });
      pos.shift(); // 先頭 (arrstopline) は不要
      //console.log(pos);
      var now = new Date();
      context.done(null, {
        time_t: ~~(now.getTime() / 1000),
        position: pos
      });
    }
  );
};
```

Githubにアップしておきます。
https://github.com/exabugs/BusNavi

### CloudFront
CloudFront の設定は以下。
注意なのは赤丸の Origin の設定部分。なんと APIGateway がリストから選択できないですが、慌てないで**APIGatewayのエンドポイントのURLを直接コピペ**すると良いです。

![スクリーンショット_2016-02-11_19_40_39.png](https://qiita-image-store.s3.amazonaws.com/0/69410/0756d353-8ca7-109a-e33a-2799c4d61ad4.png)

あとは、デフォルトでいい。


## 動作確認

サーバサイドが正常に動作しているか、以下で確認できる。


```html
<h3>AWS Cloudfront</h3>
<form action="http://d33zr06jat9rdj.cloudfront.net/tokyu_bus-location" method="POST">
  <table>
    <tr><td>DSMK</td><td><input type="text" name="DSMK" value="3020" /></td></tr>
    <tr><td>ASMK</td><td><input type="text" name="ASMK" value="3633" /></td></tr>
  </table>
  <input type="submit" />
</form>
```
上記の実験ページを、S3 にアップロードしてホスティングしておきます。
(APIGateway も上げておきますので、適当に実験してもらっていいです。)
http://tokyu.exabugs.s3-website-ap-northeast-1.amazonaws.com/


ここで、パラメータは以下となる。

|パラメータ|値|
|----|----|
|DSMK|乗車バス停 ID|
|ASMK|降車バス停 ID|

バス停のIDは、以下で調べることができます。
<a href="http://tokyu.bus-location.jp/blsys/navis?VID=top&EID=spn&PRM=&RID=&SCT=" target="_blank">http ://tokyu.bus-location.jp/blsys/navis?VID=top&EID=spn&PRM=&RID=&SCT=</a>

テストコードでは

 - DSMK 3020 鷺沼駅 (田園都市線)
 - ASMK 3633 北山田駅 (横浜市営地下鉄線)

を示しています。


以下のようなjsonがレスポンスされます。

 - time は、現在時刻 time_t です。
 - item 配列の [0] は乗車バス停を指します。[1] は一つ前のバス停。<br>6つ前のバス停まで、情報を返します。
 - 例では、二つ前のバス停までバスが来ていて、あと 3分 で到着するということ。

```json
{
  "time": 1455186143,
  "DSMK": 3020,
  "ASMK": 3633,
  "item": [
    [],
    [],
    [
      {
        "wait": 3,
        "route": "鷺０１ 終)(折)東営行"
      }
    ],
    [],
    [],
    [],
    []
  ]
}
```

このjsonを WROOM02 で処理する予定。

## まとめ

 - 東急バスがサービスしている「バスナビ」をフィルタして、JSONが取得できるAPIを用意しました。
 - WROOM02 ハード部分は「<a href="http://qiita.com/exabugs/items/8f86c3c64c34f719f255" target="_blank">ESP8266 (ESP-WROOM-02) でバスの到着を知る「バスどこメーター」を作る(後編)</a>」に続きます。