AWS
GoogleAppsScript
spreadsheet
IoT
AWSLambda

AWS IoT エンタープライズボタンで掃除の記録をGoogle Spreadsheetに残す

More than 1 year has passed since last update.

AWS IoT エンタープライズボタンがついに日本でも手に入るようになったので、浴室やトイレに設置して掃除の記録をGoogle Spreadsheetに記録するボタンを作った。


全体像

flow.png

掃除が終わったらAWS IoT エンタープライズボタンを押す



AWS Lambdaの関数が呼ばれる



Google Apps Scriptの公開URLが叩かれる



Google Spreadsheetに掃除した場所の記録が残る

なお、この投稿では実験目的/わかりやすさ重視のため、認証については実装を省略しています。もし実際に似たようなシステムを運用する場合は、適宜アクセス制限の設定と実装を行ってください。


AWS IoT エンタープライズボタンの初期設定

AWS IoTボタンのセットアップについては、長くなるので割愛します。下記の記事を参照してください。

【国内販売開始】AWS IoT Enterprise Button試してみたらホンマに簡単にLambda関数を実行できた


SpreadsheetとApps Scriptの設定


Spreadsheetの作成

掃除をした日時と場所を記録していくためのSpreadsheetを新しく作成します。

スクリーンショット 2018-05-27 12.29.39.png

一行目に「日時」「場所」というヘッダーとなる行を入力したら残りの行は削除しておきます。


スクリプトの作成

「ツール」「スクリプトエディタ」を開いて、スクリプトを作成します。

function writeHouseworkLog(place) {  

var sheet = SpreadsheetApp.getActiveSheet();
var maxRows = sheet.getMaxRows();
sheet.insertRowAfter(maxRows);
var range = sheet.getRange(maxRows + 1, 1, 1, 2);
var value = range.setValues([[new Date(), place]]);
}

function doPost(e){
var params = JSON.parse(e.postData.getDataAsString());
place = params.place;

var res = ContentService.createTextOutput();
res = res.setMimeType(ContentService.MimeType.JAVASCRIPT);

if (place != undefined) {
writeHouseworkLog(place);

res = res.setContent(JSON.stringify({"place": place}));
return res
} else {
res = res.setContent(JSON.stringify({"error": "place is empty."}));
return res
}
}

function test() {
writeHouseworkLog("洗面所の掃除");
}

POST形式のHTTPリクエストを受け取ります。パラメータはJSON形式で渡すようにして、placeという引数の中身と現在時刻をSpreadsheetの最終行の後に追加します。

スクリーンショット 2018-05-27 12.39.27.png

最終的な動作テストはCURLなどを使って行う必要がありますが、それ以前の動作確認(今回の場合であれば、Spreadsheetに新しく行を追加する処理など)はテスト用の関数(今回の場合はtest)を用意しておくとスクリプトエディタ上で即座に実行/確認をできるので便利です。


ウェブアプリケーションとして公開

「公開」「ウェブアプリケーションとして導入...」から、公開設定を行います。

スクリーンショット 2018-05-27 12.40.17.png

不正利用防止のため、本来は「アプリケーションにアクセスできるユーザー」を制限するべきですが、今回は動作確認をわかりやすくするため、匿名ユーザーでのアクセスを許可しています。(つまり、URLがわかれば誰でも実行できてしまう)

もし実際に運用する場合は、アクセスできるユーザーを制限した上で認証の設定を行ってください。

公開したら、CURLなどを使ってウェブアプリケーションのURLを叩いて、ちゃんと記録されるか確かめておきましょう。

スクリーンショット 2018-05-27 12.46.15.png


Lambdaの設定


Lambda関数の作成

AWS Lambdaコンソールに入って、新しくLambda関数を作成します。

スクリーンショット 2018-05-27 12.58.24.png

ランタイムはなんでも良いですが、今回はPythonで書きます。今回はSESなど他のサービスは利用しないので、ロールに特にポリシーテンプレートを追加する必要はないです。


Lambda関数の編集

from __future__ import print_function

import json
import logging
import urllib.request

GAS_URL = "{GASウェブアプリケーションのURL}"

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
logging.info('Received event: ' + json.dumps(event))

attributes = event['placementInfo']['attributes']
place = attributes['place']

headers = {
'Content-Type': 'application/json'
}
request_body = {"place": place}

logger.info("Request body: " + json.dumps(request_body))

req = urllib.request.Request(GAS_URL, data=json.dumps(request_body).encode('utf-8'), method='POST', headers=headers)
with urllib.request.urlopen(req) as res:
logger.info(res.read().decode("utf-8"))

logger.info('Done')

上で公開したGoogle Apps ScriptのURLにPOSTリクエストを送るようにします。

ボタンごとに設定した属性はevent['placementInfo']['attributes']以下に含まれて呼ばれます。今回はボタンごとにplaceという属性に「浴室の掃除」「トイレの掃除」のような値を設定しておくことにします。

そして、その値をHTTPリクエストの引数にしてGoogle Apps ScriptのURLを叩くようにします。


Lambda関数のテスト

画面右上「テストイベントの設定」から、ボタンが押された際に呼ばれるリクエストを再現したテストイベントを用意します。

スクリーンショット 2018-05-27 13.05.39.png

作成したテストイベントを選んで、「テスト」してみます。

スクリーンショット 2018-05-27 13.07.19.png

画面下部のコード編集画面でログを見ると、無事にリクエストを送信できたようです。

スクリーンショット 2018-05-27 13.08.23.png

Spreadsheetの方を確認すると、ちゃんと行が追加されています。

スクリーンショット 2018-05-27 13.09.36.png


IoTボタンの設定


テンプレートの設定

IoTボタンのプロジェクトのテンプレート編集画面で、ボタンが押された時に上で作ったLambda関数が呼ばれるように設定します。

スクリーンショット 2018-05-27 13.10.19.png


ボタンごとの設定

最後にプレイスメントの設定画面から、ボタンごとの設定を行います。このプレイスメント(ボタン)ではplaceに「浴室の掃除」を設定しています。別のプレイスメント(ボタン)では、placeに「トイレの掃除」を設定しました。

スクリーンショット 2018-05-27 13.12.41.png


動作確認

最後に実際にボタンを押して見ます。

スクリーンショット 2018-05-27 13.14.52.png

保存された!


まとめ

スマホを持ち歩かなくてもネット上の何かに対してアクションを実行できる、のは楽しい。

ボタンを押した際のアクションをLambdaではなく、直接Google Apps Scriptを指定できればもっと嬉しいのだけど、そこは会社が違うから仕方がない…。

なお、この記事の内容は上述の通り、実験目的/わかりやすさ重視のため認証関連の実装を省略しているため、本格的にこのようなシステムをする場合は認証関連の設定をお忘れなく!