Help us understand the problem. What is going on with this article?

Hubot × Raspberry Pi2で電車の遅延情報をSlackに流す

More than 3 years have passed since last update.

背景

我が家にRaspberry Pi 2がサーバとして置いてありました。しかし、特に何も仕事をしていなかったのと、仕事でSlackを使うようになったこともあり、Botとして仕事をさせようと思いつきました。そのときの記事は下記。

前回までは、ただ家賃振り込んだかを聞いてくれる機能しかなく、活用しきれていない感がありました。そこで、電車が遅延している時にSlackで教えてくれると便利じゃないかと思い、実際に作ってみました。

完成イメージはこんな感じ。
スクリーンショット 2016-08-12 10.50.03.png
Botが電車の遅延を検知したら、あるチャンネルに投げてくれるイメージ。また、遅延について知りたいときは、Botに聞くと答えてくれると尚良ですね。

実装アイデア

電車遅延の情報をどこから入手してくるかの候補は2つありました。ちなみに僕は通勤に京王線しか使っていませんので、ひとまず京王線で話を進めます。

  1. 公式サイトをスクレイピング
  2. 公式TwitterのTweet

1だともし路線を増やす際の手間が大きそうです。2は、Tweetの内容を処理するだけで良いので汎用性も高く、楽そうですね。
京王電鉄運行情報のアカウント
他の路線も結構やっているみたいです、使ってませんけど。

ということで、実装は以下の流れでやればできそう。

  1. 5分毎にTweetを取得する。
  2. 新たなTweetがあった場合、内容を判断する。同時にTweet情報を保持しておく。
  3. 遅延していた場合、Slackに投げる。

TwitterAPIで他人のタイムラインの取得方法は以下URL。
https://dev.twitter.com/rest/reference/get/statuses/user_timeline

ちなみに、15分間で300回まではリクエストできそう、たぶん。

実装

Raspiで実現していますが、実装的にはLinuxサーバと何ら変わらず自由です。HubotはNode.jsを利用しているので、Node.jsでコーディングします。CoffeeScriptでも書けるんですが、僕はCoffeeScript嫌いなので使いません。

実装コード

//   Description:    京王線の遅れ取得
//
//   Commands:   電車
//
//   Author:     Seiya Mogami


var twitter = require('twitter');
var fs = require('fs');
var cronJob = require('cron').CronJob;

// 認証
// 自分のを入れてね
var api = new twitter({
    consumer_key: '',
    consumer_secret: '',
    access_token_key: '',
    access_token_secret: ''
});

// スクリーン名
var name = 'keiodentetsu';

// 電車が遅延している場合は遅延情報を投稿し、遅延していない場合は何もしない
function notifyIfTrainDelay(sname, robot) {
    fs.readFile('./' + sname + '.json', 'utf-8', function(err,jsonString){
        if(err){
            return robot.messageRoom('error', err);
        }else{
            if(!jsonString || jsonString == ""){
                var data = {
                    id_str: '1',
                    text: 'まだツイートが取得されていません。5分少々お待ち下さい。'
                };
                fs.writeFile(sname + '.json', JSON.stringify(data));
            }else{
                var json = JSON.parse(jsonString);
                api.get('statuses/user_timeline', { screen_name: sname, since_id: json.id_str }, function (error, tweets, response) {
                    if (error) {
                        console.log(error);
                        return robot.messageRoom('error', err);
                    } else {
                        if (tweets.length > 0) {
                            // 最新Tweetをjsonファイルとして保持しておく
                            fs.writeFile(sname + '.json', JSON.stringify(tweets[0]));
                            for (var i = 0; i < tweets.length; i++) {
                                var text = tweets[i].text;
                                if (text.match(/京王線/) && (text.match(/遅れ/) || text.match(/見合せ/))) {
                                    // 遅延情報がある場合
                                    return robot.messageRoom('notification', "<!everyone>: 電車遅れてるみたいやで〜\n```\n" + text + "\n```");
                                }
                            }
                            return;
                        } else {
                            console.log('no tweet found');
                            return;
                        }
                    }
                });
            }
        }
    });
}

function getTrainInfo(sname) {
    var json = JSON.parse(fs.readFileSync('./' + sname + '.json', 'utf-8'));
    if(json){
        return json.text;
    }else{
        return 'まだツイートが取得されていません。5分少々お待ち下さい。';
    }
}

// slackの動作部分
module.exports = function (robot) {
    // 秒 分 時 日 月 年
    new cronJob('00 00,05,10,15,20,25,30,35,40,45,50,55 * * * *', function () {
        notifyIfTrainDelay(name, robot);
    }).start();

    robot.respond(/電車/, function (msg) {
        var message = getTrainInfo(name);
        return msg.send("今の京王線はこんな感じやな〜\n```\n" + message + "\n```");
    });
};

解説

読んでいただければわかるんですが、簡単に解説します。

必要なPackageのインストール

npm install --save twitter cron

Tweetの処理

スクリーン名とTweetIDを元にTweetを取得します。since_idは指定したID以降のTweetしか取得しないようになるオプションです。よって、どこかしらに最新Tweetを保存しておく必要があるのですが、今回は、簡単のために取得したJSON形式のTweetをそのままJSONファイルにして保存し、必要に応じて読み込むことにしました。

JSON形式のTweetは簡単に言うと、以下の様な形です。今回使っているものだけ。

{
  "id_str": "Tweetに割り当てられたID(数字)を文字列にしたもの",
  "text": "Tweetの本文"
}

idとid_strがあるのですが、違いはIntかStringかの違いです。ただ、idのほうの桁数が半端ないので、処理系統によっては丸め込みが発生してしまう可能性があります。ですので、id_strを活用することをおすすめします。

あとは、正規表現使ってtextを処理すればよいのですが、勉強不足ですごい雑な感じで書いてしまっていますね。勉強します。この部分は路線によって書かれ方が違いそうな気がします。各自適当に合わせてください。

Tweetを取得するapi.getは非同期で動作しているので、処理の内部でSlackに投稿するようにしています。

cronで定期実行

cronJobのインスタンスを生成して定期的にTweetを取得しています。今回は5分おきにしていますが、深夜帯は取得しないようにするのが本当は理想的ですね。ただ、書くのが面倒だったので今回はしていませんが。

まとめ

いろいろハマったりしましたが、まあなんとか作れました。3時間くらいですかね。今回でTwitter活用のノウハウがたまったので、Tweetに応じていろいろBotにさせることができそうです。

HerokuとかAWSとかを使ってBotをたてることもできるようなので、しかも簡単にできるので皆さんも是非。

_mogaming
Developer | Firebase系YouTuber moga.page.link/yt | プロトタイプ開発や新規サービス立ち上げが主な仕事 | ex) 実験, DeNA
https://twitter.com/_mogaming
engineerlife
技術力をベースに人生を謳歌する人たちのコミュニティです。
https://community.camp-fire.jp/projects/view/280040
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away