Androidのメモとか

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

ESP8266を使って京急の運行状況を監視するガジェットを作った

京急の運行情報を監視するガジェット作成

KEIKYU ESP8266

電車の遅延は突然起こります。5分、10分であればいいのですが、一時的な運転見合わせだったり、大幅なダイヤ乱れは一定の厳しさがあります。

我らが愛する京急はあまり遅延が起こらない路線ではあるものの、JRからの振替輸送受託の影響で理不尽な遅延が発生することもあります。

今回は、家(またはオフィス)にいるときに、京急に何か異変があったらお知らせするガジェットを作りたいと思います。

必要なもの

まずは情報源。APIが特に切られていないので、本家のサイトをあまり高くない頻度でポーリングして監視します。

unkou.keikyu.co.jp

また、今までの実装はこちらでまとめています。

relativelayout.hatenablog.com relativelayout.hatenablog.com

また、ガジェットのパーツとしては以下のものを使用しました。

  • Arduino互換のESP8266ボード
  • プロトタイプシールド
  • ジャンパケーブルみたいなもの
  • 抵抗(たぶん100Ω)
  • しょぼいLED
  • 京急のおもちゃ

ボードは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を短絡させています。

ESP8266

あと、さすがにLED直挿しはまずいと思い、一応抵抗を挟んでいます(100Ω)。抵抗値の計算はしてません。テキトーです。(写真は抵抗を挟む前)

KEIKYU ESP8266

伸ばしたLEDを京急のカプセルプラレール内に設置。本当はプラレールくらいの大きさが良かったのですが、意外とお値段が高かったので、今回はカプセルプラレール(1回200円)で代用・・・。

試運転

KEIKYU DELAY

ちょうど京急で遅延が起こっていたので、試運転させてみました。

KEIKYU ESP8266

こんな感じで電車が赤く光りました。

現状のコードでは、Wi-Fi接続するタイミング(速い点滅)と京急に遅延が生じているタイミング(遅い点滅)でLEDが光る実装になっています。

とりあえず、ファーストステップとしてはこんなもんでしょうか。NTPから時間を取得して、終電〜始発までの時間帯はサイトにアクセスしないようにしたりするのもいいかもしれませんが、未実装です。

Learning Esp8266: Build the Internet of Things With the Arduino Ide and Raspberry Pi

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

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