最近Philips社のHueがUpdateされて、お値段も若干下がったため個人的に買ってみました。(スターターパックがLED3つ+ブリッジで3万円弱です) 一つ目は玄関に設置して、雨の日には青く光らせることで傘を忘れずに持っていけるようにしています。
ちなみにこの間ペンダントライトを買ってきて、二つ目のLEDをダイニング用に使い始めました。ちょっとだけ暗いですが、ムーディなので良しとします。 さて、先日 SORACOM AirとRaspberry Piでトイレの空き状況を物理的に可視化してみた というブログを公開後、様々な反響をいただきました。 例えば…
https://twitter.com/c9katayama/status/729817828308582400
オンライン待ち行列とな…(ソラコムの片山さんにコメントいただきました!ありがとうございます!) 他にも…
https://twitter.com/okeee0315/status/729824250543017984
Slackで確認か…なるほどなるほど また、社内からも「ラズパイでトイレの状況が可視化されたことでトイレにポーリングしに行かなくなったのはいいけど、結局ラズパイまでポーリングする必要がある」といったフィードバックをもらいました。
彼の「トイレにポーリングする」という表現がとてもツボです。彼は一体何分おきにポーリングしていたのでしょうか。
本題
というわけで、沢山のフィードバックをいただいたので、Slackからトイレを予約できるシステムを実際に作ってみました。しかも最近流行りのサーバーレスです。
物理的な話
センサー・無線モジュール
前回は扉の開閉の検出に加速度センサーを使用していましたが、センサーから連続的に届く加速度から扉の開閉を正確に判断するのが難しかったため、リードスイッチに変更しました。なお、前回使った加速度センサーは無線モジュールとセットになっていたもの(TWE-Lite 2525A)ですが、リードスイッチと無線モジュールがセットになったものはないため、無線モジュールにはTWE-Lite DIPを使用しています。 リードスイッチとは、マグネットをセンサーの近くに繋げることによって、スイッチ内の回路がつながるものです。マグネットが近くにない場合はスイッチ内の回路が切れます。そのため、スイッチとマグネットを扉の端と端に取り付けることで、扉を閉じた時にはスイッチとマグネットが近づき、回路が繋がります。逆に扉が空いているときはスイッチとマグネットが離れているので、回路がつながりません。スイッチ内の回路が繋がっている状態と繋がっていない状態の電圧を数値として見ることで、今扉がどうなっているかがわかる、という仕組みです。 ちなみに、リードスイッチ・無線モジュール(TWE-Lite)はこのように設置しています。ブレッドボードには電池、TWE-Lite DIP、リードスイッチが載っています。ブレッドボードのすぐ右にあるものがリードスイッチ用の磁石です。一番右にあるのが、前回使った加速度センサーです。
回路・無線モジュール設定
回路図は以下の通りです(Fritzingにボタン電池がなかったので丸でごまかしています)。
+からリードスイッチを経由して、TWE-Lite DIPのA1(アナログ入力1)に入力しています。これだけだと、リードスイッチの回路が繋がっていない時に電圧が安定しないため、抵抗を組み込んでプルダウン回路にしています。
TWE-Lite DIPのアプリは無線タグアプリで、センサーのモードはアナログセンサモードにしています。スイッチのON/OFFの検出のために使うデジタルモードもあるのですが、このモードは立ち上がりと立ち下がり(扉が開いたか閉まったか)のどちらかしか検出できず、基本開状態の扉には不向きです。そのため、今回はアナログセンサーモードにして、30秒間隔で入力されているアナログ電圧を送信するように設定しています。扉の開閉の検出は、電圧を受け取ったEdison側で判別しています。
クラウド的な話
Slackとの連携
さて、次はクラウド側の話です。
最初はトイレ予約システムをブリ(Hubot)に組み込もうかと思ったのですが、せっかくなので今流行のサーバーレスにしてみました。
Slackとの連携はSlash Commandで行っています。Slash Commandとは「/hogehoge」のようなコマンドを定義してSlackから実行すると、任意の場所にコマンドの内容を送れるSlackの機能です。今回は3つのコマンドを作成しました。
- /toilet status: トイレの状態を確認する
- /toilet reserve: トイレが満室の場合、予約する(空き次第通知が来る)
- /toilet cancel: トイレの予約を取り消す
ちなみに、API GatewayとLambdaをSlash Commandのバックエンドとして使うBlueprintがAWSから公開されています。そのため、Slash CommandとAPI Gateway、Lambdaの連携はすぐに試すことができます。
構成図
今回のAWSの構成がこちらです。役割ごとにわけてAWSの枠を3つ用意しましたが、全て同じAWSアカウントにあります。それぞれの役割をざっくり説明すると、1段目がセンサーデータを受け取って蓄積・分析をする枠、2段目がアプリケーションのためのDBの枠、3段目がアプリケーション枠です。
1段目
1段目の枠はこれまでも行っている通りの普通のIoTです。無線モジュールからのデータをEdisonで受け取り、EdisonからAWS IoTにデータを送ります。
AWS IoTではRuleを2つ用意していて、Rule1ではそのままKinesis Firehoseに流しています。次に、Kinesis Firehoseの機能を使って、S3を経由してRedshiftにデータを貯めています。Rule1は受信したデータ全てが適用されます。
AWS IoTのRule2は、Lambdaを発火させるRuleです。このLambdaではトイレに並んでいる人が格納されているDB(DynamoDB)を見に行って、並んでいる人がいれば対象者をSlackで呼び出します。Rule2は、トイレの扉の開閉に変化があり、かつ変化が「閉->開」だった場合に適用されます(つまり、トイレが空いた時です)。
2段目
2段目はアプリケーションのためのDB枠で、具体的にはトイレの状態を保持するAWS IoTのShadowと、トイレに並んでいる人を管理するDynamoDBがあります。Shadowには、現在のトイレの個室の開閉状態と、最後にステータスが変わった時刻を記録しています。DynamoDBには、誰がいつ予約したのか、という情報が記録されています。
Shadowについては、Edisonで扉の開閉を検知した場合、EdisonからShadowを更新しています。ShadowはAPI経由でも更新できますが、MQTTのTopic($aws/things/[ThingName]/shadow/update)にPublishしても更新できます。
DynamoDBはSlackからのSlash Commandに応じてLambdaから読み書きされます。
この2つのDB(Shadow)をLambdaから参照することで、トイレの状態とトイレに並んでいる人の状態を管理しています。
3段目
最後の3段目はアプリケーションの枠です。
SlackのSlash CommandとのインターフェースになるAPI Gatewayと、Lambdaが3つです。
一つ目のLambdaはAPI Gatewayのバックエンドになるもので、Slash Commandに応じて、ShadowやDynamoDBを参照します。例えば、/toilet statusであればShadowを参照した結果を返したり、/toilet reserveであれば、Shadowを参照してトイレが満室であればDynamoDBのトイレキューにユーザを足す、トイレが空いていれば今なら空いていると促す、といった具合です。
二つ目のLambdaは1段目で説明した通り、トイレが空いた時に発火されます。DynamoDBを参照し、待っているユーザがいれば、Slack APIを使ってユーザにトイレが空いたことをコッソリ通知します。
三つ目のLambdaは定期的にShadowとDynamoDBをチェックするもので、15分間隔で発火されます。
このシステムのユーザが呼ばれるタイミング(トイレが空いたことを通知されるタイミング)はトイレのドアが「閉->開」となった時です。例えば、トイレの列に三人並んでいる時、個室が一つ空いて一人目が呼ばれたとしましょう。その人がトイレに行かなかったとしたらどうなるでしょうか。トイレは長い間「開」状態ですが、次の人を呼ぶトリガーはトイレのドアが「閉->開」となった時ですので、誰かがトイレに入って出ない限り、列に並んでいる二人目と三人目は永遠に呼ばれることがないのです。これでは社内が○○まみれになってしまいます。
そんな状況を打破してくれるのが三つ目のLambdaです。このLambdaは定期的にShadowとDynamoDBをチェックして、誰かを呼び出した後に15分以上経っていてもトイレが空き状態の場合は次の人を呼び出します。社内がいつでもキレイなのはこのLambdaのおかげです。いや〜、Lambdaって本当にいいものですね。
実際に使ってみる
ということでアーキテクチャーを理解したら実際にSlash Commandを実行してみましょう。
確認
/toilet status の例です。ちなみに 3 min はこの人が入って3分が経過していることを示しています。
予約・キャンセル
次は /toilet reserve の例です。トイレが空いていれば今がチャンスとばかりにトイレを急かされます。
トイレが空いていなければ、予約されます。トイレが空き次第通知が来ます。
予約したけど便意が去ってしまった場合でも大丈夫。/toilet cancel でキャンセルができます。譲り合いの精神は大事です。
通知
予約後、トイレが空くとトイレからコッソリ通知が来ます。正確には個人のSlackbot用のChannelに通知が届きます。
作ってみた結果
以上が、Slackでトイレを予約できるシステムの概要です。
実際に運用してわかったことは、トイレの個室(2部屋)が全て埋まっている状態というのは、意外と少ないということでした。/toilet reserveで予約しようとしても、今なら空いてるよ!と返されるのがほとんどです。
ですが今後社員が増えてトイレの使用率が上がったとしてももう心配することはありません。このコマンドがあれば何もかもスムーズに進むだろうと私は確信しています。
最後に、このコマンドの開発・運用において躓いたこと、困ったことを1つ紹介します。
3秒ルール
実はこのシステムには3秒ルールがあります。それは、SlackのSlash Commandのタイムアウト時間です。SlackのSlash Commandは、Slackからコマンドを発行した後、3秒以内にレスポンスが返ってこなければタイムアウトとされてしまいます。
LambdaのスクリプトによってはLambdaがResponseを返すまでに3秒以上かかり、Slash Commandがタイムアウトになってしまうことがあります。今回のトイレ用のLambdaも開発初期は4~5秒ほどかかっていました。これを解決するには、以下の様な方法があります。
- a. 軽量なスクリプトにする
- b. Lambdaのメモリを増やす
- c. Lambdaのコンテナが再利用されるように定期的にLambdaを発火させる
cについて説明すると、Lambdaは発火されるときにコンテナが作成され、ある程度経つとコンテナが削除されます。ですが、コンテナが削除される前に再度Lambdaが発火されると作成されたコンテナが再利用され、結果的にLambdaの実行時間のうちコンテナ作成時間を短縮することができます。 ちなみに、今回の場合はLambdaのメモリを増やすことでこれを解決しています。いや〜、お金の力って本当にいいものですね。
まとめ
というわけで、Slackでトイレを予約できるシステムをサーバーレスで構築した話、でした。今回の記事では、トイレの状態を収集できる仕組みをAWS IoTを使って構築しました。また、Slackを使ってトイレの状態を確認したり、予約したりできる仕組みをSlackのSlash Commandと、AWSのAPI Gateway、Lambdaを使って実装しました。
今回は題材としてトイレを選びましたが、身の回りにはIoTで解決できる課題はまだまだ沢山あります。今後もR&D活動を通して、オフィスをより良くしていきます!
おまけ
さて、颯爽と現れたトイレコマンドにより、サーバーワークスの平和は保たれたわけです。
ところでこの構成図、気になる点がありませんか?
この辺です。
そうです。BIです。
データをRedshiftに貯めるからには、BIっぽいことをしてみたいですよね?
どの辺がBusiness Intelligenceなのかはよくわかりませんが、サーバーワークスではトイレのドアの開閉のデータをPower BIを使って可視化をしています。
Power BIはMicrosoft社のBIツールで、様々なSaaSや、各種DBと接続してデータを取得することができます。Redshiftには公式には対応していないのですが、Postgresコネクタを使ってSQLを投げると、普通にデータを取得できます。
おまけとして、トイレのデータをPower BIで可視化している様子を紹介します。
トイレのドアの開閉のデータをPower BIを使って可視化をすると、こんなことがわかります。
一日のトイレの使用時間がわかる
一日のうち、どの時間帯にトイレが多く利用されているかがわかる
週次だってわかる
ご覧の通り、一日の使用時間や、どの時間帯に多いのか、そして室温との相関はどうなのか、など様々なことを確認することができます。いや〜、BIって本当にいいものですね。というわけで、これをおまけとして今回の記事を終わりたいと思います。
では!