AWS IoT エンタープライズボタンがついに日本でも手に入るようになったので、浴室やトイレに設置して掃除の記録をGoogle Spreadsheetに記録するボタンを作った。
全体像
掃除が終わったらAWS IoT エンタープライズボタンを押す
↓
AWS Lambdaの関数が呼ばれる
↓
Google Apps Scriptの公開URLが叩かれる
↓
Google Spreadsheetに掃除した場所の記録が残る
**なお、この投稿では実験目的/わかりやすさ重視のため、認証については実装を省略しています。**もし実際に似たようなシステムを運用する場合は、適宜アクセス制限の設定と実装を行ってください。
AWS IoT エンタープライズボタンの初期設定
AWS IoTボタンのセットアップについては、長くなるので割愛します。下記の記事を参照してください。
【国内販売開始】AWS IoT Enterprise Button試してみたらホンマに簡単にLambda関数を実行できた
SpreadsheetとApps Scriptの設定
Spreadsheetの作成
掃除をした日時と場所を記録していくためのSpreadsheetを新しく作成します。

一行目に「日時」「場所」というヘッダーとなる行を入力したら残りの行は削除しておきます。
スクリプトの作成
「ツール」「スクリプトエディタ」を開いて、スクリプトを作成します。
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の最終行の後に追加します。

最終的な動作テストはCURL
などを使って行う必要がありますが、それ以前の動作確認(今回の場合であれば、Spreadsheetに新しく行を追加する処理など)はテスト用の関数(今回の場合はtest
)を用意しておくとスクリプトエディタ上で即座に実行/確認をできるので便利です。
ウェブアプリケーションとして公開
「公開」「ウェブアプリケーションとして導入...」から、公開設定を行います。

不正利用防止のため、本来は「アプリケーションにアクセスできるユーザー」を制限するべきですが、今回は動作確認をわかりやすくするため、匿名ユーザーでのアクセスを許可しています。(つまり、URLがわかれば誰でも実行できてしまう)
もし実際に運用する場合は、アクセスできるユーザーを制限した上で認証の設定を行ってください。
公開したら、CURL
などを使ってウェブアプリケーションのURLを叩いて、ちゃんと記録されるか確かめておきましょう。

Lambdaの設定
Lambda関数の作成
AWS Lambdaコンソールに入って、新しくLambda関数を作成します。
ランタイムはなんでも良いですが、今回は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関数のテスト
画面右上「テストイベントの設定」から、ボタンが押された際に呼ばれるリクエストを再現したテストイベントを用意します。

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

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

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

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

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

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

保存された!
まとめ
スマホを持ち歩かなくてもネット上の何かに対してアクションを実行できる、のは楽しい。
ボタンを押した際のアクションをLambdaではなく、直接Google Apps Scriptを指定できればもっと嬉しいのだけど、そこは会社が違うから仕方がない…。
なお、この記事の内容は上述の通り、実験目的/わかりやすさ重視のため認証関連の実装を省略しているため、本格的にこのようなシステムをする場合は認証関連の設定をお忘れなく!