LINEAPI・GASを使ってゴミ出し通知・応答Botを作ってみた

初めての投稿です。。。

# 開発動機
燃えるゴミは毎週なので忘れないけど、燃えないごみ等は第Xの木曜日だったりして
いつも忘れてしまうので、対象のゴミ出しの日になったらLINEに通知を送ってくれるBOTがあれば忘れないと思い
作成を始めました。
最初は通知のみの機能を予定していましたが、
メッセージをBOTへ送信したら、ゴミの日を返答してくれる機能もあるといいなと思い
こちらも合わせて開発しました。

# なぜGASなのか
* スプレットとの連携が行いやすい
* サーバーを自前で建てる必要がない
* GASのトリガーで定期的に実行できる

上記の理由でGASで作成しました。

# 準備

### LINE@の準備
LINEAPIを使用するには、LINE公式アカウントの準備が必要で
以下情報を参考に設定させていただきました。

https://auto-worker.com/blog/?p=5117

### スプレットの準備
スプレットの関数[IMPORTHTML](https://support.google.com/docs/answer/3093339?hl=ja)
を使用して
https://www.city.fukuoka.lg.jp/kankyo/kateigomi/life/007hakata.html
よりゴミ出しの日を取得し、スプレットへ転記

:::note info
=IMPORTHTML("https://www.city.fukuoka.lg.jp/kankyo/kateigomi/life/007hakata.html","table",1)
:::
実際のスプレットはこんな感じになります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2214838/aac959fb-2a32-7370-0a28-a40460f92768.png)

A1セルにURLをセットしており
A2セルに上記関数をセットしてます。

# 実装

実際のコードはGitHubに上げましたので、よろしければご覧下さい。

https://github.com/link9080/LINETrashNotification

# 仕様
* スプレットのF1セルに明記している町名のゴミの日を通知・応答
* G2~I2までのセルに入力された文字をユーザーから受け取ると、対象のゴミの日を応答する。

# 詰まった点

### GASからLINEAPIを呼び出しメッセージを送信する
LINE公式アカウントより友だち登録されたユーザIDを取得するには
LINE認証アカウントもしくはプレミアムアカウントが必要らしく

https://developers.line.biz/ja/reference/messaging-api/#get-follower-ids

それ以外で取得するには、
友達登録したユーザーよりメッセージを送ってもらい、
送られたWebhookよりIDを取得する必要があるみたいです。

https://developers.line.biz/ja/docs/messaging-api/getting-user-ids/#get-user-ids-in-webhook

なのでメッセージが送られたら、スプレットへユーザーIDを取得する
仕組みを作成しました。
```javascript:
 // WebHookで取得したJSONデータをオブジェクト化し、取得
  let eventData = JSON.parse(e.postData.contents).events[0];

  //postから受け取ったオブジェクトからユーザーIDとタイムスタンプを取得しスプレットに退避
  let userId = eventData.source.userId;
  let timestamp = eventData.timestamp;
  let sheet = spreadSheetByActive.getSheetByName("シート2")
  let row = sheet.getLastRow()

  //2行目からIDを検索し存在する場合は、追加しない
  let idrange = sheet.getRange(2, 1, row).getValues().flat();

  if (idrange.indexOf(userId) === -1) {
    sheet.getRange(row + 1, 1).setValue(userId)
    sheet.getRange(row + 1, 2).setValue(timestamp)
  }
```
上記コードでスプレットへユーザーIDを溜め込み
GASからメッセージを送る際はスプレットのユーザーIDへ送信するような
作りにしました。
```javascript:
//メッセージを送る際スプレッドシートからIDを取得して送信する
  let sheet = spreadSheetByActive.getSheetByName("シート2")
  let row = sheet.getLastRow()
  let idrange = sheet.getRange(2, 1, row).getValues().flat();
  idrange = idrange.filter(item => item != "");
  if (idrange.length != 0) {
    idrange.forEach(function (item) {
      var postData = {
        "to": item,
        "messages": [
          {
            'type': 'text',
            'text': text,
          }
        ]
      };

      var options = {
        "method": "post",
        "headers": headers,
        "payload": JSON.stringify(postData)
      };

      UrlFetchApp.fetch(url, options);
    })
  }
```

# 完成して
現在運用を行っており
GASのトリガーにより、毎日ゴミの日判定を動くようにし
対象のゴミの日の場合は、LINEAPIにメッセージを投げるようにしてます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2214838/8cbaff6d-033b-7347-d910-a74b1964a3f9.png)


公式アカウントの機能としてリッチメニューという機能が用意されており
下記サイトにアクセスすることで
このようなトークルームへ変更することが可能です。

https://manager.line.biz/account/

![Screenshot_20230124-230301.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2214838/f9eaab5b-3305-98e4-5b4f-61b90a6f75de.png)

各メニューを押下することで、対象のゴミの日を返答してくれるように
しました。

初めてGAS＋APIを使った開発を行いましたが、GASからAPIへ応答をする際に
エラーが起こってもログを吐いてくれないなどがあり、なかなか手こずりましたが
(スプレットへログを吐いたりしてデバッグを行ってました・・・

無事完成までたどり着けたので良かったです。
もしご指摘やご意見などありましたら遠慮なくお願いします。