2024-01-22 AWS IoT Core、IoT Events, Greengrass V2を使ったRaspberry Piの接続状態監視の実験

1.はじめに

はじめましてトラストのテックブログです。株式会社トラストはAWSのセレクトティアパートナーとして、AWSをフル活用したクラウドネイティブな開発(AI、IoT、サーバレスといった)をいろいろやっております。AI、IoT領域ではエッジデバイスも使うため、ラズパイ、M5Stackを使ったエッジデバイスのソフト開発も行っております。

2024年3月に弊社ホームページをリニューアルするのに伴い、「トラストのテックブログ」を開設してクラウド、エッジデバイス開発のエッセンスを定期的に配信させていただくことにしました。お客様の価値創造のために日々新技術に挑戦するトラスト開発チームの活動をぜひお楽しみください。

初回の投稿は、開発チームの責任者の佐野からAWS IoT Core, AWS IoT Greengrass, AWS IoT Events,他を使ってラズパイの接続状態(オンライン、オフライン)をクラウド側で検知する方法について2回に分けて投稿いたします。なお、AWS IoT Greengrassの詳細な使い方についてはhttps://catalog.us-east-1.prod.workshops.aws/workshops/5ecc2416-f956-4273-b729-d0d30556013f/ja-JP を参照願います。

Part 1:Greengrassを使って接続確認用のラズパイコードのデプロイ

Part2:IoT Eventsを使った接続状態検知 (次回ブログにて公開予定)

トラストではAIを使った外観検査や異音検知システムの開発を行っておりますが、AIモデルのエッジデバイス(ラズパイ)へのデプロイにはAWS IoT Greengrassを使っておりますので、今回の接続状態の確認プログラムもGreengrassを使ってデプロイします。

2.やりたいこと

IoTシステムのエッジデバイスとして活用しておりますRaspberry Pi(ラズパイ)の接続状態(オンラインかオフライン)をクラウド側で検知したい。ユースケースとしましては、IoTシステムのWeb管理画面へのデバイスのオンライン、オフラインの表示用途を想定しております。

3.構成

「Part 1:Greengrassを使って接続確認用のラズパイコードのデプロイ」は下記構成図の青線で囲った部分になります。

4.デバイスの準備

今回実験に使ったデバイスはRaspberry Pi 4B 8GBです。OSのバージョンは以下となります。OSは最新版のBookwormを入れてみました。 pi@greengrass1:~ $ uname -aLinux greengrass1 6.1.0-rpi7-rpi-v8 #1 SMP PREEMPT Debian 1:6.1.63-1+rpt1 (2023-11-24) aarch64 GNU/Linuxpi@greengrass1:~ $ lsb_release -aNo LSB modules are available.Distributor ID: RaspbianDescription:    Raspbian GNU/Linux 12 (bookworm)Release:        12Codename:       bookworm

5.Greengrass のセットアップ

ラズパイをGreengrassデバイスとして登録します。

①AWS IoTのコンソール画面へ移動して左のメニューから Greengrassデバイス を選択します。

②右側の「1つのCoreデバイスをセットアップ」を選択します。

③デバイスセットアップ画面に移動するので画面上に表示されたステップ1,ステップ2の箇所で、コアデバイス名、モノのグループを設定します(今回はグループなしで進めます)

④ステップ3のGreengrassコアソフトウェアをインストールに進み、オペレーティングシステムとしてLinuxを選択します。

⑤ラズパイのターミナルを開いて Java ランタイムをデバイスにインストールします。

sudo apt install default-jdk

⑥ラズパイにAWS認証情報を設定します。

export AWS_ACCESS_KEY_ID=<AWS_ACCESS_KEY_ID>export AWS_SECRET_ACCESS_KEY=<AWS_SECRET_ACCESS_KEY>

⑦コンソール画面からコマンドをコピーしてラズパイのターミナルに貼り付けてGreengrass インストーラーをダウンロードします

curl -s https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-nucleus-latest.zip > greengrass-nucleus-latest.zip && unzip greengrass-nucleus-latest.zip -d GreengrassInstaller

⑧コンソール画面からインストールコマンドをコピーしてラズパイのターミナルに貼り付けてGreengrassソフトウェアのインストールを実行します。

sudo -E java -Droot=”/greengrass/v2″ -Dlog.store=FILE -jar ./GreengrassInstaller/lib/Greengrass.jar –aws-region ap-northeast-1 –thing-name myPi  –component-default-user ggc_user:ggc_group –provision true –setup-system-service true –deploy-dev-tools true

⑨ラズパイターミナルに Successfully set up Nucleus as a system serviceが表示されたら、ターミナルから以下のコマンドを入力して greengrass のバージョンが表示されるのを確認します。( No such file or directory と表示される場合は https://docs.aws.amazon.com/greengrass/v2/developerguide/install-gg-cli.html を参照して対応が必要です。Raspberry Pi Zeroに Greengrassを入れようとしたときは、No such file or directoryとなったので、コンソールから Greengrass CLIをデプロイして解決しました)

/greengrass/v2/bin/greengrass-cli -V

⑩AWSコンソール画面の[コアデバイスを表示]をクリックするとコアデバイス画面に移動するので、デバイスが登録されたことを確認します。

6.接続状態確認用のPythonコード

接続状態確認用のPythonコードは以下となります。このプログラムは、トピック名mypi/pingにデバイス名とタイムススタンプが入ったメッセージを10秒ごとにパブリッシュします。

ping.py

import time
import sys
import traceback
import json
import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.client as client
from awsiot.greengrasscoreipc.model import (
    IoTCoreMessage,
    QOS,
    PublishToIoTCoreRequest,
    SubscribeToIoTCoreRequest
)

args = sys.argv

publishtopic = "mypi/ping"
message =  {
  "deviceName": args[1], #引数で送られるデバイス名が入る
  "timemillis": 000000000000
}

TIMEOUT = 10
qos = QOS.AT_LEAST_ONCE
subqos = QOS.AT_MOST_ONCE

ipc_client = awsiot.greengrasscoreipc.connect()

while(True):
    print('ping send')
    message["timemillis"] = round(time.time() * 1000)

    msgstring = json.dumps(message)

    pubrequest = PublishToIoTCoreRequest()
    pubrequest.topic_name = publishtopic
    pubrequest.payload = bytes(msgstring, "utf-8")
    pubrequest.qos = qos
    operation = ipc_client.new_publish_to_iot_core()
    operation.activate(pubrequest)
    future = operation.get_response()
    future.result(TIMEOUT)
    time.sleep(10)

MQTTでパブリッシュするメッセージ。args[1]にはデバイス名が入ります

message =  {
  "deviceName": args[1], #引数で送られるデバイス名が入る
  "timemillis": 000000000000
}

7.IAMの設定

今回はすでに他のデバイスで動作確認済みのPythonコードをS3からデプロイします。そのため、GreengrassがS3へアクセスできるようIAMポリシーを設定します。

①IAM画面のサイドメニューからポリシーを選択して、右側の[ポリシーの作成]をクリックします。

②[json]を選択してS3へのs3:GetObjects3:GetBucketLocationのアクセス権を記載します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:GetBucketLocation"
            ],
            "Resource": [
                "arn:aws:s3:::*"
            ]
        }
    ]
}

③[次へ]をクリックしてポリシー名を入力し[ポリシーの作成]を選択します。

④次にロールの画面に移動して 検索欄にgreengrassと入力します。

GreengrassV2TokenExchangeRoleを選択して、[許可を追加]>[ポリシーをアタッチ]を選択します。

⑥先ほど作成したポリシーを検索して[許可を追加]を選択します

8.Pythonコードのデプロイ

他のデバイスで動作確認済みのPythonプログラムをS3へアップロードした後に AWS IoT GreengrassコンソールからPythonプログラムをラズパイへデプロイします。

①デプロイ用のS3バケットを作成した後に、ファイル格納用のフォルダを作成します。フォルダ階層は[バケット名]/artifacts/com.example.ping/1.0.0/となります

②Pythonコード (ping.py)をコンソールからアップロードします。

③AWS Greengrassのコンソール画面に移動してコンポーネントを選択します。

④[コンポーネントを作成]をクリックして[レシピをJSONとして入力]をチェックします。

⑤レシピは以下のとなります。"script": "python3 -u {artifacts:path}/ping.py '{iot:thingName}'"の行でPythonプログラムの引数に{iot:thingName}を渡すことでデバイス名をPythonコードにハードコードしないようにしてます。[コンポーネントを作成]の画面にレシピを貼り付け画面下の[コンポーネントを作成]をクリックします。("Install"下の"script"はラズパイOSがbullseyeの場合は"python3 -m pip install --user awsiotsdk"となります。)

{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.ping",
  "ComponentVersion": "1.0.0",
  "ComponentType": "aws.greengrass.generic",
  "ComponentDescription": "Comms to IoT core",
  "ComponentPublisher": "Me",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "message": "hello",
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.ping:mqttproxy:1": {
            "policyDescription": "Allows access to pub to mypi/ping.",
            "operations": [
              "aws.greengrass#PublishToIoTCore"
            ],
            "resources": [
              "mypi/ping"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux"
      },
      "Lifecycle": {
        "Install": {
          "RequiresPrivilege": true,
          "script": "pip3 install --break-system-packages --user awsiotsdk"
        },
        "Run": {
          "RequiresPrivilege": true,
          "script": "python3 -u {artifacts:path}/ping.py '{iot:thingName}'"
        }
      },
      "Artifacts": [
        {
          "Uri": "s3://trust-greengrass-test-2024-02-07/artifacts/com.example.ping/1.0.0/ping.py"
          }
        }
      ]
    }
  ],
  "Lifecycle": {}
}

⑥[デプロイ]をクリックします。

⑦[次へ]を選択します。

⑧[次へ]を選択します。

⑨[次へ]を選択します。

⑩[次へ]を選択します。

⑪[次へ]を選択します。

⑫[デプロイ]を選択します。

⑭デプロイのステータスが[完了]になるのを確認します。

9.コンポーネントの動作確認

トピック名 mypi/pingにメッセージがパブリッシュされているか AWS IoTのコンソール画面で確認します。

①AWS IoT Coreのコンソール画面からMQTTテストクライアントを選択します。

②[トピックをサブスクライブする]を選択して、トピックのフィルター欄に mypi/ping と入力し[サブスクライブ]を選択します。

③10秒ごとにメッセージが受信できることを確認します。

④メッセージが受信できない場合はラズパイのターミナルから greengrassのログを確認します。

sudo tail /greengrass/v2/logs/greengrass.log

sudo /greengrass/v2/bin/greengrass-cli component list

 sudo tail /greengrass/v2/logs/com.example.ping.log

10.最後に

従来はラズパイにsshで入ってPythonプログラムを所定フォルダに置き、ラズパイ内でSystemdを使ったプログラムの自動起動を設定しておりましたが、AWS IoT Greengrassを使うことで、ラズパイにログインせずに手軽にしかも複数台のラズパイに同時にプログラムをデプロイできてとても便利になりました。

次回のテックブログではデバイスから定期的に送られるメッセージをIoT Eventsで受けて接続状態をDynamoDBに格納する方法について報告させていただきます。お楽しみに。

トラストではAI、IoTシステムのコンサル・開発をやってます。お気軽にお問い合わせください。

11.参考文献

https://catalog.us-east-1.prod.workshops.aws/workshops/5ecc2416-f956-4273-b729-d0d30556013f/ja-JP
https://aws.amazon.com/jp/greengrass/?nc=sn&loc=2&dn=2
https://docs.aws.amazon.com/greengrass/