Googleカレンダーの予定が始まる直前にChatWorkに通知する

Googleカレンダーの予定が始まる直前にChatWorkに通知する

Googleカレンダーでスケジュールの管理をしています。 予定が近づくとポップアップで通知されるのですが、Googleカレンダーを開いていないと通知が来ません。 通知が来なくて悲しい思いをしたので、確実に開いているChatWorkに通知が飛んだらいいなと思い試してみました。

今回はGoogle Apps ScriptとチャットワークAPIを使って通知します。

Google Apps Script

ざっくり言えばGoogleのいろんなアプリ(Gmail、Googleカレンダー、Googleドキュメント、Googleマップ、その他色々)をJavaScriptから簡単に操作できるやつです。

今回はGoogleカレンダーとGoogleドキュメント(スプレッドシート)の機能を使います。

Apps Script | Google Developers

チャットワークAPI

ざっくり言えばHTTPS経由でChatWorkにメッセージを送ったり、タスクを追加したり、メッセージを受け取ったりできるやつです。

今回はChatWorkのマイチャットに向けてメッセージを送るのに利用します。

チャットワークAPIドキュメント

事前に用意するもの

  • Googleアカウント
  • チャットワークAPIのAPIトークン

やってみよう

Googleスプレッドシートにアクセスし、新しくスプレッドシートを作成する

Googleスプレッドシート

右下の+から新規作成できます。 スクリーンショット 2017-07-02 15.24.44

スクリプトエディタにソースコードを貼り付ける

「ツール」 > 「スクリプト エディタ」からエディタを開きます。 スクリーンショット 2017-07-02 14.31.15

エディタが開いたら、以下のソースコードを丸ごと貼り付けてください。 スクリーンショット 2017-07-02 15.28.34

ソースコード

//スプレッドシートに保持するデータ
//1カラム目・・・イベントの開始時刻
//2カラム目・・・イベントのID
var EVENT_START_TIME_COLUMN = 1;
var EVENT_ID_COLUMN = 2;

//------------------------------------------
//カレンダーにひもづくGmailのメールアドレス
var MAIL_ADDR = "******@gmail.com";
//ChatWorkのAPIトークン
var CHATWORK_API_TOKEN = "******";
//------------------------------------------

//何分前に通知するか
var WHAT_MINUTES_AGO = 3;

var now;

//チャットワークに開始直前のGoogleカレンダーのイベントを通知します。
//同じイベントを何度も通知しないよう、スプレッドシートに通知済みのイベントを登録します。
function notify() {
  //通知日時以内に始まる自分のイベントを取得
  now = new Date();
  var future = new Date(now.getTime() + (WHAT_MINUTES_AGO * 60 * 1000));
  var events = CalendarApp.getDefaultCalendar().getEvents(now, future);
    
  //ChatWorkClientの作成
  var client = ChatWorkClient.factory({token: CHATWORK_API_TOKEN });
  
  //スプレッドシートの取得
  var sheet = SpreadsheetApp.getActiveSheet();
  //通知済みとしてスプレッドシートに記録されているイベントで現在時刻よりも前に開始したものをクリア
  clearOldEventOnSpreadSheet(sheet);
  
  //取得できたイベント数分繰り返す
  events.forEach(function(event) {
    //すでに開始済みのイベントをスキップ
    if(event.getStartTime().getTime() <= now.getTime()){
      return;
    }
    
    //通知済みでないイベントをチャットワークに通知
    if(alreadyNotifiedEvent(sheet, event) == false){
      Logger.log("イベント:" + event.getId() + "を通知します。");
      
      //ChatWorkのマイチャットへ通知
      Logger.log(createMessage(event));
      client.sendMessageToMyChat(createMessage(event));
      //通知済みであることをスプレッドシートに記録
      writeEventIdAndStartTime(sheet,event)
      
    }else{
      Logger.log("すでに通知済みのイベント:" + event.getId() + "をスキップします。");
    }
  }); 
}

//ChatWorkへ通知するメッセージの組み立て
function createMessage(event) {
  var startDate = event.getStartTime();  
  var endDate = event.getEndTime();
  var title = event.getTitle();
  var location = event.getLocation();
  
  var msg = "【Googleカレンダー通知】";
  msg = msg + getDateString(startDate);
  msg = msg + "から" + title;
  if(location != ""){
    msg = msg + "[" + location + "]";
  }
  msg = msg + "が始まります";
  return msg;
}

//日時の組み立て
function getDateString(date){
  var hour = date.getHours();
  var minutes = date.getMinutes();
  if(minutes == 0){
      return hour + "時";
  }else{
      return hour + "時" + minutes + "分";
  }
}

//スプレッドシートに記録されたイベントの中から24時間以上前に開始したイベントを削除し開始時刻順にソート
function clearOldEventOnSpreadSheet(sheet){  
  //24時間以前の通知を削除
  var lastRow = sheet.getLastRow();
  for(var row = 1; row <= lastRow; row++){
    var startTime = sheet.getRange(row, EVENT_START_TIME_COLUMN).getValue();
    var startTimeDate = Date.parse(startTime);
    
    //イベントの開始時刻が現在時刻よりも後であればクリア
    if(startTimeDate < now.getTime()){
      //特定行の1,2カラムの値を削除
      var range = sheet.getRange(row, 1, 1, 2);
      range.clear();
    }
  }
  //スプレッドシートをイベントの開始時刻順にソート
  sheet.sort(EVENT_START_TIME_COLUMN);
}

//イベントがすでに通知済みとしてスプレッドシートに記載されていたらtrueを返却
function alreadyNotifiedEvent(sheet, event){
  var lastRow = sheet.getLastRow();

  for(var row = 1; row <= lastRow; row++){
    var eventId = sheet.getRange(row, EVENT_ID_COLUMN).getValue();

    //Idがすでにスプレッドシートに登録済みであればtrue
    if(eventId == event.getId()){
      return true;
    }
  }
  return false;
}

//スプレッドシートにイベントの開始時刻とイベントIDを記録
function writeEventIdAndStartTime(sheet, event){
  var lastRow = sheet.getLastRow();
  sheet.getRange(lastRow + 1, EVENT_START_TIME_COLUMN).setValue(event.getStartTime());
  sheet.getRange(lastRow + 1, EVENT_ID_COLUMN).setValue(event.getId());
}

8行目にGoogleカレンダーと紐づいたGoogleのメールアドレスを、10行目に自分のチャットワークAPIのAPIトークンを設定してください。 設定できたら、「ファイル」>「保存」でスクリプトを保存します。

スクリーンショット 2017-07-02 14.43.34

ChatWorkClient for Google Apps Scriptをライブラリに登録する

今回は、以下で紹介されているライブラリを使用してChatWorkへの連携を行います。

チャットワークAPI を Google Apps Script で使ってみた | チャットワーククリエーターズブログ

「リソース」>「ライブラリ」から、ライブラリを登録します。 スクリーンショット 2017-07-02 14.39.34

ChatWorkClient for Google Apps ScriptのプロジェクトキーはM6TcEyniCs1xb3sdXFF_FhI-MNonZQ_sTです。

バージョンを指定し保存します。本記事作成時点の最新バージョンは18でした。 スクリーンショット 2017-07-02 14.39.50

実行してみる

関数を「notify」に設定し、再生ボタン▶︎をクリックします。 スクリーンショット 2017-07-02 14.40.23

初回実行時は、以下の承認を求められるので許可します。

  • カレンダーの管理
  • Google ドライブのスプレッドシートの表示と管理
  • 外部サービスへの接続

Googleカレンダーの予定がChatWorkに連携されるか試してみる

Googleカレンダーに3分以内に始まる予定を登録します。 スクリーンショット 2017-07-02 16.47.55

再度再生ボタン▶︎をクリックすると、ChatWorkに通知が来ました。 スクリーンショット 2017-07-02 14.58.41

定期的に実行する

自動で通知させるため、定期実行の設定をします。 「編集」>「現在のプロジェクトのトリガー」から定期実行の設定をします。 スクリーンショット 2017-07-02 15.00.02

それぞれの値は以下を設定してください。

  • 実行:notify
  • イベント:時間主導型、分タイマー、1分ごと スクリーンショット 2017-07-02 16.21.48

設定が完了すると、イベントの3分前に自動でChatWorkに通知が来るようになります。

感想

思ったより簡単にできました。JavaScriptがなんとなくわかればかなりいろんなことができそうです。

今回は通知したイベントを再度通知しないためにスプレッドシートに通知を記録し、記録されていたらスキップ、ということをしています。 スプレッドシートじゃなくてもっと安直にデータを記録できる何かがあればいいのになと思ったので、気が向いたらスプレッドシートを意識せずに使えるデータの保存場所(実態はスプレッドシート)を作ってみようかなと思います。

最終的にChatWork以外何も見なくてもなんとかなるようになったらいいなと思うので、次回はChatWorkとGitHubと連携させてみたいと思います。

弊社ブログでは他にもGoogle Apps Script、ChatWorkについて色々紹介しています。

Google Apps Script | Developers.IO

ChatWork | Developers.IO

私からは以上です。