概要
ESP8266 (ESP-WROOM-02) でバスの到着を知ることができる装置を作る
はじめに
以前、Qiitaで「cloudBitとIFTTTで「おとうさんいまどこメーター」を作る」という記事を読んだ。素晴らしい着想だ。
当時は全く、手も足も出なかったが、今ならできる気がする。そう、WROOM02 なら。
アイデアをそのまま繰り返しても面白くないので、自分なりに考えた。
そうだ、朝の慌ただしい時間帯に、最寄りのバス停に、あとどれ位でバスが来るかをサクッと確認できるメーターを作ろう!
スマフォから「東急バスナビ」で確認できるが、いちいち見てられないので。
「東急バスナビ」は、東急バスが提供する、このようなサービスです。→ 東急バスナビ
機械的なサービスの利用について事前に問合せたのですが、そういったサービスは無いそうです。
担当部署へこの件に関しまして確認いたしましたところ、一般的なブラウザによる閲覧を想定しており、
それ以外の用途による質問についてはお答えしかねます。との回答がございました。
今回は営利目的ではない個人的な利用なので、ちょっとグレーですが、使わせてもらうことにします。(自己責任で)
もし問題あれば連絡ください。
アーキテクチャ
全体のアーキテクチャは以下のようになります。
ここは得意の AWS で、サーバレス な構成にします。
サーバサイド
AWS APIGateway + Lambda をつかって、サーバサイドの処理を実装します。
- バス会社からの「バスなび」情報(HTML)をパースして、必要な部分だけをjsonにして返すフィルタの役割になります。
Lambda は、リクエストがあるときだけ起動する、サーバレスなアーキテクチャ。
APIGateway と Lambda については、「AWS Lambda を使って Slack ボット (命名: Lambot [ランボー]) を低予算で作ろうじゃないか」を参照して下さい。
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 関数は以下。
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を直接コピペすると良いです。
あとは、デフォルトでいい。
動作確認
サーバサイドが正常に動作しているか、以下で確認できる。
<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は、以下で調べることができます。
http ://tokyu.bus-location.jp/blsys/navis?VID=top&EID=spn&PRM=&RID=&SCT=
テストコードでは
- DSMK 3020 鷺沼駅 (田園都市線)
- ASMK 3633 北山田駅 (横浜市営地下鉄線)
を示しています。
以下のようなjsonがレスポンスされます。
- time は、現在時刻 time_t です。
- item 配列の [0] は乗車バス停を指します。[1] は一つ前のバス停。
6つ前のバス停まで、情報を返します。 - 例では、二つ前のバス停までバスが来ていて、あと 3分 で到着するということ。
{
"time": 1455186143,
"DSMK": 3020,
"ASMK": 3633,
"item": [
[],
[],
[
{
"wait": 3,
"route": "鷺01 終)(折)東営行"
}
],
[],
[],
[],
[]
]
}
このjsonを WROOM02 で処理する予定。
まとめ
- 東急バスがサービスしている「バスナビ」をフィルタして、JSONが取得できるAPIを用意しました。
- WROOM02 ハード部分は「ESP8266 (ESP-WROOM-02) でバスの到着を知る「バスどこメーター」を作る(後編)」に続きます。