LoginSignup
0
0

More than 3 years have passed since last update.

Owntracks の位置情報を AWS IoT にMQTT連携し Timestream に緯度・経度をストアする

Last updated at Posted at 2021-04-15

はじめに

AWS IoT と、Timestream の学習&アウトプットになります。
簡単に作り直せるように AWS CLI で構築しています。

2021年4月現在 Timestream は東京リージョンにローンチされていないので Lambda を利用してデータ転送しています。

構成

qiita-f52c0841775f9fc4d0c5-owntracks.png

利用環境

  • AWS CLI: aws-cli/2.1.18 Python/3.7.9 Windows/10 exe/AMD64 prompt/off
  • AWS SAM CLI: version 1.22.0
  • AWS IoT Core
  • AWS Timestream
  • Owntracks (Android): Version 2.3.0 (23024)
  • Windows 10 Pro: 20H2
  • Git Bash for Windows (AWS CLI実行ターミナル): 2.28.0.windows.1
  • Windows PowerShell: 5.1.19041.868

構築フロー

  • 1. AWS環境変数セット
  • 2. AWS IoT Core 構築
    • 2-1. AWS IoT core > ACT > ルール 作成
      • S3バケット作成
      • Timestream 構築
        • Lambda ビルド&デプロイ
      • ルールのロール作成
      • ルール作成
    • 2-2. AWS IoT core > 安全性 > 証明書 作成
      • 証明書、秘密鍵、公開鍵の作成
      • PKCS #12 個人情報交換ファイル(p12)作成
    • 2-3. AWS IoT core > 安全性 > ポリシー 作成
    • 2-4. AWS IoT core > 管理 > モノ 作成
    • 2-5. IOT Core の ATS エンドポイント(ホスト)取得
  • 3. Owntracks 設定
  • 4. AWS Timestream 構築
    • 4-1. Lambda ビルド&デプロイ
    • 4-2. AWS IoT core > ACT > ルール 追加

1. AWS環境変数、作業変数の設定

ここでは kikudai プロファイル、リージョンを環境変数にセットして利用しますが、defaultのプロファイルを利用する場合は設定不要です。

export AWS_PROFILE=kikudai
export AWS_DEFAULT_REGION=ap-northeast-1
bucket_name="qiita-f52c0841775f9fc4d0c5-owntracks"
common_name="qiita_f52c0841775f9fc4d0c5_owntracks"
mkdir ~/${common_name}
cd ~/${common_name}

2. AWS IoT core の構築

2-1. AWS IoT core > ACT > ルール 作成

Owntracks テレメトリデータ(MQTT Publish データ)を S3 に連携するルールとロールを作成します。

この S3 連携の主な目的はテレメトリデータのバックアップ、デバック、リストアになります。
後述の Lambda による Timestream 連携ルールの設定の方で、Timestream にデータ(緯度・経度など)をストアします。

S3 バケット作成

Owntracks テレメトリデータを保存する S3 バケットを作成します。

S3バケット作成
aws s3 mb "s3://${bucket_name}"

Timestream 構築

Owntracks のテレメトリデータ(MQTT Publish メッセージ)を AWS Lambda アクションで Timestream に連携します。
Lambda サンプルCode(Python)

Lambda ビルド&デプロイ

SAM cli で Lambda をビルド、デプロイします。

Windows の場合、
pip install -U aws-sam-cli
で sam cli をインストールするのが一番手っ取り早いと思います。

Lambdaビルド&デプロイ
git clone https://github.com/kikudai/qiita_f52c0841775f9fc4d0c5_owntracks.git
cd qiita_f52c0841775f9fc4d0c5_owntracks

sam build

# 対話形式のデプロイ
sam deploy --guided | tee deploy.log

sam ddeploy --guided を実行すると下記のような対話形式となるので [XXXX]: はエンター、 Y/n は一律 y を入力します。

対話形式の入力例
Configuring SAM deploy
======================

        Looking for config file [samconfig.toml] :  Found
        Reading default arguments  :  Success

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [to-timestream]: エンター
        AWS Region [ap-northeast-1]: エンター
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [Y/n]: yエンター
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: yエンター
        Save arguments to configuration file [Y/n]: yエンター
        SAM configuration file [samconfig.toml]: エンター
        SAM configuration environment [default]: エンター

        Looking for resources needed for deployment: Not found.
        Creating the required resources...
        Successfully created!
...

Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]:
yエンター
...

ローカル docker で動作確認したい場合は以下のコマンド

ローカルdockerによる起動テスト
sam build --use-container
sam local invoke OwntracksFunction --event /events/event_is_u.json

ただ、このテスト event.json が tst (Timestream に書き込むときの Time)のままだと、Timestream のメモリストアの期限に(今回は1時間としてます)ヒットして、 RejectedRecordsException が発生するはずなので、 sed などで今のUNIX時間に書き換えてご利用ください。

sedでUNIX時間を書換サンプル
# 本当はこういう感じでファイルを書き換えることなく、 sed を利用したいところです
sam local invoke OwntracksFunction \
  --event <(sed -e "/tst/ s/[0-9]+/$(date +'%s')/g" ./events/event_is_u.json)

# ただし、Git Bash for Windows では上記のような bash のプロセス置換がうまくいかず
# 普通にファイルを書き換えました
sed -ie --regexp-extended "/tst/ s/[0-9]+/$(date +'%s')/g" ./events/event.json

参考

ルールのロール作成

AWS IoT core > ACT > ルール のロールを作成します。
また、 AWS 管理ポリシーで用意されている次の Iot 関連ポリシー( IAM ポリシー - AWS IoT Core )をアタッチします。

  • AWSIoTThingsRegistration
  • AWSIoTLogging
  • AWSIoTRuleActions

Git Bash for Windows による aws cli 実行で file:// は、カレントのファイルでないと読み込めないようです。
例えば、こういったことができません。

echo 'hoge' > /tmp/hoge.json
aws iot hoge --hogehoge file:///tmp/hoge.json

(Windows のリアルパスを指定すると可能かもしれません)

ルールのロール作成
cat <<'EOF' > ${common_name}_iot_role.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "iot.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

aws iam create-role \
  --role-name ${common_name}_iot_role \
  --assume-role-policy-document file://${common_name}_iot_role.json

aws iam attach-role-policy \
  --role-name ${common_name}_iot_role \
  --policy-arn "arn:aws:iam::aws:policy/service-role/AWSIoTThingsRegistration"

aws iam attach-role-policy \
  --role-name ${common_name}_iot_role \
  --policy-arn "arn:aws:iam::aws:policy/service-role/AWSIoTLogging"

aws iam attach-role-policy \
  --role-name ${common_name}_iot_role \
  --policy-arn "arn:aws:iam::aws:policy/service-role/AWSIoTRuleActions"

ルール作成

AWS IoT core > ACT > ルール を作成します。
--topic-rule-payload の sql の FROM 句 'owntracks/#'` は Owntracksアプリで設定されるTopicを指定しています。
この指定で、Owntracks のすべてテレメトリを取得するようにします。

Lambda のトリガーを aws cli で追加するコマンドがなかなか探し出せず時間がかかりました。
トリガー追加の cli コマンドは lambda add-permission になります。
コンソール画面だと、ルールのアクション追加でさりげなく Lambda のトリガーも追加されますが、 aws cli の場合は、 iot create-topic-rule で作成しただけでは lambda トリガーの設定がされません。
また、 lambda トリガーの状態確認は以下になります。

Lambdaトリガー状態確認のサンプル
aws lambda get-policy --function-name ${lambda}) | jq -r .Policy | jq .

このことから lambda トリガーはポリシーとして設定されているようですね。

ルール作成
arn_iot_role=$(
  aws iam get-role \
  --role-name ${common_name}_iot_role \
  | jq .Role.Arn
)

lambda_arn=$(aws lambda list-functions \
  | jq -rc .Functions[].FunctionArn \
  | grep to-timestream-OwntracksFunction
)

cat <<EOF > ${common_name}_iot_s3_and_timestream_rule.json
{
  "sql": "SELECT clientid() AS clientid, timestamp() AS event_t, * FROM 'owntracks/#'",
  "ruleDisabled": false,
  "awsIotSqlVersion": "2016-03-23",
  "actions": [
    {
      "lambda": {
        "functionArn": "${lambda_arn}"
      }
    },
    {
      "s3": {
        "roleArn": ${arn_iot_role},
        "bucketName": "${bucket_name}",
        "key": "\${clientId()}/\${timestamp()}.json"
       }
    }
  ]
}
EOF

aws iot create-topic-rule \
  --rule-name ${common_name}_topic_rule \
  --topic-rule-payload  file://${common_name}_iot_s3_and_timestream_rule.json

lambda=$(aws lambda list-functions \
  | jq -rc .Functions[].FunctionName \
  | grep to-timestream-OwntracksFunction
)

source_arn=$(aws iot get-topic-rule \
  --rule-name ${common_name}_topic_rule \
  | jq -r .ruleArn)

# 素直に上記 source_arn で利用した aws iot get-topic-rule の結果から
# Account 部分を切り取ったほうがいいケースがありそう
source_account=$(aws sts get-caller-identity | jq -r .Account)

aws lambda add-permission \
  --function-name ${lambda} \
  --principal iot.amazonaws.com \
  --source-arn "${source_arn}" \
  --action "lambda:InvokeFunction" \
  --statement-id ${common_name}_topic_rule \
  --source-account ${source_account}

参考情報

2-2. AWS IoT core > 安全性 > 証明書 作成

証明書、秘密鍵、公開鍵 作成

証明書、秘密鍵、公開鍵作成
aws iot create-keys-and-certificate \
  --certificate-pem-outfile "${common_name}.cert.pem" \
  --public-key-outfile "${common_name}.public.key" \
  --private-key-outfile "${common_name}.private.key" \
  | tee "${common_name}_certificate.json"

証明書のアクティブ化

作成した証明書を有効化します。

証明書のアクティブ化
aws iot update-certificate \
  --certificate-id $(
    cat ${common_name}_certificate.json | jq -r .certificateId
  ) \
  --new-status ACTIVE

個人情報交換ファイル(PKCS #12)作成

Owntracks では拡張子が p12 の PKCS #12 個人情報交換ファイル必要なため、 openssl コマンド を利用し上記で取得した証明書と秘密鍵とパスワードから p12 ファイルを作成します。

Git Bash for Windows で openssl コマンドを実行すると Git Bash が固まったので、 PowerShell で実行しました。

Enter Export Password: とパスワードを求められるので(確認パスワードも)入力します。
このパスワードは Owntracks アプリで証明書として p12 ファイルを登録するとき必要になります。

個人情報交換ファイル(PKCS#12)作成
# PowerShellによる実行
$common_name = "qiita_f52c0841775f9fc4d0c5_owntracks"
cd ~/${common_name}
openssl pkcs12 `
  -export `
  -in "${common_name}.cert.pem" `
  -inkey "${common_name}.private.key" `
  -out "${common_name}.identity.p12"

参考情報

CA 証明書取得(サーバー認証用)

Owntracks アプリの証明書設定で必要な CA 証明書を取得します。

URLリンク切れの場合は サーバー認証 - AWS IoT Coreaws iot ca証明書 - Google 検索 で、探してください。
また、Windows10 や Android に既に設定されている Amazon CA証明書 があれば、それでも利用できると思います。

CA証明書取得(サーバー認証用)
curl -O https://www.amazontrust.com/repository/AmazonRootCA1.pem

2-3. AWS IoT core > 安全性 > ポリシー 作成

ポリシーを作成し、そのポリシーを証明書にアタッチします。

ポリシー作成
cat <<EOF > ${common_name}_policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Publish",
        "iot:Subscribe",
        "iot:Receive",
        "iot:Connect"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}
EOF

aws iot create-policy \
  --policy-name ${common_name}_policy \
  --policy-document file://${common_name}_policy.json

aws iot attach-policy \
  --policy-name ${common_name}_policy \
  --target $(
    cat ${common_name}_certificate.json | jq -r .certificateArn
  )

2-4. AWS IoT core > 管理 > モノ 作成

モノを作成し、証明書をアタッチします。

モノ作成
aws iot create-thing \
  --thing-name ${common_name}_android

aws iot attach-thing-principal \
  --thing-name ${common_name}_android \
  --principal $(
    cat ${common_name}_certificate.json | jq -r .certificateArn
  )

2-5. IOT Core の ATS エンドポイント(ホスト)取得

Owntracks のホストに設定するATSエンドポイントを取得します。

ATSエンドポイント(ホスト)取得
aws iot describe-endpoint \
    --endpoint-type iot:Data-ATS

参考情報

Owntracks の設定

カレントディレクトリにある、以下のファイルを Google Drive などに保存します。

  • AmazonRootCA1.pem
  • qiita_f52c0841775f9fc4d0c5_owntracks.identity.p12

Connection > Mode 設定

  • MQTT に設定します

Connection > Host 設定

  • Host2-5. IOT Core の ATS エンドポイント(ホスト)取得 の ホスト を設定します

endpointAddress で取得できた値の xxxxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com を設定します。

ATSエンドポイント取得結果サンプル
{
    "endpointAddress": "xxxxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com"
}
  • Port8883 に設定します
  • Client ID に 適当な ID を設定します
    (自動で設定されていればそのまま利用で問題ありません)

IoT ルール作成で設定した sql
"SELECT clientid() AS clientid, timestamp() AS timestamp, * FROM 'owntracks/#'"
clientid() で取得できる値になります。

owntracks_host_s.jpg

Connection > Security 設定

  • TLS をオンにします
  • CA certificate に Google Drive などに保存した AmazonRootCA1.pem を選択します
  • Client certificate に Google Drive などに保存した qiita_f52c0841775f9fc4d0c5_owntracks.identity.p12 を選択します
  • Client certificate password に p12ファイルを設定したときの パスワードを入力します

owntracks_security_s.jpg

Owntracks MQTT 接続確認

画面右上の 丸 i マーク を押して Status を確認します。
owntracks_i_s.jpg

Endpoint state が Connected になっていれば、問題なく接続されています。
Error になっている場合は 設定の何かで不足か間違いがあります。
awntracks_status_s.jpg

ここまでの設定が問題なければ、 Timestream 米国東部 (バージニア北部: us-east-1) にデータが書き込まれ、 S3 のバケット qiita-f52c0841775f9fc4d0c5-owntracks に Owntracks からのテレメトリデータ(json)が格納されていきます。

クリーニング(削除)

削除のための環境変数、変数設定

export AWS_PROFILE=kikudai
export AWS_DEFAULT_REGION=ap-northeast-1
bucket_name="qiita-f52c0841775f9fc4d0c5-owntracks"
common_name="qiita_f52c0841775f9fc4d0c5_owntracks"
cd ~/${common_name}

S3バケット削除

aws s3 rb s3://${bucket_name} \
  --force

IoTルールのロール削除

aws iam detach-role-policy \
  --role-name ${common_name}_iot_role \
  --policy-arn "arn:aws:iam::aws:policy/service-role/AWSIoTThingsRegistration"

aws iam detach-role-policy \
  --role-name ${common_name}_iot_role \
  --policy-arn "arn:aws:iam::aws:policy/service-role/AWSIoTLogging"

aws iam detach-role-policy \
  --role-name ${common_name}_iot_role \
  --policy-arn "arn:aws:iam::aws:policy/service-role/AWSIoTRuleActions"

aws iam delete-role \
  --role-name ${common_name}_iot_role 

IoTルールの削除

aws iot delete-topic-rule \
  --rule-name ${common_name}_topic_rule 

IoTポリシー削除

aws iot delete-policy \
  --policy-name ${common_name}_policy

IoTモノ削除

aws iot delete-thing \
  --thing-name ${common_name}_android

IoT証明書削除

aws iot update-certificate \
  --certificate-id $(
    cat ${common_name}_certificate.json | jq -r .certificateId
  ) \
  --new-status INACTIVE

aws iot delete-certificate \
  --certificate-id $(
    cat ${common_name}_certificate.json | jq -r .certificateId
  )

作業ディレクトリの削除

cd
rm -rf ~/${common_name}

CloudFormation スタック削除

SAM CLI のデプロイ時に利用したスタックとLambdaの削除

aws-sam-cli-managed-default というスタックも作成されますが、他の方が SAM CLIを利用していた場合は削除しないほうが無難です。
S3バケット、aws-sam-cli-managed-default-samclisourcebucket-XXXXXXXXも同様です。
削除しても問題ない場合は、S3バケットを空にしてから
aws cloudformation delete-stack --stack-name aws-sam-cli-managed-default
してください。

aws cloudformation delete-stack --stack-name to-timestream

Timestream 削除

aws timestream-write delete-table \
  --region us-east-1 \
  --database-name ${common_name} \
  --table-name location

aws timestream-write delete-table \
  --region us-east-1 \
  --database-name ${common_name} \
  --table-name lwt

aws timestream-write delete-database \
  --region us-east-1 \
  --database-name ${common_name}

参考情報

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0