From da6574632cc84aa42940a546abdf4b606a159deb Mon Sep 17 00:00:00 2001 From: Wolfgang Hottgenroth Date: Tue, 22 Feb 2022 18:07:21 +0100 Subject: [PATCH] extended output and readme --- readme.md | 86 +++++++++++++++++++++++++++++++------ snippets/test2.py | 11 ++++- src/FlatDataObject.py | 18 +++++--- src/OpcUaRequester.py | 9 ++-- src/StructuredDataObject.py | 13 ++++-- src/config.json | 2 +- 6 files changed, 110 insertions(+), 29 deletions(-) diff --git a/readme.md b/readme.md index 2801e79..50d7fd5 100644 --- a/readme.md +++ b/readme.md @@ -54,26 +54,88 @@ The attribute `nodes` finally contains the list of variables to be queried. It c ## Example Output +Besides the value itself the output contains the status of the value and a couple of timestamps (from device `t1`, server `t2` and bridge `t3`). + In `flat` mode the final topic will be `${mqtt.publicTopicPrefix}/${opcua.name}/${opcua.node.ns}/${opcua.node.d}` An example for the MQTT messages according to the above configuration in `flat` mode is: - opcua/apl/0/pv {"serverName": "apl", "nameSpaceIndex": 0, "variableName": "pv", "value": 19.849281311035156} - opcua/apl/0/sv {"serverName": "apl", "nameSpaceIndex": 0, "variableName": "sv", "value": 1688.5152587890625} - opcua/apl/0/tv {"serverName": "apl", "nameSpaceIndex": 0, "variableName": "tv", "value": 22.574615478515625} - opcua/apl/0/qv {"serverName": "apl", "nameSpaceIndex": 0, "variableName": "qv", "value": NaN} - opcua/apl/0/pv {"serverName": "apl", "nameSpaceIndex": 0, "variableName": "pv", "value": 19.849281311035156} - opcua/apl/0/sv {"serverName": "apl", "nameSpaceIndex": 0, "variableName": "sv", "value": 1688.5152587890625} - opcua/apl/0/tv {"serverName": "apl", "nameSpaceIndex": 0, "variableName": "tv", "value": 22.574615478515625} - opcua/apl/0/qv {"serverName": "apl", "nameSpaceIndex": 0, "variableName": "qv", "value": NaN} + + opcua/apl/0/pv { + "server": "apl", + "ns": 0, + "d": "pv", + "value": 19.833280563354492, + "status": "Good", + "t1": "2022-02-22 17:03:41.189000", + "t2": "2022-02-22 17:03:41.189000", + "t3": "2022-02-22 17:03:41.575504" + } + opcua/apl/0/sv { + "server": "apl", + "ns": 0, + "d": "sv", + "value": 1706.15771484375, + "status": "Good", + "t1": "2022-02-22 17:03:41.189000", + "t2": "2022-02-22 17:03:41.189000", + "t3": "2022-02-22 17:03:41.625721" + } + opcua/apl/0/tv { + "server": "apl", + "ns": 0, + "d": "tv", + "value": 23.29559326171875, + "status": "Good", + "t1": "2022-02-22 17:03:41.189000", + "t2": "2022-02-22 17:03:41.189000", + "t3": "2022-02-22 17:03:41.675352" + } + opcua/apl/0/qv { + "server": "apl", + "ns": 0, + "d": "qv", + "value": NaN, + "status": "Good", + "t1": "2022-02-22 17:03:41.189000", + "t2": "2022-02-22 17:03:41.189000", + "t3": "2022-02-22 17:03:41.725487" + } In `structured` mode the final topic will be `${mqtt.publicTopicPrefix}/${opcua.name}` An example for the MQTT messages according to the above configuration in `flat` mode is: - opcua/apl {"pv": 19.844480514526367, "sv": 1689.9193115234375, "tv": 22.68524169921875, "qv": NaN} - opcua/apl {"pv": 19.844480514526367, "sv": 1689.9193115234375, "tv": 22.68524169921875, "qv": NaN} - opcua/apl {"pv": 19.844480514526367, "sv": 1689.9193115234375, "tv": 22.68524169921875, "qv": NaN} - opcua/apl {"pv": 19.844480514526367, "sv": 1689.93701171875, "tv": 22.620391845703125, "qv": NaN} + opcua/apl { + "pv": { + "value": 19.835201263427734, + "status": "Good", + "t1": "2022-02-22 16:58:21.188000", + "t2": "2022-02-22 16:58:21.188000", + "t3": "2022-02-22 16:58:22.071619" + }, + "sv": { + "value": 1704.4019775390625, + "status": "Good", + "t1": "2022-02-22 16:58:21.188000", + "t2": "2022-02-22 16:58:21.188000", + "t3": "2022-02-22 16:58:22.121559" + }, + "tv": { + "value": 23.08197021484375, + "status": "Good", + "t1": "2022-02-22 16:58:21.188000", + "t2": "2022-02-22 16:58:21.188000", + "t3": "2022-02-22 16:58:22.171498" + }, + "qv": { + "value": NaN, + "status": "Good", + "t1": "2022-02-22 16:58:21.188000", + "t2": "2022-02-22 16:58:21.188000", + "t3": "2022-02-22 16:58:22.221639" + } + } + diff --git a/snippets/test2.py b/snippets/test2.py index 20ecc84..4fcff07 100644 --- a/snippets/test2.py +++ b/snippets/test2.py @@ -4,13 +4,20 @@ from asyncua import Client async def test(): - client = Client(url='opc.tcp://192.168.254.5:4863', timeout=10.0) + client = Client(url='opc.tcp://172.16.3.60:4840', timeout=10.0) # await client.set_security_string('') async with client: - node = client.get_node('ns=1;s=t|SERVER::A201CD124/MOT_01.AV_Out#Value') + node = client.get_node('ns=0;i=345') value = await node.read_value() displayName = (await node.read_display_name()).Text + print(dir(node)) print(f"{displayName=} = {value=}") + print(f"X1: {await node.read_data_value()}") + print(f"X2: {(await node.read_data_value()).Value.Value}") + print(f"X3: {dir((await node.read_data_value()).StatusCode)}") + print(f"X3: {(await node.read_data_value()).StatusCode.name}") + print(f"X4: {(await node.read_data_value()).SourceTimestamp}") + print(f"X4: {(await node.read_data_value()).ServerTimestamp}") asyncio.run(test()) diff --git a/src/FlatDataObject.py b/src/FlatDataObject.py index 309e850..1dfe2e6 100644 --- a/src/FlatDataObject.py +++ b/src/FlatDataObject.py @@ -1,21 +1,25 @@ import re import json from AbstractDataObject import AbstractDataObject - +from datetime import datetime class FlatDataObject(AbstractDataObject): - def __init__(self, serverName, nameSpaceIndex, variableName, value): + def __init__(self, serverName, nameSpaceIndex, variableName, dataValue): super().__init__(serverName + '/' + str(nameSpaceIndex) + '/' + variableName) self.serverName = serverName self.nameSpaceIndex = nameSpaceIndex self.variableName = variableName - self.value = value + self.dataValue = dataValue def getPayload(self): payload = { - "serverName": self.serverName, - "nameSpaceIndex": self.nameSpaceIndex, - "variableName": self.variableName, - "value": self.value + "server": self.serverName, + "ns": self.nameSpaceIndex, + "d": self.variableName, + "value": self.dataValue.Value.Value, + "status": self.dataValue.StatusCode.name, + "t1": str(self.dataValue.SourceTimestamp), + "t2": str(self.dataValue.ServerTimestamp), + "t3": str(datetime.utcnow()) } return json.dumps(payload) diff --git a/src/OpcUaRequester.py b/src/OpcUaRequester.py index 1187711..b241cc2 100644 --- a/src/OpcUaRequester.py +++ b/src/OpcUaRequester.py @@ -36,13 +36,14 @@ class OpcUaRequester(threading.Thread): try: logger.debug(f"Trying {self.name} {self.url} ns={nodeSpec['ns']};{nodeSpec['n']}") node = client.get_node(f"ns={nodeSpec['ns']};{nodeSpec['n']}") - value = await node.read_value() + + dataValue = await node.read_data_value() displayName = nodeSpec['d'] if ('d' in nodeSpec) else (await node.read_display_name()).Text - logger.debug(f"Got: {displayName=} = {value=}") + logger.debug(f"Got: {displayName=} = {dataValue.Value.Value=}") if self.flat: - self.queue.put(FlatDataObject(self.name, nodeSpec['ns'], displayName, value)) + self.queue.put(FlatDataObject(self.name, nodeSpec['ns'], displayName, dataValue)) else: - dataObject.add(displayName, value) + dataObject.add(displayName, dataValue) self.stats.incOpcUaRequests() except ua.UaError as e: self.stats.incOpcUaErrors() diff --git a/src/StructuredDataObject.py b/src/StructuredDataObject.py index e085dd5..3e2d7e1 100644 --- a/src/StructuredDataObject.py +++ b/src/StructuredDataObject.py @@ -1,15 +1,22 @@ import re import json from AbstractDataObject import AbstractDataObject - +from datetime import datetime class StructuredDataObject(AbstractDataObject): def __init__(self, topicPart): super().__init__(topicPart) self.keyValuePairs = {} - def add(self, key, value): - self.keyValuePairs[key] = value + def add(self, key, dataValue): + self.keyValuePairs[key] = { + "value": dataValue.Value.Value, + "status": dataValue.StatusCode.name, + "t1": str(dataValue.SourceTimestamp), + "t2": str(dataValue.ServerTimestamp), + "t3": str(datetime.utcnow()) + } + def getPayload(self): return json.dumps(self.keyValuePairs) diff --git a/src/config.json b/src/config.json index e9d5540..06ae2ff 100644 --- a/src/config.json +++ b/src/config.json @@ -11,7 +11,7 @@ "opcua": [ { "enabled": "true", - "type": "structured", + "type": "flat", "url": "opc.tcp://172.16.3.60:4840", "name": "apl", "period": 1.0,