繰り返しの予定を通知するLINE botを作ってみたよ

本記事は以下の記事を参考に、プログラミング初心者がLINE Botを作ってみた勉強レポです。
[ゴミの日も記念日も何でも通知してくれるLINE BotをGASで作ってみよう](https://qiita.com/commojun/items/363b8b9f41b78d00ca3c)

# はじめに自己紹介
みなさんこんにちは！
Progateで広報を担当しているおおつぶらいです🍢<br>
今回はPathチームやユーザーのみなさんに混ぜてもらい、初めてのアドベントカレンダーに参加します！

- **お名前：** 大粒来 美穂（おおつぶらい みほ）
- **所属：** 株式会社Progate
- **お仕事：** 広報・PR

実は私はエンジニア職ではないのですが、半ば趣味として制作したLINE Botについてまとめてみたいと思います。


# なにしたの？
ごみの日や請求書の発行など、毎週・毎月繰り返しリマインドして欲しい予定をお知らせしてくれるLINE Botを作成しました。
名付けて **「お知らせくん」** です。

![スクリーンショット 2023-12-05 14.21.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620092/16d6b188-20be-3f0b-c039-c206f00415d4.png)

# きっかけ
Progateの元社員の方がTwitterで同じようなLINE Botを作成していたことでした。
「これは便利だぞ！」と思い、私も真似して作ってみることに…。

# 作り方
今回使うものは、以下の4つです。

1. Google SpreadSheet
1. Google AppScript（以下、GAS）
1. LINE Messaging API
1. LINE

<br>

仕組みとしては、
1. Google SpreadSheetをマスターとして、お知らせ内容や日程を登録する。
1. GASでLINEに通知を飛ばす。

という流れです。

今回はこちらの記事のコードをベースお借りして作っていきます。
[ゴミの日も記念日も何でも通知してくれるLINE BotをGASで作ってみよう](https://qiita.com/commojun/items/363b8b9f41b78d00ca3c)

## LINE Messaging APIを用意する
詳しい説明は省略させていただきます。こちらの公式ドキュメントをご参照ください。
「5.チャネルを確認する」まで完了させましょう。
[Messaging APIを始めよう](https://developers.line.biz/ja/docs/messaging-api/getting-started/)



## マスターのSpreadSheetを作る
まずは通知内容やタイミングを管理するためのスプレッドシートを作ります。
内容はこんな感じです。
- A列〜G列：通知タイミングや頻度を指定
- H列：通知内容を指定
- I列〜J列：通知先のLINEグループを指定

J列「グループ名」は通知の仕組みには関係ありませんが、通知先のグループが複数ある場合にも分かりやすいように記載しています。


![スクリーンショット 2023-12-05 14.44.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620092/a1f2d28c-7376-6dc3-24b0-5871a874f46b.png)



## GASを用意する
作成したマスターのスプレッドシートのメニューバーから【拡張機能 > AppScript】を開きます。

今回、参考記事のコードを使用させていただいているので、コードの各部分がどんな役割なのかを解説していこうと思います。

### アクセストークンとシートの指定
まずはアクセストークンと、取得対象となるスプレッドシートのキーを定義します。
~~~javascript
// 「メッセージ送受信設定」のアクセストークン（ロングターム）を記入。
var ACCESS_TOKEN = '{YOUR_ACCESS_TOKEN}';

// 発言させたい日時と内容が書かれたシートのKeyを記入してください。
// シート名には「alarm」としてください。
var SHEET_KEY = '{YOUR_SHEET_KEY}';
~~~

### JSONをパースする
GASとLINE Messaging APIでメッセージをやり取りするために、
- LINE MessagingAPIから送られてきた文字列をGASが扱えるようにするために、JSONをパースする
- GASからLINE Messaging APIに文字列を送るために、GASのメッセージをJSON文字列に戻す


という処理が必要になります。

~~~javascript
function doPost(e) {
    //「JSON.parse」メソッドでJSONをパースする
    var event = JSON.parse(e.postData.contents).events[0];
    var userMessage = event.message.text;

    var message = "";
    //「ID」というメッセージを受信したことを判定する  
    if ( userMessage === "ID" ) {
    message = tellID(event);
    }

    //「JSON.stringify」メソッドでGASの文字列をJSON文字列に変換する
    replyMessage(event.replyToken, message);
        return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}
~~~

### 応答メッセージを送る
応答メッセージを送信する部分です。LINE Messanger APIのエンドポイントを使用します。
詳しくはこちらのリファレンスに記載があるので、興味のある方はご参照ください。
[Messaging APIリファレンス](https://developers.line.biz/ja/reference/messaging-api/#send-reply-message)

~~~javascript
function replyMessage(token, message) {
  UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'muteHttpExceptions': true,
    'payload': JSON.stringify({
      'replyToken': token,
      'messages': [{
        'type': 'text',
        'text': message,
      }],
    }),
  });
}
~~~

### 任意のタイミングでメッセージを送信する
こちらもLINE Messanger APIのエンドポイントを使用して、プッシュメッセージの送信を指示します。
~~~javascript
function pushMessage(to, message) {
  UrlFetchApp.fetch('https://api.line.me/v2/bot/message/push', {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'muteHttpExceptions': true,
    'payload': JSON.stringify({
      'to': to,
      'messages': [{
        'type': 'text',
        'text': message,
      }],
    }),
  });
}
~~~

### IDを返す

JSONをパースするパートで、「ID」というメッセージが送られてきた場合に自分のIDとグループチャットのIDを送信する、というif文がありました。
ここのtellID関数で、IDを返すメッセージを指定します。

~~~javascript
function tellID(event) {
  // ID
  var userID = event.source.userId;
  var talkID = "";
  if (event.source.type === "group") {
    talkID = event.source.groupId;
  } else if (event.source.type === "room") {
    talkID = event.source.roomId;
  }

  var message = "あなたのID: " + userID;
  if (talkID != "") {
    message += "\nこのチャットのID: " + talkID;
  }

  return message;
}
~~~


### 通知を送る
いよいよ通知を送信する部分です。
スプレッドシートから通知タイミングや内容を取得し、送付有無を判別します。

~~~javascript
function notice() {
  //シートを取得
  var sheet = SpreadsheetApp.openById(SHEET_KEY).getSheetByName('alarm');
  //通知する内容を取得
  var data  = sheet.getDataRange().getValues();

　　　//通知タイミングを取得 
　　　//曜日の文字列を取得
  var dayStr = ["日", "月", "火", "水", "木", "金", "土"];
  //スプレッドシートA列〜G列より日時、送付内容、宛先を取得
  var now = new Date();
  for (var i=1; i<data.length; i++) {
    var [year, month, dayOfMonth, weekNum, dayOfWeek, hour, minute, message, to] = data[i];

    // 本文と発言する場所が空の場合はスキップ
    if (message === "" || to === "") { continue; }

    //取得した送付日時を判別し、通知を送付
    if ( (year       ==  now.getFullYear()               || year       === "")
      && (month      ==  now.getMonth() + 1              || month      === "")
      && (dayOfMonth ==  now.getDate()                   || dayOfMonth === "")
      && (weekNum    ==  parseInt(now.getDate() / 7) + 1 || weekNum    === "")
      && (dayOfWeek  === dayStr[now.getDay()]            || dayOfWeek  === "")
      && (hour       ==  now.getHours()                  || hour       === "")
      && (minute     ==  now.getMinutes()                || minute     === "")
      ) {
        pushMessage(to, message);
      }
  }
}
~~~

これでGASのコードができました。

# LINEと連携する
GASのコードを保存し、右上の【デプロイ > 新しいデプロイ】を選択します。

![スクリーンショット 2023-12-05 16.44.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620092/b4ccaec1-5045-7095-c9c4-4424816fa512.png)


出てきたポップアップで種類「ウェブアプリ」を選択、名前、実行やアクセスの権限は任意で変更してください。
今回は私がアクセスできれば問題ないので、全て自分のみの実行・アクセス権限にしています。
設定ができたら【デプロイ】をぽちっとします。

![スクリーンショット 2023-12-05 16.45.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620092/44d0a53e-2e4f-dfc1-4a3c-537c038e52bd.png)

最後に、表示されたウェブアプリのURLをコピーします。

![スクリーンショット 2023-12-05 16.47.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620092/2e9a6628-1309-a148-8442-51a908362add.png)


ここで、LINE Developersに移動し、はじめに作成したチャネルの【Messaging API】のタブを開きます。
Webhook settingの部分にコピーしたURLを貼り付け、「Use webhook」を有効にして保存します。
「接続確認」が成功したら完了です！

![スクリーンショット 2023-12-05 16.53.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620092/3546fc96-4b17-70e6-3c18-95fdd2251a80.png)


## IDを教えてもらい、スプレッドシートで通知を設定する
お知らせくんとのグループチャットを作成し、「ID」というメッセージを送るとグループチャットのIDを教えてくれるはずです。
「このチャットのID」をマスターのスプレッドシートのI列に記載しましょう。

![スクリーンショット 2023-12-05 16.57.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620092/01f9b5ad-eb35-90b1-4ddf-1a3316e290f8.png)

## GASの実行トリガーを設定する

またまたGASに移動し、左側のメニューバーから【トリガー】を選択します。

![スクリーンショット 2023-12-05 17.02.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620092/8523cfcf-a6c8-335b-a453-c38a696c3400.png)

右下の【トリガーを追加】を選択し、今回は分単位で通知が飛ばせるように毎分実行されるように設定します。
設定できたら保存しましょう。
この後、指定した日時に通知が飛ぶようになったら成功です🎉

![スクリーンショット 2023-12-05 17.03.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620092/f827ef2f-1a80-dab0-597c-5cdd910fb063.png)


# まとめ
今回は初めてのLINE Bot作成にチャレンジしました。
実は1年近く前に作って使っていたものでほぼ参考記事からお借りしたコードの踏襲なのですが、今回アドベントカレンダーを書くにあたってコードの意味を解読したり手順を見直したりなど、改めて勉強になりました。

これを作成した後、「Google Formの回答内容をLNEに飛ばすBot」も作っているので、いつかこちらもネタにできたらいいなと思います。

ちなみに、今回Botのアイコンとなっているのは私が書いたメガホンの妖精「お知らせくん」です笑

![Sketches.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620092/5e83758e-323e-92ce-92e3-965a972343ee.png)

それでは今日はこの辺で。
明日のアドベントカレンダーもぜひお楽しみに！