-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.py
129 lines (105 loc) · 4.28 KB
/
server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env python
import sys, asyncio, OpenOPC, decimal
from asyncua import ua, Server, uamethod
UA_URI = 'https://hv.se'
OPCDA_SERVER_STRING = ""
readable_variables = {}
writeable_variables = {}
tree = {}
obj_in_node = {}
#Constants
ITEM_ACCESS_RIGHTS = 5
ACCESS_READ = 0
ACCESS_WRITE = 1
ACCESS_READ_WRITE = 2
ITEM_VALUE = 2
class SubHandler(object):
"""
Subscription handler to receive events from the server.
"""
def datachange_notification(self, node, val, data):
p_a_string = node.get_path_as_string() #Get a list containing root, objects, opc da server
da_address = '.'.join([a.split(':')[1] for a in p_a_string[3:]])
da = OpenOPC.client()
da.connect(OPCDA_SERVER_STRING)
print('Datachanged ', da_address, val)
da.write((da_address, val,))
da.close()
def read_value(value):
value = value[0]
if isinstance(value,decimal.Decimal):
value = float(value)
elif isinstance(value,list):
if len(value) == 0:
value = None
elif isinstance(value,tuple):
if len(value) == 0:
value = None
return value
async def sort_nodes_list(list, idx, root, da):
for node in list:
parts = node.split('.') #We split it into parts to separate each "part"
folders = parts[:-1] # The first part is the folder, typically multiple ones
file = parts[-1] #Then we have the file that is in the folder
for i, folder in enumerate(folders,1):
if i == 1:
parent = root
else:
parent = tree[path]
path = '.'.join(folders[0:i])
if path not in tree.keys():
tree[path] = await parent.add_folder(idx, folder)
for id, description_of_id, value in da.properties(node):
if id is ITEM_ACCESS_RIGHTS:
if value == 'Read':
value = ACCESS_READ
elif value == 'Write':
value = ACCESS_WRITE
elif value == 'Read/Write':
value = ACCESS_READ_WRITE
obj_in_node[id] = value
curr_value = read_value((obj_in_node[ITEM_VALUE],))
if type(curr_value) != int:
curr_value = 0
opcua_node = await tree[path].add_variable(idx, file, ua.Variant(curr_value, ua.VariantType.UInt16))
if obj_in_node[ITEM_ACCESS_RIGHTS] in [ACCESS_READ]:
readable_variables[node] = opcua_node
#print(opcua_node)
if obj_in_node[ITEM_ACCESS_RIGHTS] in [ACCESS_WRITE, ACCESS_READ_WRITE]:
await opcua_node.set_writable()
writeable_variables[node] = opcua_node
#print(opcua_node)
async def main():
#We connect to the OPC-DA server (I assume there will only be one, else this will have to be changed)
#We can also check if there is a server and if there isn't one we'll run only an OPC UA server without conversion
da = OpenOPC.client()
OPCDA_SERVER_STRING = da.servers()[0]
da.connect(OPCDA_SERVER_STRING) #Connect to the first server in the array
print(OPCDA_SERVER_STRING)
#Setup the server for UA
server = Server()
await server.init()
server.set_endpoint('opc.tcp://0.0.0.0:4840/freeopcua/server/')
idx = await server.register_namespace(UA_URI)
root = await server.nodes.objects.add_object(idx,OPCDA_SERVER_STRING)
#We want to find the OPC-DA server nodes in aliases
nodes_list = da.list('*', recursive=True) #A list of dot-delimited strings
await sort_nodes_list(nodes_list, idx, root, da)
try:
async with server: #Starting the server
handler = SubHandler() #Subscribing to datachanges coming from the UA clients
sub = await server.create_subscription(500, handler)
handle = await sub.subscribe_data_change(writeable_variables.values())
readable_vars = list(writeable_variables) #readable_variables
#print(writeable_variables)
while True:
await asyncio.sleep(1)
for i in da.list(readable_vars):
da_id = i[0]
var_handler = readable_variables[da_id]
var_handler.set_value(read_value(i[1:]))
finally:
await server.stop()
da.close()
if __name__ == "__main__":
asyncio.run(main())