AWS IoT EduKit を使ってみた (前篇)

2020 年末に発売された、AWS IoT EduKit。

オールインワンのエッジデバイスとして使える M5Stack Core2 をベースとしたカスタムモデルです。

スペック

  • M5Stack Core2 (コア部分)

  • M5GO Bottom2 for AWS

  • デジタルマイクロフォン
  • プログラマブルRGB LED ×10
  • HY2.0-4P 拡張ポート ×2
  • LEGO互換穴(底面部)
  • バッテリー
  • ATECC608A Trust&GO セキュアエレメント ★AWS IoT EduKit 独自

特徴的なのは「Trust&GO セキュアエレメント」のようです。

参考)

ワークショップ

EduKit ということで、専用のワークショップ(ハンズオン)があります。まずはこれで学べということで。

私は以下の環境でおこないました。手順は基本的にハンズオンに沿っておこなっていますが、理解しづらかった概要的なことやつまづいた点などコメントしていきます。

  • MacBook Pro (13-inch, 2018) / macOS 11.3.1
  • 以下はインストール済みなので省略します。
  • AWS CLI v2
  • Visual Studio Code + PlatformIO

注意: 2021-05-01 時点の内容をベースに進めました。その後手順が変わっている可能性もありますのでご注意ください。(以前にも一度トライしたのですが、その頃と変わっている気がする。)

1. 開始方法

USB to UART ブリッジ VCP(仮想COMポート)ドライバーのインストール

M5Stack デバイスとシリアル通信するためのドライバーです。

Silicon Labs 社の USB to UART Bridge VCP Drivers ページから CP210x VCP Mac OSX Driver をダウンロードし、インストーラーに従ってインストールしておきます。

ソースコードを取得

GitHub のリポジトリ (m5stack/Core2-for-AWS-IoT-EduKit) からソースコードを取得します。

git clone https://github.com/m5stack/Core2-for-AWS-IoT-EduKit.git

中には各章で使用するサンプルソースが含まれています。

RainMaker

ここは PlatformIO の使い方を試すステップです。やらなくても良かったです。

RainMaker アプリのインストール

TODO: RainMaker とは?

Android/iPhone 用のアプリがあります。

ESP RainMaker Agent の実行

PlatformIO の PIOHome > Open > Open Project から、ダウンロードしたソースの Getting-Started フォルダを開きます。いちど開いたプロジェクトは一覧に追加されるため、次回以降は一覧から Open をクリックします。複数のプロジェクトやワークスペースを開いている場合は作業中のプロジェクトが選択されていることを確認しておきます。

ステータスバー

plaformio.ini に、M5Stack を接続したシリアルデバイスを指定します。デバイスは PIO Home > Devices から確認できます。

upload_port = /dev/cu.SLAB_USBtoUART

Miscellaneous > New Terminal でターミナルを開き、コマンドを実行してファームウェアをビルドしたりインストールしたりします。ビルドやインストール等はコマンドで説明されていますが、VSCode のステータスバーに表示されるアイコンをクリックすることで実行することもできます。

操作 メニュー/コマンド アイコン
コンソールを開く Miscellaneous > New Terminal コンソールアイコン
ビルド pio run --environment core2foraws ビルドアイコン
アップロード pio run --environment core2foraws --target upload アップロードアイコン
出力を監視 pio run --environment core2foraws --target monitor モニターアイコン

この状態で M5Stack デバイスを再起動すると、ターミナルに QR コードが表示されます。

これをスマホに入れたアプリで読み取ると、RainMaker にデバイスが登録されるようです。

ファームウェアを削除する。

pio run --environment core2foraws --target erase

2. L チカ

PlatformIO でソースの Blinky-Hello-World を開きます。「L チカ」って英語ではこう言うんですね。

AWS IoT Core への登録

M5Stack デバイスを USB で接続し、AWS CLI の認証情報を設定した状態で以下のコマンドを実行すると、デバイスが AWS IoT Core に登録されます。AWS IoT EduKit で独自に実装されたセキュアエレメントが使うことで面倒な作業が不要とのことで、AWS IoT EduKit の一番の特徴はこれ。

AWS IoT Core にデバイス登録

cd utilities/AWS_IoT_registration_helper
python3 registration_helper.py -p /dev/cu.SLAB_USBtoUART
cd ../..

ここでは以下の流れでセキュリティエレメントに安全に保存された秘密鍵を元に AWS IoT Core にデバイスを登録します。デバイスと AWS IoT Core との通信時、この情報を使って認証をおこないます。

registration_helper.py

uml diagram

正常に登録されたかどうか、以下のコマンドで確認することができます。

$ aws iot list-things
{
    "things": [
        {
            "thingName": "(ID)",
            "thingArn": "arn:aws:iot:(AWSリージョン):(AWSアカウント番号):thing/(ID)",
            "attributes": {},
            "version": 1
        }
    ]
}

Blinky-Hello-World ファームウェアの設定・デプロイ

AWS との通信をおこなうための設定を埋め込んだファームウェアを作成し、デバイスにアップロードします。

以下のコマンドで AWS IoT のエンドポイントを確認します。

aws iot describe-endpoint --endpoint-type iot:Data-ATS

以下のコマンドで設定メニューを起動し、以下の項目を設定します。

pio run --environment core2foraws --target menuconfig
  • Component config
  • Amazon Web Services IoT Platform
    • AWS IoT Endpoint Hostname : 先ほど調べた AWS IoT エンドポイントを設定
  • AWS AWS IoT EduKit Configuration
  • WiFi SSID : 接続する Wi-Fi の SSID
  • WiFi Password : 接続する Wi-Fi のパスワード

設定した内容は sdkconfig ファイルに保存されるようです。

CONFIG_AWS_IOT_MQTT_HOST="xxxxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com"
CONFIG_WIFI_SSID="(WiFi SSID)"
CONFIG_WIFI_PASSWORD="(WiFi Password)"

以上の設定をしたらファームウェアをビルドし、デバイスにアップロードします。起動すると、以下のような画面が表示されました。

Blinky 画面

送受信

AWS IoT との通信が確立すると、MQTT プロトコルでデバイスとのメッセージ送受信をおこなうことができるようになります。

トピックに (デバイスID)/# を指定して Subscribe すると、デバイスからのすべてのメッセージを受信できます。このファームウェアでは 1 秒ごとに「Hello from AWS IoT EduKit ...」というメッセージが送信されてくることが確認できました。

MQTT Subscribe

(デバイスID)/blink トピックに何らかのメッセージを送信すると、LED が点滅します。もういちど送信すると、消灯します。

MQTT Publish

3. スマートサーモスタット

スマートサーモスタットファームウェア

ファームウェアは用意されたものを使うだけ。このファームウェアでは、センサーから雑音レベル(sound)と温度(temperature)を測定し、AWS IoT に継続的に送信します。状態として空調(HAVC)の状態(hvacStatus)と在室状況(roomOccupancy)を保持します。

  1. Smart-Thermostat プロジェクトを開く。

  2. L チカ同様に sdkconfig を設定する。

    dotenv CONFIG_AWS_IOT_MQTT_HOST="xxxxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com" CONFIG_WIFI_SSID="(WiFi SSID)" CONFIG_WIFI_PASSWORD="(WiFi Password)"

  3. ファームウェアをビルド、アップロードする。

管理コンソールのテストページから $aws/things/(デバイス ID)/shadow/update/accepted を Subscribe すると、以下のような情報が受信できることが確認できます。

{
  "state": {
    "reported": {
      "temperature": 68.452881,
      "sound": 3,
      "roomOccupancy": false,
      "hvacStatus": "STANDBY"
    }
  },
  "metadata": {
    "reported": {
      "temperature": {
        "timestamp": 1620125076
      },
      "sound": {
        "timestamp": 1620125076
      },
      "roomOccupancy": {
        "timestamp": 1620125076
      },
      "hvacStatus": {
        "timestamp": 1620125076
      }
    }
  },
  "version": 2556,
  "timestamp": 1620125076,
  "clientToken": "012342f74eab8e1201-2555"
}

トピック $aws/things/<<CLIENT_ID>>/shadow/update に以下のようなメッセージを Publish すると状態を更新します。hvacStatus が HEATING なら赤く、COOLING なら青く LED が点灯します。

{
  "state": {
    "desired": {
      "hvacStatus": "HEATING",
      "roomOccupancy": true
    }
  }
}

音声から部屋の在室状況を更新する IoT Rule の作成

以降は AWS IoT サービスの使い方になります。ワークショップでは管理コンソールからの手順になりますが、CLI での手順を記述してみました。

部屋の在室状況を更新する

  1. IoT Rule からスマートサーモスタットデバイスにメッセージを送信する権限を持つ IAM ロールを作成する。

    ```shell UPDATE_IAM_ROLE_NAME=SmartThermostatUpdateRole UPDATE_IOT_RULE_NAME=SmartThermostatUpdateRule CLIENT_ID=012342f74eab8e1201 AWS_REGION=ap-northeast-1 THERMOSTAT_TOPIC_NAME=\$aws/things/${CLIENT_ID}/shadow/update

    AWS_ACCOUNT_NUMBER=$(aws sts get-caller-identity | jq -r '.Account') THERMOSTAT_TOPIC_ARN=arn:aws:iot:${AWS_REGION}:${AWS_ACCOUNT_NUMBER}:topic/${THERMOSTAT_TOPIC_NAME} aws iam create-role --role-name "${UPDATE_IAM_ROLE_NAME}" --path "/service-role/" \ --assume-role-policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"iot.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}" aws iam put-role-policy --role-name "${UPDATE_IAM_ROLE_NAME}" --policy-name "${UPDATE_IAM_ROLE_NAME}Policy" \ --policy-document "{\"Version\":\"2012-10-17\",\"Statement\":{\"Effect\":\"Allow\",\"Action\":\"iot:Publish\",\"Resource\":\"${THERMOSTAT_TOPIC_ARN}\"}}" ```

  2. 在室状況(roomOccupancy)を更新する IoT Rule を作成する。

    shell UPDATE_ROLE_ARN=$(aws iam get-role --role-name "${UPDATE_IAM_ROLE_NAME}" | jq -r '.Role.Arn') aws iot create-topic-rule --rule-name "${UPDATE_IOT_RULE_NAME}" \ --topic-rule-payload "{ \"sql\": \"SELECT CASE state.reported.sound > 20 WHEN true THEN true ELSE false END AS state.desired.roomOccupancy FROM '${THERMOSTAT_TOPIC_NAME}/accepted' WHERE state.reported.sound <> Null\", \"awsIotSqlVersion\": \"2016-03-23\", \"actions\": [{ \"republish\": { \"roleArn\": \"${UPDATE_ROLE_ARN}\", \"topic\": \"\$${THERMOSTAT_TOPIC_NAME}\" } }] }"

スマートサーモスタットデバイスから受信したメッセージを IoT Events に渡す

メッセージを IoT Events に渡す

  1. IoT Events でメッセージを受信するために、構造を定義した Input を作成する。(手順では管理コンソールからメッセージデータをアップロードすることで、それを元に属性が自動的に解析されますが、CLI の場合は構造を直接指定する。)

    ```shell INPUT_NAME=thermostat

    aws iotevents create-input \ --input-name "${INPUT_NAME}" \ --input-definition "{ \"attributes\": [ {\"jsonPath\": \"current.state.reported.sound\"}, {\"jsonPath\": \"current.state.reported.temperature\"}, {\"jsonPath\": \"current.state.reported.roomOccupancy\"}, {\"jsonPath\": \"current.state.reported.hvacStatus\"}, {\"jsonPath\": \"current.version\"}, {\"jsonPath\": \"timestamp\"} ] }" ```

  2. メッセージを IoT Events に送信する権限を持つ IAM ロールを作成する。

    ```shell EVENT_IAM_ROLE_NAME=SmartThermostatEventRole EVENT_IOT_RULE_NAME=SmartThermostatEventRule

    INPUT_ARN=arn:aws:iotevents:${AWS_REGION}:${AWS_ACCOUNT_NUMBER}:input/${INPUT_NAME} aws iam create-role --role-name "${EVENT_IAM_ROLE_NAME}" --path "/service-role/" \ --assume-role-policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"iot.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}" aws iam put-role-policy --role-name "${EVENT_IAM_ROLE_NAME}" --policy-name "${EVENT_IAM_ROLE_NAME}Policy" \ --policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"iotevents:BatchPutMessage\",\"Resource\":[\"${INPUT_ARN}\"]}]}" ```

  3. メッセージを IoT Events に送信する IoT Rule を作成する。

    shell EVENT_IAM_ROLE_ARN=$(aws iam get-role --role-name "${EVENT_IAM_ROLE_NAME}" | jq -r '.Role.Arn') aws iot create-topic-rule --rule-name "${EVENT_IOT_RULE_NAME}" \ --topic-rule-payload "{ \"sql\": \"SELECT current.state as current.state, current.version as current.version, timestamp FROM '${THERMOSTAT_TOPIC_NAME}/documents'\", \"awsIotSqlVersion\": \"2016-03-23\", \"actions\": [{ \"iotEvents\": { \"inputName\": \"${INPUT_NAME}\", \"roleArn\": \"${EVENT_IAM_ROLE_ARN}\" } }] }"

IoT Events にクラウドアプリケーションを作成

IoT Events に送信されたメッセージから取得した在室状況(roomOccupancy)と温度(temparature)を元に状態管理をおこない、空調状態(havcStatus)を制御するアプリケーションです。ここの詳細は触れていないので割愛します。

クリーンアップ

ここまでの手順で作成したリソースは、以下のコマンドで削除することができます。

aws iot delete-topic-rule --rule-name "${EVENT_IOT_RULE_NAME}"
aws iam delete-role-policy --role-name "${EVENT_IAM_ROLE_NAME}" --policy-name "${EVENT_IAM_ROLE_NAME}Policy"
aws iam delete-role --role-name "${EVENT_IAM_ROLE_NAME}"
aws iot delete-topic-rule --rule-name "${UPDATE_IOT_RULE_NAME}"
aws iam delete-role-policy --role-name "${UPDATE_IAM_ROLE_NAME}" --policy-name "${UPDATE_IAM_ROLE_NAME}Policy"
aws iam delete-role --role-name "${UPDATE_IAM_ROLE_NAME}"

Factory Firmware

ソースの Factory-Firmware フォルダに工場出荷用ファームウェア(?)が用意されていました。RTC の時刻設定や各種センサーのテストができるようです。(自分が購入したときのファームウェアではありませんでした。)

PlatformIO の PIOHome > Open > Open Project から、ダウンロードしたソースの Factory-Firmware フォルダを開き、同様にビルド、アップロードするだけです。