LINEボットのリッチメニューで、スプレッドシートの情報を教えてもらう

# 目的
LINEボットにリッチメニューを追加し、スプレッドシートの情報(日程情報、メンバーの出欠 ~~、天気予報（tenki.jpのスクレイピング）~~)を回答する機能を追加する。
![日程情報](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/b0b89871-83e1-3d76-85e2-a758cc00252b.png)
※ボットとの1対1トークだとリッチメニューが出る。
※グループトークだとリッチメニューは出ないが、コマンドには応答してくれる。
※2022年になってからtenki.jpがrequestsで取得できなくなった。記事を書き直すのも大変なので、そのまま公開する。詳しく調べてないが、たぶんUser Agentをチェックして応答を拒否していると思われる。

# 背景
前回記事「[LINEボットでチャット内容をメールに転送する](https://qiita.com/igapon1/items/559a89e669d6633eaa80)」に続き、趣味のグループについて、日程情報やメンバーの出欠~~や天気予報~~を、ボットが教えてくれたら便利かもしれないと思ったので、機能を追加してみた。

# 環境
- iPhoneX 14.4.2
 - LINE 11.6.5
- Google Apps Script(GAS) March 15, 2021
- Windows10 バージョン2004(OSビルド19041.928)
 - Google Chrome バージョン: 90.0.4430.93（Official Build） （64 ビット）

# 全体像
## ユースケース図
![uml_usecase_LINE_BOT_TOBA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/79ac9518-3b75-5d26-a4b6-a1f0eac2fb0b.png)
#### アクターの補足説明
GAS(Google Apps Script)トリガーとは、指定時刻になったり、スプレッドシートが更新されたら、GASを自動で実行してくれるトリガー機能とする。

## クラス図っぽいもの
![uml_class_LINE_BOT_TOBA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/55245de6-b41e-12bd-5904-3fa94e6e531e.png)
天気予報のスクレイピングはただの関数でやってるので、クラス図に出てこない。
他にもクラスに入ってないものがあるけどご愛敬。

# やったこと
1. ボットの作成などは前回記事「[LINEボットでチャット内容をメールに転送する](https://qiita.com/igapon1/items/559a89e669d6633eaa80)」でできているものとする
1. スプレッドシートの作成（名簿、日程 ~~、天気予報~~ 、リッチメニューのキャッシュ）
1. GASの作成
1. GASトリガーの設定
1. リッチメニューの画面を作成
1. リッチメニューを登録

##  ボットの作成などは前回記事でできているものとする
前回記事「[LINEボットでチャット内容をメールに転送する](https://qiita.com/igapon1/items/559a89e669d6633eaa80)」をリファクタしたコードを[GitHub LINE_BOT_TENSOU tag 1.0.2](https://github.com/igapon50/LINE_BOT_TENSOU/releases/tag/1.0.2)に用意した。(詳しくはReadme参照)

##  スプレッドシートの作成
ユースケースにもある以下の四つのスプレッドシートを作成して、IDとシート名をそれぞれ控える。

※スプレッドシートのURLは、以下の書式となっており、XXXXXXXの部分がIDになる。

```
https://docs.google.com/spreadsheets/d/XXXXXXX/edit
```

1. 名簿スプレッドシート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/994cfc80-3f7d-934c-2b04-db375d9df3b7.png)
※Q列の「LINEボット転送mai...」だけボットで使用している。

1. 日程情報スプレッドシート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/ace73eec-40dd-28e9-cc34-f2c12e9fa6db.png)
※1行目（F列以降）にはメンバーの名前が入っている。
※2行目以降がイベント予定で、E列が空欄になっているイベントはボットに無視される。
※2行目以降（F列以降）には出欠が入っている。

1. 天気予報スプレッドシート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/52a170c1-a287-a019-e471-00ebe2fe9ee0.png)
※2022年以降はスクレイピングできなくなったため、空のままである。

1. リッチメニュー応答文のキャッシュ用スプレッドシート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/55c44d9f-8278-6e15-0631-c9d676134285.png)

## GASの作成
そして、今回の機能追加したボットを[GitHub LINE_BOT_TOBA tag 1.0.2](https://github.com/igapon50/LINE_BOT_TOBA/releases/tag/1.0.2)に用意した。
チャンネルアクセストークンはスクリプトプロパティに設定する。以下はコードの利用箇所。

```
const CHANNEL_ACCESS_TOKEN = PropertiesService.getScriptProperties().getProperty('CHANNEL_ACCESS_TOKEN');
```
また、先に控えたスプレッドシートのIDとシート名をスクリプトプロパティに設定する。以下はコードの利用箇所。

```
// 「名簿」のスプレッドシート
const MEMBER_SPREADSHEET_ID = PropertiesService.getScriptProperties().getProperty('MEMBER_SPREADSHEET_ID');
const MEMBER_SHEET_NAME = PropertiesService.getScriptProperties().getProperty('MEMBER_SHEET_NAME');
// 「日程調整」のスプレッドシート
const SCHEDULE_SPREADSHEET_ID = PropertiesService.getScriptProperties().getProperty('SCHEDULE_SPREADSHEET_ID');
const SCHEDULE_SHEET_NAME = PropertiesService.getScriptProperties().getProperty('SCHEDULE_SHEET_NAME');
// 「天気予報」のスプレッドシート
const FORECAST_SPREADSHEET_ID = PropertiesService.getScriptProperties().getProperty('FORECAST_SPREADSHEET_ID');
const FORECAST_SHEET_NAME = PropertiesService.getScriptProperties().getProperty('FORECAST_SHEET_NAME');
// 「リッチメニュー」のスプレッドシート
const RICHMENUS_SPREADSHEET_ID = PropertiesService.getScriptProperties().getProperty('RICHMENUS_SPREADSHEET_ID');
const RICHMENUS_SHEET_NAME = PropertiesService.getScriptProperties().getProperty('RICHMENUS_SHEET_NAME');
```

## GASトリガーの設定
~~以下の画面イメージの様に、指定時刻のトリガーを仕掛ける。~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/f2f00a28-765c-d21a-0066-fee2118d0332.png)
~~getForecastFromUrlToSpreadsheet() は、ユースケースの「天気予報スプレッドシート」にある「tenki.jpから10日間天気予報を取得して、スクレイピングして、スプレッドシートを更新」する処理である。私は12時間毎に起動させている。ちなみに石川県七尾市の天気予報をとってきているので、変えたい場合は、コードの以下のgetUrlを変更する。~~

```
  //tenki.jpから10日予報取得
  let getUrl = 'https://tenki.jp/forecast/4/20/5620/17202/10days.html';
```

~~updateRichMenuAll() は、ユースケースの「リッチメニュー応答文のキャッシュ用スプレッドシート」にある「新しいリッチメニュー応答文で、スプレッドシートを更新」する処理である。こちらも12時間ごとに起動させている。~~

また、日程情報スプレッドシートが変更されたら、キャッシュ用スプレッドシートを更新しなおす必要がある。日程情報スプレッドシートのスクリプトエディタで、以下の画面イメージの様なonChange()にupdateRichMenuAll()を設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/ddedcb55-97e1-6273-1251-0a08415a846f.png)

## リッチメニューの画面を作成
リッチメニューに使う、四分割画像を用意するために、元となる画像を４枚用意して、１枚の画像に合成する。
使い慣れたツールがなければ、ブラウザで[画像結合ツール](https://photocombine.net/cb/) にアクセスして画像を合成する。

リッチメニューの文字を画像に埋め込む。
使い慣れたツールがなければ、ブラウザで[画像にウォーターマークを挿入するツール](https://photocombine.net/watermark/)にアクセスして、画像に文字を埋め込む。

作成した画像をGoogleDriveに保存してリンクを取得する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/03b09dca-2411-ff5b-04a0-0e8d6d4588a3.png)
リンクの<ファイルID>部分を、後の「リッチメニューを登録」に使用する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/dc0a6dcb-87d6-7b2a-0e7b-f671bbc68926.png)

※GoogleDriveで共有リンクを生成すると以下のURLとなる

```
https://drive.google.com/file/d/<ファイルID>/view?usp=sharing
https://drive.google.com/open?id=<ファイルID>
```

## リッチメニューを登録
1. 先の章でGoogleDriveに保存したリッチメニュー画像のファイルIDを、GASのスクリプトプロパティDRIVE_FILE_IDに登録する
1. GASの「LINEボットMessageingAPI.gs」を開く
1. myMakeRichMenu()を選択し実行する
1. mySetDefaultRichMenu()を選択し実行する

# 使い方
1. GitHubから[1.0.2](https://github.com/igapon50/LINE_BOT_TOBA/releases/tag/1.0.2)をダウンロードする
1. ダウンロードしたファイルを解凍する
1. GoogleDriveにスクリプトファイル(GAS)を作り、解凍したファイルからコピペなどして同じ内容になるようにする※
1. GoogleDriveに以下のスプレッドシートを作成する(本文を見てヘッダーをそろえること)
 - ~~天気予報~~
 - リッチメニュー
 - 日程調整
 - 名簿
1. 作成したスプレッドシートやファイルのIDを調べる
1. GASに以下のスクリプトプロパティを作成する
 - CHANNEL_ACCESS_TOKEN：チャンネルアクセストークン
 - FORECAST_SPREADSHEET_ID：天気予報スプレッドシートのID
 - FORECAST_SHEET_NAME：天気予報スプレッドシートのシート名
 - RICHMENUS_SPREADSHEET_ID：リッチメニュースプレッドシートのID
 - RICHMENUS_SHEET_NAME：リッチメニュースプレッドシートのシート名
 - SCHEDULE_SPREADSHEET_ID：日程調整スプレッドシートのID
 - SCHEDULE_SHEET_NAME：日程調整スプレッドシートのシート名
 - MEMBER_SPREADSHEET_ID：名簿スプレッドシートのID
 - MEMBER_SHEET_NAME：名簿スプレッドシートのシート名
 - DRIVE_FILE_ID：リッチメニュー画像のファイルID
1. リッチメニュースプレッドシートにシート名「ログ」を追加する
1. GASに以下のライブラリを追加する
 - Moment
 - Parser
1. GASに以下のトリガーに設定する
 - ~~getForecastFromUrlToSpreadsheet：10日間天気予報をスクレイピングして天気予報スプレッドシートを更新する(七尾市和倉町の10日間天気予報を対象にスクレイピングするので、変えたい場合はgetUrlにセットするURLを変更する)~~
 - updateRichMenuAll：リッチメニューの応答文を更新する
1. 日程調整スプレッドシートのonChange()にupdateRichMenuAll()を設定する
1. リッチメニューの画面を作成する
1. リッチメニューを登録する

※もっと良い方法があれば、教えていただけると助かります。

# おわりに
今回、応答文のキャッシュをスプレッドシートに持たせたが、リッチメニューの応答は、タップ後3秒ぐらいかかっている。とても遅く感じるので、Jsonに持たせるとか他の方法にした方がよさそうだ。ただし、スプレッドシートは分かりやすくてとても勉強になったので、趣味のレベルで今後も活用したい。

# リンク
## 使用ツールサイト

1. photocombine.net さん
 - [画像結合ツール](https://photocombine.net/cb/)
 - [画像にウォーターマークを挿入するツール](https://photocombine.net/watermark/)

## 参考サイト
1. タカハシさん
 - [【保存版】初心者向け実務で使えるGoogle Apps Script完全マニュアル](https://tonari-it.com/google-apps-script-manual/)
1. luthさん
 - [【GAS/LINE】リッチメニューをMessaging APIで作りてぇ…！](https://note.com/luth/n/ne6d340cec623)
1. @baby-degu さん(原著Atit さん)
 - [2021年に知っておきたいJavaScript最適化技術34選](https://qiita.com/baby-degu/items/396edbaefea64140a5d0?utm_source=Qiita%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9&utm_campaign=5f6890a642-Qiita_newsletter_465_06_09_2021&utm_medium=email&utm_term=0_e44feaa081-5f6890a642-33718969#1-%E8%A4%87%E6%95%B0%E3%81%AE%E6%9D%A1%E4%BB%B6%E3%82%92%E6%8C%81%E3%81%A4if)

## ドキュメント
- [LINE Developersドキュメント](https://developers.line.biz/ja/docs/)
- [Google Apps Script Reference](https://developers.google.com/apps-script/reference)