IoTボタンによる回数記録基盤をAWSとRaspberry Piで構築する

f:id:apt-k-ueno:20211221090608j:plain

aptpod Advent Calendar 2021の22日目を担当する、製品開発グループintdash チームの呉羽です。

以下の要件を満たした回数記録基盤を、以前に個人開発したので紹介します。

  • Bluetoothで接続されたIoTボタンが押された回数を記録したい
  • ボタンが押された時刻と共に永続化したい
  • 永続化されたデータを集計して閲覧したい

利用したもの

構築までの流れ

今回は以下の図のように、ボタンを押してから永続化される流れとなります。

f:id:aptpod_tech-writer:20211221184015p:plain
IoTボタンによる回数記録までの流れ

IoTボタンの準備

今回はIoTボタンとしてCamKix カメラシャッターボタンを利用します。 この製品はBluetoothで接続可能なスマホのカメラシャッター向けボタンですが、実質的にはボリュームアップキーが1つあるキーボードです。価格は1000円ほど(2021/12/20確認)。

Raspberry Piの準備

IoTボタンとAWSを仲介するための機器として、今回はRaspberry Pi 4(OSはUbuntu Server)を利用します。Raspberry Piでなくとも、以下の要件を満たせば代替可能です。

  • IoTボタンをBluetoothで接続可能
  • インターネットを利用可能

IoTボタンとの接続

LinuxでBluetoothデバイスの管理をする際、bluetoothctlというソフトウェアを用います。広く利用されているため接続手順は省略します。

IoTボタン押下時の処理

IoTボタンが押下された際、後述するAmazon API GatewayのURLを叩くことで、AWSとの橋渡しを行います。

今回はevdev-triggerを利用し、接続されたデバイスの特定のキーが押下された時にコマンドを実行させます。以下のような設定ファイルを用意すれば、IoTボタン押下時に、curlコマンドが実行されます。

# physical id of device
phys: a1:b2:c3:d4:e5:f6
triggers:
  # Key is the input event code to trigger the command.
  115:
    command: ["curl", "https://example.com"]

evdev-triggerはフォアグラウンドで動作するソフトウェアなので、supervisorによりバックグラウンドとして常に動作させておきます。以下がsupervisorの設定ファイル例です。

# cat /etc/supervisor/conf.d/evdev-trigger.conf 

[program:evdev-trigger--camkix]
command=/usr/local/bin/evdev-trigger --config /etc/evdev-trigger/camkix.yml
autorestart=true

AWSの準備

最後にAWS上で以下を構築します。

  • Amazon Timestreamによる記録の永続化
  • API Gatewayによる記録実行URLの実装
  • 集計結果をAmazon SNSを通じてメール通知

実装コードやCloudFormationのテンプレートはGitHubで公開しているため、以下の手順でデプロイ可能です。 https://gist.github.com/hareku/30023706e854015bfa289bd4a2081022

Amazon Timestreamによる記録の永続化

今回はデータの保存先としてAmazon Timestreamを利用します。保存先として、他にDynamoDBも候補として挙げられますが、Timestreamは後述する集計機能を提供しているため、今回はTimestreamを選択します。

Timestreamは時系列データベースで、AWS SDKを通して容易に扱えます。 今回のGo言語による実装コードはgithub.com/hareku/go-timestreamerで公開しており、Lambdaのエントリーファイルはcmd/simple/lambda/record/main.goです。

API Gatewayによる記録実行URLの実装

上述のLambdaをHTTPプロトコル経由で実行させるために、Amazon API Gatewayを用います。 また不特定多数から呼び出されないよう、API Gatewayが提供しているAPIキーを設定することが推奨されます。

集計結果をAmazon SNSを通じてメール通知

TimestreamはSQL-likeな集計機能を提供しています。そこで集計結果を以下の手順で通知させます。

f:id:aptpod_tech-writer:20211221185014p:plain
回数記録基盤の結果通知の流れ

  1. CloudWatch Eventsで定期的にLambdaを実行する
  2. 実行したLambda上でTimestreamの集計SQLを発行し、結果をAmazon SNSのトピックへ送信する
  3. Amazon SNSのトピックを購読しているメールアドレスに集計結果が送信される

以下のように、一日ごとの総記録回数がプレーンテキスト形式のメールで送信されます。

2021-11-27: 7
2021-11-26: 4
2021-11-25: 5
....

今回は以下のようなクエリをTimestreamに投げました。

SELECT bin(time, 24h) as date,
SUM(measure_value::bigint) as count
FROM "db"."meas"
WHERE time between ago(30d) and now()
GROUP BY bin(time, 24h)
ORDER BY date DESC

Timestreamは時系列関連の関数が多く実装されており、簡潔に集計することが出来ました。慣れ親しんだSQLで表現力高く書けますので、気になる方はAWSドキュメントのTimestreamを使った集計のSQL例の一読をおすすめします。

今回実装した集計用Lambdaのエントリーファイルはcmd/simple/lambda/publish-sns/main.goです。

まとめ

以上が、IoTボタンによる回数記録基盤の構築の流れです。例に挙げたコードでは、AWSの利用料金は月に1ドルも掛からないため(2021/12/20確認)、低コストで運用が可能です。