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
ef9e89f1
Commit
ef9e89f1
authored
Feb 24, 2019
by
oroulet
Committed by
oroulet
Feb 25, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add sync/client-example.py and make it run
parent
1fb9d6bc
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
261 additions
and
17 deletions
+261
-17
asyncua/sync.py
asyncua/sync.py
+63
-17
examples/sync/custom_nodes.xml
examples/sync/custom_nodes.xml
+33
-0
examples/sync/server-example.py
examples/sync/server-example.py
+165
-0
No files found.
asyncua/sync.py
View file @
ef9e89f1
...
...
@@ -5,6 +5,7 @@ import asyncio
from
threading
import
Thread
,
Condition
import
logging
from
asyncua
import
ua
from
asyncua
import
client
from
asyncua
import
server
from
asyncua.common
import
node
...
...
@@ -79,32 +80,21 @@ def release_thread_loop():
stop_thread_loop
()
def
_get_super
(
func
):
classname
=
func
.
__qualname__
.
split
(
'.'
,
1
)[
0
]
if
hasattr
(
node
,
classname
):
return
getattr
(
node
,
classname
)
if
hasattr
(
client
,
classname
):
return
getattr
(
client
,
classname
)
if
hasattr
(
server
,
classname
):
return
getattr
(
server
,
classname
)
if
hasattr
(
subscription
,
classname
):
return
getattr
(
subscription
,
classname
)
return
AttributeError
(
f"Could not find super of parent class for method
{
func
}
"
)
def
syncmethod
(
func
):
def
wrapper
(
self
,
*
args
,
**
kwargs
):
#name = func.__name__
args
=
list
(
args
)
#FIXME: might be very inefficient...
for
idx
,
arg
in
enumerate
(
args
):
if
isinstance
(
arg
,
Node
):
args
[
idx
]
=
arg
.
aio_obj
aio_func
=
getattr
(
self
.
aio_obj
,
func
.
__name__
)
#sup = _get_super(func)
#super_func = getattr(sup, name)
global
_tloop
print
(
"CALLING"
,
func
,
func
.
__name__
,
args
)
result
=
_tloop
.
post
(
aio_func
(
*
args
,
**
kwargs
))
if
isinstance
(
result
,
node
.
Node
):
return
Node
(
result
)
if
isinstance
(
result
,
list
)
and
len
(
result
)
>
0
and
isinstance
(
result
[
0
],
node
.
Node
):
return
[
Node
(
i
)
for
i
in
result
]
if
isinstance
(
result
,
server
.
event_generator
.
EventGenerator
):
return
EventGenerator
(
result
)
return
result
return
wrapper
...
...
@@ -144,6 +134,12 @@ class Server:
def
set_endpoint
(
self
,
url
):
return
self
.
aio_obj
.
set_endpoint
(
url
)
def
set_server_name
(
self
,
name
):
return
self
.
aio_obj
.
set_server_name
(
name
)
def
set_security_policy
(
self
,
security_policy
):
return
self
.
aio_obj
.
set_security_policy
(
security_policy
)
@
syncmethod
def
register_namespace
(
self
,
url
):
return
self
.
aio_obj
.
register_namespace
(
url
)
...
...
@@ -156,14 +152,40 @@ class Server:
def
stop
(
self
):
pass
@
syncmethod
async
def
get_event_generator
(
self
,
etype
=
None
,
emitting_node
=
ua
.
ObjectIds
.
Server
):
pass
def
get_node
(
self
,
nodeid
):
return
Node
(
server
.
Server
.
get_node
(
self
,
nodeid
))
def
import_xml
(
self
,
path
=
None
,
xmlstring
=
None
):
return
self
.
aio_obj
.
import_xml
(
path
=
None
,
xmlstring
=
None
)
def
set_attribute_value
(
self
,
nodeid
,
datavalue
,
attr
=
ua
.
AttributeIds
.
Value
):
return
self
.
aio_obj
.
set_attribute_value
(
nodeid
,
datavalue
,
attr
)
class
EventGenerator
:
def
__init__
(
self
,
aio_evgen
):
self
.
aio_obj
=
aio_evgen
@
property
def
event
(
self
):
return
self
.
aio_obj
.
event
def
trigger
(
self
,
time
=
None
,
message
=
None
):
return
self
.
aio_obj
.
trigger
(
time
,
message
)
class
Node
:
def
__init__
(
self
,
aio_node
):
self
.
aio_obj
=
aio_node
global
_tloop
@
property
def
nodeid
(
self
):
return
self
.
aio_obj
.
nodeid
@
syncmethod
def
get_browse_name
(
self
):
...
...
@@ -177,14 +199,34 @@ class Node:
def
get_child
(
self
,
path
):
pass
@
syncmethod
def
set_modelling_rule
(
self
,
mandatory
:
bool
):
pass
@
syncmethod
def
add_variable
(
self
,
ns
,
name
,
val
):
pass
@
syncmethod
def
add_property
(
self
,
ns
,
name
,
val
):
pass
@
syncmethod
def
add_object
(
self
,
ns
,
name
):
pass
@
syncmethod
def
add_object_type
(
self
,
ns
,
name
):
pass
@
syncmethod
def
add_folder
(
self
,
ns
,
name
):
pass
@
syncmethod
def
add_method
(
self
,
*
args
):
pass
@
syncmethod
def
set_writable
(
self
,
writable
=
True
):
pass
...
...
@@ -193,6 +235,10 @@ class Node:
def
set_value
(
self
,
val
):
pass
@
syncmethod
def
get_value
(
self
,
val
):
pass
def
__eq__
(
self
,
other
):
return
self
.
aio_obj
==
other
.
aio_obj
...
...
examples/sync/custom_nodes.xml
0 → 100644
View file @
ef9e89f1
<?xml version='1.0' encoding='utf-8'?>
<UANodeSet
xmlns=
"http://opcfoundation.org/UA/2011/03/UANodeSet.xsd"
xmlns:uax=
"http://opcfoundation.org/UA/2008/02/Types.xsd"
xmlns:xsd=
"http://www.w3.org/2001/XMLSchema"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
>
<NamespaceUris>
<Uri>
urn:freeopcua:example
</Uri>
</NamespaceUris>
<Aliases>
<Alias
Alias=
"HasModellingRule"
>
i=37
</Alias>
<Alias
Alias=
"Float"
>
i=10
</Alias>
<Alias
Alias=
"HasTypeDefinition"
>
i=40
</Alias>
<Alias
Alias=
"HasSubtype"
>
i=45
</Alias>
<Alias
Alias=
"HasComponent"
>
i=47
</Alias>
</Aliases>
<UAObjectType
BrowseName=
"1:MyXmlObj"
NodeId=
"ns=1;i=2001"
>
<DisplayName>
MyXmlObj
</DisplayName>
<Description>
MyXmlObj
</Description>
<References>
<Reference
IsForward=
"false"
ReferenceType=
"HasSubtype"
>
i=58
</Reference>
<Reference
ReferenceType=
"HasComponent"
>
ns=1;i=2002
</Reference>
</References>
</UAObjectType>
<UAVariable
BrowseName=
"1:MyXmlVar"
DataType=
"Float"
NodeId=
"ns=1;i=2002"
ParentNodeId=
"ns=1;i=2001"
>
<DisplayName>
MyXmlVar
</DisplayName>
<Description>
MyXmlVar
</Description>
<References>
<Reference
IsForward=
"false"
ReferenceType=
"HasComponent"
>
ns=1;i=2001
</Reference>
<Reference
ReferenceType=
"HasTypeDefinition"
>
i=63
</Reference>
<Reference
ReferenceType=
"HasModellingRule"
>
i=78
</Reference>
</References>
<Value>
<uax:Float>
0.0
</uax:Float>
</Value>
</UAVariable>
</UANodeSet>
examples/sync/server-example.py
0 → 100644
View file @
ef9e89f1
from
threading
import
Thread
import
copy
import
logging
from
datetime
import
datetime
import
time
from
math
import
sin
import
sys
sys
.
path
.
insert
(
0
,
"../.."
)
try
:
from
IPython
import
embed
except
ImportError
:
import
code
def
embed
():
myvars
=
globals
()
myvars
.
update
(
locals
())
shell
=
code
.
InteractiveConsole
(
myvars
)
shell
.
interact
()
from
asyncua
import
ua
,
uamethod
from
asyncua.sync
import
Server
,
start_thread_loop
,
stop_thread_loop
class
SubHandler
(
object
):
"""
Subscription Handler. To receive events from server for a subscription
"""
def
datachange_notification
(
self
,
node
,
val
,
data
):
print
(
"Python: New data change event"
,
node
,
val
)
def
event_notification
(
self
,
event
):
print
(
"Python: New event"
,
event
)
# method to be exposed through server
def
func
(
parent
,
variant
):
ret
=
False
if
variant
.
Value
%
2
==
0
:
ret
=
True
return
[
ua
.
Variant
(
ret
,
ua
.
VariantType
.
Boolean
)]
# method to be exposed through server
# uses a decorator to automatically convert to and from variants
@
uamethod
def
multiply
(
parent
,
x
,
y
):
print
(
"multiply method call with parameters: "
,
x
,
y
)
return
x
*
y
class
VarUpdater
(
Thread
):
def
__init__
(
self
,
var
):
Thread
.
__init__
(
self
)
self
.
_stopev
=
False
self
.
var
=
var
def
stop
(
self
):
self
.
_stopev
=
True
def
run
(
self
):
while
not
self
.
_stopev
:
v
=
sin
(
time
.
time
()
/
10
)
self
.
var
.
set_value
(
v
)
time
.
sleep
(
0.1
)
if
__name__
==
"__main__"
:
# optional: setup logging
logging
.
basicConfig
(
level
=
logging
.
WARN
)
#logger = logging.getLogger("opcua.address_space")
# logger.setLevel(logging.DEBUG)
#logger = logging.getLogger("opcua.internal_server")
# logger.setLevel(logging.DEBUG)
#logger = logging.getLogger("opcua.binary_server_asyncio")
# logger.setLevel(logging.DEBUG)
#logger = logging.getLogger("opcua.uaprocessor")
# logger.setLevel(logging.DEBUG)
start_thread_loop
()
# now setup our server
server
=
Server
()
#server.disable_clock()
#server.set_endpoint("opc.tcp://localhost:4840/freeopcua/server/")
server
.
set_endpoint
(
"opc.tcp://0.0.0.0:4840/freeopcua/server/"
)
server
.
set_server_name
(
"FreeOpcUa Example Server"
)
# set all possible endpoint policies for clients to connect through
server
.
set_security_policy
([
ua
.
SecurityPolicyType
.
NoSecurity
,
ua
.
SecurityPolicyType
.
Basic256Sha256_SignAndEncrypt
,
ua
.
SecurityPolicyType
.
Basic256Sha256_Sign
])
# setup our own namespace
uri
=
"http://examples.freeopcua.github.io"
idx
=
server
.
register_namespace
(
uri
)
# create a new node type we can instantiate in our address space
dev
=
server
.
nodes
.
base_object_type
.
add_object_type
(
idx
,
"MyDevice"
)
dev
.
add_variable
(
idx
,
"sensor1"
,
1.0
).
set_modelling_rule
(
True
)
dev
.
add_property
(
idx
,
"device_id"
,
"0340"
).
set_modelling_rule
(
True
)
ctrl
=
dev
.
add_object
(
idx
,
"controller"
)
ctrl
.
set_modelling_rule
(
True
)
ctrl
.
add_property
(
idx
,
"state"
,
"Idle"
).
set_modelling_rule
(
True
)
# populating our address space
# First a folder to organise our nodes
myfolder
=
server
.
nodes
.
objects
.
add_folder
(
idx
,
"myEmptyFolder"
)
# instanciate one instance of our device
mydevice
=
server
.
nodes
.
objects
.
add_object
(
idx
,
"Device0001"
,
dev
)
mydevice_var
=
mydevice
.
get_child
([
"{}:controller"
.
format
(
idx
),
"{}:state"
.
format
(
idx
)])
# get proxy to our device state variable
# create directly some objects and variables
myobj
=
server
.
nodes
.
objects
.
add_object
(
idx
,
"MyObject"
)
myvar
=
myobj
.
add_variable
(
idx
,
"MyVariable"
,
6.7
)
mysin
=
myobj
.
add_variable
(
idx
,
"MySin"
,
0
,
ua
.
VariantType
.
Float
)
myvar
.
set_writable
()
# Set MyVariable to be writable by clients
mystringvar
=
myobj
.
add_variable
(
idx
,
"MyStringVariable"
,
"Really nice string"
)
mystringvar
.
set_writable
()
# Set MyVariable to be writable by clients
mydtvar
=
myobj
.
add_variable
(
idx
,
"MyDateTimeVar"
,
datetime
.
utcnow
())
mydtvar
.
set_writable
()
# Set MyVariable to be writable by clients
myarrayvar
=
myobj
.
add_variable
(
idx
,
"myarrayvar"
,
[
6.7
,
7.9
])
myarrayvar
=
myobj
.
add_variable
(
idx
,
"myStronglytTypedVariable"
,
ua
.
Variant
([],
ua
.
VariantType
.
UInt32
))
myprop
=
myobj
.
add_property
(
idx
,
"myproperty"
,
"I am a property"
)
mymethod
=
myobj
.
add_method
(
idx
,
"mymethod"
,
func
,
[
ua
.
VariantType
.
Int64
],
[
ua
.
VariantType
.
Boolean
])
multiply_node
=
myobj
.
add_method
(
idx
,
"multiply"
,
multiply
,
[
ua
.
VariantType
.
Int64
,
ua
.
VariantType
.
Int64
],
[
ua
.
VariantType
.
Int64
])
# import some nodes from xml
server
.
import_xml
(
"custom_nodes.xml"
)
# creating a default event object
# The event object automatically will have members for all events properties
# you probably want to create a custom event type, see other examples
myevgen
=
server
.
get_event_generator
()
myevgen
.
event
.
Severity
=
300
# starting!
server
.
start
()
print
(
"Available loggers are: "
,
logging
.
Logger
.
manager
.
loggerDict
.
keys
())
vup
=
VarUpdater
(
mysin
)
# just a stupide class update a variable
vup
.
start
()
try
:
# enable following if you want to subscribe to nodes on server side
#handler = SubHandler()
#sub = server.create_subscription(500, handler)
#handle = sub.subscribe_data_change(myvar)
# trigger event, all subscribed clients wil receive it
var
=
myarrayvar
.
get_value
()
# return a ref to value in db server side! not a copy!
var
=
copy
.
copy
(
var
)
# WARNING: we need to copy before writting again otherwise no data change event will be generated
var
.
append
(
9.3
)
myarrayvar
.
set_value
(
var
)
mydevice_var
.
set_value
(
"Running"
)
myevgen
.
trigger
(
message
=
"This is BaseEvent"
)
server
.
set_attribute_value
(
myvar
.
nodeid
,
ua
.
DataValue
(
9.9
))
# Server side write method which is a but faster than using set_value
embed
()
finally
:
vup
.
stop
()
server
.
stop
()
stop_thread_loop
()
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