Skip to content
Snippets Groups Projects
Commit 586e09e5 authored by Taya Snijder's avatar Taya Snijder
Browse files

Merge branch 'L2SS-465-lookup-nodes-in-bulk' into 'master'

Resolve L2SS-465 "Lookup nodes in bulk"

Closes L2SS-465

See merge request !179
parents e5d3dbfd 684ff0fe
No related branches found
No related tags found
1 merge request!179Resolve L2SS-465 "Lookup nodes in bulk"
......@@ -58,6 +58,9 @@ class OPCUAConnection(AsyncCommClient):
# prefix path to all nodes with this. this allows the user to switch trees more easily.
self.node_path_prefix = []
# cache of looked up child node lists for each comma-separated parent path
self._node_cache = {}
super().__init__(fault_func, event_loop)
def _servername(self):
......@@ -130,13 +133,41 @@ class OPCUAConnection(AsyncCommClient):
return path
async def get_node(self, path):
""" Retrieve an OPC-UA node from either the cache, or the server. """
if not path:
return self.obj
cache_key = ",".join(path)
# lookup in cache
if cache_key in self._node_cache:
return self._node_cache[cache_key]
# cache it and all of its siblings to save us the round trips for them later on.
parent_path = path[:-1]
parent_node = await self.obj.get_child(parent_path) if parent_path else self.obj
child_nodes = await parent_node.get_children_descriptions()
for child_node in child_nodes:
# add node to the cache
child_path = parent_path + [f"{self.name_space_index}:{child_node.DisplayName.Text}"]
self._node_cache[",".join(child_path)] = self.client.get_node(child_node.NodeId)
# lookup in cache again. if the name is valid, it should be in there.
if cache_key in self._node_cache:
return self._node_cache[cache_key]
# we couldnt find the requested child, ask server directly to get the appropriate error
return await self.obj.get_child(path)
async def setup_protocol_attribute(self, annotation, attribute):
# process the annotation
path = self.get_node_path(annotation)
try:
node = await self.obj.get_child(path)
node = await self.get_node(path)
except Exception as e:
logger.exception("Could not get node: %s on server %s", path, self._servername())
raise Exception("Could not get node: %s on server %s", path, self._servername()) from e
......@@ -180,7 +211,7 @@ class OPCUAConnection(AsyncCommClient):
try:
# call method in its parent node
node = await self.obj.get_child(method_path[:-1]) if len(method_path) > 1 else self.obj
node = await self.get_node(method_path[:-1])
result = await node.call_method(method_path[-1], *args)
except Exception as e:
raise Exception(f"Calling method {method_path} failed") from e
......
......@@ -86,6 +86,7 @@ class TestOPCua(base.AsyncTestCase):
m_opc_client_members.send_hello = asynctest.asynctest.CoroutineMock()
m_objects_node = asynctest.Mock()
m_objects_node.get_child = asynctest.asynctest.CoroutineMock()
m_objects_node.get_children_descriptions = asynctest.asynctest.CoroutineMock()
m_opc_client_members.get_objects_node = asynctest.Mock(return_value=m_objects_node)
m_opc_client.return_value = m_opc_client_members
......@@ -108,7 +109,7 @@ class TestOPCua(base.AsyncTestCase):
m_attribute = mock_attr(i.numpy_type, dim_x, dim_y)
# pretend like there is a running OPCua server with a node that has this name
m_annotation = ["2:PCC", f"2:testNode_{str(i.numpy_type)}_{str(dim_x)}_{str(dim_y)}"]
m_annotation = [f"2:testNode_{str(i.numpy_type)}_{str(dim_x)}_{str(dim_y)}"]
test_client = OPCUAConnection("opc.tcp://localhost:4874/freeopcua/server/", "http://lofar.eu", 5, mock.Mock(), self.loop)
try:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment