やりたいこと
Googleカレンダーで家族の予定を共有しているけど、頻繁にアプリを開いて確認するのが億劫
だったら新しく予定が追加された時と、予定の開始時刻1日前に通知するBotをLINEのMessaging APIとGASを使って実現できないかやってみる。
更新履歴
2023/11/14 繰り返しの予定を作成した際、同じメッセージを何回も送信するバグを直した。
目次
LINE公式アカウントの作成
LINE Developersにアクセスしてアカウントを作成します。
ログインできたら、Create New Providerをクリックして新しいプロバイダーを作成します。
そうしたら、Create New ChannelからMessaging APIを選択して新しいチャンネルを作っていきます。
ここで、Botの名前やアイコン、アカウントのカテゴリーなどを設定していきます。
作成できたら、Bot informationのところにある友達追加用のQRコードから追加しておきましょう。
GASの方でスクリプトを書くときに以下の2点が必要になるので、控えておきましょう。 * Your user ID * Channel access token
Channel access tokenは初期状態では発行されていないので、Messaging APIタブから発行しておきましょう。
グループLINEにBotを追加する場合
作成したBotをグループLINEに追加する場合は、LINE Official Account featuresのところにある、Allow bot to join group chatsを有効化しておいてください。
なお、グループに追加するのは後述するグループIDを取得する準備ができてからするようにしてください。
Calendar IDの取得
予定の変更を通知したいカレンダーのIDを控えておきます。
xxxxxxxx@group.calendar.google.com
こんな感じの形式になってます。
GASの作成
ここから、メッセージを送るためのスクリプトを作成していきます。
Google Apps Scriptにアクセスして以下のコード貼り付てください。
const TOKEN = "Token"; const DESTID = "User ID or Group ID"; const CALENDARID = "CalendarID"; const URL = "https://api.line.me/v2/bot/message/push"; // 初回のイベント一覧を取得、次回から差分を取得するためのnextSyncTokenを保存する関数 function initSync() { var items = Calendar.Events.list(CALENDARID); var nextSyncToken = items.nextSyncToken; var properties = PropertiesService.getScriptProperties(); properties.setProperty("syncToken", nextSyncToken); console.log("Initial Sync Done"); properties.setProperty("prevtitle", "") // 前回のイベントタイトルを格納するようのproperties console.log("Initial property Done"); } // LINEにメッセージを送信する関数 function sendLINE(body){ UrlFetchApp.fetch(URL, { 'headers': { 'Content-Type': 'application/json; charset=UTF-8', 'Authorization': 'Bearer ' + TOKEN, }, 'method': 'POST', 'payload': JSON.stringify({ 'to': DESTID, 'messages':[{ 'type': 'text', 'text': body , }] }) }) } // カレンダーが編集されたときに実行される関数 function onCalendarEdit() { // nextSyncTokenを使って差分を取得 var properties = PropertiesService.getScriptProperties(); var nextSyncToken = properties.getProperty("syncToken"); var optionalArgs = {syncToken: nextSyncToken}; const events = Calendar.Events.list(CALENDARID, optionalArgs); console.log(events); // 変更された予定をプリント var nextSyncToken = events.nextSyncToken; properties.setProperty("syncToken", nextSyncToken); // nextSyncTokenの保存 var prevevent = properties.getProperty("prevtitle"); // 前回のイベントタイトルを取得 // 繰り返しの予定で2回目以降はスクリプト停止 if ((events.items[0].hasOwnProperty("recurrence")) && (prevevent == events.items[0].summary)){ console.log("This event is recurrenced"); return ; } // ステータスが削除の場合、property初期化 else if (events.items[0].status == "cancelled"){ properties.setProperty("prevtitle", ""); } // それ以外(通常のイベント、繰り返し1回目の場合)は今回処理したイベント名をpropに格納 else{ properties.setProperty("prevtitle", events.items[0].summary); } // メッセージの作成 switch (events.items[0].status) { case "confirmed": var msg = ("【予定の追加・変更】\n"+ "\n"+ "タイトル: "+events.items[0].summary+"\n"+ "開始時刻: "+Utilities.formatDate(new Date(events.items[0].start["dateTime"]), events.items[0].start["timeZone"], "yyyy/MM/dd (E) HH時mm分")+"\n"+ "終了時刻: "+Utilities.formatDate(new Date(events.items[0].end["dateTime"]), events.items[0].end["timeZone"], "yyyy/MM/dd (E) HH時mm分")+"\n"+ "作成者: "+events.items[0].creator.email+"\n\n"+ "詳細はアプリを開いて確認してください。" ); break; case "cancelled": var msg = ("【予定の削除】\n"+ "\n\n"+ "詳細はアプリを開いて確認してください。" ); break; case "tentative": var msg = ("【予定の追加・変更】\n"+ "\n"+ "タイトル: "+events.items[0].summary+"\n"+ "開始時刻: "+Utilities.formatDate(new Date(events.items[0].start["dateTime"]), events.items[0].start["timeZone"], "yyyy/MM/dd (E) HH時mm分")+"\n"+ "終了時刻: "+Utilities.formatDate(new Date(events.items[0].end["dateTime"]), events.items[0].end["timeZone"], "yyyy/MM/dd (E) HH時mm分")+"\n"+ "作成者: "+events.items[0].creator+"\n\n"+ "詳細はアプリを開いて確認してください。" ); break; case "draft": var msg = ("【下書きの予定があります】\n"+ "\n"+ "タイトル: "+events.items[0].summary+"\n\n"+ "詳細はアプリを開いて確認してください。" ); default: return ; } console.log(msg); sendLINE(msg) }
なお、グループLINEにメッセージを送りたい人はDESTIDにUser IDではなくGroup IDを入力する必要があります。
この取得方法がめんどくさいので、後述します。
貼り付ける事ができたら、初めて使う際はinitSync関数を実行する必要があります。
下の画像のように、Debugの右にある関数を選ぶところからinitSync
を選択し、Runをクリックします。
エラー無く実行できたら成功です。
グループLINEにメッセージを送る方法
グループIDを取得するには、Webhookを受信するサーバーが必要になります。
自前で用意するのもありですが、めんどくさいのでGASとスプレッドシートを使ってグループIDを取得します。
まず、スプレッドシートを新規作成しExtensionからApps Scriptを選択してGASの画面に行きます。
そうしたら、以下のコードを貼り付けます。
なお、コードは三十路街道 ボンバィエ様のサイトにあるものを使わせていただきました。
function doPost(e){ var json = JSON.parse(e.postData.contents); var UID = json.events[0].source.userId; var GID = json.events[0].source.groupId; var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); sheet.getRange(1,1).setValue(GID); }
貼り付けたら、これをWEBアプリとしてデプロイしていきます。
上の方にあるDeployからNew Deployを選択して、以下のように設定します。
デプロイできたら、URLが表示されるのでそれをコピーしてLINE DevelopersのWebhook URLに貼り付けます。
そうしたら、下にあるUse webhookを有効化します。ここまで出来たらBotをグループLINEに招待してください。
そうすると、先程のスプレッドシートのA1にグループIDが表示されています。これをDESTIDに入力してください。
完了したら、セキュリティのためにUse webhookを無効化し、スクリプトを削除しておいてください。
トリガーの設定
最後に、Googleカレンダーに変更があった際にスクリプトが実行されるよう、トリガーを設定していきます。
Choose which function to runにはonCalendarEdit
Enter calendar detailsにはCalendar Updated
Owner emailにはカレンダーのIDをそれぞれ設定してください。
あとは、放置でOKです。