Python で OPC UA の変数ノードを監視する
opcua-asyncio を使って OPC UA の変数ノードを購読し、ポーリングではなくサーバーからの通知で変更を処理します。
必要要件
以下のコマンドで opcua-asyncio をインストールします。
pip install asyncuaPython スクリプト
import asyncioimport random
from asyncua import Server
ENDPOINT = 'opc.tcp://localhost:4840'NAMESPACE = 'http://examples.freeopcua.github.io'
async def main() -> None: # Start a server. server = Server() await server.init() server.set_endpoint(ENDPOINT) idx = await server.register_namespace(NAMESPACE) await server.start() print(f'Server started: {server}')
# Create a node. myobj = await server.get_objects_node().add_object(idx, 'MyObject') myvar = await myobj.add_variable(idx, 'MyVariable', 1) await myvar.set_writable()
# Write a new value every second. while True: await myvar.write_value(random.randint(1, 100)) await asyncio.sleep(1)
if __name__ == '__main__': asyncio.run(main())import asyncio
from asyncua import Client, Nodefrom asyncua.common.subscription import DataChangeNotif, SubHandler
ENDPOINT = 'opc.tcp://localhost:4840'NAMESPACE = 'http://examples.freeopcua.github.io'
class MyHandler(SubHandler): def __init__(self): self._queue = asyncio.Queue()
def datachange_notification(self, node: Node, value, data: DataChangeNotif) -> None: self._queue.put_nowait([node, value, data]) print(f'Data change notification was received and queued.')
async def process(self) -> None: try: while True: # Get data in a queue. [node, value, data] = self._queue.get_nowait() path = await node.get_path(as_string=True)
# *** Write your processing code ***
print(f'New value {value} of "{path}" was processed.')
except asyncio.QueueEmpty: pass
async def main() -> None: async with Client(url=ENDPOINT) as client: # Get a variable node. idx = await client.get_namespace_index(NAMESPACE) node = await client.get_objects_node().get_child([f'{idx}:MyObject', f'{idx}:MyVariable'])
# Subscribe data change. handler = MyHandler() subscription = await client.create_subscription(period=0, handler=handler) await subscription.subscribe_data_change(node)
# Process data change every 100ms while True: await handler.process() await asyncio.sleep(0.1)
if __name__ == '__main__': asyncio.run(main())テスト
以下のコマンドでサーバーを起動します。
$ python server.pyServer started: OPC UA Server(opc.tcp://localhost:4840)以下のコマンドでクライアントを起動します。
$ python client.pyData change notification was received and queued.New value 4 of "['0:Root', '0:Objects', '2:MyObject', '2:MyVariable']" was processed.Data change notification was received and queued.New value 79 of "['0:Root', '0:Objects', '2:MyObject', '2:MyVariable']" was processed.Data change notification was received and queued.New value 75 of "['0:Root', '0:Objects', '2:MyObject', '2:MyVariable']" was processed....まとめ
opcua-asyncio を使うと、OPC UA の変数ノードを購読し、ポーリングせずにサーバーからの変更通知を処理できます。create_subscription で購読を作成し、subscribe_data_change で MyVariable を登録すると、サーバーから新しい値が通知されるたびにライブラリが datachange_notification を呼び出します。
通知を datachange_notification 内で直接処理せず、asyncio.Queue を経由させます。これにより、同期的な通知ハンドラーを短く保ち、100 ms ごとにキューを確認する非同期の process() ループと分離できます。
この分離により、通知の受信方法を変えずに、処理ブロックへ監視ロジックを追加できます。
Related posts
Tesseract と Pytesseract による日本語 PDF の OCR 処理
Tesseract OCR v4 と pytesseract を使って PDF から日本語テキストを抽出し、出力を整えるための正規化処理も行います。
インターネット接続なしで Python パッケージをインストールする
接続可能なマシンで Python パッケージをダウンロードして転送し、インターネットに接続できない環境へインストールする方法を解説します。
EC2 上で Proxy.py を軽量 HTTP プロキシとして動かす
認証機構を持たない Proxy.py を EC2 インスタンス上で動かし、SSH トンネル経由で安全にアクセスします。
SiteWise Edge Gateway で OPC UA データを Kinesis にストリーミングする
SiteWise Edge Gateway とカスタムの Greengrass コンポーネントを使い、OPC UA テレメトリを Kinesis Data Streams へ橋渡しします。
保守性とテストしやすさのための依存性注入
密結合な TypeScript クラスを、給与計算、システムクロック、Amazon SES のメーラーを注入する構成へリファクタリングします。
