Commit fcffcb04 authored by Christoph Ziebuhr's avatar Christoph Ziebuhr Committed by oroulet

Automatically add ConditionId (NodeId) to select_clauses

when subscribing to ConditionType
parent 3552cccf
......@@ -3,7 +3,7 @@ from typing import Dict, List, TYPE_CHECKING
from asyncua import ua
import asyncua
from ..ua.uaerrors import UaError
from .ua_utils import get_node_subtypes
from .ua_utils import get_node_subtypes, is_subtype
if TYPE_CHECKING:
from asyncua.common.node import Node
......@@ -178,10 +178,19 @@ async def _select_clause_from_childs(child: "Node", refs: List[ua.ReferenceDescr
async def select_clauses_from_evtype(evtypes: List["Node"]):
select_clauses = []
already_selected = {}
add_condition_id = False
for evtype in evtypes:
if not add_condition_id and await is_subtype(evtype, ua.NodeId(ua.ObjectIds.ConditionType)):
add_condition_id = True
refs = await select_event_attributes_from_type_node(evtype, lambda n: n.get_references(ua.ObjectIds.Aggregates, ua.BrowseDirection.Forward, ua.NodeClass.Object | ua.NodeClass.Variable, True, _BROWSE_MASK))
if refs:
await _select_clause_from_childs(evtype, refs, select_clauses, already_selected, [])
if add_condition_id:
# also request ConditionId, which is not modelled as a component of the ConditionType
op = ua.SimpleAttributeOperand()
op.AttributeId = ua.AttributeIds.NodeId
op.TypeDefinitionId = ua.NodeId(ua.ObjectIds.ConditionType)
select_clauses.append(op)
return select_clauses
......
......@@ -273,17 +273,7 @@ class Subscription:
MaxUInt32 for max queue size
:return: Handle for changing/cancelling of the subscription
"""
sourcenode = Node(self.server, sourcenode)
if evfilter is None:
evfilter = await self._create_eventfilter(evtypes)
# Add SimpleAttribute for NodeId if missing.
matches = [a for a in evfilter.SelectClauses if a.AttributeId == ua.AttributeIds.NodeId]
if not matches:
conditionIdOperand = ua.SimpleAttributeOperand()
conditionIdOperand.TypeDefinitionId = ua.NodeId(ua.ObjectIds.ConditionType)
conditionIdOperand.AttributeId = ua.AttributeIds.NodeId
evfilter.SelectClauses.append(conditionIdOperand)
return await self._subscribe(sourcenode, ua.AttributeIds.EventNotifier, evfilter, queuesize=queuesize) # type: ignore
return await self.subscribe_events(sourcenode, evtypes, evfilter, queuesize)
async def _subscribe(
self,
......
......@@ -211,6 +211,17 @@ async def get_node_supertype(node):
return None
async def is_subtype(node, supertype):
"""
return if a node is a subtype of a specified nodeid
"""
while node:
if node.nodeid == supertype:
return True
node = await get_node_supertype(node)
return False
async def is_child_present(node, browsename):
"""
return if a browsename is present a child from the provide node
......
......@@ -39,6 +39,9 @@ class EventGenerator:
if node:
self.event = await events.get_event_obj_from_type_node(node)
if isinstance(self.event, event_objects.Condition):
# Add ConditionId, which is not modelled as a component of the ConditionType
self.event.add_property('NodeId', None, ua.VariantType.NodeId)
if isinstance(emitting_node, Node):
pass
......
......@@ -601,6 +601,16 @@ async def test_get_event_attributes_from_type_node_AlarmConditionType(opc):
assert child in allVariables
async def test_get_filter(opc):
auditType = opc.opc.get_node(ua.ObjectIds.AuditEventType)
baseType = opc.opc.get_node(ua.ObjectIds.BaseEventType)
properties = await baseType.get_properties()
properties.extend(await auditType.get_properties())
evfilter = await asyncua.common.events.get_filter_from_event_type([auditType])
# Check number of elements in select clause
assert len(evfilter.SelectClauses) == len(properties)
async def test_get_filter_from_ConditionType(opc):
condType = opc.opc.get_node(ua.ObjectIds.ConditionType)
baseType = opc.opc.get_node(ua.ObjectIds.BaseEventType)
......@@ -613,13 +623,15 @@ async def test_get_filter_from_ConditionType(opc):
subproperties.extend(await var.get_properties())
evfilter = await asyncua.common.events.get_filter_from_event_type([condType])
# Check number of elements in select clause
assert len(evfilter.SelectClauses) == (len(properties) + len(variables) + len(subproperties))
assert len(evfilter.SelectClauses) == (len(properties) + len(variables) + len(subproperties) + 1)
# Check browse path variable with property
browsePathList = [o.BrowsePath for o in evfilter.SelectClauses if o.BrowsePath]
browsePathEnabledState = [ua.uatypes.QualifiedName("EnabledState")]
browsePathEnabledStateId = [ua.uatypes.QualifiedName("EnabledState"), ua.uatypes.QualifiedName("Id")]
assert browsePathEnabledState in browsePathList
assert browsePathEnabledStateId in browsePathList
# Check for additional NodeId attribute, which is not directly contained in ConditionType
assert len([o for o in evfilter.SelectClauses if o.AttributeId == ua.AttributeIds.NodeId]) == 1
# Check some subtypes in where clause
alarmType = opc.opc.get_node(ua.ObjectIds.AlarmConditionType)
systemType = opc.opc.get_node(ua.ObjectIds.SystemOffNormalAlarmType)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment