Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
opcua-asyncio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Nikola Balog
opcua-asyncio
Commits
fcffcb04
Commit
fcffcb04
authored
Jul 21, 2023
by
Christoph Ziebuhr
Committed by
oroulet
Jul 31, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Automatically add ConditionId (NodeId) to select_clauses
when subscribing to ConditionType
parent
3552cccf
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
38 additions
and
13 deletions
+38
-13
asyncua/common/events.py
asyncua/common/events.py
+10
-1
asyncua/common/subscription.py
asyncua/common/subscription.py
+1
-11
asyncua/common/ua_utils.py
asyncua/common/ua_utils.py
+11
-0
asyncua/server/event_generator.py
asyncua/server/event_generator.py
+3
-0
tests/test_subscriptions.py
tests/test_subscriptions.py
+13
-1
No files found.
asyncua/common/events.py
View file @
fcffcb04
...
@@ -3,7 +3,7 @@ from typing import Dict, List, TYPE_CHECKING
...
@@ -3,7 +3,7 @@ from typing import Dict, List, TYPE_CHECKING
from
asyncua
import
ua
from
asyncua
import
ua
import
asyncua
import
asyncua
from
..ua.uaerrors
import
UaError
from
..ua.uaerrors
import
UaError
from
.ua_utils
import
get_node_subtypes
from
.ua_utils
import
get_node_subtypes
,
is_subtype
if
TYPE_CHECKING
:
if
TYPE_CHECKING
:
from
asyncua.common.node
import
Node
from
asyncua.common.node
import
Node
...
@@ -178,10 +178,19 @@ async def _select_clause_from_childs(child: "Node", refs: List[ua.ReferenceDescr
...
@@ -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"
]):
async
def
select_clauses_from_evtype
(
evtypes
:
List
[
"Node"
]):
select_clauses
=
[]
select_clauses
=
[]
already_selected
=
{}
already_selected
=
{}
add_condition_id
=
False
for
evtype
in
evtypes
:
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
))
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
:
if
refs
:
await
_select_clause_from_childs
(
evtype
,
refs
,
select_clauses
,
already_selected
,
[])
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
return
select_clauses
...
...
asyncua/common/subscription.py
View file @
fcffcb04
...
@@ -273,17 +273,7 @@ class Subscription:
...
@@ -273,17 +273,7 @@ class Subscription:
MaxUInt32 for max queue size
MaxUInt32 for max queue size
:return: Handle for changing/cancelling of the subscription
:return: Handle for changing/cancelling of the subscription
"""
"""
sourcenode
=
Node
(
self
.
server
,
sourcenode
)
return
await
self
.
subscribe_events
(
sourcenode
,
evtypes
,
evfilter
,
queuesize
)
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
async
def
_subscribe
(
async
def
_subscribe
(
self
,
self
,
...
...
asyncua/common/ua_utils.py
View file @
fcffcb04
...
@@ -211,6 +211,17 @@ async def get_node_supertype(node):
...
@@ -211,6 +211,17 @@ async def get_node_supertype(node):
return
None
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
):
async
def
is_child_present
(
node
,
browsename
):
"""
"""
return if a browsename is present a child from the provide node
return if a browsename is present a child from the provide node
...
...
asyncua/server/event_generator.py
View file @
fcffcb04
...
@@ -39,6 +39,9 @@ class EventGenerator:
...
@@ -39,6 +39,9 @@ class EventGenerator:
if
node
:
if
node
:
self
.
event
=
await
events
.
get_event_obj_from_type_node
(
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
):
if
isinstance
(
emitting_node
,
Node
):
pass
pass
...
...
tests/test_subscriptions.py
View file @
fcffcb04
...
@@ -601,6 +601,16 @@ async def test_get_event_attributes_from_type_node_AlarmConditionType(opc):
...
@@ -601,6 +601,16 @@ async def test_get_event_attributes_from_type_node_AlarmConditionType(opc):
assert
child
in
allVariables
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
):
async
def
test_get_filter_from_ConditionType
(
opc
):
condType
=
opc
.
opc
.
get_node
(
ua
.
ObjectIds
.
ConditionType
)
condType
=
opc
.
opc
.
get_node
(
ua
.
ObjectIds
.
ConditionType
)
baseType
=
opc
.
opc
.
get_node
(
ua
.
ObjectIds
.
BaseEventType
)
baseType
=
opc
.
opc
.
get_node
(
ua
.
ObjectIds
.
BaseEventType
)
...
@@ -613,13 +623,15 @@ async def test_get_filter_from_ConditionType(opc):
...
@@ -613,13 +623,15 @@ async def test_get_filter_from_ConditionType(opc):
subproperties
.
extend
(
await
var
.
get_properties
())
subproperties
.
extend
(
await
var
.
get_properties
())
evfilter
=
await
asyncua
.
common
.
events
.
get_filter_from_event_type
([
condType
])
evfilter
=
await
asyncua
.
common
.
events
.
get_filter_from_event_type
([
condType
])
# Check number of elements in select clause
# 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
# Check browse path variable with property
browsePathList
=
[
o
.
BrowsePath
for
o
in
evfilter
.
SelectClauses
if
o
.
BrowsePath
]
browsePathList
=
[
o
.
BrowsePath
for
o
in
evfilter
.
SelectClauses
if
o
.
BrowsePath
]
browsePathEnabledState
=
[
ua
.
uatypes
.
QualifiedName
(
"EnabledState"
)]
browsePathEnabledState
=
[
ua
.
uatypes
.
QualifiedName
(
"EnabledState"
)]
browsePathEnabledStateId
=
[
ua
.
uatypes
.
QualifiedName
(
"EnabledState"
),
ua
.
uatypes
.
QualifiedName
(
"Id"
)]
browsePathEnabledStateId
=
[
ua
.
uatypes
.
QualifiedName
(
"EnabledState"
),
ua
.
uatypes
.
QualifiedName
(
"Id"
)]
assert
browsePathEnabledState
in
browsePathList
assert
browsePathEnabledState
in
browsePathList
assert
browsePathEnabledStateId
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
# Check some subtypes in where clause
alarmType
=
opc
.
opc
.
get_node
(
ua
.
ObjectIds
.
AlarmConditionType
)
alarmType
=
opc
.
opc
.
get_node
(
ua
.
ObjectIds
.
AlarmConditionType
)
systemType
=
opc
.
opc
.
get_node
(
ua
.
ObjectIds
.
SystemOffNormalAlarmType
)
systemType
=
opc
.
opc
.
get_node
(
ua
.
ObjectIds
.
SystemOffNormalAlarmType
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment