遅刻連絡サービスを作ってみた

# はじめに  

社内で「満員電車で携帯を取り出すことも困難な状態で、自動で遅刻の連絡をしてくれるサービスを作れないものか？」という話がちょっと上がったので、週末にコソコソと既存のサービス連携して作ってみました:hammer:  

申し訳ありませんが、サービスの使い方とか連携部分とかは一番下の参考を見てみてください（とてもわかりやすくまとまっています:bow:）
そしてこの記事の内容はあくまで遊びなので、激しい突っ込みは勘弁してください:cry:  

# 仕様

- 8時40分（ひとによりけり）に自分の位置情報を確認  
- 会社から1kmの範囲にいなかったら「すみません遅刻します！連絡もできない状況なので詳細は後ほど:innocent:」というメッセージをSlackに投げる。  
範囲内なら仕組みは一応動いているという確認のために「今日も仕事がんばれ:muscle:」というメッセージをSlackの自分専用チャンネルに投げる
- 地下鉄通勤でも正常に通勤できていれば8時40分には地上に出ているはずという前提の仕様

# 全体構成
<img src="https://qiita-image-store.s3.amazonaws.com/0/96682/66f726f5-524d-a270-ca76-2d9fa04598ca.png" width="500px">

1. Taskerで現在の自分の位置情報を取得、GoogleAppsScript(GAS)にPost
2. GASは取得した位置情報をGoogleMapsDistanceMatrixAPIに投げて、会社との距離を計算してもらう。
3. 計算結果を取得したらその結果からSlackWebApiを通してSlackに通知。  

# 今回使用したもの

- **トリガー**  
  [Tasker(Androidアプリ)](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm&hl=ja)
  <img src="https://qiita-image-store.s3.amazonaws.com/0/96682/3f7d4745-c04c-405d-0cc9-34fec45ff24b.png" width="80px">  

タスクとトリガーを組み合わせることで、いろんなことを実現できるAndroidアプリです。  
  有料ですが、自由度が高いためかなり遊べます。
今回はTaskerを使用しましたが、この遅刻報告サービスでは定時に位置情報を取得して（念のため更新をかけている）HttpPOSTをしているだけなので、他にも代替手段はあると思います。  
<br>

- **ロジック処理**  
<br>
  - **処理スクリプト**  
    [Google Apps Script](https://developers.google.com/apps-script/)
<img src="https://qiita-image-store.s3.amazonaws.com/0/96682/c47af308-b3c7-2cc7-eaa1-9c3f3c4818a3.png" width="80px">  
Googleが提供するjavaScriptで簡単にWebApiをつくれるサービスです。  
こちらも自由度が高く（javascriptかけるので当たり前）とっても便利！  
[SlackApp ライブラリ](https://github.com/soundTricker/SlackApp)なんてのも公開されていて（ありがたや:relaxed:）、簡単にSlackと連携が出来ます。  
<br>
  - **距離の測定**  
    [Google Maps Distance Matrix API](https://developers.google.com/maps/documentation/distance-matrix/intro?hl=ja)
<img src="https://qiita-image-store.s3.amazonaws.com/0/96682/632b8d30-ddf6-87ad-6727-7f33b70b9fb3.png" width="80px">  
GoogleMapのAPI。  
今回使ったのは緯度、経度で渡した2点間の距離を計算してくれるAPIです。
こんな結果を返してくれました。  

```js
{
    "destination_addresses": [
        "日本, 〒160-0023 東京都新宿区西新宿６丁目８−１"
    ],
    "origin_addresses": [
        "日本, 〒166-xxxx 東京都杉並区◯◯１丁目１−１"
    ],
    "rows": [
        {
            "elements": [
                {
                    "distance": {
                        "text": "5.8 km",
                        "value": 5777
                    },
                    "duration": {
                        "text": "1時間12分",//mode=walkingと設定したので歩いた場合の時間
                        "value": 4329
                    },
                    "status": "OK"
                }
            ]
        }
    ],
    "status": "OK"
}
```
- **通知**  
  [Slack(Slack Web Api)](https://api.slack.com/web)  <img src="https://qiita-image-store.s3.amazonaws.com/0/96682/c4a2569a-c6e4-2c61-b616-cd56d1cf5581.png" width="200px">  
SlackへのPOSTとかをWebAPIで行うためのサービスです。

# ちょっと中身の紹介

## Taskerのタスク  
<img src="https://qiita-image-store.s3.amazonaws.com/0/96682/340a7dff-9cce-6873-2893-a97dc0738cbe.png" width="200px">　<img src="https://qiita-image-store.s3.amazonaws.com/0/96682/0548b0a7-a17b-484b-9f79-e7eccf1a4117.png" width="200px">  



左: Taskの設定
以下の処理を `submit_location` というタスクに設定

- 位置情報を更新(念のために)
- 位置情報を`location`としてパラメータにもたせてGASにHttpPOSTする  


右: Taskの実行設定

- 8時15分に `submit_location` を実行（失敗確認用）
- 8時40分に `submit_location` を実行

## GASのコード

postリクエストがあると `doPost()` が呼ばれます。
requestからlocationを取得し、GoogleMapsDistanceMatrixAPIに投げています。

``` javascript
// 会社の緯度経度
var OFFICE_LOCATION_LATITUDE = 35.6939314;
var OFFICE_LOCATION_LONGITUDE = 139.6905425;
var OFFICE_LOCATION = OFFICE_LOCATION_LATITUDE + ',' + OFFICE_LOCATION_LONGITUDE;

var GOOGLE_API_KEY = '[APIKey]';

var URL = 'https://maps.googleapis.com/maps/api/distancematrix/json?origins=[MY_LOCATION]&destinations=' + OFFICE_LOCATION + '&mode=walking&language=ja&key=' + GOOGLE_API_KEY;// language,modeは別に無くても良い

/**
* Postリクエストがここに来る
*/
function doPost(request) {
  try {
    var location = request.parameter.location;
    var url = URL.replace(/\[MY_LOCATION\]/g, location);
    var result = UrlFetchApp.fetch(url);
    var resultStr = result.getContentText();
    var metre = JSON.parse(resultStr).rows[0].elements[0].distance.value;

    // 1km以上離れていたら遅刻連絡
    if (metre > 1000) {
      sendMsgToSlack('test1', 'すみません遅刻します！連絡もできない状況なので詳細は後ほど:innocent:');
    } else {// 別チャンネルにメッセージをポスト
      sendMsgToSlack('test2', '今日も仕事がんばれ:muscle:');
    }
  } catch (e) {
    // エラーをslackに投げる
    sendErrorMsg(e);
  }
}

function sendMsgToSlack(ch, msg) {
  var token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN');

  var slackApp = SlackApp.create(token); //SlackApp インスタンスの取得

  var options = {
    channelId: ch, //チャンネル名
    userName: "魚Bot", //投稿するbotの名前
    message: msg //投稿するメッセージ
  };

  slackApp.postMessage(options.channelId, options.message, {
    username: options.userName
  });

}

function sendErrorMsg(msg) {
  sendMsgToSlack('test2', 'エラーが発生したお:ng: \n' + msg);
}
```

# 結果

普通に通勤してみたところ、正常に動作しました:clap:

![ng.png](https://qiita-image-store.s3.amazonaws.com/0/96682/4381a0a5-b956-9b6e-1a1d-e4e561a99235.png)
![ok.png](https://qiita-image-store.s3.amazonaws.com/0/96682/140e6608-b8ea-d017-1e26-5106d4b888db.png)  


やったね٩( 'ω' )و 

# まとめ  

こういうの楽しい！！
ここはこうしたら良いんじゃないかとかある方是非教えてください:grinning:  

# 参考
以下、参考にさせて頂きました:bow:  

- GASの使い方の(めっちゃ丁寧): [非プログラマ社員向けに「Google Apps ScriptでつくるWebアプリケーション勉強会」を始めた話](http://kazuph.hateblo.jp/entry/2016/02/01/121213)  
- GASのSlack連携:　[掃除当番の割当を Google Apps Script で自動化して Slack の BOT として通知](http://qiita.com/amotz/items/332b26a1c9237b215f1e)