2020/10/09
どうも、こんにちは!JellyWareです。
Getting Started!! Riiiver tutorialの第18弾となります。
このシリーズは、Riiiverやプログラミングを学び、初心者の方でもEco-Drive Riiiverを活用したオリジナルアプリを理解して作れるようになることを目指します。
前回学んだ内容を活かして、今回はPieceを作成します。
スプレッドシートをデータベース代わりにして、怒った回数を記録させます。また、実行した時間に応じて以下のように処理を変えます。
順に Trigger, Service, Action Piece を解説します。
既存の「ボタン押し」を使用します。
Eco-Drive Riiiver のボタンを押すと iiidea を実行できます。
今回新しく作成します。
Google Sheets APIを使って、スプレッドシートと連携させます。
既存の「端末に文字を通知」を使用します。
Eco-Drive Riiiverと連携している端末に通知が届きます。
まずは、Piece JSONについて解説します。
{
"title": {
"en": "Anger Management",
"ja": "怒りっぽさを改善"
},
"version": "1.0.0",
"sdkVersion": "1.0.0",
"deviceId": "none",
"vendorId": "none",
"description": {
"en": "Register every time you get angry. Every time you trigger this Piece, the date and time you triggered it will be sent to a connected Google Sheet.* A message is then sent on to the next Piece based on the number of times so far today you’ve been marked as angry.\n\n*You need to create and publish your own Google sheet to connect to the Piece. The sheet sharing settings must be set to “Anyone on the internet with this link can edit.”\n\nNOTE: This Piece currently only outputs Japanese text and registers time based on Japan Standard Time."
"ja": "スプレッドシートをデータベースの代わりにして、何回怒ったかを記録します。スプレッドシートの日付と怒った回数を更新し、怒った回数に応じて次のPieceに渡すテキストが変更します。使用するスプレッドシートのキーを入力してください。また、権限を「このリンクを知っているインターネット上の全員が編集できます」にしてください。"
},
"blockType": "service",
"executor": "RBCCommonWebServiceExecutor",
"serviceProxy": {
"service": "cureIrritability"
},
"osType": "none",
"categoryIds": ["cat_0001"],
"preferences": {
"type": "object",
"properties": {
"spreadSheetKey": {
"x-input-type": "text",
"type": "string",
"x-title": {
"en": "Spreadsheet Key",
"ja": "スプレッドシートのキー"
},
"x-description": {
"en": "Enter Google Sheet key, which is the string of numbers and letters located in your sheet URL where “KEY” is written here: https://docs.google.com/spreadsheets/d/KEY/",
"ja": "スプレッドシートのキーを入力してください。"
}
}
}
},
"output": {
"type": "object",
"properties": {
"message": {
"type": "string",
"format": "text"
}
}
}
}
今回作成するPieceの要点となる、"preferences"
, "output"
について解説します。
ユーザーがスプレッドシートのシートキーを入力できるようにします。
"preferences": {
"type": "object",
"properties": {
"spreadSheetKey": {
"x-input-type": "text",
"type": "string",
"x-title": {
"en": "Spreadsheet Key",
"ja": "スプレッドシートのキー"
},
"x-description": {
"en": "Enter Google Sheet key, which is the string of numbers and letters located in your sheet URL where “KEY” is written here: https://docs.google.com/spreadsheets/d/KEY/",
"ja": "スプレッドシートのキーを入力してください。"
}
}
}
}
実際のアプリの画面では、以下のようになります。
次のPieceに文字列を渡せるようにします。
"output": {
"type": "object",
"properties": {
"message": {
"type": "string",
"format": "text"
}
}
}
文字列のみを渡せるように、"type"
は"string"
,"format"
は"text"
にしています。
"format"
については、ドキュメントを参照ください。
次に Piece Funcを解説します。
// google-spreaesheetの読み込み
const { GoogleSpreadsheet } = require('google-spreadsheet');
// 認証情報jsonファイルを読み込む
const credit = require('./credentials.json');
exports.handler = async (event) => {
if (event.call === 'lambda') {
console.log('CALLED:LAMBDA');
/* If you use the external modules, please code the following: - 外部モジュールを使う場合に記入してくだい。
e.g. if ( xxxx !== null ){} // xxxx: instance for the module. - xxxx : 生成したインスタンス */
if (GoogleSpreadsheet !== null) { }
return;
}
// スプレッドシートキー
const spreadSheetKey = event["properties"]["preferences"]["spreadSheetKey"]
// スプレッドシートの指定
const doc = new GoogleSpreadsheet(spreadSheetKey);
// 認証
await doc.useServiceAccountAuth({
client_email: credit["client_email"],
private_key: credit["private_key"]
});
// スプレッドシートの情報取得
await doc.loadInfo();
// シートの取得
const sheet = doc.sheetsByIndex[0];
// 通知メッセージ
let message;
// 次のPieceに渡す
let response;
// ヘッダーの追加
await sheet.setHeaderRow(["日にち", "怒った回数"]);
// タイムスタンプ(年と月と日)
const today = new Date();
today.setHours(today.getHours() + 9);// 日本時間に変換
const timeStamp = `${today.getFullYear()}年${today.getMonth() + 1}月${today.getDate()}日`;
// 行情報の取得
let rows = await sheet.getRows();
// 最終行の日にちと怒った回数
let lastDate;
let angryNumber;
try {
lastDate = rows.slice(-1)[0]["日にち"];
angryNumber = rows.slice(-1)[0]["怒った回数"];
angryNumber = Number(angryNumber);
} catch(error) { // 初回実行時はデータが空のため作成
lastDate = timeStamp;
angryNumber = 0;
// 行を追加
await sheet.addRow([timeStamp, angryNumber]);
// 再取得
rows = await sheet.getRows();
}
// 22時以降の場合 怒った回数のみを返す
if (today.getHours() > 21) {
// 実行日のデータがない場合
if (timeStamp == lastDate) {
message = `今日の怒った回数は${angryNumber}回です`;
} else {
message = "今日は一度も怒っていません!";
}
response = {
status: 200,
body: {
message: message
}
}
return response;
}
if (timeStamp == lastDate) {
// 更新
rows[rows.length - 1]['怒った回数'] = angryNumber + 1;
await rows[rows.length - 1].save();
} else { // 今日初めての実行
angryNumber = 1;
// シートに追加
await sheet.addRow([timeStamp, angryNumber]);
}
// 怒った回数に応じてテキストを変更
if (angryNumber < 3) {
message = `今日の怒った回数は、まだ${angryNumber}回です。このまま落ち着いていきましょう`;
} else if (angryNumber < 5) {
message = `今日の怒った回数は、現在${angryNumber}回です。少し気分をリフレッシュしましょう`;
} else {
message = `今日の怒った回数は、現在${angryNumber}回です。気分転換をして落ち着きましょう`;
}
response = {
status: 200,
body: {
message: message
}
};
return response;
}
今回は、少し複雑なコードになっています。以下が行っている内容です。
1
を追加それでは1行目から順に解説していきます。
// google-spreaesheetの読み込み
const { GoogleSpreadsheet } = require('google-spreadsheet');
// 認証情報jsonファイルを読み込む
const credit = require('./credentials.json');
exports.handler = async (event) => {
if (event.call === 'lambda') {
console.log('CALLED:LAMBDA');
/* If you use the external modules, please code the following: - 外部モジュールを使う場合に記入してくだい。
e.g. if ( xxxx !== null ){} // xxxx: instance for the module. - xxxx : 生成したインスタンス */
if (GoogleSpreadsheet !== null) { }
return;
}
// スプレッドシートキー
const spreadSheetKey = event["properties"]["preferences"]["spreadSheetKey"]
// スプレッドシートの指定
const doc = new GoogleSpreadsheet(spreadSheetKey);
// 認証
await doc.useServiceAccountAuth({
client_email: credit["client_email"],
private_key: credit["private_key"]
});
// スプレッドシートの情報取得
await doc.loadInfo();
// シートの取得
const sheet = doc.sheetsByIndex[0];
// 通知メッセージ
let message;
// 次のPieceに渡す
let response;
...
}
1~38行目です。
モジュールの読み込み、スプレッドシートの指定〜認証〜シートの取得、変数の宣言を行っています。
また、認証情報はJSONファイルからrequire
を使って読み込んでいます。ファイル名はわかりやすいようにcredentials.json
にしています。
// ヘッダーの追加
await sheet.setHeaderRow(["日にち", "怒った回数"]);
// タイムスタンプ(年と月と日)
const today = new Date();
today.setHours(today.getHours() + 9);// 日本時間に変換
const timeStamp = `${today.getFullYear()}年${today.getMonth() + 1}月${today.getDate()}日`;
40~46行目です。
ヘッダーを追加して、タイムスタンプを作成しています。Lambda上でnew Date()
を実行すると、協定世界時で時刻を取得するので、日本時間に変換する必要があります。
// 行情報の取得
let rows = await sheet.getRows();
// 最終行の日にちと怒った回数
let lastDate;
let angryNumber;
try {
lastDate = rows.slice(-1)[0]["日にち"];
angryNumber = rows.slice(-1)[0]["怒った回数"];
angryNumber = Number(angryNumber);
} catch(error) { // 初回実行時はデータが空のため作成
lastDate = timeStamp;
angryNumber = 0;
// 行を追加
await sheet.addRow([timeStamp, angryNumber]);
// 再取得
rows = await sheet.getRows();
}
48 ~ 66行目です。
シートから行情報を取得します。そしてrows.slice(-1)[0]["日にち"]
、rows.slice(-1)[0]["怒った回数"]
とそれぞれ最終行の「日にち」「怒った回数」を取得しています。
またNumber()
を使って文字列を数値に変換しています。
ただし初めて実行する場合、上記画像のようにシートには何も記載されていません。そのため「日にち」「怒った回数」を取得しようとしてもエラーが発生します。そのためtry…catch文を利用して、エラーが起きる場合(=初回実行時)は行を追加して、行情報を再取得しています。
// 22時以降の場合 怒った回数のみを返す
if (today.getHours() > 21) {
// 実行日のデータがない場合
if (timeStamp == lastDate) {
message = `今日の怒った回数は${angryNumber}回です`;
} else {
message = "今日は一度も怒っていません!";
}
response = {
status: 200,
body: {
message: message
}
}
return response;
}
68~85行目です。
if文を使って、実行した時間(=today.getHours()
)が22時以降である場合に実行されます。22時以降の場合は、怒った回数をカウントするのではなく、怒った回数が何回かを通知するのみとなります。
また、最終行の日にちとタイムスタンプが一致するかをさらにif文で判定しています。一致する場合は、そのまま取得した怒った回数を通知します。一致しない場合というのは、その日初めて実行することになるので今日は一度も怒っていません!
と通知するようにしています。
また、return
を実行すると、それ以降のコードは実行されません。つまり、22時以降の場合は、ここで処理が終わります。
if (timeStamp == lastDate) {
angryNumber = angryNumber + 1;
// 更新
rows[rows.length - 1]['怒った回数'] = angryNumber + 1;
await rows[rows.length - 1].save();
} else { // 今日初めての実行
angryNumber = 1;
// シートに追加
await sheet.addRow([timeStamp, angryNumber]);
}
87 ~ 97行目です。
ここからは、22時以前に実行した場合の処理となります。同じように、最終行の日にちとタイムスタンプが一致するかを判定して、その日初めて実行したかをチェックしています。
2回目以降の場合は、怒った回数に1
を足して更新します。初めての実行の場合は、怒った回数を1
として行を追加しています。
// 怒った回数に応じてテキストを変更
if (angryNumber < 3) {
message = `今日の怒った回数は、まだ${angryNumber}回です。このまま落ち着いていきましょう`;
} else if (angryNumber < 5) {
message = `今日の怒った回数は、現在${angryNumber}回です。少し気分をリフレッシュしましょう`;
} else {
message = `今日の怒った回数は、現在${angryNumber}回です。気分転換をして落ち着きましょう`;
}
response = {
status: 200,
body: {
message: message
}
};
return response;
99 ~ 115行目です。
怒った回数に応じて、通知するメッセージを変更しています。
Google Sheets APIを使用すると、Node.js側でスプレッドシートの操作を行えるのが分かったと思います。
また、通常データベースと言えばMySQLなどのミドルソフトウェアだと思いますが、このようにスプレッドシートを簡易データベースとして活用することで時間短縮やコストの削減ができます。
今回は「怒った回数」を記録するようにしましたが、他のものを記録できるPieceを是非作ってみてください。
ご覧くださいましてありがとうございました。