設備機器の稼働データを SiteWise ゲートウェイを使って OPC UAプロトコルで AWS IoT SiteWise へ送ってみた

AWS IoT SiteWise で 製造業 IoT !!
2022.03.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

今回は、AWS IoT SiteWise の基本的な使い方を確認してみました。
AWS IoT SiteWise を使うと、OPC-UA や Modbus TCP、Ethernet/IP といった製造機器間の通信に使われる産業用プロトコルで機器のデータを AWS に送信したり、データを蓄積・分析・可視化することができるようになります。

全体の構成

想定する環境

今回作成する環境は、以下のような製造現場の環境を模したものになります。

00-genba-sitewise-gw-diagram

作成する環境構成

上記の環境を次のような構成で AWS 上に作成します。

00-sitewise-gw-diagram

実機としての PLC などは無いので 「仮想 OPC UA サーバ」 上で擬似的にデータを生成します。「仮想 OPC UA サーバ」は IoT ゲートウェイ想定の Cloud9 インスタンス上に作成して「SiteWise ゲートウェイ」によりデータ収集および AWS へのデータ転送を行います。

最終的に SiteWise に届いたデータを IoT Core に転送して、リアルタイムにデータが届いている様子を確認したいと思います。

なお、本エントリでは、SiteWise Monitor を使ったデータのグラフ化は行いません。SiteWise Monitor については別エントリにてご紹介したいと思います。

作業内容

本エントリで行う作業概要は下記のとおりです。

  • Cloud9 で SiteWise ゲートウェイを作成
  • 仮想 OPC UA サーバを作成
  • SiteWise 側でアセットモデル、アセットの作成
  • データ送信 & データ到達の確認

SiteWise へデータを送る 3 つの方法

SiteWise にデータを送る場合、次の 3 つの方法があります。

  • SiteWise ゲートウェイ経由で送信
  • API で直接送信
  • MQTT で AWS IoT Core 経由で送信

この内、今回は 「SiteWise ゲートウェイで送る方法」 を試してみました。

SiteWiseゲートウェイの作成

SiteWise ゲートウェイには下記の要件があるので、Cloud9 の Amazon Linux 2 を利用することにします。

  • OS:
    • Ubuntu 20.04 または 18.04
    • Red Hat Enterprise Linux (RHEL) 8
    • Amazon Linux 2
  • アーキテクチャ:x86_64 (AMD64)

その他の要件は下記を確認してください。

Cloud9 環境の作成

Cloud9 環境の作成方法は割愛しますが、Cloud9 からインターネットにアクセスできるようにしておきます。 なお、メモリが 1GB だとメモリ不足の警告が時々出たので、インスタンスタイプは t3.smallにしておくと良いかと思います。

Cloud9 のインスタンスが作成できたら、一旦 Cloud9 の作業は中断して SiteWise ゲートウェイの作成に進みましょう。

コンソールで SiteWise ゲートウェイを作成

次に、コンソールから SiteWise ゲートウェイを作成します。作業は以下の流れになります。

  • SiteWise コンソールからゲートウェイを作成(設定・登録)する
  • インストーラをダウンロードして Cloud9 にアップロードする
  • Cloud9 上でインストーラを実行する

それでは作っていきましょう。
SiteWise のコンソールから 「ゲートウェイ」 の画面を開いて 「ゲートウェイを作成」 をクリックします。

01-make-sw-gw

次に「ゲートウェイ名」を適当な名前で設定します。SiteWise ゲートウェイは Greengrass コアデバイスとして動作するので、ここで「コアデバイス名」に付けた名前で Greengrass コアデバイスが作成されます。

実際には、後で生成されるインストーラの中でコアデバイス名がセットされています。そしてインストーラを実行することで指定した名前のコアデバイスが Greengrass に登録されることになります。
(今回は SiteWiseGateWayTest としました。

02-set-gateway

「エッジ機能」の画面では 「データ収集パック」だけが選択されている状態で 「次へ」をクリックします。
(データ処理パックは今回は使いません。)

03-select-pack

オプション画面もデフォルトのままとします。

04-config-option

次にデータソースを追加します。データソースとは、ゲートウェイがデータを収集するソースの設定です。今回は OPC UA プロトコルでデータ収集するので、対象は 「OPC UA サーバ」 となります。

05-add-data-source

ソース名は適当な名前を付けます。
次の 「データストリームのプレフィックス」 は空にしてください。 ソースが単一の時にこのオプションが設定されていると、ゲートウェイからデータを送信することができません。

06-set-source-name-and-option

画面の下側にある「ローカルエンドポイント」の箇所で、データソースとなる OPC UA サーバの指定を行います。
今回は、ゲートウェイと同じ Cloud9 インスタンス上に仮想の OPC UA サーバを作るので localhost を指定します。ポートはサーバの設定に合わせてください。今回は 4840 ポートを使うので下記のようにセットしてください。

opc.tcp://localhost:4840

送信先はデフォルトの 「AWS IoT SiteWise」 を選択します。最後に忘れず に 「追加」をクリックしてください。

07-set-endpoint-and-destination

次の画面でデータソースが追加できていることを確認できたら、次へ進みます。

08-review-source-next

最後に全体のレビューを行います。

09-review

レビュー画面の一番下でゲートウェイデバイスの OS を選択します。今回は 「Amazon Linux 2」を使うので「Amazon Linux」を選択して「生成」をクリックしてください。「生成」をクリックすると選択した OS に合わせた「ゲートウェイのインストーラ」が生成されます。

10-gen-installer

「生成」をクリックすると次の画面が出るので 「承認」 をクリックしましょう。このインストーラにはGreengrass コアデバイスにセットされる「デバイス証明書」や「秘密鍵」が含まれていますが、後でダウンロードすることができないので注意してください。

11-approve-gen-installer

インストーラを適当なところに保存します。

12-download-installer

次に、ダウンロードしたインストーラを Cloud9 にアップロードします。今回は /home/ec2-user/直下にアップロードします。

13-select-home

Cloud9 の IDE にあるメニュー「File」を選んで「Upload Local Files...」よりアップロードします。

14-upload-file

先程ダウンロードしたインストーラをドラッグ&ドロップします。

15-select-installer-file

アップロードできたら完了です。

16-list-files

SiteWise ゲートウェイのインストーラを実行

最後に先程アップロードしたインストーラを実行します。インストーラのファイル名は、事前に SiteWise コンソールで作成したゲートウェイ名により変わるので環境に合わせてコマンドを実行してください。

$ cd ~
$ chmod +x SiteWiseGateWayTest.deploy.sh
$ sudo ./SiteWiseGateWayTest.deploy.sh

実行結果の最後に Successfully set up Nucleus as a system service と表示されることを確認します。

17-provisioning-ggc

SiteWise ゲートウェイは Greengrass V2 の 2つのパブリックコンポーネントで構成されるので、これらのコンポーネントが正常にデプロイできていることを確認しておきます。

Greengrass のコンソールで 「デプロイ」画面からゲートウェイ名を確認します。

18-greengrass-deploy

対象のデプロイ画面を開いて次の2つのコンポーネントがデプロイされていることを確認します。

  • aws.iot.SiteWiseEdgeCollectorOpcua
  • aws.iot.SiteWiseEdgePublisher

また 「デプロイのステータス」が「完了」 になっていることを確認します。

19-components

OPC UA サーバの作成

次に仮想の OPC UA サーバを作成します。Python の場合 opcua-asyncio というライブラリで OPC UA サーバやクライアントを作成することができます。

事前に Cloud9 にこのライブラリをインストールしておきましょう。

$ pip install asyncua

なお、以前は下記の python-opcua というライブラリが使われていたようですが、こちらはすでに deprecated となっており、opcua-asyncio の利用が推奨されています。

インストールできたら、下記のサンプルをベースに OPC UA サーバを作成します。

そのまま使ってもいいですが、それではつまらないので下記のデータを生成するように修正します。

  • 疑似的な CPU クロック数
  • 擬似的な CPU 温度
  • データ生成した回数(カウントアップ値)

コードは下記になります。
29 〜 31 行目の数字は OPC UA データの初期値です。29 行目の mycount はカウンタ用の変数ですが 6.7 に特別な意味はありません。元々のコードにあったものをそのまま使っているだけですが、カウンタとして 6.7 からスタートすることになります。

custom-server.py

import logging
import asyncio
import sys
import time
import random
sys.path.insert(0, "..")

from asyncua import ua, Server
from asyncua.common.methods import uamethod

@uamethod
def func(parent, value):
    return value * 2

async def main():
    _logger = logging.getLogger('asyncua')
    # setup our server
    server = Server()
    await server.init()
    server.set_endpoint('opc.tcp://localhost:4840')

    # setup our own namespace, not really necessary but should as spec
    uri = 'http://examples.freeopcua.github.io'
    idx = await server.register_namespace(uri)

    # populating our address space
    # server.nodes, contains links to very common nodes like objects and root
    myobj = await server.nodes.objects.add_object(idx, 'MyObject')
    mycount = await myobj.add_variable(idx, 'MyCount', 6.7) # 数値は初期値
    myclock = await myobj.add_variable(idx, 'MyClock', 0.0)
    mytemperature = await myobj.add_variable(idx, 'MyTemperature', 0.0)

    # Set MyVariable to be writable by clients
    await mycount.set_writable()
    await myclock.set_writable()
    await mytemperature.set_writable()
    await server.nodes.objects.add_method(ua.NodeId('ServerMethod', 2), ua.QualifiedName('ServerMethod', 2), func, [ua.VariantType.Int64], [ua.VariantType.Int64])
    _logger.info('Starting server!')
    async with server:
        while True:
            await asyncio.sleep(5)
 
           # データを送信(生成)した回数を0.1刻みでカウントして送る
            count = await mycount.get_value() + 0.1
            print('count: ' + str(count))
            _logger.info('Set value of %s(COUNT) to %.1f', mycount, count)
            await mycount.write_value(count)

            # CPUクロックを取得する
            # Cloud9では vcgencmd コマンドが使えないのでランダムな数値をダミーデータとして利用する
            clock = float(random.randint(600000000,1500000000))
            _logger.info('Set value of %s(CLOCK) to %.1f', myclock, clock)
            print('clock: ' + str(clock))
            await myclock.write_value(clock)

            # CPU温度を取得する
            # Cloud9では vcgencmd コマンドが使えないのでランダムな数値をダミーデータとして利用する
            temperature = random.uniform(30, 85)
            _logger.info('Set value of %s(TEMPERATURE) to %.1f', mytemperature, temperature)
            print('temperature: ' + str(temperature))
            await mytemperature.write_value(temperature)

if __name__ == '__main__':

    logging.basicConfig(level=logging.DEBUG)

    asyncio.run(main(), debug=True)

インストーラをアップロードした時と同じ要領で、この custom-server.py ファイルをアップロードします。アップロードできたら実行して OPC UA サーバを起動しましょう。

$ python custom-server.py

色々なメッセージが流れますが、下記のような表示が確認できればOKです。
count の初期値が 6.7 なので初めて出力されたメッセージであれば、下記のように 6.8 からスタートしているはずです。

count: 6.800000000000103
INFO:asyncua:Set value of ns=2;i=2(COUNT) to 6.8
INFO:asyncua:Set value of ns=2;i=3(CLOCK) to 1488455126.0
clock: 1488455126.0
INFO:asyncua:Set value of ns=2;i=4(TEMPERATURE) to 55.0
temperature: 54.98935838353067

アセットモデルの作成

SiteWise ゲートウェイと OPC UA サーバの準備が終わったので、次は データを取り込むための SiteWise 側の設定を行います。
ここからは 「アセットモデル」と「アセット」 を作成していきます。

ざっくり説明すると、アセットはデバイスやプロセスなどから送られてくる個々のデータで、その雛形となるものがアセットモデルです。そのため最初にアセットモデルを作成します。
用語の詳細は下記に説明が記載されています。

SiteWise のコンソールより 「モデルの作成」 をクリックします。

20-make-asset-model

適当な名前をつけます。

21-model-name

次に 「測定の定義」 をセットします。この定義はデータソースに指定している OPC UA の設定に合わせてセットしてください。
今回は「カウンタ」,「CPU クロック数」,「CPU 温度」の 3 つをOPC UA サーバで生成・保持しているので、下記のとおり適当な名前を付けて定義します。

22-define-measure

「データ型」 も OPC UA サーバの設定に合わせてください。今回は作成した OPC UA サーバのコードで下記のように定義しているので、全て 「ダブル型」 にします。

mycount = await myobj.add_variable(idx, 'MyCount', 6.7)
myclock = await myobj.add_variable(idx, "MyClock", 0.0)
mytemperature = await myobj.add_variable(idx, "MyTemperature", 0.0)

最後に 「モデルの作成」 をクリックします。

23-submit-model

次に 「アセット」 を作成します。

25-make-asset

「モデル」 は先程作成したアセットモデル 「my-custom-server」 を選択します。名前は適当なものを付けてください。

26-set-asset-name

これでアセットモデルとアセットの作成は完了です。
最後に「OPC UA サーバ(SiteWise ゲートウェイ)から送られてくるデータ」と「作成したアセット」を関連付けることで SiteWise にデータを取り込むことができるようになります。

この「アセットとデータの関連付け」作業は、下記のようなことを行います。

  • SiteWise に送る各データの「パス」を OPC UA サーバ上で事前に確認
    • 例:MyObject/MyTemperature
  • 確認したパスを SiteWise の各アセットの各プロパティエイリアスに事前に設定
    • プロパティエイリアスは「ノード ID」 のパスの先頭に「/」を付けたもの
      • 例:パスが turbine/7/temperatureであれば、プロパティエイリアスは /turbine/7/temperature

以前は上記の作業をデータの数だけ行う必要があり面倒でした。
しかし 2021 年末のアップデートで、SiteWise に届いた OPC UA サーバのデータから「パス」を自動的に読み取り、簡単にアセットに関連付けることができるようになりました。

下記のように正常に SiteWise ゲートウェイから SiteWise 側にデータが届いていれば「データストリーム」の画面に 3 つの「データストリームエイリアス」が表示されます。

事前に OPC UA データの「パス」を確認しなくても、SiteWise ゲートウェイ経由でデータを送るだけで自動的に解析して、プロパティエイリアスに登録すべき「パス」を抽出してくれるので便利です。

27-data-stream

さらに便利なのは、このデータストリームの画面から事前に作成しておいた「空」のアセットを関連付けるだけで、そのアセットのプロパティにプロパティエイリアスを登録してくれようになっています。
実際に試してどんな動作なのか確認してみましょう。

読み取られたデータストリームエイリアスを全て選択して 「データストリームを管理」 をクリックします。
(1つずつ設定しても構いません)

28-manage-data-stream

次の画面で下記の番号順に操作します。

  • ①:最初に /MyObject/MyTemperature「測定値を選択」 をクリックします。
  • ②:作成済みの 「test-asset-1」 をクリックして展開します。
  • ③:紐付けたい「測定値」を選択します。ここでは temperature を選択します。
  • ④:最後に 「選択」 をクリックします。

29-select-measure-temp

ここまで完了すれば /MyObject/MyTemperature の測定値の箇所がグレーアウトして、設定完了の状態になります。

30-glay-out-selected-alias

次の /MyObject/MyCount も同じように設定します。

31-select-count

全て完了すれば 「更新」 をクリックして完了です。

32-reconfig-datastream

正しく設定できれば下記のようになり、アセット「test-asset-1」に関連づいた状態になります。つまり、送られてくるデータはアセット「test-asset-1」として取得・参照することができるようになりました。

33-managed-stream-alias

データの確認

実際に SiteWise にデータが取り込めていることを確認してみましょう。コンソールでアセット test-asset-1 の画面を開きます。

34-select-asset

下記のように先程データストリームの画面で関連付けた結果として、正しく Alias がセットされていることが確認できます。
また 「最新の値」 の項目で OPC UA サーバで生成したデータが入っていることが確認できます。

35-measurement-for-asset

なお、この「最新の値」は 15 秒間隔で更新されるので、15 秒よりも短いサイクルでデータが来ている場合、その間のデータはここでは表示されず「最新の値」しか表示されません。

そこで、取り込まれたデータを AWS IoT Core に送ってリアルタイムにデータが届く様子を見てみましょう。 そのためにはアセットの設定を変更する必要があるので、アセットの画面から 「編集」 をクリックします。

36-edit-asset

アセットの 「測定」 の設定箇所にある 「MQTT 通知ステータス」を全て「有効」に変更して保存します。
(下側に通知されるトピック名が記載されていますね)

37-notifi-mqtt

設定変更が終わると、アセットの画面からトピック名をコピーすることができるようになっています。試しに適当な測定値のトピックで確認してみましょう。

38-copy-topic

AWS IoT Core のコンソールで 「MQTT テストクライアント」 を開きます。次にコピーしたトピックをフィルターに記入してサブスクライブします。

39-subscribe-topic-temp

下記は 「CPU 温度」 のデータです。
今回使っている OPC UA サーバでは ループ処理で 5 秒間のスリープを入れています。そのため送られてくるデータも timeInSeconds を見ると 5 秒間隔でデータが生成されていることが分かります。

41-subscribe-data

また、下記の通り SiteWise ゲートウェイからは 「10秒間隔」でデータが送られてきている事も分かります。つまり、SiteWise ゲートウェイは 10 秒間の間に生成されたデータをまとめて定期的に送っていることが分かります。
(今回は 5 秒間隔でデータ生成されるので、2 件の温度情報が 1 データとして 10 秒間隔で送られている事になります。)

40-opcua-data-temp

SiteWise ゲートウェイがデータを送ってくる 「10秒」 という間隔は変更できないので、間隔を調整したい場合は ゲートウェイのデータ送信先を SiteWise ではなく、ゲートウェイ上の Stream Manager に変更する必要があります。
(この場合は、Greengrass コンポーネントとして Stream Manager を追加でゲートウェイにデプロイする必要があります。)

最後に

今回は、OPC UA プロトコルの勉強も兼ねて OPC UA サーバの自作から クラウド側でのデータ確認までやってみました。
引き続き、API や MQTT によるデータの送り方、SiteWise Monitor の機能などを確認していきたいと思います。