たけびしDxpSERVER向けOPC-UAクライアントを書いてみた


たけびしDxpSERVERのOPC-UAクライアントのサンプルを作ることになったので、手順を記録しておく。

1. 使用環境

デモ版が上記サイトからダウンロード可。OPC-UAも利用可。

2. OPC-UAサーバ設定

2-1. 共通プロパティ

ツール(T)>オプション(O)で、共通プロパティタブを表示する。

OPC UAサーバー設定を有効にする。アプリケーションを再起動するように促されるので、再起動する。

2-2. UAサーバー設定

共通プロパティタブのOPC UAサーバー設定の右側に...が表示されているところをクリックすると、UAサーバー設定のダイアログが表示される。

  • UAサーバー使用
  • Anonymous接続の許可
  • セキュリティポリシー/セキュリティモード:None

にチェックが入っていること。

2-3. タグの追加

プロジェクトエクスプローラからSYSTEMポートを選択して、タグを追加する。
タグの追加は プロジェクト(P)>新規作成(N)>タグ(T) で行う。

ここでは、以下の3つのタグを作っておく。

No. タグ名 データ型 サイズ
1 value_string STRING 32
2 value_long Long 1
3 value_float Float 1

注意事項:

  • STRINGのサイズはデフォルトで1なので、そのままでは1文字しか保持できない
  • 一度タグを設定してからサイズだけ変更すると、後続のタグのアドレス位置が移動いないので、領域を上書きされる場合がある(これでハマった)

2-4. プロジェクトの保存

ファイル(F)>保存(S)でプロジェクトを保存する。ここでは OPCUA_sampleで保存する。

3. OPC-UAクライアント

3-1. OPC-UAサーバーの設定

DxpSERVER v6のデフォルト設定は以下の通り。

No. 項目名 デフォルト値 内容
1 HOST - DxpSERVERのIPアドレス文字列。localhostも可。
2 PORT 52240 ポート番号
3 PATH (空文字列) end_pointのパス
4 URI urn:Takebishi:DxpOpcUaServer:customprovider 名前空間のURI

上記の設定値から、OPC-UAのアクセス先を示すend_pointは以下の文字列で設定する。

end_point = f'opc.tcp://{HOST}:{PORT}{PATH}'

3-2. パッケージのインストール

asyncuaパッケージをインストールしておく。

$ pip install asyncua

3-3. サンプルプログラム

以下に示す。

dxp6_client.py
import asyncio
from asyncua import Client, ua

# for v5
# URI = 'http://takebishi.co.jp/DeviceXPlorer5/UA'
# PORT = 52210

# for v6
URI = 'urn:Takebishi:DxpOpcUaServer:customprovider'
port = 52240

# local machine
HOST = 'localhost'
PATH = ''

OBJ = 'SYSTEM'  # オブジェクト名はプロジェクト直下のポート名と対応


async def main():
    end_point = f'opc.tcp://{HOST}:{PORT}{PATH}'

    try:
        async with Client(url=end_point) as client:
            """
            # URI一覧を表示
            print('[URI List]')
            for uri in await client.get_namespace_array():
                print(uri)
            print()
            """

            # ノードのread/write
            idx = await client.get_namespace_index(URI)
            node1 = client.get_node(f'ns={idx};s={OBJ}.value_string')
            node2 = client.get_node(f'ns={idx};s={OBJ}.value_long')
            node3 = client.get_node(f'ns={idx};s={OBJ}.value_float')

            print('[Read]')
            print(node1.nodeid, ':', await node1.read_value())
            print(node2.nodeid, ':', await node2.read_value())
            print(node3.nodeid, ':', await node3.read_value())
            print()

            # DxpSERVERだとこの形式が未サポート
            # await node1.write_value('HELLO')

            # Write
            # DataValueでset_valueを使用する
            print('[Write]')
            dv1 = ua.DataValue(ua.Variant(u'HELLO', ua.VariantType.String))
            await node1.set_value(dv1)
            dv2 = ua.DataValue(ua.Variant(123, ua.VariantType.Int32))
            await node2.set_value(dv2)
            dv3 = ua.DataValue(ua.Variant(9.8, ua.VariantType.Float))
            await node3.set_value(dv3)
            print()

            print('[Read]')
            print(node1.nodeid, ':', await node1.read_value())
            print(node2.nodeid, ':', await node2.read_value())
            print(node3.nodeid, ':', await node3.read_value())
            print()

    except Exception as e:
        print(e)
        exit()


if __name__ == '__main__':
    asyncio.run(main())

read/writeについては、ここで示した方法で動作することを確認した。

3-4. コードについて補足

コメントにも書いているので、察した方もいらっしゃるかも知れませんが補足しておきます。

  • URIのリストはclient.get_namespace_array()で取得できる
  • node.write_value()で書き込みができたOPC-UAサーバーもあるが、DxpSERVERではDataValueをnode.set_value()で設定する方法しか確認できなかった