LINENotify・IFTTT・GooleAppScriptでお手軽LineBotを作った

## 概要

LINENotify・IFTTT・GooleAppScriptを使って、明日のゴミとその担当をお知らせするBOTの作り方。

正確には、ボット: BOT(双方向のコミュニケーション)ではなく通知。

これを応用すれば、ゴミ捨て当番の担当のお知らせだけではなく、
好きなお知らせをLINEに送付できるようになるかと。

## やりたかったこと

私の家では、週次でこみ捨ての当番が変わります。

ただ、「今日誰がゴミ当番だったか」、「明日のゴミはなんだったか」、忘れられちゃうので、それを防止するために、LINEグループに明日のゴミを通知できればいいなという話になりました。

## できるようになったこと

- 毎日決まった時間に、LineNotifyから明日のLine通知を送る。

- 日曜日になったら、ゴミ捨て担当を変えて通知する。

## ざっくりした構成

使用したものは、LineNotify・ITFFF・GoogleAppScript・GoogleSpreadSheetです。

- GoogleSpreadSheet: データベース。今週の当番を保存しておく
- GoogleAppScript: ロジックの作成。データベースの書き換え。時間ごとの実行。URLのフェッチ。
- IFTTT: WebhooksとLineNotify(ルームかグループチャット)の連携
- LineNotify: 招待されているルームかチャットに内容を通知。

ちなみに、Webhooksはほぼ、ルームごとにメッセージを投げるためにしか使っていません。
APIというわけではありません。。。。

## GoogleSpreadSheetの内容

名前の一覧と、今週の担当者にTRUEを振っておく

| Name | isPIC | 
| -- | -- | 
| NAME1 | FALSE |
| NAME2 | TRUE |
| NAME3 | FALSE |
| *** | FALSE |
| *** | FALSE |

また、URLの末尾から、SpreadSheetのKeyを取得しておく。

## GoogleAppScriptの内容

はじめてGASを作成したので汚さ満載ですが、動けばいいということで。

(本来はGASではあまりClassとか使わないらしいですね)

やっていることは

- 明日の曜日を取得する
  - 日曜日ならスプレッドシートの担当者を変えて通知する
  - 登録されたゴミがあれば通知する 
- この関数をケジュールで毎日18-19時に実行設定しておく

```javascript
class Trash {
    constructor() {
      this.monday = "<月曜日のゴミ>";
      this.tuseday = "<火曜日のゴミ>";
      this.wednesday = "<水曜日のゴミ>";
      this.thursday = "<木曜日のゴミ>";
      this.friday = "<金曜日のゴミ>";
      this.saturday = "<土曜日のゴミ>";
      this.sunday = "<日曜日のゴミ>";
    }

  getTrash(weekNum) {
      let trash = ""
      if (weekNum === 1) {
        trash = this.monday}
      else if (weekNum === 2) {
        trash = this.tuseday}
      else if (weekNum === 3) {
        trash = this.wednesday}
      else if (weekNum === 4) {
        trash = this.thursday}
      else if (weekNum === 5) {
        trash = this.friday}
      else if (weekNum === 6) {
        trash = this.saturday}
      else{
        trash = this.sunday}
      return(trash)
    }

    getTomorrowTrash(weekNum)
    {return this.getTrash(weekNum + 1)}
  }

function getTodayWeekNum() {
  const date = new Date();
  const dayOfWeek = date.getDay();
  return dayOfWeek
  }

function getThisWeekPerson(sheet, nameColumn, trashColumn) {
  const lastRow = sheet.getLastRow();
  let thisWeekPerson = "";
  for(let i = 2; i <= lastRow; i++) {
    let cell = sheet.getRange(i, trashColumn)
    let cellValue = cell.getValue()
    if(cellValue === true){ 
      let cellOfThisWeekPerson = sheet.getRange(i, nameColumn);
      thisWeekPerson = cellOfThisWeekPerson.getValue();
    }
  }
  return thisWeekPerson
}

function changePersonToNext(sheet, nameColumn, trashColumn) {
  const lastRow = sheet.getLastRow();
  let currentTrueTrashCell = null;
  for(let i = 2; i <= lastRow; i++) {
    let cell = sheet.getRange(i, trashColumn)
    let cellValue = cell.getValue()
    if(cellValue === true){ 
      currentTrueTrashCell = cell
      cell.setValue(false)
    }
  }
  let isBottomCell = currentTrueTrashCell.activate().offset(1,0).isBlank();
  if (isBottomCell) {
    sheet.getRange(2, trashColumn).setValue(true);
    }
  else {
    currentTrueTrashCell.offset(1, 0).setValue(true);
  }
}

function notifyChangePerson(url, pic) {
  const data = {
    'value1': 'ゴミ当番交代のお知らせです。<br> 来週のゴミ当番: ' + pic,
  };
  const options = {
    'method' : 'post',
    'contentType': 'application/json',
    'payload' : JSON.stringify(data)
  };
  UrlFetchApp.fetch(url, options);
  Logger.info("[info]  URL FETCHED:" + url)
}

function notifyTomorrowTrash(url, trash, pic){
  const data = {
    'value1': '明日のゴミのお知らせです。<br> 明日のゴミ: ' + trash + '<br>現在のゴミ当番:' + pic,
  };
  const options = {
    'method' : 'post',
    'contentType': 'application/json',
    'payload' : JSON.stringify(data)
  };
  UrlFetchApp.fetch(url, options);
  Logger.info("[info]  URL FETCHED:" + url)
}

function getSpreadSheetKey () {
  return "SPREAD_SHEET_KEY"
}

function getIftttKey() {
  return "IFTTT_KEY"
}

function getEventName(event_name) {
  const EVENT_NAME1 = "EVENT_NAME1";
  if (event_name === EVENT_NAME1) {
    return EVENT_NAME1; 
  }
}

function myFunction() {
  const SPREAD_SHEET_TAB_NAME = 'Residents';
  const EVENT_NAME = "message_to_me";

  const nameColumn = 1;
  const trashColumn = 2;

  const spreadSheetKey = getSpreadSheetKey();
  const residentsSheet = SpreadsheetApp.openById(spreadSheetKey).getSheetByName(SPREAD_SHEET_TAB_NAME);
  const lineUrl = "https://maker.ifttt.com/trigger/" + getEventName(EVENT_NAME) + "/with/key/" + getIftttKey();

  const trash = new Trash();
  const todayWeekNum = getTodayWeekNum();
  tomorrowTrash = trash.getTomorrowTrash(todayWeekNum);

  let thisWeekPerson = "";
  if (todayWeekNum === 0) {
    changePersonToNext(residentsSheet, nameColumn, trashColumn);
    thisWeekPerson = getThisWeekPerson(residentsSheet, nameColumn, trashColumn);
    notifyChangePerson(lineUrl, thisWeekPerson);
    Logger.log("[info] ChangedPIC")
  }

  thisWeekPerson = getThisWeekPerson(residentsSheet, nameColumn, trashColumn);

  Logger.log("[WeekNum] " + todayWeekNum) ;
  Logger.log("[TomorrowTrash] " + tomorrowTrash);
  Logger.log("[ThisWeekPIC] " + thisWeekPerson);

  if (!tomorrowTrash == ""){ 
    notifyTomorrowTrash(lineUrl, tomorrowTrash, thisWeekPerson);
  }
}
```

### IFTTTとLineNotifyの連携

[IFTTT](https://ifttt.com/)　-> Create -> AppletsでWebhooksとLine検索してそれぞれアカウント設定連携させる。

この時点で、通知したいトークルームを選ぶ。また、Webhooksの設定から自分のKeyが取得できる。

Lineのメッセージの欄を下記にしておく。

```
【Bot】<br>
{{Value1}}<br>
```

あとはLineNotifyをグループチャットやグループLINEに招待すればOKですね。

IFTTTのKeyはトークルームの変更など設定を変えると変わるので注意です。

### できたもの

![スクリーンショット 2021-05-23 8.11.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627146/09626be2-1b7a-e7da-de02-d8f90b6c7c0b.png)

![スクリーンショット 2021-05-23 8.12.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627146/eede68d8-f6ac-913a-4f92-a70fdd009888.png)

### あとがき

本当は、ドメインを取得して、FlaskでAPIを書いて、サーバーにデプロイして、LineMessangerを使って完全なBOTを作りたかった。が、そこまでやる気力がなくなってしまった。

### (追記)WebhookがRunしなくなったら

Keyは合っているはずなのにPOSTしてもActivitiyログにもRunされた様子がなかった。
この場合は[Webhooks Setting](https://ifttt.com/maker_webhooks/settings)から
Keyを再発行させるのが正解。

![スクリーンショット 2021-05-31 20.16.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627146/5682b1ca-4f54-7dd5-7980-e94a373fd496.png)

- https://stackoverflow.com/questions/64806750/ifttt-webhook-not-triggering

### 参考にしたもの

- [IFTTT を使って LINE に送信](https://soracom.github.io/iot-showcase/projects/LTE-M_button/mkmk/b-work/line-notify-with-ifttt.html)
- [GAS ビギナーが GAS を使いこなすために知るべきこと 10 選](https://qiita.com/tanabee/items/2c51681396fe12b6a0e4)
- [Google Apps Script で Spreadsheet にアクセスする方法まとめ](https://qiita.com/negito6/items/c64a7a8589faaffcfdcf)