はじめに
LINE を使用して 赤ちゃんのおむつ交換記録を行うBOTを作成しました。(※大きい方です。)
子供がたびたび便秘になっていたこと、便秘が続いていた日数を忘れてしまうことが多かったことがありましたので、BOTを作成しました。しかし、この記事を執筆時にはすでに子供のおむつは取れていました。(時の流れは速いです...。)
機能としては下記の通りです。
- キーワードを入力すると、現在日時が記録されます。
-
履歴
メッセージを入力すると、過去の記録を閲覧できます。 - 便秘が続いていた場合、毎日何日目か通知します。
事前準備
- GoogleDriveにてGoogleAppsScriptを開いて、以下のスクリプトを実装します。
-
LINE_CHANNEL_TOKEN
にLINE Messaging APIで発行したトークンを指定します。 -
SSID
にスプレッドシートのIDとSSN_USER
、SSN_HISTORY
にシート名を指定します。
main.gs
/**
* 赤ちゃんのおむつ交換BOT
*/
const LINE_CHANNEL_TOKEN = '*****'; // LINE NOTIFYのアクセストークン
const SSID = '*****';
const SSN_USER = 'user';
const SSN_HISTORY = 'history';
フォロー登録
フォロー解除
リプライ
メッセージを入力するとLINE Messaging API
からGASにPOSTが通知されます。GASでは、スプレッドシートにメッセージ入力時刻を保存します。結果をLINE Messaging API
にPOSTで返します。
main.gs
/**
* メッセージイベント処理
* @param {Object} reqEvent
*/
function executeMessage(reqEvent) {
let msgList = [];
let user = getUser(reqEvent.source.userId);
if (user) {
let reqReport = -1;
switch (reqEvent.message.type) {
case 'text':
reqReport = getReportFromText(reqEvent.message.text);
break;
case 'sticker':
reqReport = getReporFromSticker(reqEvent.message.packageId, reqEvent.message.stickerId);
break;
}
let nowTime = (new Date()).getTime();
switch (reqReport) {
case 0:
msgList.push({
'type': 'text',
'text': 'うんこ承りました。',
});
if (user.item.lastDate) {
let diffTime = nowTime - user.item.lastDate;
if (DAY_TIME < diffTime) {
let day = Math.floor(diffTime / DAY_TIME);
msgList.push({
'type': 'text',
'text': `${day}日ぶりに出たね。`,
});
}
}
sendLineReply(reqEvent.replyToken, msgList);
userSheet.getRange(user.index + 2, 4).setValue(nowTime);
historySheet.appendRow([user.item.userId, nowTime]);
break;
case 1:
let historyList = getHistoryList(reqEvent.source.userId);
let msg = '直近の記録(最大10件)\n\n';
for (let i in historyList) {
let history = historyList[i];
let timestamp = Utilities.formatDate(new Date(history.recortDt), 'Asia/Tokyo', 'MM月dd日 HH:mm');
msg += timestamp + '\n';
}
msgList.push({
'type': 'text',
'text': msg,
});
sendLineReply(reqEvent.replyToken, msgList);
break;
default:
msgList.push({
'type': 'text',
'text': 'わからないよ\nもう一度入力してね',
});
sendLineReply(reqEvent.replyToken, msgList);
break;
}
}
}
/**
* テキストからイベント種別を取得する
* @param {String} text
*/
function getReportFromText(text) {
const REPORT_LIST = [
['うんこ', 'ウンコ', '出た', 'でた'],
['直近', '履歴']
];
for (let i in REPORT_LIST) {
let itemList = REPORT_LIST[i];
for (let j in itemList) {
let item = itemList[j];
if (text == item) {
return parseInt(i);
}
}
}
}
/**
* スタンプからイベント種別を取得する
* @param {String} packageId
* @param {String} stickerId
*/
function getReporFromSticker(packageId, stickerId) {
const REPORT_LIST = [
[{
packageId: '4',
stickerId: '284'
}, {
packageId: '2000011',
stickerId: '455795'
}, {
packageId: '2000011',
stickerId: '455798'
}, {
packageId: '2000013',
stickerId: '483667'
}, {
packageId: '2000013',
stickerId: '483668'
}]
];
for (let i in REPORT_LIST) {
let itemList = REPORT_LIST[i];
for (let j in itemList) {
let item = itemList[j];
if (item.packageId == packageId && item.stickerId == stickerId) {
return parseInt(i);
}
}
}
}
/**
* 履歴一覧を取得する
* @param {String} userId
*/
function getHistoryList(userId) {
let historyList = [];
let allHistoryList = getAllHistoryList();
for (let i in allHistoryList) {
let hitory = allHistoryList[i];
if (hitory.userId === userId) {
historyList.push(hitory);
}
}
return historyList.slice(-10);
}
/**
* 全履歴一覧を取得する
*/
function getAllHistoryList() {
let allHistoryList = [];
let lastRow = historySheet.getLastRow();
if (1 < lastRow) {
allHistoryList = historySheet.getRange(1, 1, lastRow, 2).getValues();
allHistoryList = allHistoryList.map((row) => {
return {
userId: row[0],
recortDt: row[1],
}
});
}
return allHistoryList;
}
/**
* LINEに応答メッセージを送信する
* @param {String} replyToken リプライトークン
* @param {Object} msgList メッセージリスト
*/
function sendLineReply(replyToken, msgList) {
let url = 'https://api.line.me/v2/bot/message/reply';
let options = {
'method': 'post',
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': `Bearer ${LINE_CHANNEL_TOKEN}`
},
'payload': JSON.stringify({
replyToken: replyToken,
messages: msgList
})
};
let response = UrlFetchApp.fetch(url, options);
return JSON.parse(response.getContentText('UTF-8'));
}
-
execute
関数では、LINE Messaging APIからの通知内容により、処理を振り分けしています。message
の場合は、メッセージの内容を解析します。メッセージの現在日時を記録します。 - 保存結果メッセージを作成して
sendLineReply
関数でLINE Messaging APIにPOSTします。
プッシュ通知
GASにて、1日1回、赤ちゃんの便秘が続いていた場合、何日目であるかを通知します。
main.gs
/**
* 通知
*/
function notify() {
try {
let nowTime = (new Date()).getTime();
let userList = getUserList();
for (let i in userList) {
let user = userList[i];
if (user.lastDate) {
let diffTime = nowTime - user.lastDate;
if (DAY_TIME < diffTime) {
let day = Math.floor(diffTime / DAY_TIME);
let msgList = [{
'type': 'text',
'text': `うんこが止まって${day}日目です。`,
}];
sendLinePush(user.userId, msgList);
}
}
}
} catch (e) {
console.error(e.stack);
}
}
/**
* LINEにメッセージを送信する
* @param {String} targetId ターゲットID(userId/groupId/roomId)
* @param {Object} msgList メッセージリスト
*/
function sendLinePush(targetId, msgList) {
let url = 'https://api.line.me/v2/bot/message/push';
let options = {
'method': 'post',
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': `Bearer ${LINE_CHANNEL_TOKEN}`
},
'payload': JSON.stringify({
to: targetId,
messages: msgList
})
};
let response = UrlFetchApp.fetch(url, options);
return JSON.parse(response.getContentText('UTF-8'));
}
- 1日1回
notify
関数を実行します。
参考リンク
- Google Homeに話しかけて娘のおむつ交換を記録する
- Google Homeを使って娘のオムツの情報をGoogle Spreadsheetに記録する
- (GAS)スプレッドシートに記録した排泄記録をSlackにポストする
さいごに
ソースコードをGitHubに公開しています。
以上です。