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
...
@@ -13,6 +13,7 @@ from ..common.subscription import Subscription
from
..common.shortcuts
import
Shortcuts
from
..common.shortcuts
import
Shortcuts
from
..common.structures
import
load_type_definitions
,
load_enums
from
..common.structures
import
load_type_definitions
,
load_enums
from
..common.utils
import
create_nonce
from
..common.utils
import
create_nonce
from
..common.ua_utils
import
value_to_datavalue
from
..crypto
import
uacrypto
,
security_policies
from
..crypto
import
uacrypto
,
security_policies
_logger
=
logging
.
getLogger
(
__name__
)
_logger
=
logging
.
getLogger
(
__name__
)
...
@@ -28,7 +29,6 @@ class Client:
...
@@ -28,7 +29,6 @@ class Client:
use UaClient object, available as self.uaclient
use UaClient object, available as self.uaclient
which offers the raw OPC-UA services interface.
which offers the raw OPC-UA services interface.
"""
"""
def
__init__
(
self
,
url
:
str
,
timeout
:
int
=
4
,
loop
=
None
):
def
__init__
(
self
,
url
:
str
,
timeout
:
int
=
4
,
loop
=
None
):
"""
"""
:param url: url of the server.
:param url: url of the server.
...
@@ -78,9 +78,7 @@ class Client:
...
@@ -78,9 +78,7 @@ class Client:
"""
"""
_logger
.
info
(
"find_endpoint %r %r %r"
,
endpoints
,
security_mode
,
policy_uri
)
_logger
.
info
(
"find_endpoint %r %r %r"
,
endpoints
,
security_mode
,
policy_uri
)
for
ep
in
endpoints
:
for
ep
in
endpoints
:
if
(
ep
.
EndpointUrl
.
startswith
(
ua
.
OPC_TCP_SCHEME
)
and
if
(
ep
.
EndpointUrl
.
startswith
(
ua
.
OPC_TCP_SCHEME
)
and
ep
.
SecurityMode
==
security_mode
and
ep
.
SecurityPolicyUri
==
policy_uri
):
ep
.
SecurityMode
==
security_mode
and
ep
.
SecurityPolicyUri
==
policy_uri
):
return
ep
return
ep
raise
ua
.
UaError
(
"No matching endpoints: {0}, {1}"
.
format
(
security_mode
,
policy_uri
))
raise
ua
.
UaError
(
"No matching endpoints: {0}, {1}"
.
format
(
security_mode
,
policy_uri
))
...
@@ -117,11 +115,12 @@ class Client:
...
@@ -117,11 +115,12 @@ class Client:
raise
ua
.
UaError
(
"Wrong format: `{}`, expected at least 4 comma-separated values"
.
format
(
string
))
raise
ua
.
UaError
(
"Wrong format: `{}`, expected at least 4 comma-separated values"
.
format
(
string
))
policy_class
=
getattr
(
security_policies
,
"SecurityPolicy{}"
.
format
(
parts
[
0
]))
policy_class
=
getattr
(
security_policies
,
"SecurityPolicy{}"
.
format
(
parts
[
0
]))
mode
=
getattr
(
ua
.
MessageSecurityMode
,
parts
[
1
])
mode
=
getattr
(
ua
.
MessageSecurityMode
,
parts
[
1
])
return
await
self
.
set_security
(
return
await
self
.
set_security
(
policy_class
,
parts
[
2
],
parts
[
3
],
parts
[
4
]
if
len
(
parts
)
>=
5
else
None
,
mode
)
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
,
server_certificate_path
:
str
=
None
,
mode
:
ua
.
MessageSecurityMode
=
ua
.
MessageSecurityMode
.
SignAndEncrypt
):
mode
:
ua
.
MessageSecurityMode
=
ua
.
MessageSecurityMode
.
SignAndEncrypt
):
"""
"""
...
@@ -580,8 +579,18 @@ class Client:
...
@@ -580,8 +579,18 @@ class Client:
async
def
get_values
(
self
,
nodes
):
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
]
node
id
s
=
[
node
.
nodeid
for
node
in
nodes
]
results
=
await
self
.
uaclient
.
get_attribute
(
node
s
,
ua
.
AttributeIds
.
Value
)
results
=
await
self
.
uaclient
.
get_attribute
s
(
nodeid
s
,
ua
.
AttributeIds
.
Value
)
return
[
result
.
Value
.
Value
for
result
in
results
]
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:
...
@@ -642,15 +642,35 @@ class UaClient:
response
.
ResponseHeader
.
ServiceResult
.
check
()
response
.
ResponseHeader
.
ServiceResult
.
check
()
# nothing to return for this service
# nothing to return for this service
async
def
get_attribute
(
self
,
node
s
,
attr
):
async
def
get_attribute
s
(
self
,
nodeid
s
,
attr
):
self
.
logger
.
info
(
"get_attribute"
)
self
.
logger
.
info
(
"get_attribute
s of several nodes
"
)
request
=
ua
.
ReadRequest
()
request
=
ua
.
ReadRequest
()
for
node
in
node
s
:
for
node
id
in
nodeid
s
:
rv
=
ua
.
ReadValueId
()
rv
=
ua
.
ReadValueId
()
rv
.
NodeId
=
node
rv
.
NodeId
=
node
id
rv
.
AttributeId
=
attr
rv
.
AttributeId
=
attr
request
.
Parameters
.
NodesToRead
.
append
(
rv
)
request
.
Parameters
.
NodesToRead
.
append
(
rv
)
data
=
await
self
.
protocol
.
send_request
(
request
)
data
=
await
self
.
protocol
.
send_request
(
request
)
response
=
struct_from_binary
(
ua
.
ReadResponse
,
data
)
response
=
struct_from_binary
(
ua
.
ReadResponse
,
data
)
response
.
ResponseHeader
.
ServiceResult
.
check
()
response
.
ResponseHeader
.
ServiceResult
.
check
()
return
response
.
Results
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 @@
...
@@ -2,11 +2,12 @@
High level node object, to access node attribute
High level node object, to access node attribute
and browse address space
and browse address space
"""
"""
from
datetime
import
datetime
import
logging
import
logging
from
asyncua
import
ua
from
asyncua
import
ua
from
.ua_utils
import
value_to_datavalue
from
.events
import
Event
,
get_filter_from_event_type
from
.events
import
Event
,
get_filter_from_event_type
from
.ua_utils
import
data_type_to_variant_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
,
\
from
.manage_nodes
import
create_folder
,
create_object
,
create_object_type
,
create_variable
,
create_variable_type
,
\
...
@@ -214,16 +215,8 @@ class Node:
...
@@ -214,16 +215,8 @@ class Node:
and you modfy it afterward, then the object in db will be modified without any
and you modfy it afterward, then the object in db will be modified without any
data change event generated
data change event generated
"""
"""
datavalue
=
None
dv
=
value_to_datavalue
(
value
,
varianttype
)
if
isinstance
(
value
,
ua
.
DataValue
):
await
self
.
set_attribute
(
ua
.
AttributeIds
.
Value
,
dv
)
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
)
set_data_value
=
set_value
set_data_value
=
set_value
...
...
asyncua/common/ua_utils.py
View file @
a29444fb
...
@@ -13,6 +13,22 @@ from asyncua import ua
...
@@ -13,6 +13,22 @@ from asyncua import ua
logger
=
logging
.
getLogger
(
'__name__'
)
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
):
def
val_to_string
(
val
,
truncate
=
False
):
"""
"""
convert a python object or python-asyncua object to a string
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):
...
@@ -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 node: can be a ua.Node or ua.NodeId
:param includeitself: include also node to the list
:param includeitself: include also node to the list
:param skipbase don't include the toplevel one
: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
=
[]
parents
=
[]
if
includeitself
:
if
includeitself
:
...
@@ -202,7 +218,7 @@ async def is_child_present(node, browsename):
...
@@ -202,7 +218,7 @@ 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
:param node: node wherein to find the browsename
:param node: node wherein to find the browsename
:param browsename: browsename to search
: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
()
child_descs
=
await
node
.
get_children_descriptions
()
for
child_desc
in
child_descs
:
for
child_desc
in
child_descs
:
...
@@ -229,7 +245,7 @@ async def get_base_data_type(datatype):
...
@@ -229,7 +245,7 @@ async def get_base_data_type(datatype):
Looks up the base datatype of the provided datatype Node
Looks up the base datatype of the provided datatype Node
The base datatype is either:
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.
A primitive type (ns=0, i<=21) or a complex one (ns=0 i>21 and i<=30) like Enum and Struct.
Args:
Args:
datatype: NodeId of a datype of a variable
datatype: NodeId of a datype of a variable
Returns:
Returns:
...
@@ -245,7 +261,7 @@ async def get_base_data_type(datatype):
...
@@ -245,7 +261,7 @@ async def get_base_data_type(datatype):
async
def
get_nodes_of_namespace
(
server
,
namespaces
=
None
):
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:
Args:
server: opc ua server to use
server: opc ua server to use
namespaces: list of string uri or int indexes of the namespace to export
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):
...
@@ -87,3 +87,24 @@ async def test_custom_enum_struct(server, client):
val
=
await
myvar
.
get_value
()
val
=
await
myvar
.
get_value
()
assert
242
==
val
.
IntVal1
assert
242
==
val
.
IntVal1
assert
ua
.
ExampleEnum
.
EnumVal2
==
val
.
EnumVal
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