株式会社GENZが運営する技術ブログです。

  1. Google Apps Script
  2. 978 view

GASでGoogleチャットに流すリマインダーを作ってみた

リマインダーが欲しい!

「毎朝10時05分に、固定メッセージのリマンダーをGoogleチャットに自動で流したい」
ある日、こんな相談が来ました。

よし!じゃあ

1. GAS(Google Apps Script)でGoogleチャットにメッセージを流すコードを作る
2. GASのトリガーで自動実行をセット

これでいけるでしょ😌

トリガーで「05分」が狙えない・・

1. GAS(Google Apps Script)でGoogleチャットにメッセージを流すコードを作る

これは何度も作ってる(使い回している)コードがあるから簡単。

function post2chat() {
  const webhook = 【Google Chatのアプリと統合 > Webhookから取得したWebhook URL】;
  const sendMessage = 【Google Chatで投稿したいメッセージ】;

  // 以下おまじないとしての固定コード
  const payload = {
    "text": sendMessage
  }
  const options = {
    "method": "POST",
    "headers": { "Content-Type": "application/json; charset=UTF-8" },
    "payload": JSON.stringify(payload),
    "muteHttpExceptions": true
  }
  UrlFetchApp.fetch(webhook, options)
}

 

2. GASのトリガーで自動実行をセット

次に、2のトリガー設定を・・・
って、考えたら日付ベースのタイマーの1時間毎だと、5分とか狙った「分」に実行できないぞ😵

「05」分の対策

日付ベースのタイマーでトリガーがセットできない。
じゃあ、「分」を狙ってのトリガー実行は出来ないかというと、そうでもない。
特定の日時のトリガーなら YYYY-MM-DD HH:MM で指定できるので05分を狙うことが可能。
ただ、それだと日付も指定しているので1回きりのトリガーになってしまう。

無理やり分ベースのタイマーで出来ないこともない。分ベースのタイマーは1分毎の実行も可能なので

  1. 分ベースのタイマーで1分間隔のトリガーにして毎分実行
  2. 毎分のGAS実行時に、狙った時間(今回であれば10時05分)以外は、GASの処理をやめる

これなら狙った時間に実行できるけど、無駄にGASを実行し続けるのもなんだかなぁ・・🤔

そう思ってネットを検索してみたら、こんな記事が!
GASで特定時刻を時間指定して繰り返し定期実行するトリガー登録方法!
なるほど!特定の日時のトリガーを毎日作るのか。

トリガー操作を実装

トリガーを作成する関数

では、まずさっそく特定の日付を設定するGASを作ってみる。

function setTrigger() {
  const today = new Date();
  // 時刻を指定
  today.setHours(10);
  today.setMinutes(5);
  
  // トリガーにセット
  ScriptApp.newTrigger(post2chat).timeBased().at(today).create();
}

8行目は「ScriptApp.newTrigger(【実行する関数】).timeBased().at(【実行日時】).create(); 」という形になります。
【実行する関数】で指定するのは、上で作ったGoogle Chatに投げる post2chat です。

次は、post2chatを実行する【実行日時】の設定です。
毎日実行して欲しいので、まず2行目の「const today = new Date();」でGAS実行の日時を取得します。
これで実行日(今日)の日時が取得できます。
次に 10時05分 に実行して欲しいので、new Date() で取得した today の日付を4行目(today.setHours(10);)、5行目(today.setMinutes(5);)で変更します。
これで、その日の10時05分実行のトリガーが作られるはずなので、この setTrigger 関数を実行してみましょう。
実行してから、トリガー画面を確認すると

トリガーができている!
一応中身も見てみると

ん???時間が 10:05 になっていない😵(ちなみにセットされている21:19はsetTriggerを実行した時間)
なぜぇぇぇ?と思いましたが、どうやら過去の日付をセット(今日の10:05を指定したので過去)した場合は、強制的に今の時間になるようです。
なのでsetTriggerは完成ということになります。

トリガーを削除する関数

トリガーが作成できればOKなのですが、上の参照したサイトにも書いてあったように、作りっぱなしにすると1度きりで使用済みのトリガーがどんどん増えてしまいます
そのため実行したトリガーは消す処理を入れましょう。

function deleteTriggers() {
  // 既存トリガーをすべて取得
  const triggers = ScriptApp.getProjectTriggers();
  // トリガーをすべて削除
  for (let i = 0; i < triggers.length; i++) {
    ScriptApp.deleteTrigger(triggers[i]);
  }
}

3行目の「const triggers = ScriptApp.getProjectTriggers();」で設定してあるトリガーを取得します。
取得したトリガー(triggers)にいくつトリガーが入っているか分からないので、5行目〜7行目でトリガーを一つずつ取り出して、6行目の「ScriptApp.deleteTrigger(triggers[i]);」で削除します。
トリガーの削除は以上です。

完成・・・・してない!?

最後に上で作った、トリガーを作る関数と削除する関数自体を毎日実行させる必要があるので、トリガー指定できるように関数を作ります。

function myFunction() {
  // トリガー作成前にトリガーがあったら消す
  deleteTriggers()
  // トリガーを作る
  setTrigger()
}

この myFunction を毎日実行するトリガーを作ったら完成!
・・・いや、違う。
その状態で deleteTriggers を実行したら、毎日実行するこのmyFunctionのトリガーも消えちゃう。
というわけで、deleteFunctionで消すトリガーを、特定の日時のトリガーだけ消すように変更します。

function deleteTriggers() {
  // 既存トリガーをすべて取得
  const triggers = ScriptApp.getProjectTriggers();
  // 既存トリガーをすべて削除
  for (let i = 0; i < triggers.length; i++) {
    if(triggers[i].getHandlerFunction() === 'post2chat') {
      ScriptApp.deleteTrigger(triggers[i]);
    }
  }
}

setTrigger 関数で指定した実行する関数名(post2chat)は、トリガーオブジェクトの getHandlerFunction で取得できます。
そのため、6行目のように getHandlerFunction が post2chat の時のみ削除するようにします。

よし、ようやく完成。

と思ったら、このままだと休みの日も実行されて、チャットに飛んじゃうので平日のみ動くようにします。
平日判定は、土曜、日曜の判定と、祝日はGoogleカレンダーの日本の祝日を利用すると実装できます。
まず土日判定。

function myFunction() {
  const today = new Date();

  if(today.getDay() !== 0 || today.getDay() !== 6) {
    deleteTriggers()
    setTrigger()
  } 
}

getDay() をすると曜日情報が取れ、曜日は以下の数値として入っています。

日曜 月曜 火曜 水曜 木曜 金曜 土曜
0 1 2 3 4 5 6

なので、getDayの結果、日曜日の0土曜日の6以外で実行すれば、平日での実行となります。

次に祝日ですが、祝日は

const calendar = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com');

このコードで、日本の祝日カレンダーを取得でき

const events = calendar.getEventsForDay(today);

このコードで、日本の祝日カレンダーの中の指定日(=今日)のイベントを取得します。
このカレンダーにはイベントとして、祝日(例えば、海の日とか)情報が入っています。
そのため、取得した events の中身を確認し、中身が空(=祝日情報がない)と祝日ではないとなります。

function myFunction() {
  const today = new Date();
  const calendar = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com');
  const events = calendar.getEventsForDay(today);

  if(events.length === 0) {
    // トリガー作成前にトリガーがあったら消す
    deleteTriggers()
    // トリガーを作る
    setTrigger()
  } 
}

ということで、土日祝を合体させると以下のようになります。

function myFunction() {
  // 土日祝を確認
  const today = new Date();
  const calendar = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com');
  const events = calendar.getEventsForDay(today);

  // events.lengthがあれば土日祝なのでトリガー設定を実行
  if(events.length === 0 || today.getDay() !== 0 || today.getDay() !== 6) {
    // トリガー作成前にトリガーがあったら消す
    deleteTriggers()
    // トリガーを作る
    setTrigger()
  } 
}

完成!

全コードは以下になります。
この myFunction を毎日任意の時間の日付ベースのタイマーのトリガー設定をすれば完成です!
お疲れ様でした!

function myFunction() {
  // 土日祝を確認
  const today = new Date();
  const calendar = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com');
  const events = calendar.getEventsForDay(today);

  // events.lengthがあれば土日祝なのでトリガー設定を実行
  if(events.length === 0 || today.getDay() !== 0 || today.getDay() !== 6) {
    // トリガー作成前にトリガーがあったら消す
    deleteTriggers()
    // トリガーを作る
    setTrigger()
  } 
}

// トリガーをセット
function setTrigger() {
  let today = new Date();
  // 時刻を指定
  today.setHours(10);
  today.setMinutes(5);
  
  // トリガーにセット
  ScriptApp.newTrigger('post2chat').timeBased().at(today).create();
}

// 既存トリガーを取得して削除
function deleteTriggers() {
  // 既存トリガーをすべて取得
  const triggers = ScriptApp.getProjectTriggers();
  // 既存トリガーをすべて削除
  for (let i = 0; i < triggers.length; i++) { if(triggers[i].getHandlerFunction() === 'post2chat') { ScriptApp.deleteTrigger(triggers[i]); } } } function post2chat() { // 開発テスト用 const webhook = 【Google Chatのアプリと統合 > Webhookから取得したWebhook URL】;

  const sendMessage = 【Google Chatで投稿したいメッセージ】;

  // 以下おまじないとしての固定コード
  const payload = {
    "text": sendMessage
  }
  const options = {
    "method": "POST",
    "headers": { "Content-Type": "application/json; charset=UTF-8" },
    "payload": JSON.stringify(payload),
    "muteHttpExceptions": true
  }
  UrlFetchApp.fetch(webhook, options)
}

GENZへのお問い合わせはこちら

レスポンシブ対応

Google Apps Scriptの最近記事

  1. GASでGoogleチャットに流すリマインダーを作ってみた

  2. 開発タスクフォースの活動紹介①~活動の様子~

  3. 開発タスクフォースを立ち上げました ~ プロローグ ~

関連記事