たけびし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. サンプルプログラム
以下に示す。
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()で設定する方法しか確認できなかった