京急の運行情報を監視するガジェット作成
電車の遅延は突然起こります。5分、10分であればいいのですが、一時的な運転見合わせだったり、大幅なダイヤ乱れは一定の厳しさがあります。
我らが愛する京急はあまり遅延が起こらない路線ではあるものの、JRからの振替輸送受託の影響で理不尽な遅延が発生することもあります。
今回は、家(またはオフィス)にいるときに、京急に何か異変があったらお知らせするガジェットを作りたいと思います。
必要なもの
まずは情報源。APIが特に切られていないので、本家のサイトをあまり高くない頻度でポーリングして監視します。
また、今までの実装はこちらでまとめています。
relativelayout.hatenablog.com relativelayout.hatenablog.com
また、ガジェットのパーツとしては以下のものを使用しました。
ボードはEPS8266が搭載されている開発ボードを使用。京急のおもちゃは、京急の品川駅のセブンイレブンとかで売っているカプセルプラレールを使用しました。
ESP8266で動かすコード
なにはともあれ、コードが必要なのでコードを書きます。毎度毎度のクソコードですが、以下のようになっています。
ポイントは3つです。
- Wi-Fi接続を行うAP情報をコード上で持っておいて、京急の運行情報を取得するページにアクセスするたびに接続する
- 情報が取得できたらWi-Fiを切断して、運行情報をパースする
- 情報のページには時間をおいてアクセスするが、京急が正常運転している場合はDeepSleepをして消費電力を低減する
#include <ESP8266WiFi.h> #include <WiFiClient.h> char ssid[] = "XXXXXXXX"; char password[] = "xxxxxxxx"; char unkopage[] = "unkou.keikyu.co.jp"; int led = 14; int intervalSec = 10 * 60; void setup() { pinMode(led, OUTPUT); Serial.begin(115200); Serial.println(""); } void loop() { connectWifi(); String result = getPageSource(); Serial.println(result); disconnectWifi(); if (result.indexOf("unko-panel") < 0) { Serial.println("取得エラー"); delay(5000); } else if (result.indexOf("平常") < 0) { Serial.println("遅延してるかもしれません"); blinkLed(intervalSec * 1000, false); } else { Serial.println("平常通り運転してます"); ESP.deepSleep(intervalSec * 1000 * 1000, WAKE_RF_DEFAULT); delay(1000); } } void connectWifi() { WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); blinkLed(1000, true); } Serial.println("connected!"); } void disconnectWifi() { WiFi.disconnect(); Serial.println("disconnected!"); } String getPageSource() { WiFiClient client; if ( !client.connect(unkopage, 80) ) { return String(""); } client.print(String("GET ") + "/" + " HTTP/1.1\r\n" + "Host: " + unkopage + "\r\n" + "Range: bytes=8000-9000\r\n" + "Connection: close\r\n\r\n"); client.println(); delay(1000); String body = ""; while (client.available()) { body += client.readStringUntil('\r'); } return body; } void blinkLed(int msec, boolean fast) { int totalTime = 0; while (totalTime < msec) { int onTime; int offTime; if (fast) { onTime = 20; offTime = 80; } else { onTime = 200; offTime = 800; } digitalWrite(led, HIGH); delay(onTime); digitalWrite(led, LOW); delay(offTime); totalTime += onTime + offTime; } }
もちろん、課題もあります。
- 「平常」という文字列をパースして遅延が起こっているかどうかを判断しているので、日本語の言い回しが変わると、運行情報を正確に判断できなくなる(今は大丈夫)
- APの設定によって、約1KB以上の情報の取得に失敗してしまうので、HTTPリクエストのヘッダにRangeを指定して、必要な部分だけを取得するようにしている
- DeepSleep中は消費電力が非常に低くなるため、モバイルバッテリーなどで電源を供給していると、モバイルバッテリーがデバイス未接続と勘違いをして給電をやめてしまうケースがある(今はAC-DCで給電してる)
まぁ、いろいろありますが、温かい目で見てください。
「なんでこいつは、こんなにunko、unkoと騒いでいるのか。そんなインスタンス名にしなくてもいいのではないか。」と思う方もいるかもしれません。たしかに、サイトのアドレスは
unkou
となっています。しかし、HTML上のDIVの名前はunko-panel
という斬新なネーミングとなっています。私は、この文字列からインスタンス名を決めただけです。
組み立てる
配線自体はシンプルです。
DeepSleepからEPS8266を叩き起こすために、GPIO16とRESETを短絡させています。
あと、さすがにLED直挿しはまずいと思い、一応抵抗を挟んでいます(100Ω)。抵抗値の計算はしてません。テキトーです。(写真は抵抗を挟む前)
伸ばしたLEDを京急のカプセルプラレール内に設置。本当はプラレールくらいの大きさが良かったのですが、意外とお値段が高かったので、今回はカプセルプラレール(1回200円)で代用・・・。
試運転
ちょうど京急で遅延が起こっていたので、試運転させてみました。
こんな感じで電車が赤く光りました。
現状のコードでは、Wi-Fi接続するタイミング(速い点滅)と京急に遅延が生じているタイミング(遅い点滅)でLEDが光る実装になっています。
とりあえず、ファーストステップとしてはこんなもんでしょうか。NTPから時間を取得して、終電〜始発までの時間帯はサイトにアクセスしないようにしたりするのもいいかもしれませんが、未実装です。
Learning Esp8266: Build the Internet of Things With the Arduino Ide and Raspberry Pi