298.ラズパイ無双[26 OPC-UA FreeOpcUa]
初回:2023/2/8
Raspberry Pi (ラズベリーパイ、通称"ラズパイ")で何か作ってみようという新シリーズです。これから数回に分けて、ラズパイ上にOPC-UAサーバーと、クライアントを入れて、通信させるところまで行ってみたいと思います。今回は、一番単純なサーバーとクライアントを実行して通信させてみましょう。
P子「実践編ね」※1
とりあえずサーバーとクライアント間で通信する所から初めて、色々と特性を見てみたいと思います。
1.OPC UAライブラリ「FreeOpcUa」
PythonでOPC UAを動かすのですが、今回は「FreeOpcUa」というライブラリを使用します。これだけで、サーバー・クライアント両方に対応していますし、サンプルも充実しています。
≪参考1≫
https://misoji-engineer.com/archives/opc-ua-model.html
OPC UAの情報モデルをサーバー作って確認してみた
インストールも簡単です。
$ sudo pip3 install opcua
ソースコードやサンプルは、「FreeOpcUa」の github にあります。
≪参考2≫
https://github.com/FreeOpcUa/python-opcua
FreeOpcUa/python-opcua
この github の examples の中から、server-minimal.py と、client-minimal.py を使用します。
2.server-minimal.py
server-minimal.py の ソースコードを提示しておきます。ただし、下記に提示するのは、コメントや関係ないコードは削除しておきます。
≪参考3≫
https://github.com/FreeOpcUa/python-opcua/blob/master/examples/server-minimal.py
server-minimal.py
import time from opcua import ua, Server if __name__ == "__main__": # setup our server server = Server() server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/") # setup our own namespace, not really necessary but should as spec uri = "http://examples.freeopcua.github.io" idx = server.register_namespace(uri) # get Objects node, this is where we should put our nodes objects = server.get_objects_node() # populating our address space myobj = objects.add_object(idx, "MyObject") myvar = myobj.add_variable(idx, "MyVariable", 6.7) myvar.set_writable() # Set MyVariable to be writable by clients # starting! server.start() try: count = 0 while True: time.sleep(1) count += 0.1 myvar.set_value(count) finally: #close connection, remove subcsriptions, etc server.stop()
Server インスタンスを生成し、endpoint の設定とnamespaceからidxを取り出します。そして、オブジェクトノードを生成して、先ほど取得したidxに、"MyObject"を追加し、そのマイオブジェクトに、"MyVariable" を追加します。
サーバーを、start()して、while True: で無限ループを形成し、1秒ごとに、カウント値を先ほどの "MyVariable" に設定します。
P子「ソースを単純に文字にしただけね」
server-minimal.py というだけあって、単純でわかりやすいと思います。
3.client-minimal.py
次に、クライアント側のサンプルを見てみましょう。クライアントソフトで有名なのは「UaExpert」だそうですが、今回はあくまでラズパイ間で通信させることで OPC-UA の基礎を理解しようという試みなので、やはりPythonで作成してみます。
client-minimal.py の ソースコードを提示しておきます。こちらも、コメントや関係ないコードは削除しておきます。
≪参考4≫
https://github.com/FreeOpcUa/python-opcua/blob/master/examples/client-minimal.py
client-minimal.py
from opcua import Client if __name__ == "__main__": client = Client("opc.tcp://localhost:4840/freeopcua/server/") try: client.connect() # Client has a few methods to get proxy to UA nodes that should always be in address space such as Root or Objects root = client.get_root_node() print("Objects node is: ", root) # Node objects have methods to read and write node attributes as well as browse or populate address space print("Children of root are: ", root.get_children()) # Now getting a variable node using its browse path myvar = root.get_child(["0:Objects", "2:MyObject", "2:MyVariable"]) obj = root.get_child(["0:Objects", "2:MyObject"]) print("myvar is: ", myvar) print("myobj is: ", obj) finally: client.disconnect()
Clientインスタンスを生成して、接続(connect())します。当然、実行前には、サーバーを起動しておいてください。その後、ルートノードを取得します。
root.get_child(["0:Objects", "2:MyObject"]) ですが、"2:MyObject" というのが、サーバーで作成した、idx 番号です。この最小サンプルでは、ルートノードから、直接idx番号と「MyObject」キーワードを指定しています。
このクライアントサンプルでは、サーバーが連続してカウントを返しているのとは異なり、実行後、値を取り出して、すぐに終了します。
4.まとめ
今回は、「FreeOpcUa」の最小サンプルをそのまま実行してみました。ただし、これだけではよく分かりませんので、これを元に、色々と調査していきたいと思います。
少し回数が増えるかもしれませんが、気長にお付き合いください。
ほな、さいなら
===== <<注釈>>=====
※1 P子「実践編ね」
P子とは、私があこがれているツンデレPythonの仮想女性の心の声です。