AWS IoT TwinMaker Samples のクッキー工場バージョン3(CookieFactoryV3)を試してみた 〜その2 ダッシュボード操作編〜

2024.01.24

こんにちは、CX 事業本部製造ビジネステクノロジー部の若槻です。

前回の記事では、CookieFactoryV3 の環境を構築するところまで行いました。

今回は、構築した環境を使用してダッシュボードを実際に操作してみたいと思います。

操作してみる

Web アプリケーションの起動

まずダッシュボードとなる Web アプリケーションをローカル端末上で起動します。

手順にある通りなのですが、

プロジェクトのルートから dashboard ディレクトリに移動し、Vite でアプリケーションを実行します。

# ディレクトリ移動
cd dashboard

# アプリケーションの起動(コマンドの実体は `vite serve --host --https --force`)
npm run dev

起動後のダッシュボードへのアクセス

アプリケーションの起動直後は次のロール選択画面となります。選択できるロールは Spencer(Line Operator)のみです。中央のユーザーアイコンをクリックして選択します。

すると認証中となり、数秒画面が青色になります。

次にロケーション選択画面となります。となります。選択できるロケーションは Cookie Factory(1 Main Street, Bakersville, NC, USA)のみです。中央のロケーションアイコンをクリックして選択します。

すると IoT TwinMaker の 3D コンポーザーのローティングが走ります。

その後に 3D コンポーザー上に Cookie Factory の 3D モデルが表示されます。

生産ラインのステータスの表示

生産ライン上には各種装置のステータスアイコンが表示されています。ステータスは時間経過で変化します。

  • Cookie Former(クッキー成形機)
  • Freezer Tunnel(冷蔵トンネル)
  • Cookie Inspector(クッキー監視装置)
  • Conveyor Vertical(垂直コンベヤー)
  • Conveyor Left Turn(コンベヤー右側)
  • Conveyor Right Turn(コンベヤー左側)
  • Plastic Liner(プラスチックライナー)
  • Box Erector(箱組み立て機)
  • Box Sealer(箱シーラー)
  • Labeling Belt(ラベリングベルト)

アイコンをクリックすると、詳細なステータスが表示されます。Box Erector では良品(Good Product)と不良品(Rejected Product)の分毎の数がデータとして確認できます。

良品が増えることによりアイコンのステータスが変化します。

このデータはコンポーネントタイプから取得されます。コンポーネントタイプの実体は、AWS マネジメントコンソールで IoT TwinMaker ワークスペースのエンティティ詳細から確認できます。

そしてコンポーネントタイプのデータはコンソール上でテスト取得できます。下記は Box Erector で対応しているプロパティ(AlarmmessageTemperature および Alarm_status)を時系列(Time-series)データとして取得した様子です。

取得した時系列データは結果から確認可能です。

データ全文

[
  {
    "entityPropertyReference": {
      "componentName": "CookieLineComponent",
      "externalIdProperty": {
        "alarm_key": "BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40",
        "telemetryAssetId": "BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40"
      },
      "entityId": "BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40",
      "propertyName": "AlarmMessage"
    },
    "values": [
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T11:58:30Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T11:58:40Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T11:58:50Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T11:59:00Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T11:59:10Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T11:59:20Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T11:59:30Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T11:59:40Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T11:59:50Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T12:00:00Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T12:00:10Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T12:00:20Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T12:00:30Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T12:00:40Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T12:00:50Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T12:01:00Z"
      },
      {
        "value": {
          "stringValue": "Low"
        },
        "time": "2024-01-24T12:01:10Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:01:20Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:01:30Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:01:40Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:01:50Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:02:00Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:02:10Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:02:20Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:02:30Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:02:40Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:02:50Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:03:00Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:03:10Z"
      },
      {
        "value": {
          "stringValue": "Normal"
        },
        "time": "2024-01-24T12:03:20Z"
      }
    ]
  },
  {
    "entityPropertyReference": {
      "componentName": "CookieLineComponent",
      "externalIdProperty": {
        "alarm_key": "BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40",
        "telemetryAssetId": "BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40"
      },
      "entityId": "BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40",
      "propertyName": "Temperature"
    },
    "values": [
      {
        "value": {
          "integerValue": 30
        },
        "time": "2024-01-24T11:58:30Z"
      },
      {
        "value": {
          "integerValue": 48
        },
        "time": "2024-01-24T11:58:40Z"
      },
      {
        "value": {
          "integerValue": 26
        },
        "time": "2024-01-24T11:58:50Z"
      },
      {
        "value": {
          "integerValue": 39
        },
        "time": "2024-01-24T11:59:00Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T11:59:10Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T11:59:20Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T11:59:30Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T11:59:40Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T11:59:50Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T12:00:00Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T12:00:10Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T12:00:20Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T12:00:30Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T12:00:40Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T12:00:50Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T12:01:00Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T12:01:10Z"
      },
      {
        "value": {
          "integerValue": 18
        },
        "time": "2024-01-24T12:01:20Z"
      },
      {
        "value": {
          "integerValue": 17
        },
        "time": "2024-01-24T12:01:30Z"
      },
      {
        "value": {
          "integerValue": 44
        },
        "time": "2024-01-24T12:01:40Z"
      },
      {
        "value": {
          "integerValue": 18
        },
        "time": "2024-01-24T12:01:50Z"
      },
      {
        "value": {
          "integerValue": 36
        },
        "time": "2024-01-24T12:02:00Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T12:02:10Z"
      },
      {
        "value": {
          "integerValue": 30
        },
        "time": "2024-01-24T12:02:20Z"
      },
      {
        "value": {
          "integerValue": 30
        },
        "time": "2024-01-24T12:02:30Z"
      },
      {
        "value": {
          "integerValue": 30
        },
        "time": "2024-01-24T12:02:40Z"
      },
      {
        "value": {
          "integerValue": 48
        },
        "time": "2024-01-24T12:02:50Z"
      },
      {
        "value": {
          "integerValue": 26
        },
        "time": "2024-01-24T12:03:00Z"
      },
      {
        "value": {
          "integerValue": 39
        },
        "time": "2024-01-24T12:03:10Z"
      },
      {
        "value": {
          "integerValue": 24
        },
        "time": "2024-01-24T12:03:20Z"
      }
    ]
  },
  {
    "entityPropertyReference": {
      "componentName": "CookieLineComponent",
      "externalIdProperty": {
        "alarm_key": "BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40",
        "telemetryAssetId": "BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40"
      },
      "entityId": "BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40",
      "propertyName": "alarm_status"
    },
    "values": [
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T11:58:30Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T11:58:40Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T11:58:50Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T11:59:00Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T11:59:10Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T11:59:20Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T11:59:30Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T11:59:40Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T11:59:50Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T12:00:00Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T12:00:10Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T12:00:20Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T12:00:30Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T12:00:40Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T12:00:50Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T12:01:00Z"
      },
      {
        "value": {
          "stringValue": "ACTIVE"
        },
        "time": "2024-01-24T12:01:10Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:01:20Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:01:30Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:01:40Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:01:50Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:02:00Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:02:10Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:02:20Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:02:30Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:02:40Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:02:50Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:03:00Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:03:10Z"
      },
      {
        "value": {
          "stringValue": "NORMAL"
        },
        "time": "2024-01-24T12:03:20Z"
      }
    ]
  }
]

ただし、ダッシュボード上で表示されていた良品や不良品などの情報はこのデータには含まれておらず、コンポーネントタイプから取得されたデータが本ダッシュボードでそのまま使われているわけではないようです。

プロセスグラフの表示

画面下部の[Process]をクリックすると、生産ラインの各装置のプロセスグラフが表示されます。

グラフ中のノードが生産ライン上の装置に対応しています。ノードをクリックすると、対応する装置のステータスが表示されます。逆に 3D コンポーザー上の装置をクリックすると、プロセスグラフのノードがハイライトされます。

このように、3D コンポーザーとプロセスグラフが連動することにより、各装置の関係性、ステータスおよび位置関係を生産管理者は容易に把握することができます。

データのダッシュボード表示

また画面下部の[Dashboard]をクリックすると、生産ライン上で選択中の装置のデータがダッシュボード表示されます。

Cookie Inspector を選択した場合はクッキーの検査写真が確認できます。

ダッシュボードは AWS IoT Application Kit を使って実装されている

さてここまで確認したダッシュボードは非常にリッチなビジュアライズが行われていましたが、これらは AWS IoT Application Kit を使って実装されています。

AWS IoT Application Kit は AWS IoT のリソースやデータを表示するダッシュボードを簡単に構築するためのキットとして提供されている React Component です。AWS IoT の各種サービスごとに Sub Component が提供されており、IoT TwinMaker の場合は下記となります。

この Component をベースにカスタマイズすることにより、既存のアプリケーションに IoT TwinMaker の 3D コンポーザーを組み込んだり、今回紹介したようなリッチなダッシュボードを実装したりすることができます。

トラブルシュート

Cloud9 環境上だと Vite で起動したアプリケーションにアクセスできない

CookieFactoryV3 でのデモ手順の冒頭で、前提条件として Cloud9 環境上でのアプリケーションの実行が推奨されています。

しかし Vite でアプリケーションを起動し、Cloud9 のプレビュー機能でアクセスしようとすると、下記のようなエラーとなりアクセスできませんでした。

Oops
No application seems to be running here!

以前に CookieFactoryV3 でないアプリケーションで試した時は問題無かったのですが、今回は何らかの問題が発生しているようです。

よって、本記事でのアプリケーションでの起動はローカル端末上で行いました。

ネクストアクション

次回はいよいよこの V3 のサンプルに下記で紹介されている Amazon Bedrock の実装を追加したいと思います。楽しみですね。

以上