文系でも分かる、GASによる授業通知のLINE bot の作成 その④ 〜setTriggerを使って、指定の時間にプッシュ通知を送る〜
文系でも分かる、GASによる授業通知のLINE bot の作成 その③の続きです。
今回で最後になります。
- 文系でも分かる、GASによる授業通知のLINE bot の作成 その① 〜GASを使ったLINE botの作成〜
- 文系でも分かる、GASによる授業通知のLINE bot の作成 その② 〜GASとスプレッドシートの連携、日付のフォーマット〜
- 文系でも分かる、GASによる授業通知のLINE bot の作成 その③
- 文系でも分かる、GASによる授業通知のLINE bot の作成 その④ 〜setTriggerを使って、指定の時間にプッシュ通知を送る〜 ←今回
setTriggerというものを使い、授業開始10分前に通知が来るようにします。
この記事でわかること
- GASのsetTrigger の使い方
- Messaging APIのプッシュ通知の送り方
今回やること
- 要件④授業の10分前に授業を通知する機能の追加
- 要件④授業の10分前に授業を通知する機能の追加
要件定義
- push通知を送るfunctionの作成
- push通知で送る授業情報を取得するfunctionを作成
- 上のfunctionが指定の時間に実行されるためのfunctionを作成
push通知を送るfunctionの作成
Code.gs
function push(text, zoom) {
//メッセージを送信(push)する時に必要なurlでこれは、皆同じなので、修正する必要ありません。
//この関数は全て基本コピペで大丈夫です。
var url = "https://api.line.me/v2/bot/message/push";
var headers = {
"Content-Type" : "application/json; charset=UTF-8",
'Authorization': 'Bearer ' + access_token,
};
//toのところにメッセージを送信したいユーザーのIDを指定します。(toは最初の方で自分のIDを指定したので、linebotから自分に送信されることになります。)
//textの部分は、送信されるメッセージが入ります。createMessageという関数で定義したメッセージがここに入ります。
var postData = {
"to" : user_id,
"messages" : [
{
'type':'text',
'text':text,
},
{
'type':'text',
'text':zoom,
}
]
};
var options = {
"method" : "post",
"headers" : headers,
"payload" : JSON.stringify(postData)
};
return UrlFetchApp.fetch(url, options);
}
function push(text, zoom) {
//メッセージを送信(push)する時に必要なurlでこれは、皆同じなので、修正する必要ありません。
//この関数は全て基本コピペで大丈夫です。
var url = "https://api.line.me/v2/bot/message/push";
var headers = {
"Content-Type" : "application/json; charset=UTF-8",
'Authorization': 'Bearer ' + access_token,
};
//toのところにメッセージを送信したいユーザーのIDを指定します。(toは最初の方で自分のIDを指定したので、linebotから自分に送信されることになります。)
//textの部分は、送信されるメッセージが入ります。createMessageという関数で定義したメッセージがここに入ります。
var postData = {
"to" : user_id,
"messages" : [
{
'type':'text',
'text':text,
},
{
'type':'text',
'text':zoom,
}
]
};
var options = {
"method" : "post",
"headers" : headers,
"payload" : JSON.stringify(postData)
};
return UrlFetchApp.fetch(url, options);
}
"messages" : [{}{}]
の形にすることで、パスワードが別のメッセージとして送られてくるようにしています(上の画像参照)。こうすることで、パスワードのコピーが容易になっています。
push通知で送る授業情報を取得するfunctionを作成
Code.gs
function pushClassInfo() {
//function findNextClassを実行
var classInfos = findNextClass();
var today = new Date();
//あとで、現在より15分後の日時を取得します。
var quarterAfter = new Date();
var day = today.getDay();
var array = ["日", "月", "火", "水", "木", "金", "土"];
//quarterAfterに入っている日時が、現在より15分後になりました。
quarterAfter.setMinutes(quarterAfter.getMinutes() + 15);
var hhmmToday = Utilities.formatDate( today, 'Asia/Tokyo', 'HH:mm');
var hhmmQuarter = Utilities.formatDate( quarterAfter, 'Asia/Tokyo', 'HH:mm');
console.log(classInfos);
console.log(classInfos.startTime <= hhmmQuarter); //授業が始まるのは、今から15分後より前、つまりもうすぐ授業が始まる。
//findNextClassで取得した授業が現在の曜日のものか
if(classInfos.classDay == array[day] && classInfos.startTime <= hhmmQuarter ){
var message = "もうすぐ次の授業です。\n" + classInfos.classDay + "曜" + classInfos.classNum + "限 (" + classInfos.startTime + "-" + classInfos.endTime +
")\n授業名:" + classInfos.className +
"\nZoomID:" + classInfos.zoomID +
"\nPass:" + classInfos.zoomPass;
console.log(message);
//function pushを実行
push(message, classInfos.zoomPass);
} else {console.log("not upcoming one ");}
}
function pushClassInfo() {
//function findNextClassを実行
var classInfos = findNextClass();
var today = new Date();
//あとで、現在より15分後の日時を取得します。
var quarterAfter = new Date();
var day = today.getDay();
var array = ["日", "月", "火", "水", "木", "金", "土"];
//quarterAfterに入っている日時が、現在より15分後になりました。
quarterAfter.setMinutes(quarterAfter.getMinutes() + 15);
var hhmmToday = Utilities.formatDate( today, 'Asia/Tokyo', 'HH:mm');
var hhmmQuarter = Utilities.formatDate( quarterAfter, 'Asia/Tokyo', 'HH:mm');
console.log(classInfos);
console.log(classInfos.startTime <= hhmmQuarter); //授業が始まるのは、今から15分後より前、つまりもうすぐ授業が始まる。
//findNextClassで取得した授業が現在の曜日のものか
if(classInfos.classDay == array[day] && classInfos.startTime <= hhmmQuarter ){
var message = "もうすぐ次の授業です。\n" + classInfos.classDay + "曜" + classInfos.classNum + "限 (" + classInfos.startTime + "-" + classInfos.endTime +
")\n授業名:" + classInfos.className +
"\nZoomID:" + classInfos.zoomID +
"\nPass:" + classInfos.zoomPass;
console.log(message);
//function pushを実行
push(message, classInfos.zoomPass);
} else {console.log("not upcoming one ");}
}
流れとしては、fuction findNextClass
で1番近い授業を取得して、それが始まるのが今から15分以内かどうか判別し、trueならクラスの情報をpushするという感じです。
指定時間に通知が送られてくるようにする
コード(コピペで動きます)
//授業時間が設定されている時、その授業時間の10分前にpushClassInfoを実行するタイマーをセットする
function setTrigger(){
var today = new Date();
var year = today.getFullYear();
var month = today.getMonth();
var date = today.getDate();
for(let i=3; i <= 27; i+=4) {
if(sheet.getRange(i, 1).getValue()){
var classStart = sheet.getRange(i, 1).getValue();
var startMinutes = classStart.getMinutes();
classStart.setFullYear(year);
classStart.setMonth(month);
classStart.setDate(date);
classStart.setMinutes(startMinutes - 10);
console.log(classStart);
ScriptApp.newTrigger('pushClassInfo').timeBased().at(classStart).create();
}
}
}
function delTrigger() {
var triggers = ScriptApp.getProjectTriggers();
for(let i=0; i < triggers.length; i++) {
if (triggers[i].getHandlerFunction() == "pushClassInfo") {
ScriptApp.deleteTrigger(triggers[i]);
}
}
}
トリガーの使い方
ScriptApp.newTrigger('function名').timeBased().at(時間).create()
でトリガーというものをセットすることがでます。このトリガーによって、指定した日時にfunctionを実行させることができます。
ただ、セットしたトリガーは残り続けてしまうので、 deleleTrigger
で削除します。
あとは、function setTriggerを早朝に、delTriggerを深夜に実行する設定をすれば完了です。
setTriggerとdelTriggerを毎日呼び出す
https://tonari-it.com/gas-trigger-set/#toc4
こちらの記事の、「5. 毎日指定の時刻のDateオブジェクトを作成する」を参考に、setTriggerを早朝(1限より前の時間)に、delTriggerを深夜(7限よりあとの時間)にセットしてください。つまり、記事の作業を2回おこないます。
ちなみに1〜4もScriptApp.newTrigger
について詳しく解説してくれているので、読むと勉強になります。
これで完成です!
最後に更新を忘れないようにしましょう。
最終的なコードの全体像
全て書き終えた後のコードは以下のようになります
var access_token = "アクセストークン"
// 自分のユーザーIDを指定します。LINE Developersの「Your user ID」の部分です。
var user_id = "ユーザーID"
//★★スプレッドシートID★★
var ss = SpreadsheetApp.openById("スプレッドシートID");
//★★シート名★★
var sheet = ss.getSheetByName("シート名");
function doPost(e) {
var event = JSON.parse(e.postData.contents).events[0];
var returnMessage = "曜日と時限(半角:1〜7)を指定してね!\n次の授業が知りたいときは、「次」と入力してね!";
if(event.source.userId == user_id){
//返信するためのトークン取得
var reply_token= event.replyToken;
if (typeof reply_token === 'undefined') {
return;
}
var message = event.message.text;
for(let i=3; i<=7; i ++) {
var dateColumn = i;
var day = sheet.getRange(1, i).getValue();
if(message.includes(day)){
for(let j=2; j<=26; j += 4) {
var classNumRow = j;
var classNum = sheet.getRange(j, 1).getValue();
if(message.includes(classNum) && sheet.getRange(classNumRow, dateColumn).getValue()){
var classInfos = getClassInfo(classNumRow, dateColumn);
var returnMessage = classInfos.classDay + "曜" + classInfos.classNum + "限 (" + classInfos.startTime + "-" + classInfos.endTime +
")\n授業名:" + classInfos.className +
"\nZoomID: " + classInfos.zoomID +
"\nPass: " + classInfos.zoomPass;
reply(reply_token, returnMessage);
} else if(message.includes(classNum) && !sheet.getRange(classNumRow, dateColumn).getValue()) {
var returnMessage = "授業はありません。"
reply(reply_token, returnMessage);
}
}
}
}
if(message.includes("次")){
var classInfos = findNextClass();
var returnMessage = classInfos.classDay + "曜" + classInfos.classNum + "限 (" + classInfos.startTime + "-" + classInfos.endTime +
")\n授業名:" + classInfos.className +
"\nZoomID: " + classInfos.zoomID +
"\nPass: " + classInfos.zoomPass;
reply(reply_token, returnMessage);
} else {reply(reply_token, returnMessage);}
}
}
function reply(reply_token, returnMessage) {
var reply_url = 'https://api.line.me/v2/bot/message/reply';
// メッセージを返信
UrlFetchApp.fetch(reply_url, {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + access_token,
},
'method': 'post',
'payload': JSON.stringify({
'replyToken': reply_token,
'messages': [{
'type': 'text',
'text': returnMessage,
}],
}),
});
return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}
function push(text, zoom) {
//メッセージを送信(push)する時に必要なurlでこれは、皆同じなので、修正する必要ありません。
//この関数は全て基本コピペで大丈夫です。
var url = "https://api.line.me/v2/bot/message/push";
var headers = {
"Content-Type" : "application/json; charset=UTF-8",
'Authorization': 'Bearer ' + access_token,
};
//toのところにメッセージを送信したいユーザーのIDを指定します。(toは最初の方で自分のIDを指定したので、linebotから自分に送信されることになります。)
//textの部分は、送信されるメッセージが入ります。createMessageという関数で定義したメッセージがここに入ります。
var postData = {
"to" : user_id,
"messages" : [
{
'type':'text',
'text':text,
},
{
'type':'text',
'text':zoom,
}
]
};
var options = {
"method" : "post",
"headers" : headers,
"payload" : JSON.stringify(postData)
};
return UrlFetchApp.fetch(url, options);
}
function pushClassInfo() {
var classInfos = findNextClass();
var today = new Date();
var quarterAfter = new Date();
var day = today.getDay();
var array = ["日", "月", "火", "水", "木", "金", "土"];
quarterAfter.setMinutes(quarterAfter.getMinutes() + 15);
var hhmmToday = Utilities.formatDate( today, 'Asia/Tokyo', 'HH:mm');
var hhmmQuarter = Utilities.formatDate( quarterAfter, 'Asia/Tokyo', 'HH:mm');
console.log(classInfos);
console.log(classInfos.startTime <= hhmmQuarter); //授業が始まるのは、今から15分後より前、つまりもうすぐ授業が始まる。
if(classInfos.classDay == array[day] && classInfos.startTime <= hhmmQuarter ){
var message = "もうすぐ次の授業です。\n" + classInfos.classDay + "曜" + classInfos.classNum + "限 (" + classInfos.startTime + "-" + classInfos.endTime +
")\n授業名:" + classInfos.className +
"\nZoomID:" + classInfos.zoomID +
"\nPass:" + classInfos.zoomPass;
console.log(message);
push(message, classInfos.zoomPass);
} else {console.log("not upcoming one ");}
}
function findNextClass() {
var today = new Date();
var hour = today.getHours();
var minutes = today.getMinutes();
console.log(today);
for(let i=0; i <= 6; i++) {
var day = (today.getDay() + i) % 7;
var dateColumn = day + 3;
var array = ['日','月','火','水','木', '金', '土'];
console.log("曜日:" + array[day]);
var searchHour = 0;
if(day == today.getDay()){searchHour = hour;} else { searchHour = 6;}
for(var j=0; j < 24-searchHour; j++) {
console.log(searchHour + "時");
for(let k=2; k <= 26; k+=4){
var classNumRow = k;
var startTimeRow = k + 1;
//始業時間が設定されている場合、始業時間を取得
if(sheet.getRange(startTimeRow, 1).getValue()) {
var startTime = sheet.getRange(startTimeRow, 1).getValue();
var startHour = startTime.getHours();
var startMinutes = startTime.getMinutes();
console.log("start hour: " + startHour);
//検索した時、今と検索時間の日付と時間が一致していても、今の分が始業の分を超えている場合は情報を取得しない
if(searchHour === startHour && today.getDay() === day && hour === searchHour && minutes > startMinutes){
console.log("\nalready orver\n");
//時間が一致し、授業が存在する場合、情報を取得
} else if(searchHour === startHour && sheet.getRange(classNumRow, dateColumn).getValue()){
var classInfos = getClassInfo(classNumRow, dateColumn);
return classInfos;
}
}
}
searchHour += 1;
}
}
}
function getClassInfo(rowNum, dateColumn){
var className = sheet.getRange(rowNum, dateColumn).getValue();
var classDay = sheet.getRange(1, dateColumn).getValue();
var classNum = sheet.getRange(rowNum, 1).getValue();
var startTime = Utilities.formatDate( sheet.getRange(rowNum + 1, 1).getValue(), 'Asia/Tokyo', 'HH:mm');
var endTime = Utilities.formatDate( sheet.getRange(rowNum + 3, 1).getValue(), 'Asia/Tokyo', 'HH:mm');
var zoomID = sheet.getRange(rowNum + 1, dateColumn).getValue();
var zoomPass = sheet.getRange(rowNum + 2, dateColumn).getValue();
var classInfos = {className: className, classDay: classDay, classNum: classNum, startTime: startTime, endTime: endTime, zoomID: zoomID, zoomPass: zoomPass};
return classInfos;
}
function setTrigger(){
var today = new Date();
var year = today.getFullYear();
var month = today.getMonth();
var date = today.getDate();
for(let i=3; i <= 27; i+=4) {
if(sheet.getRange(i, 1).getValue()){
var classStart = sheet.getRange(i, 1).getValue();
var startMinutes = classStart.getMinutes();
classStart.setFullYear(year);
classStart.setMonth(month);
classStart.setDate(date);
classStart.setMinutes(startMinutes - 10);
console.log(classStart);
ScriptApp.newTrigger('pushClassInfo').timeBased().at(classStart).create();
}
}
}
function delTrigger() {
var triggers = ScriptApp.getProjectTriggers();
for(let i=0; i < triggers.length; i++) {
if (triggers[i].getHandlerFunction() == "pushClassInfo") {
ScriptApp.deleteTrigger(triggers[i]);
}
}
}
最後に
いかがだったでしょうか?
僕はこれを作った時、文系でもこんなものが作れるんだと感動しました。
文系目線でなるべくわかりやすく解説を入れたつもりなので、少しでも役に立てば嬉しいです。
なお、未経験文系大学生が書いているので、誤り等あるかもしれませんがご了承ください。
最後まで取り組んでくださってありがとうございました!
Author And Source
この問題について(文系でも分かる、GASによる授業通知のLINE bot の作成 その④ 〜setTriggerを使って、指定の時間にプッシュ通知を送る〜), 我々は、より多くの情報をここで見つけました https://qiita.com/Ko001/items/d35a74e3be452198b8f2著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .