家庭内ポイントを導入して1年
kura@ちゅらデータのエンジニア(44)です。
はっぴばーすでーとぅみーー、はっぴばーすでーとぅみーー
44歳と60歳で一気に老化が進むそうです、・・・そんな年齢になりました!
こちらは
の15日目の記事になります。子供のお小遣いについて
子どもがいるエンジニアの方々もいらっしゃると思います。お小遣いのルールは決められていますか?
上の子も小学生になったので我家では親が楽できたらお手伝いをしたら報酬お小遣いをあげるということにしました。
ただ、毎回小銭を渡すのも面倒なので何かしら記録をつけて子たちが必要なときにポイントを換金するというルールにしました。
当初、携帯でGoogleのスプレッドシートを編集しようって妻に提案したんですが面倒だと反論があがったので少し仕組みを考えました。
要件
- スプレッドシートを直接さわらなくていい
- 私と妻の携帯からポイントを追加できる(お手伝い内容、ポイントを入力できる)
- 私と妻の携帯からポイントを削減できる(使いたいポイントを入力できる)
- 私と妻がどっちが入力したか記録できる
- ポイント残高を確認できる
- 直近のお手伝い内容を確認できる
上記を踏まえて下記のような仕組みを考えました。
仕事柄AWSやGCPを使おっかと思いましたが自分の趣味以外に運用コストかけるともったいないと怒られそうなので一旦これでスタートしました。
Messaging APIを使えるようにする
LINE公式アカウントを作成し、LINE公式アカウントでMessaging APIの利用を有効するだけでMessaging APIが使えるようになります。
手順はLINE Developersのサイトをみると丁寧に解説してあります。
Googleスプレッドシートを用意してGASを書く
※説明しやすいように実際のコードから変えてます
メインの処理
メッセージを受け取って、履歴を表示するか入力するか残高を表示するかで処理を分けてます
function doPost(e) {
const json = JSON.parse(e.postData.contents);
const MESSAGE_TEXT = json.events[0].message.text;
const USER_ID = json.events[0].source.userId;
const DISPLAY_NAME = getDisplayName(USER_ID);
let sheet = getSheet();
let result = extractNumber(MESSAGE_TEXT);
if (MESSAGE_TEXT.startsWith("履歴")) {
let history = getHistory(sheet, 5);
if (history.length > 0) {
let responseMessage = `直近${history.length}件の履歴を表示します\n`;
responseMessage += history.map((value, index) => `${index + 1}: ${value}`).join("\n");
reply(json, responseMessage);
} else {
reply(json, "履歴がありません。");
}
}
else if (result !== null) {
logging("[" + result + "]を検出");
inputData(sheet, DISPLAY_NAME, result, MESSAGE_TEXT)
reply(json, result + "円入力しました\n残高:" + getLastData(sheet) + "円")
}
else{
reply(json, "残高:" + getLastData(sheet) + "円")
}
}
その他細々した処理
入力から妻か私かを判断するためにユーザIDから表示名を取得
function getDisplayName(userId) {
let url = 'https://api.line.me/v2/bot/profile/' + userId;
let response = UrlFetchApp.fetch(url, {
'headers': {
'Authorization': 'Bearer ' + LINE_TOKEN
}
});
return JSON.parse(response.getContentText()).displayName;
}
入力するシートを取得(実際は年ごとに自動でシート分けたりしている)
function getSheet(){
return SpreadsheetApp.getActiveSpreadsheet();
}
履歴表示用にE列に記入している入力内容を最後から逆順で返す
function getHistory(sheet, n) {
let lastRow = sheet.getLastRow();
if (lastRow === 0) {
return [];
}
let startRow = Math.max(1, lastRow - n + 1);
let range = sheet.getRange(startRow, 5, lastRow - startRow + 1, 1);
let values = range.getValues();
// E列のデータを配列に格納し逆順で取得
let history = values.map(row => row[0]).reverse();
return history;
}
スプレッドシートの最後の行の下に新しい入力を追加します。
D列には集計値を入れているので前の行の値にC列を加算した値を入れます。
function inputData(sheet, displayName, number, text_message) {
let today = new Date();
let lastRow = sheet.getLastRow();
if(lastRow != 0){
let lastValueInD = sheet.getRange(lastRow, 4).getValue();
let newValue = lastValueInD + number;
sheet.getRange(lastRow + 1, 4).setValue(newValue);
}
else{
sheet.getRange(lastRow + 1, 4).setValue(number);
}
sheet.getRange(lastRow + 1, 1).setValue(today);
sheet.getRange(lastRow + 1, 2).setValue(displayName);
sheet.getRange(lastRow + 1, 3).setValue(number);
sheet.getRange(lastRow + 1, 5).setValue(text_message);
}
入力テキストの中から数値を取り出し
最初に出てきた数値をポイントとして扱うので「雑巾掛け5分、50ポイント」とか入力すると5をポイントとして見てしまう悲しい状況です。
そのうち弊社のサイエンティストに相談しよう。
function extractNumber(text) {
// 正規表現を使用して数値を検索(整数のみを取り出す)
var match = text.match(/-?\d+/);
if (match) {
return parseInt(match[0], 10);
}
return null;
}
コードができたらGASをデプロイするとエンドポイントが作成されて、エンドポイントをMessageAPIに登録して、ボットを自分のLINEに追加するだけで動作します
結果
一年使ってみて子たちにも変化がありました。
求めていたこと
- 毎日コツコツお手伝いをするようになる
- できないことができるようになるように努力する
- しっかりポイントを貯めて好きなものを買えるようになる
- 欲しいもを手にいれるためには働かないといけないと理解する
実際の状況
- やれる手伝いの種類が増えた
- 下の子(5歳)も手伝いをやり始めた(お兄ちゃんだけズルいとなった)
- 手伝いをする前に
お金ポイントを確認するようになった - ちょっと溜まったら手伝わなくなった(使いきらないと手伝わない)
- 手伝いをえり好みするようになった(トイレ掃除は嫌らしい)
- 借ポイントを覚えた(させなきゃいいんですが、片方の子だけ0円になっていると騒ぐので)
微妙な点もありますが、欲しいものをねだられても「お手伝いしてポイント貯めなさい」で片付くようになったので大変助かってます。
今後も状況を見ながらやれることを増やしていく予定です。
早く朝晩の飯を作れるようになってほしい!
Discussion