家族のGoogleカレンダーの予定をLINEに通知する

# やりたいこと

Googleカレンダーの予定をLINEに通知します。

具体的には

* 定期的に(毎週日曜の夜に)
* 複数アカウントのカレンダーの予定を
* 1週間分
* LINEのグループに

通知するようにした手順を記載します。

### 背景

我が家では予定をGoogleカレンダーで管理しています。
カレンダー(Googleアカウント)は3つあり、夫個人用/妻(私)個人用/家族共有用にそれぞれ予定を入れています。

全員の予定を確認するため、以前は家族用のslackチームで[SlackAppのGoogleカレンダー](https://slack.com/apps/A0F8149ED-google-calendar)のサマリー投稿機能を利用していました。
しかしプライベートではslackはなかなか使わず、頻繁に使うLINEに専用グループを作ってそちらへ投稿することにしました。

### 所要時間

スクリプト等もコピペであれば、1時間あれば設定できると思います。

# 手順

## 1. 1つのGoogleカレンダーで複数アカウントのカレンダーを確認できるようにする

※ 家族のGoogleアカウントがそれぞれ別であることを前提としていますが、通知したいカレンダーのGoogleアカウントが1つだけの場合は、この手順は不要です。

まず、家族全員のGoogleカレンダーをまとめて見られるGoogleアカウント(以降「集約用Googleアカウント」)を作成します。
この集約アカウントは家族誰かのアカウントで代用しても、新しく作成してもどちらでも構いません。

次に家族の個人Googleアカウント側のカレンダー設定画面から、「特定ユーザーとの共有」で集約用Googleアカウントを追加します。
<img width="600" alt="スクリーンショット 2018-09-10 22.35.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/63954/24185518-44e7-501f-7e5e-a7a91cc85b77.png">

設定後、集約用Googleアカウントのカレンダーに個人アカウントの予定が表示できていれば設定完了です。

ちなみにここで表示されているのは、個人アカウント側で公開設定が「公開」となっている予定だけです。
公開設定を「非公開」とすれば共有Googleアカウントにはその予定は表示されなくなりますし、今回のLINE通知対象からも外れます。


## 2. LINE Notify
LINEグループへの通知は[LINE Notify](https://notify-bot.line.me/ja/)を利用します。

### ログイン
まず、[LINE Notify](https://notify-bot.line.me/ja/)に自分のLINEアカウントでログインします。
ログインすると「LINE Notify」というLINEアカウントが友達に追加されます。

<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/63954/726aea87-584d-61d9-532a-4264f8bbe697.png" >


### 通知用のLINEグループを作成

予定を通知したい家族とLINE NotifyのLINEアカウントを入れたLINEグループを作成します。

### アクセストークンを作成

LINE Notifyのサイトに戻り、「トークンを発行する」ボタンよりアクセストークンを発行します。
<img width="600" alt="スクリーンショット 2018-09-10 19.51.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/63954/736637dd-0b72-ace9-6c91-43e487bed725.png">

ここで指定したトークン名は、通知の際に`[トークン名]`形式で通知メッセージの先頭に表示されます。
後からトークン名は変更はできませんが、削除して再作成は可能です。
ここでは「〇〇家の予定Bot」というトークン名にしておきます。

通知を送信するトークルームには先ほど作成したLINEグループを選択します。
<img width="300" alt="スクリーンショット 2018-09-10 20.08.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/63954/4789bf9f-cac5-f25f-bcce-c9d2b3066f62.png">

作成したアクセストークンは後で使用するので残しておいてください。

## 3. GoogleAppsScript
通知内容の設定は[GoogleAppsScript](https://developers.google.com/apps-script/)で行います。

### 通知用スクリプトを作成

集約用Googleアカウントで[Googleドライブ](https://drive.google.com/drive)を開き、「新規」ボタンより`GoogleAppsScript`を新規作成します。
<img width="500" alt="スクリーンショット 2018-09-10 20.32.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/63954/47d10c5a-64ba-3e48-79de-1b9ef60f8c12.png">

`GoogleAppsScript`を1度も使用したことがない場合は、「＋ アプリを追加」より追加してください。
<img width="500" alt="スクリーンショット 2018-09-10 20.40.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/63954/7b3c4256-b979-b6c6-a716-7ecdb40ea339.png">

スクリプトを新規作成したら、以下の内容をコピペします。
この際に2点だけ修正をしてください。

* `token`の設定 (1行目)
  * LINE Notifyで作成したアクセストークンを設定します。
* `calendarTitleMap`の設定(4行目あたり)
  * 個人アカウント(gmailアドレス)とカレンダーの名称を対応付けます

```js
var token = "作成したtoken"; // TODO: ここに発行したアクセストークンを記載

// TODO: ここにカレンダー名を設定
var calendarTitleMap = {
  "hoge@gmail.com" : "hogeの予定",
  "piyo.share@gmail.com": "〇〇家の予定",
  "ja.japanese#holiday@group.v.calendar.google.com": "日本の祝日",
};

var weekday = ["日", "月", "火", "水", "木", "金", "土"];

function notifyWeekly() {
  
  var calendars = CalendarApp.getAllCalendars();
  var dt = new Date()
  var message = "来週の予定だよ！\n\n";
  
  for ( var i = 0;  i < 7;  i++ ) {
    
    dt.setDate(dt.getDate() + 1);
    message += Utilities.formatDate(dt, 'JST', '★ MM/dd(' + weekday[dt.getDay()] + ')') + "\n";
  
    var dayText = "";
    for(j in calendars) {
      var calendar = calendars[j];
    
      var calendarName = calendarTitleMap[calendar.getId()]
      if ( calendarName == undefined ) {
        continue;
      }
 
      var events = calendar.getEventsForDay(dt);
      if( events.length == 0 ) {
        continue;
      }
      
      dayText += "< " + calendarName + " >\n";
      for(j in events) {
        dayText += toDayText(events[j]);
      }
      dayText += "\n"
    }
    
    if ( dayText == "") {
        dayText += "予定はありません\n\n";
    }
    message += dayText;
  }
 
  sendToLine(message);
}
 
function sendToLine(message){
  var options =
   {
     "method"  : "post",
     "headers" : {"Authorization" : "Bearer "+ token},
     "payload" : "message=" + message
   };
  
   UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}
 
function toDayText(event) {
  return toTimeText(event.getStartTime()) + ' - ' + toTimeText(event.getEndTime()) + " " + event.getTitle() + '\n';
}

function toTimeText(str){
  return Utilities.formatDate(str, 'JST', 'HH:mm');
}
```

### スクリプトが定期実行されるように設定

LINEグループに通知が送られる日時を設定します。

同じGoogleAppsScriptの画面から時計のマークを押してトリガーを設定します。
今回は毎週日曜の夜に通知されて欲しいので、

- 実行: `notifyWeekly`
- `時間主導型`
- `週タイマー`
- `毎週日曜日`
- `午後8〜9時`

で設定してみます。

<img width="800" alt="スクリーンショット 2018-09-10 23.07.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/63954/c0d86e60-8d96-4cbd-5ebc-638a74ebeb7d.png">



## 4. LINEヘの通知結果

以上の設定が完了すると、日曜の夜8時〜9時の間に以下のようなメッセージがLINE Notifyから送られてきます。

<img width=300px src="https://qiita-image-store.s3.amazonaws.com/0/63954/334ec2ed-4da0-3563-30ce-144fbe73abb3.png">



# 参考

『LINE Notify API Document』
https://notify-bot.line.me/doc/ja/

『Google Apps Script > Calendar Service』
https://developers.google.com/apps-script/reference/calendar/

『Googleカレンダーの予定を毎朝LINEに通知する』
https://blog.piyo.tech/posts/2018-04-17-line-notify/