Edited at

ゴミの日も記念日も何でも通知してくれるLINE BotをGASで作ってみよう

LINE Botをリマインダ的に活用して生活に役立てるのが流行っていますね。特に、LINE BotのMessaging APIとGoogle Apps Script(通称GAS)との相性が良くて、とても簡単にBotが作れるみたいです。

本記事では、LINE Messaging APIとGASを使って、何でも通知してくれる便利なLINE Botを作ってみたいと思います。


追記

2019/09/12

プログラミングに馴染みのない人が通知設定シートを編集することをイメージし、以下の機能追加と変更を行いました。


  • 新たに「年」を指定できるようにしました。

  • 毎日、毎時といった指定をしたい場合、「*」を入力するのではなく、セルを空白にすれば良いように変更しました。

  • 列の並びを、より日常生活に馴染みのある「年、月、日~」の並びに変更しました。

2019/09/11

思ったよりもいいねが伸びたので、「本文」が空欄だったり、「発言する場所」に不適切な文字が入っていてエラーとなった場合でも、止まらずに次の行の通知の処理へ進むよう微調整しました。

中身のロジックの理解は後回しに、とりあえず動くものを作ってみて欲しいという思いを込めて「新人プログラマ応援」のタグを追加しました。


関連する記事との比較

ゴミの種類を通知するLINE Botは、既にいくつか作ってみた記事があります。やはり分別は面倒ですね。

これらの記事では、ゴミの種類と曜日をコード内で定義しています。例えば、引っ越しをしてゴミの曜日や分別方法が変わった場合、コードを変更する必要があります。本記事では、通知する内容とコードを切り離し、コードがわからない人でも、通知する日時と内容を編集できることを目指します。


設計

以下の3つを利用して、何でも通知してくれるLINE Botを実装します。


  • LINE Messaging API

  • Google スプレッドシート

  • Google Apps Script


LINE Messaging API の準備

通知する内容を喋ってくれるLINE Botのアカウントを作成します。これに関しては、わかりやすく説明してくれる記事が沢山あるので、それに従ってください。

LINE BOTの作り方を世界一わかりやすく解説(1)【アカウント準備編】

アカウントが準備できたら、「チャネル基本設定」>「メッセージ送受信設定」から、「アクセストークン

(ロングターム)」を発行してください。これを後に利用します。


スプレッドシートの準備

Google スプレッドシートを新規作成し、このような形式の表を作成してください。

表の構成を見ていただければわかるかと思いますが、以下のことが実現できるようになります。


  • 日時や曜日を指定して、狙ったタイミングで通知ができる

  • 毎分、毎時、毎日のように、定期的な通知をしたい場合はセルを空白にすることで実現可能

  • 第1月曜日、第2火曜日のように、何番目の何曜日という指定も可能(ゴミ分別の通知に役立ちます!!

  • 「発言する場所」を指定することで、通知内容ごとに別々の場所で発言できる

※本記事では、「発言する場所」に入力するIDを調べるためのBotの機能も同時に実装します。

シートのサンプルも用意しました。具体的な設定例をなるべく沢山載せておきますので、細かな通知の設定方法はサンプルをご確認ください。

注意点

- 年、月、日、第n週、曜日、時、分、本文、発言する場所という列の並びを変えないこと

- シート名(スプレッドシートの画面下部)を「alarm」とすること

- いずれも変更する場合は後述するGASのコードを変更する必要があります。


Google Apps Scriptのコード

スプレッドシートの「ツール」>「スクリプトエディタ」で、Google Apps Scriptのエディタを開いてください。

以下のコードをエディタで記入してください。コードはGithubにも一応公開しています。

ここで、ACCESS_TOKEN変数に、LINE Messaging APIの準備で準備した「アクセストークン(ロングターム)」を記載してください。

SHEET_KEYは、スプレッドシートのURLに含まれている文字列です。

https://docs.google.com/spreadsheets/d/{この部分の文字列です!}/edit#gid=0


Code.gs


// 「メッセージ送受信設定」のアクセストークン(ロングターム)を記入してください。
var ACCESS_TOKEN = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';

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

function doPost(e) {
var event = JSON.parse(e.postData.contents).events[0];
var userMessage = event.message.text;

var message = "";
if ( userMessage === "ID" ) {
message = tellID(event);
}
else {
// 疎通確認が終わったらコメントアウトすると良いです。
message = "メッセージを受け取ったわよ!";
}

replyMessage(event.replyToken, message);
return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}

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,
}],
}),
});
}

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,
}],
}),
});
}

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;
}

function notice() {
var sheet = SpreadsheetApp.openById(SHEET_KEY).getSheetByName('alarm');
var data = sheet.getDataRange().getValues();

var dayStr = ["", "", "", "", "", "", ""];
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);
}
}
}



疎通確認

コードが準備できたら、「ウェブアプリケーションとして導入」をしてください。

注意点

- 「アプリケーションにアクセスできるユーザ」を、「全員(匿名ユーザーを含む)」にすること

- コードを修正した場合は、「プロジェクトバージョン」を「New」に指定し、更新すること

完了したら、ウェブアプリケーションのURLを、LINE Developerの「チャンネル基本設定」>「メッセージ送受信設定」>「Webhook URL」に入力します。「Webhook送信」も有効化してください。

「接続確認」に成功すればOKです。

この状態でBotに何か話かけてみましょう。

メッセージが返ってくればOKです。


発言先のIDを調べて通知を設定する

通知内容の発言先「発言する場所」に入力するIDを調べてみましょう。通知をさせたいトークルームにBotを招待して、「ID」と発言すればOKです。

頭文字がUのものが、個人のID、Rのものが、グループではないトークルームのID、Gのものが、グループのトークルームIDのようです。ここで調べたIDを、スプレッドシートの「発言する場所」に記入します。


トリガーを設定する

時間になったら通知をするためのトリガーを設定します。Google Apps Scriptのエディタから時計マークをクリックしてください。

トリガーを追加

実行する関数: notice

イベントのソース: 時間主導型

トリガーのタイプ: 分ベースのタイマー

時間の間隔: 1分おき

これで設定は一通り完了です。

シートに設定した通りの通知が来れば成功です!


最後に

通知する内容、日時、通知先をGoogleスプレッドシートで指定可能なLINE Botを作成してみました。このBotを一度設定すれば、GASのコードがわからない家族や友達であっても、スプレッドシートの編集権限を与えて共有することで、各々が好きな内容の通知を好きなトークルームへ設定できるようになります。どこかで活用してくださる方が現れると嬉しいです。