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
// 「メッセージ送受信設定」のアクセストークン(ロングターム)を記入してください。
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のコードがわからない家族や友達であっても、スプレッドシートの編集権限を与えて共有することで、各々が好きな内容の通知を好きなトークルームへ設定できるようになります。どこかで活用してくださる方が現れると嬉しいです。