乗換駅に着いたら次の電車までの時間を声で知らせてくれる

#やりたいこと
私は電車通勤をしているのですが，途中で電車の乗換をするところがあります．
乗換のとき電車のタイミング次第で，急がないと電車に乗り逃してしまうときと，ゆっくり歩いても間に合うときがあります．
いちいちスマホで次の電車までの時間を検索して「今回はダッシュする必要あるのか，ないのか」を判断していましたが，
乗換駅に着くタイミングで自動で検索してほしい．

そして，その通知はイヤホンから音声で「あと○分後です」と流してほしい．
スマホ画面への通知だけだと，スマホを取り出して画面を見る必要があり面倒なので．


#処理の流れ
下図の通り，IFTTTとGoogle Apps Scriptを組合せたシステムをつくりました．
自宅から会社に向かうときと，会社から自宅に向かうときの両方に対応しています．

![システムnotifyNextTrain4.png](https://qiita-image-store.s3.amazonaws.com/0/239549/5224b259-4662-06be-b301-67ef0f45be7c.png)



1. 「乗換駅から1つ自宅側の駅」または「乗換駅から1つ会社側の駅」に到着したら，Google Sheetsに到着時刻のログを残す．
2. 「乗換駅」に到着したら，Google Sheetsに到着時刻のログを残す．
3. 「乗換駅」のGoogle Sheetsの内容が変更されたら（=2でログが追記されたら），会社と自宅のどちらに向かっているのかと，その方面の次の電車が何分後に発車するかを調べて，web requestを送る．
4. web requestを受け取ったら，VoIPで電話をかける．
5. 電話をとると，「次の○○方面の電車は○分後です」と合成音声が流れる．


######補足
- 音声は自動では流れません．かかってくる電話をとる必要があります．
    - 自動で流れるようにしたかったのですが，iPhoneの場合は着信音の代わりに声で通知するというのが基本的に出来ないようです．
    - イヤホンをつけている場合はイヤホンのボタンを押すだけで電話に出れるので，それほど面倒ではないかと思います．
    - 音声の再生が終わると勝手に電話が切れますので，手動で電話を切る必要はありません．
- 「会社と自宅のどちらに向かっているのか」は，各駅の到着時刻ログから判断します．
    - 「乗換駅から1つ自宅側の駅」の到着時刻と「乗換駅」の到着時刻の差をみて自宅側の駅から来たのかを判断します．会社側の駅の場合も同じです．
    - この条件をつけることによって，たとえば車で乗換駅の近くを通ったときの誤報をある程度防ぐことができます．

以下，詳細です．

---

#1. 自宅側または会社側の駅に到着したらログを残す
上の図中では簡易的にIFTTTのみを記載しましたが，実際には次の通り２段階としました．
（時刻のデータをIFTTTで直接Google Sheetsに入力するのは難しそうだからです．）

1-1. 駅に着くと，「到着した」というテキストをGoogle Sheetsに入力する（IFTTT）
1-2. Google Sheetsの値が変更されると，時刻を入力する（Google Apps Script）

これらを「乗換駅から1つ自宅側の駅」と「乗換駅から1つ会社側の駅」のそれぞれについて設定します．

##1-1. 駅に着くとテキストをGoogle Sheetsに入力する
IFTTTで「If "Location" Then "Google Sheets"」のAppletを作成します．
方法は[前回の投稿](https://qiita.com/ikechan/items/5e4bf2b9868d0d804af5)とだいたい同じですが，入力内容を単に適当なテキストにしました．（ここでは"arrive"）

<img width="342" alt="スクリーンショット 2018-03-27 22.56.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/239549/70baa044-22d9-887b-e097-f591fec0161c.png">

なお，[前回の投稿](https://qiita.com/ikechan/items/5e4bf2b9868d0d804af5)のようにFormatted rowの欄を"OccuredAt"とすれば，年月日＋時刻を入力できるのですが，後の処理をする上でフォーマットに不都合がありそうなので，単にテキストにしました．

ここまでの設定で，駅に着くとGoogle SheetsのA列に"arrive"と入力されるようになりました．
<img width="363" alt="スクリーンショット 2018-03-27 23.02.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/239549/1434bf52-b995-5a2e-1f2b-c111591bc207.png">

なお，何度か試していると，IFTTTのLocationトリガーが働かないことがありました．IFTTTのスマホアプリが変な状態で固まっていたためと思われます．

##1-2. Google Sheetsの値が変更されると時刻を入力する
Google Sheetsの画面からスクリプトエディタを開き，時刻を入力するプログラムを書きます（Google Apps Script）．
[前回の投稿](https://qiita.com/ikechan/items/5e4bf2b9868d0d804af5)と同様に，こちらの記事を参考にさせて頂きました：
[Google Home、IFTTT、Googleスプレッドシートを使って独自音声コマンドでログをとる（ついでにNode.jsやngrokやらも使ってLINEやGoogle Homeに通知する）](https://qiita.com/miso_develop/items/be562d8a823ad2639d94)

```javascript
var sheet = SpreadsheetApp.getActiveSheet();

function addTime() {
  setTime(2, "yyyy/M/d");
  setTime(3, "H:m:s");
  Logger.log("addTime done");
}

function setTime(col, format) {
  var lastrow = sheet.getLastRow();
  Logger.log(lastrow);
  if (sheet.getRange(lastrow, col).getValue() == "") 
    sheet.getRange(lastrow, col).setValue(formatTime(new Date(), format));
}

function formatTime(date, format) {
  return Utilities.formatDate(date, 'Asia/Tokyo', format)
}
```
次に，このプログラム中の"addTime"が，Google Sheetsの値が変更されたときに実行するようトリガーを設定します．
<img width="650" alt="スクリーンショット 2018-03-27 23.09.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/239549/54927cd7-0823-3fe9-5380-006d12258175.png">

以上より，Google Sheetsの値が変更されると，B列に年月日，C列に時刻が入力されます．
<img width="355" alt="スクリーンショット 2018-03-27 23.11.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/239549/28d8ab76-8a55-48b3-a091-d2a10af0a079.png">

なお，このトリガー設定は，設定後すぐには働かないことがありました．数分待つ必要があるようです．

#2. 乗換駅に到着したらログを残す
方法は基本的に「１」と同じです．
違いはIFTTTのLocationトリガーが働く地点を乗換駅周辺にすることや，Google Sheetsの名称（Spreadsheet name）を別のものにするくらいです．
1と2を合わせて，作成するGoogle Sheetsは合計3つとなります．


#3. 「2」のトリガーがかかったら向かっている方向と次の電車までの時間を調べてweb requestを送る
2でつくった乗換駅のGoogle Apps Scriptにプログラムを追加します．
乗換駅に関するIFTTTとGoogle Apps Scriptの内容をまとめると次の通りとなります．

 - 乗換駅に着いたらGoogle Sheetsにテキストが入力される（2で設定済みのIFTTT）
 - Google Sheetsの値が変更されたら時刻が入力される（2で設定済みのGoogle　Apps Script）
 - Google Sheetsの値が変更されたら向かっている方向と次の電車までの時間を調べてweb requestする（NEW! 　追加するGoogle Apps Script）

この追加プログラムでは下記を参照します．

 - 「1」で作ったGoogle Sheetsの時刻（=「乗換駅から1つ自宅側の駅」および「乗換駅から1つ会社側の駅」の到着時刻）
 - 「2」で作ったGoogle Sheetsの時刻（=「乗換駅」の到着時刻）
 - 時刻表

プログラムは少し長くなったので[こちらのgistページ](https://gist.github.com/ryotaikeuchi/12ecea01cb4cdc82b5ad0d50bf2908b3)に置きました．


##3-1. 会社と自宅のどちらに向かっているのかを判断する
「乗換駅」の到着時刻から「乗換駅から1つ自宅側の駅」の到着時刻を引いて，その結果が0〜+5分なら，自宅方面から来たと判断します．
会社方面の場合も同じです．

なお，下記の最終行を求めるプログラムでは，途中に空白行があると正しく動作しません：

```javascript
var lastRow = range.filter(String).length;
```
※NG例：　３行目が最終行ですが，誤って最終行は２行目と判断してしまう．
<img width="361" alt="スクリーンショット 2018-03-28 0.28.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/239549/18b15194-3638-e0fd-0ec1-fcb2968ac6e6.png">


##3-2. 時刻表
時刻表は予め手動で入力しておきます．
「2」でつくった乗換駅のログの残すGoogle Sheetsに，「timetable」という名称のシートを追加しました．
<img width="334" alt="スクリーンショット 2018-03-27 23.57.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/239549/6691f939-655a-ffbf-1067-fd6227c87f3d.png">
１列目には会社方面行き，２列目には自宅方面行きの時刻表を入力しました．
今回はひとまず平日だけにしましたが，それぞれ平日/土曜/日曜を列ごとに分けて入力すれば，土日でも使えます．
なお，Google Sheetsに「○:○○」と時刻のみ入力すると，年月日は100年前とかに自動設定されるようですが，今回のプログラムでは年月日は無視して時刻のみを比較するため問題ありません．

##3-3. 次の電車が何分後かを調べる
現在時刻と時刻表を比較して，次の電車が何分後かを調べます．
プログラムはこちらを参考にさせて頂きました：
[IFTTT,GAS,Line-notifyを使ってボタン１プッシュでLineに直近のバス情報を通知する](https://qiita.com/k_keisuke/items/c6c9201e3cbdbd27c329)

また，時刻表データの行と列を入れ替えるのにはこちらを参考にしました（今回は実際には使わなくてもよかったかも）：
[Google Apps Scriptで100以上の便利関数が使える定番ライブラリUnderscore for GAS](https://tonari-it.com/gas-underscore-for-gas/)

##3-4. web requestを送る
Google Apps Scriptで次の通りUrlFetchを実行します：

```javascript
var url = "https://maker.ifttt.com/trigger/notify_next_train/with/key/XXXXXXXX?value1=" + value1 + '&value2=' + value2;
UrlFetchApp.fetch(url);
```
（↑gistのプログラムからの抜粋）
value1には，次の電車までの時間[分]を，
value2には，"自宅方面行き" or "会社方面行き"というテキストを予め代入しておきます．


#4. web requestを受け取ったらVoIPで電話をかける
またまたIFTTTを使います．
「IF "webhooks" Then "VoIP"」とします．
<img width="348" alt="スクリーンショット 2018-03-28 0.18.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/239549/0118f526-ff94-1a04-ea25-11f248a8b026.png">
このVoice messageの欄に入力した言葉を，電話に出たときに合成音声で読み上げてくれます．
この欄にvalue1やvalue2を入れることで，次の電車までの時間や「○○方面行き」というのも読み上げてくれるのです．すごく便利です．
実際には，「○分後に」というのを最初に言う方がいいですね．すぐ知りたいのはその部分なので．
（読み上げ内容は、iPhoneのIFTTTアプリで変更できるので、外出先で思い立ったときに手軽に変更できるのでよいです）


#おわりに
乗換駅に着いたら次の電車までの時間を声で知らせてくれるシステムをつくりました．

実装では，次の電車までの時間を求めるところでハマってしまったのですが，既に似たことを実装された方のプログラムを見つけてなんとかなりました．感謝．やっぱり，似たことをしている記事などを探すのは大事ですね．
当初はそもそも時刻表を予め手動で入力しておくという発想がなく，電車の時刻検索するためのサービスを探したけどフリーのものはないなーと悩んでたりもしました…．

また，スマホから声で通知させるにはどうすれば…というのもしばらく悩みました．少し大胆かもしれませんがVoIPを使うのは悪くないと思っています．
「電話がかかってくる　→　電話に出ると合成音声が再生される」というのは意外と楽しいです．初めて試したときは，何度も何度も遊びました．