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
a29444fb
Commit
a29444fb
authored
Aug 01, 2019
by
oroulet
Committed by
Christian Bergmiller
Aug 29, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add Client.set_values for wrtting multiple node values at once
parent
9cb6411c
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
89 additions
and
30 deletions
+89
-30
asyncua/client/client.py
asyncua/client/client.py
+20
-11
asyncua/client/ua_client.py
asyncua/client/ua_client.py
+24
-4
asyncua/common/node.py
asyncua/common/node.py
+4
-11
asyncua/common/ua_utils.py
asyncua/common/ua_utils.py
+20
-4
tests/test_client.py
tests/test_client.py
+21
-0
No files found.
asyncua/client/client.py
View file @
a29444fb
...
...
@@ -13,6 +13,7 @@ from ..common.subscription import Subscription
from
..common.shortcuts
import
Shortcuts
from
..common.structures
import
load_type_definitions
,
load_enums
from
..common.utils
import
create_nonce
from
..common.ua_utils
import
value_to_datavalue
from
..crypto
import
uacrypto
,
security_policies
_logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -28,7 +29,6 @@ class Client:
use UaClient object, available as self.uaclient
which offers the raw OPC-UA services interface.
"""
def
__init__
(
self
,
url
:
str
,
timeout
:
int
=
4
,
loop
=
None
):
"""
:param url: url of the server.
...
...
@@ -78,9 +78,7 @@ class Client:
"""
_logger
.
info
(
"find_endpoint %r %r %r"
,
endpoints
,
security_mode
,
policy_uri
)
for
ep
in
endpoints
:
if
(
ep
.
EndpointUrl
.
startswith
(
ua
.
OPC_TCP_SCHEME
)
and
ep
.
SecurityMode
==
security_mode
and
ep
.
SecurityPolicyUri
==
policy_uri
):
if
(
ep
.
EndpointUrl
.
startswith
(
ua
.
OPC_TCP_SCHEME
)
and
ep
.
SecurityMode
==
security_mode
and
ep
.
SecurityPolicyUri
==
policy_uri
):
return
ep
raise
ua
.
UaError
(
"No matching endpoints: {0}, {1}"
.
format
(
security_mode
,
policy_uri
))
...
...
@@ -117,11 +115,12 @@ class Client:
raise
ua
.
UaError
(
"Wrong format: `{}`, expected at least 4 comma-separated values"
.
format
(
string
))
policy_class
=
getattr
(
security_policies
,
"SecurityPolicy{}"
.
format
(
parts
[
0
]))
mode
=
getattr
(
ua
.
MessageSecurityMode
,
parts
[
1
])
return
await
self
.
set_security
(
policy_class
,
parts
[
2
],
parts
[
3
],
parts
[
4
]
if
len
(
parts
)
>=
5
else
None
,
mode
)
return
await
self
.
set_security
(
policy_class
,
parts
[
2
],
parts
[
3
],
parts
[
4
]
if
len
(
parts
)
>=
5
else
None
,
mode
)
async
def
set_security
(
self
,
policy
,
certificate_path
:
str
,
private_key_path
:
str
,
async
def
set_security
(
self
,
policy
,
certificate_path
:
str
,
private_key_path
:
str
,
server_certificate_path
:
str
=
None
,
mode
:
ua
.
MessageSecurityMode
=
ua
.
MessageSecurityMode
.
SignAndEncrypt
):
"""
...
...
@@ -580,8 +579,18 @@ class Client:
async
def
get_values
(
self
,
nodes
):
"""
Read the value of multiple nodes in one
roundtrip
.
Read the value of multiple nodes in one
ua call
.
"""
nodes
=
[
node
.
nodeid
for
node
in
nodes
]
results
=
await
self
.
uaclient
.
get_attribute
(
node
s
,
ua
.
AttributeIds
.
Value
)
node
id
s
=
[
node
.
nodeid
for
node
in
nodes
]
results
=
await
self
.
uaclient
.
get_attribute
s
(
nodeid
s
,
ua
.
AttributeIds
.
Value
)
return
[
result
.
Value
.
Value
for
result
in
results
]
async
def
set_values
(
self
,
nodes
,
values
):
"""
Write values to multiple nodes in one ua call
"""
nodeids
=
[
node
.
nodeid
for
node
in
nodes
]
dvs
=
[
value_to_datavalue
(
val
)
for
val
in
values
]
results
=
await
self
.
uaclient
.
set_attributes
(
nodeids
,
dvs
,
ua
.
AttributeIds
.
Value
)
for
result
in
results
:
result
.
check
()
asyncua/client/ua_client.py
View file @
a29444fb
...
...
@@ -642,15 +642,35 @@ class UaClient:
response
.
ResponseHeader
.
ServiceResult
.
check
()
# nothing to return for this service
async
def
get_attribute
(
self
,
node
s
,
attr
):
self
.
logger
.
info
(
"get_attribute"
)
async
def
get_attribute
s
(
self
,
nodeid
s
,
attr
):
self
.
logger
.
info
(
"get_attribute
s of several nodes
"
)
request
=
ua
.
ReadRequest
()
for
node
in
node
s
:
for
node
id
in
nodeid
s
:
rv
=
ua
.
ReadValueId
()
rv
.
NodeId
=
node
rv
.
NodeId
=
node
id
rv
.
AttributeId
=
attr
request
.
Parameters
.
NodesToRead
.
append
(
rv
)
data
=
await
self
.
protocol
.
send_request
(
request
)
response
=
struct_from_binary
(
ua
.
ReadResponse
,
data
)
response
.
ResponseHeader
.
ServiceResult
.
check
()
return
response
.
Results
async
def
set_attributes
(
self
,
nodeids
,
datavalues
,
attributeid
=
ua
.
AttributeIds
.
Value
):
"""
Set an attribute of multiple nodes
datavalue is a ua.DataValue object
"""
self
.
logger
.
info
(
"set_attributes of several nodes"
)
request
=
ua
.
WriteRequest
()
for
idx
,
nodeid
in
enumerate
(
nodeids
):
attr
=
ua
.
WriteValue
()
attr
.
NodeId
=
nodeid
attr
.
AttributeId
=
attributeid
attr
.
Value
=
datavalues
[
idx
]
request
.
Parameters
.
NodesToWrite
.
append
(
attr
)
data
=
await
self
.
protocol
.
send_request
(
request
)
response
=
struct_from_binary
(
ua
.
WriteResponse
,
data
)
response
.
ResponseHeader
.
ServiceResult
.
check
()
return
response
.
Results
asyncua/common/node.py
View file @
a29444fb
...
...
@@ -2,11 +2,12 @@
High level node object, to access node attribute
and browse address space
"""
from
datetime
import
datetime
import
logging
from
asyncua
import
ua
from
.ua_utils
import
value_to_datavalue
from
.events
import
Event
,
get_filter_from_event_type
from
.ua_utils
import
data_type_to_variant_type
from
.manage_nodes
import
create_folder
,
create_object
,
create_object_type
,
create_variable
,
create_variable_type
,
\
...
...
@@ -214,16 +215,8 @@ class Node:
and you modfy it afterward, then the object in db will be modified without any
data change event generated
"""
datavalue
=
None
if
isinstance
(
value
,
ua
.
DataValue
):
datavalue
=
value
elif
isinstance
(
value
,
ua
.
Variant
):
datavalue
=
ua
.
DataValue
(
value
)
datavalue
.
SourceTimestamp
=
datetime
.
utcnow
()
else
:
datavalue
=
ua
.
DataValue
(
ua
.
Variant
(
value
,
varianttype
))
datavalue
.
SourceTimestamp
=
datetime
.
utcnow
()
await
self
.
set_attribute
(
ua
.
AttributeIds
.
Value
,
datavalue
)
dv
=
value_to_datavalue
(
value
,
varianttype
)
await
self
.
set_attribute
(
ua
.
AttributeIds
.
Value
,
dv
)
set_data_value
=
set_value
...
...
asyncua/common/ua_utils.py
View file @
a29444fb
...
...
@@ -13,6 +13,22 @@ from asyncua import ua
logger
=
logging
.
getLogger
(
'__name__'
)
def
value_to_datavalue
(
val
,
varianttype
=
None
):
"""
convert anyting to a DataValue using varianttype
"""
datavalue
=
None
if
isinstance
(
val
,
ua
.
DataValue
):
datavalue
=
val
elif
isinstance
(
val
,
ua
.
Variant
):
datavalue
=
ua
.
DataValue
(
val
)
datavalue
.
SourceTimestamp
=
datetime
.
utcnow
()
else
:
datavalue
=
ua
.
DataValue
(
ua
.
Variant
(
val
,
varianttype
))
datavalue
.
SourceTimestamp
=
datetime
.
utcnow
()
return
datavalue
def
val_to_string
(
val
,
truncate
=
False
):
"""
convert a python object or python-asyncua object to a string
...
...
@@ -160,7 +176,7 @@ async def get_node_supertypes(node, includeitself=False, skipbase=True):
:param node: can be a ua.Node or ua.NodeId
:param includeitself: include also node to the list
:param skipbase don't include the toplevel one
:returns list of ua.Node, top parent first
:returns list of ua.Node, top parent first
"""
parents
=
[]
if
includeitself
:
...
...
@@ -202,7 +218,7 @@ async def is_child_present(node, browsename):
return if a browsename is present a child from the provide node
:param node: node wherein to find the browsename
:param browsename: browsename to search
:returns returne True if the browsename is present else False
:returns returne True if the browsename is present else False
"""
child_descs
=
await
node
.
get_children_descriptions
()
for
child_desc
in
child_descs
:
...
...
@@ -229,7 +245,7 @@ async def get_base_data_type(datatype):
Looks up the base datatype of the provided datatype Node
The base datatype is either:
A primitive type (ns=0, i<=21) or a complex one (ns=0 i>21 and i<=30) like Enum and Struct.
Args:
datatype: NodeId of a datype of a variable
Returns:
...
...
@@ -245,7 +261,7 @@ async def get_base_data_type(datatype):
async
def
get_nodes_of_namespace
(
server
,
namespaces
=
None
):
"""
Get the nodes of one or more namespaces .
Get the nodes of one or more namespaces .
Args:
server: opc ua server to use
namespaces: list of string uri or int indexes of the namespace to export
...
...
tests/test_client.py
View file @
a29444fb
...
...
@@ -87,3 +87,24 @@ async def test_custom_enum_struct(server, client):
val
=
await
myvar
.
get_value
()
assert
242
==
val
.
IntVal1
assert
ua
.
ExampleEnum
.
EnumVal2
==
val
.
EnumVal
async
def
test_multiple_read_and_write
(
server
,
client
):
f
=
await
server
.
nodes
.
objects
.
add_folder
(
3
,
'Multiple_read_write_test'
)
v1
=
await
f
.
add_variable
(
3
,
"a"
,
1
)
await
v1
.
set_writable
()
v2
=
await
f
.
add_variable
(
3
,
"b"
,
2
)
await
v2
.
set_writable
()
v3
=
await
f
.
add_variable
(
3
,
"c"
,
3
)
await
v3
.
set_writable
()
v_ro
=
await
f
.
add_variable
(
3
,
"ro"
,
3
)
vals
=
await
client
.
get_values
([
v1
,
v2
,
v3
])
assert
vals
==
[
1
,
2
,
3
]
await
client
.
set_values
([
v1
,
v2
,
v3
],
[
4
,
5
,
6
])
vals
=
await
client
.
get_values
([
v1
,
v2
,
v3
])
assert
vals
==
[
4
,
5
,
6
]
with
pytest
.
raises
(
ua
.
uaerrors
.
BadUserAccessDenied
):
await
client
.
set_values
([
v1
,
v2
,
v_ro
],
[
4
,
5
,
6
])
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