server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/") server.set_server_name("FreeOpcUa Example Server") server.load_certificate("robotarm_cert.der") server.load_private_key("robotarm_pk.pem") # setup our own namespace, not really necessary but should as spec uri = "http://examples.freeopcua.github.io" idx = server.register_namespace(uri) # get Objects node, this is where we should put our custom stuff objects = server.get_objects_node() # populating our address space myfolder = objects.add_folder(idx, "GFISmartFleet") myobj = server.get_root_node().get_child(["0:Objects", "2:GFISmartFleet" ]).add_object(idx, "RobotArm") var_Servo_left_angle = myobj.add_variable(idx, "Servo_left_angle", 90) var_Servo_left_angle.set_writable() var_Servo_right_angle = myobj.add_variable(idx, "Servo_right_angle", 90) var_Servo_right_angle.set_writable() var_Servo_middle_angle = myobj.add_variable(idx, "Servo_middle_angle", 90) var_Servo_middle_angle.set_writable() var_Servo_claw_angle = myobj.add_variable(idx, "Servo_claw_angle", 25) var_Servo_claw_angle.set_writable() #myarrayvar = myobj.add_variable(idx, "myarrayvar", [6.7, 7.9]) #myarrayvar = myobj.add_variable(idx, "myStronglytTypedVariable", ua.Variant([], ua.VariantType.UInt32))
from opcua import ua, Server import asyncio, random, time from datetime import datetime server = Server() server.set_endpoint("opc.tcp://127.0.0.1:4840") server.set_server_name("OPCUA-Test") address_space = server.register_namespace("http://andreas-heine.net/UA") root_node = server.get_root_node() object_node = server.get_objects_node() server_node = server.get_server_node() parameter_obj = object_node.add_object(address_space, "Parameter") random_node = parameter_obj.add_variable(address_space, "random", ua.Variant(0, ua.VariantType.UInt64)) etype = server.create_custom_event_type( address_space, 'MyFirstEvent', ua.ObjectIds.BaseEventType, [('MyNumericProperty', ua.VariantType.Float), ('MyStringProperty', ua.VariantType.String)]) myevgen = server.get_event_generator(etype, parameter_obj) vars_obj = object_node.add_object(address_space, "Vars") var_list = [] for i in range(100): var = vars_obj.add_variable( ua.NodeId.from_string(f'ns={address_space};s=DB_DATA.Test.var{i}'), f'Test.var{i}', 0) var.set_writable(True) var_list.append(var)
def main(): # logging.basicConfig(level=logging.ERROR) # logger=logging.getLogger("opcua.server.internal_subscription") # logger.setLevel(logging.ERROR) read = open('config.txt', 'r') configs = read.readlines() read.close() server = Server() endpoint = configs[0].split('@')[1].rstrip('\n') servername = configs[1].split('@')[1].rstrip('\n') kafkaservers = configs[2].split('@')[1].replace("'", "").replace( "\"", "").rstrip('\n') kafkaserver = kafkaservers[1:-1].split(',') kafkatopic = configs[3].split('@')[1].rstrip('\n') eventname = configs[4].split('@')[1].rstrip('\n') # auto_offset_reset='earlist' consumer = KafkaConsumer(kafkatopic, bootstrap_servers=kafkaserver) server.set_endpoint(endpoint) server.set_server_name(servername) print("Program running......") print("Please do not close this page") # 证书 # server.load_certificate("certificate-example.der") # server.load_private_key("private-key-example.pem") # 安全策略 server.set_security_policy([ ua.SecurityPolicyType.NoSecurity, # ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt, # ua.SecurityPolicyType.Basic256Sha256_Sign ]) uri = "http://taiji.com.cn" idx = server.register_namespace(uri) objs = server.get_objects_node() myobj = objs.add_object(idx, "MyObject") # 节点 taglists = readFile("node.csv") for taglist in taglists: # myobj.add_variable(idx, taglist, 6.7).set_writable() myobj.add_variable(idx, taglist, random.random()).set_writable() # myobj.add_variable(idx, taglist, 6.7) attrs = readFile("ae_attr.csv") custom_etype = server.nodes.base_event_type.add_object_type(idx, eventname) for attr in attrs: custom_etype.add_property(2, attr, ua.Variant("", ua.VariantType.String)) myevent = server.get_event_generator(custom_etype, myobj) server.start() try: rootnode = server.get_root_node().get_child( ["0:Objects", "{}:MyObject".format(idx)]) rootnodes = rootnode.get_variables() nodeAll = {} for i in range(len(rootnodes)): nodeId = rootnodes[i] nodeName = rootnodes[i].get_browse_name().Name nodeAll.update({nodeName: nodeId}) for message in consumer: recv = message.value.decode("utf8") # print("recvevent=",recv) if recv[0] == '{' and recv[-1] == '}': nodeKafka = json.loads(recv) # print("nodeKafka=", nodeKafka) comName = nodeKafka.keys() & nodeAll.keys() for row in comName: rootnode.get_child(["2:{}".format(row) ]).set_value(nodeKafka[row]) else: recv = recv.replace('\n', '').replace('\r', '') datas = recv.split("|")[1:] # print("datas=", datas) if len(datas) == 9: for i in range(len(attrs)): # exec("myevent.event.{}='{}'".format(attrs[i], datas[i].replace('\n', '').replace('\r', ''))) exec("myevent.event.{}='{}'".format( attrs[i], datas[i])) myevent.trigger() else: # continue f = open('ErrorAE.bak', 'a', encoding='utf8') f.write(recv) f.write('\n') f.close # print("mysecondevgen=",mysecondevgen) # print("mysecondevgen=", myevent.event) except Exception as e: print(e) finally: server.stop()
return items if __name__ == "__main__": # setup our server server = Server() server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/") # setup our own namespace, not really necessary but should as spec uri = "http://examples.freeopcua.github.io" nsidx = server.register_namespace(uri) # -------------------------------------------------------- # create custom enum data type # -------------------------------------------------------- enums = server.get_root_node().get_child( ["0:Types", "0:DataTypes", "0:BaseDataType", "0:Enumeration"]) # 1. # Create Enum Type myenum_type = enums.add_subtype(nsidx, 'MyEnum', ua.NodeClass.DataType) # 2. # Add enumerations as EnumStrings (Not yet tested with EnumValues) # Essential to use namespace 0 for EnumStrings ! # By hand # es = myenum_type.add_variable(0, "EnumStrings" , [ua.LocalizedText("ok"), # ua.LocalizedText("idle")]) # Or convert the existing IntEnum MyEnum es = myenum_type.add_variable(0, "EnumStrings", enum_to_stringlist(MyEnum))
class StationUAServer: def __init__(self, pick_by_light): self._pbl = pick_by_light self._setup_nodes() self._generate_tags() self.ua_server.start() self._generate_subscriptions() Thread(target=self._var_updater, daemon=True).start() def _setup_nodes(self): # Create server instance self.ua_server = Server('./opcua_cache') self.ua_server.set_endpoint('opc.tcp://0.0.0.0:4840/UA/PickByLight') self.ua_server.set_server_name("Pick By Light Server") # idx name will be used later for creating the xml used in data type dictionary # setup our own namespace, not really necessary but should as spec idx_name = 'http://examples.freeopcua.github.io' self.idx = self.ua_server.register_namespace(idx_name) # Set all possible endpoint policies for clients to connect through self.ua_server.set_security_policy([ ua.SecurityPolicyType.NoSecurity, ua.SecurityPolicyType.Basic128Rsa15_SignAndEncrypt, ua.SecurityPolicyType.Basic128Rsa15_Sign, ua.SecurityPolicyType.Basic256_SignAndEncrypt, ua.SecurityPolicyType.Basic256_Sign ]) # get Objects node, this is where we should put our custom stuff objects = self.ua_server.get_objects_node() # Create objects for the pack tags using the above created packMLBasedObjectType self.Status = objects.add_folder('ns=2;s=Status', "Status") self.Command = objects.add_folder('ns=2;s=Command', "Command") self.Command.add_method('ns=2;s=Command.SelectPort', "SelectPort", self._select_method, [ua.VariantType.Int32, ua.VariantType.String], [ua.VariantType.Boolean]) self.Command.add_method('ns=2;s=Command.DeselectPort', "DeselectPort", self._deselect_method, [ua.VariantType.Int32], [ua.VariantType.Boolean]) self.Command.add_method('ns=2;s=Command.DeselectAllPorts', "DeselectAllPorts", self._deselect_all_method, [], [ua.VariantType.Boolean]) root = self.ua_server.get_root_node() DummyFestoObj = root.add_object( "ns=2;s=|var|CECC-LK.Application.Flexstation_globalVariables", "DummyFesto") DummyFestoObj.add_variable( "ns=2;s=|var|CECC-LK.Application.Flexstation_globalVariables.FlexStationStatus", "FlexStationStatus", val=0).set_writable() DummyFestoObj.add_variable( "ns=2;s=|var|CECC-LK.Application.FBs.stpStopper1.stAppControl.uiOpNo", "uiOpNo", val=0).set_writable() DummyFestoObj.add_variable( "ns=2;s=ns=2;s=|var|CECC-LK.Application.AppModul.stRcvData.sOderDes", "sOderDes", val="").set_writable() def _generate_tags(self): # for all ports generate tags for port_number, port in self._pbl.get_ports(): # Make a folder with the port_number as the name b_obj = self.Status.add_object( 'ns=2;s=Status.Port_{}'.format(port_number), "Port_{}".format(port_number)) content = self._pbl.get_content(port_number) b_obj.add_variable( "ns=2;s=Status.Port_{}.Selected".format(port_number), "Selected", bool()) b_obj.add_variable( "ns=2;s=Status.Port_{}.WorkFinished".format(port_number), "WorkFinished", bool()) b_obj.add_variable( "ns=2;s=Status.Port_{}.Instructions".format(port_number), "Instructions", "") b_obj.add_variable( "ns=2;s=Status.Port_{}.Activity".format(port_number), "Activity", bool()) b_obj.add_variable( "ns=2;s=Status.Port_{}.ActivityTimestamp".format(port_number), "ActivityTimestamp", datetime.fromtimestamp(0)) b_obj.add_variable( "ns=2;s=Status.Port_{}.LightState".format(port_number), "LightState", 0) b_obj.add_variable( "ns=2;s=Status.Port_{}.ContentDisplayName".format(port_number), "ContentDisplayName", content['display_name']) b_obj.add_variable( "ns=2;s=Status.Port_{}.ContentName".format(port_number), "ContentName", content['name']) b_obj.add_variable( "ns=2;s=Status.Port_{}.ContentDescription".format(port_number), "ContentDescription", content['description']) b_obj.add_variable( "ns=2;s=Status.Port_{}.ContentImagePath".format(port_number), "ContentImagePath", content['image_path']) ''' create command tags for clients that does not support ua methods. ''' b_obj = self.Command.add_object( 'ns=2;s=Command.Port_{}'.format(port_number), "Port_{}".format(port_number)) b_obj.add_variable( "ns=2;s=Command.Port_{}.Select".format(port_number), "Select", bool()).set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.Deselect".format(port_number), "Deselect", bool()).set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.Instructions".format(port_number), "Instructions", "").set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.ContentDisplayName".format( port_number), "ContentDisplayName", content['display_name']).set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.ContentName".format(port_number), "ContentName", content['name']).set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.ContentDescription".format( port_number), "ContentDescription", content['description']).set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.ContentImagePath".format(port_number), "ContentImagePath", content['image_path']).set_writable() ''' Generate some common commands ''' # Make a folder for the commons b_obj = self.Command.add_object('ns=2;s=Command.ByContent', 'ByContent') b_obj.add_variable("ns=2;s=Command.ByContent.Select", "Select", bool()).set_writable() b_obj.add_variable("ns=2;s=Command.ByContent.Deselect", "Deselect", bool()).set_writable() b_obj.add_variable("ns=2;s=Command.ByContent.Name", "Name", "").set_writable() b_obj.add_variable("ns=2;s=Command.ByContent.Instructions", "Instructions", "").set_writable() b_obj.add_variable("ns=2;s=Command.ByContent.Result", "Result", -1).set_writable() def _generate_subscriptions(self): # Create UA subscriber node for the box. Set self as handler. sub = self.ua_server.create_subscription(100, self) # Subscribe to the Select tag and all the content tags for port_number, port in self._pbl.get_ports(): ac = self.ua_server.get_node( "ns=2;s=Command.Port_{}.Select".format(port_number)) sub.subscribe_data_change(ac) ac = self.ua_server.get_node( "ns=2;s=Command.Port_{}.Deselect".format(port_number)) sub.subscribe_data_change(ac) b = self.ua_server.get_node( "ns=2;s=Command.Port_{}.ContentDisplayName".format( port_number)) sub.subscribe_data_change(b) c = self.ua_server.get_node( "ns=2;s=Command.Port_{}.ContentName".format(port_number)) sub.subscribe_data_change(c) d = self.ua_server.get_node( "ns=2;s=Command.Port_{}.ContentDescription".format( port_number)) sub.subscribe_data_change(d) e = self.ua_server.get_node( "ns=2;s=Command.Port_{}.ContentImagePath".format(port_number)) sub.subscribe_data_change(e) a = self.ua_server.get_node("ns=2;s=Command.ByContent.Select") sub.subscribe_data_change(a) a = self.ua_server.get_node("ns=2;s=Command.ByContent.Deselect") sub.subscribe_data_change(a) a = self.ua_server.get_node("ns=2;s=Command.ByContent.Name") sub.subscribe_data_change(a) a = self.ua_server.get_node( "ns=2;s=Command.ByContent.Instructions") sub.subscribe_data_change(a) def _event_notification(self, event): logger.warning( "Python: New event. No function implemented. {}".format(event)) def _select_method(self, parrent, port_number, instructions): r = self._pbl.select_port(port_number.Value, instructions=instructions.Value) return [ua.Variant(value=r, varianttype=ua.VariantType.Boolean)] def _deselect_method(self, parrent, port_number): r = self._pbl.deselect_port(port_number.Value) return [ua.Variant(value=r, varianttype=ua.VariantType.Boolean)] def _deselect_all_method(self, parrent): r = self._pbl.deselect_all() return [ua.Variant(value=r, varianttype=ua.VariantType.Boolean)] def datachange_notification(self, node, val, data): """UA server callback on data change notifications Arguments: node {Node} -- [description] val {[type]} -- [description] data {[type]} -- [description] """ logger.debug("New data change event. node:{}, value:{}".format( node, val)) # Sorry about these lines of code, but I don't see any nicer way of determining the port number than from # the identifier string. Then splitting it up to isolate the port number. # Example "Status.Port_2.Selected" is split into ['Status', 'Port_2', 'Selected'] then 'Port_2' is split into # ['Port', '2'] and then the '2' is turned into an intiger. path_list = str(node.nodeid.Identifier).split(".") # We can safely assume that the last term is the tag that updated. tag = path_list[-1] # Figure out the port number port_number = None if 'Port' in path_list[1]: port_number = int(path_list[1].split("_")[-1]) """ Switch for each possible tag""" # If the command tag "Select" changes go select that port with the instructions saved in the command tag. if tag == 'Select' and port_number: if val == True: node = self.ua_server.get_node( "ns=2;s=Command.Port_{}.Instructions".format(port_number)) instructions = node.get_value() self._pbl.select_port(port_number, instructions=instructions) # Reset the select flag node = self.ua_server.get_node( "ns=2;s=Command.Port_{}.Select".format(port_number)) node.set_value(False) elif tag == 'Deselect' and port_number: if val == True: self._pbl.deselect_port(port_number, work_finished=True) # Reset the select flag node = self.ua_server.get_node( "ns=2;s=Command.Port_{}.Deselect".format(port_number)) node.set_value(False) elif tag == 'ContentDisplayName' and port_number: self._pbl.set_content_key(port_number, 'display_name', str(val)) elif tag == 'ContentName' and port_number: self._pbl.set_content_key(port_number, 'name', str(val)) elif tag == 'ContentDescription' and port_number: self._pbl.set_content_key(port_number, 'description', str(val)) elif tag == 'ContentImagePath' and port_number: self._pbl.set_content_key(port_number, 'image_path', str(val)) elif tag == 'Select' and 'ByContent' in path_list[1]: if val == True: instructions = self.ua_server.get_node( "ns=2;s=Command.ByContent.Instructions").get_value() name = self.ua_server.get_node( "ns=2;s=Command.ByContent.Name").get_value() _, selected_port = self._pbl.select_content( name=name, instructions=instructions) # Reset the select flag node = self.ua_server.get_node( "ns=2;s=Command.ByContent.Select") node.set_value(False) node = self.ua_server.get_node( "ns=2;s=Command.ByContent.Result") node.set_value(selected_port) elif tag == 'Deselect' and 'ByContent' in path_list[1]: if val == True: name = self.ua_server.get_node( "ns=2;s=Command.ByContent.Name").get_value() self._pbl.deselect_content(name=name, work_finished=True) # Reset the select flag node = self.ua_server.get_node( "ns=2;s=Command.ByContent.Deselect") node.set_value(False) def _var_updater(self): while True: sleep(0.1) # for all boxes update tags for port_number, port in self._pbl.get_ports(): # get the object in the packml status object using our unique idx node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.Activity".format(port_number)) node.set_value(port.activity) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.ActivityTimestamp".format( port_number)) node.set_value(port.activity_timestamp) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.LightState".format(port_number)) node.set_value(port.get_light()) state = self._pbl.get_port_state(port_number) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.Selected".format(port_number)) node.set_value(state.selected) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.WorkFinished".format(port_number)) node.set_value(state.work_finished) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.Instructions".format(port_number)) node.set_value(state.select_instructions) content = self._pbl.get_content(port_number) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.ContentDisplayName".format( port_number)) node.set_value(content['display_name']) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.ContentName".format(port_number)) node.set_value(content['name']) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.ContentDescription".format( port_number)) node.set_value(content['description']) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.ContentImagePath".format( port_number)) node.set_value(content['image_path'])
uri = "http://examples.freeopcua.github.io" idx = server.register_namespace(uri) # Import customobject type server.import_xml('customobject.xml') # get Objects node, this is where we should put our custom stuff objects = server.get_objects_node() # get nodeid of custom object type by : # 1) Use node ID # 2) Or Full path # 3) Or As child from parent nodeid_a = ua.NodeId.from_string('ns=1;i=1002') nodeid_b = server.get_root_node().get_child( ["0:Types", "0:ObjectTypes", "0:BaseObjectType", "1:MyObjectType"]).nodeid nodeid_c = server.get_node(ua.ObjectIds.BaseObjectType).get_child( ["1:MyObjectType"]).nodeid myobject_type_nodeid = nodeid_a # populating our address space myobj = objects.add_object( idx, "MyObject", ) myobj = objects.add_object(idx, "MyCustomObject", myobject_type_nodeid) # starting! server.start()
uri = "http://examples.freeopcua.github.io" idx = server.register_namespace(uri) # get Objects node, this is where we should put our custom stuff objects = server.get_objects_node() # Example 1 - create a basic object #------------------------------------------------------------------------------- myobj = objects.add_object(idx, "MyObject") #------------------------------------------------------------------------------- # Example 2 - create a new object type and a instance of the new object type #------------------------------------------------------------------------------- types = server.get_node(ua.ObjectIds.BaseObjectType) object_type_to_derive_from = server.get_root_node().get_child( ["0:Types", "0:ObjectTypes", "0:BaseObjectType"]) mycustomobj_type = types.add_object_type(idx, "MyCustomObject") mycustomobj_type.add_variable(0, "var_should_be_there_after_instantiate", 1.0) # demonstrates instantiate myobj = objects.add_object(idx, "MyCustomObjectA", mycustomobj_type.nodeid) #------------------------------------------------------------------------------- # Example 3 - import a new object from xml address space and create a instance of the new object type #------------------------------------------------------------------------------- # Import customobject type server.import_xml('customobject.xml') # get nodeid of custom object type by one of the following 3 ways: # 1) Use node ID # 2) Or Full path
items.append(ua.LocalizedText(value.name)) return items if __name__ == "__main__": # setup our server server = Server() server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/") # setup our own namespace, not really necessary but should as spec uri = "http://examples.freeopcua.github.io" nsidx = server.register_namespace(uri) # -------------------------------------------------------- # create custom enum data type # -------------------------------------------------------- enums = server.get_root_node().get_child(["0:Types", "0:DataTypes", "0:BaseDataType", "0:Enumeration"]) # 1. # Create Enum Type myenum_type = enums.add_subtype(nsidx, 'MyEnum', ua.NodeClass.DataType) # 2. # Add enumerations as EnumStrings (Not yet tested with EnumValues) # Essential to use namespace 0 for EnumStrings ! # By hand # es = myenum_type.add_variable(0, "EnumStrings" , [ua.LocalizedText("ok"), # ua.LocalizedText("idle")]) # Or convert the existing IntEnum MyEnum es = myenum_type.add_variable(0, "EnumStrings" , enum_to_stringlist(MyEnum))
class CustomServer(object): def __init__(self): self.SERVER_ENDPOINT = os.environ.get("SERVER_ENDPOINT") self.NAMESPACE = os.environ.get("NAMESPACE") self.SERVER_NAME = os.environ.get("SERVER_NAME") self.ENABLE_CERTIFICATE = bool( strtobool(os.environ.get("ENABLE_CERTIFICATE"))) # setup our server self.server = Server() self.server.set_endpoint(self.SERVER_ENDPOINT) self.server.set_server_name(self.SERVER_NAME) # set the security endpoints for identification of clients if self.ENABLE_CERTIFICATE: # load server certificate and private key. This enables endpoints with signing and encryption. self.CERTIFICATE_PATH_SERVER_CERT = os.path.dirname( os.getcwd()) + os.environ.get("CERTIFICATE_PATH_SERVER_CERT") self.CERTIFICATE_PATH_SERVER_PRIVATE_KEY = os.path.dirname( os.getcwd()) + os.environ.get( "CERTIFICATE_PATH_SERVER_PRIVATE_KEY") self.server.load_certificate(self.CERTIFICATE_PATH_SERVER_CERT) self.server.load_private_key( self.CERTIFICATE_PATH_SERVER_PRIVATE_KEY) # set all possible endpoint policies for clients to connect through self.server.set_security_policy([ # ua.SecurityPolicyType.NoSecurity, ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt, # ua.SecurityPolicyType.Basic256Sha256_Sign, ]) self.server.set_security_IDs(["Username", "Basic256Sha256"]) else: self.server.set_security_policy([ua.SecurityPolicyType.NoSecurity]) self.server.set_security_IDs(["Anonymous", "Username"]) # set the user_manager function self.server.user_manager.set_user_manager(user_manager) # setup our own namespace, not really necessary but should as spec uri = self.NAMESPACE self.idx = self.server.register_namespace(uri) # get important nodes self.root = self.server.get_root_node() self.obj = self.server.get_objects_node() self.init_methods() def init_methods(self): # method: ADD_OBJECTS_DIR inarg1 = ua.Argument() inarg1.Name = "objects folder" inarg1.DataType = ua.NodeId(ua.ObjectIds.String) # String inarg1.ValueRank = -1 inarg1.ArrayDimensions = [] inarg1.Description = ua.LocalizedText("Name the new objects folder") method_node = self.obj.add_method(self.idx, "ADD_NEW_OBJECTS_FOLDER", self.add_objects_subfolder, [inarg1]) # method: ADD_OPC_TAG inarg1 = ua.Argument() inarg1.Name = "opctag" inarg1.DataType = ua.NodeId(ua.ObjectIds.String) # String inarg1.ValueRank = -1 inarg1.ArrayDimensions = [] inarg1.Description = ua.LocalizedText("Name new OPC variable") inarg2 = ua.Argument() inarg2.Name = "variant_type" inarg2.DataType = ua.NodeId(ua.ObjectIds.String) # String inarg2.ValueRank = -1 inarg2.ArrayDimensions = [] inarg2.Description = ua.LocalizedText("Type of variable") inarg3 = ua.Argument() inarg3.Name = "parent_node" inarg3.DataType = ua.NodeId(ua.ObjectIds.String) # String inarg3.ValueRank = -1 inarg3.ArrayDimensions = [] inarg3.Description = ua.LocalizedText( "Type in the name of the parent node the new variable should assigned to" ) method_node = self.obj.add_method(self.idx, "ADD_OPC_TAG", self.register_opc_tag, [inarg1, inarg2, inarg3]) # method: SET_PV_LIMIT inarg1 = ua.Argument() inarg1.Name = "active_power_setpoint" inarg1.DataType = ua.NodeId(ua.ObjectIds.Int32) # Integer inarg1.ValueRank = -1 inarg1.ArrayDimensions = [] inarg1.Description = ua.LocalizedText( "Type in active power setpoint in percent [0 ... 100]") inarg2 = ua.Argument() inarg2.Name = "parent_node" inarg2.DataType = ua.NodeId(ua.ObjectIds.String) # String inarg2.ValueRank = -1 inarg2.ArrayDimensions = [] inarg2.Description = ua.LocalizedText( "Type in the name of the parent node") method_node = self.obj.add_method(self.idx, "SET_PV_LIMIT", self.set_pv_active_power_setpoint, [inarg1, inarg2]) # method: RUN_ONLINE_GRID_PROTECTION inarg1 = ua.Argument() inarg1.Name = "On/Off" inarg1.DataType = ua.NodeId(ua.ObjectIds.Int32) # Integer inarg1.ValueRank = -1 inarg1.ArrayDimensions = [] inarg1.Description = ua.LocalizedText( "Type in 1 to RUN or 0 to STOP ONLINE_GRID_PROTECTION") inarg2 = ua.Argument() inarg2.Name = "parent_node" inarg2.DataType = ua.NodeId(ua.ObjectIds.String) # String inarg2.ValueRank = -1 inarg2.ArrayDimensions = [] inarg2.Description = ua.LocalizedText( "Type in the name of the parent node") method_node = self.obj.add_method(self.idx, "RUN_ONLINE_GRID_PROTECTION", self.run_online_grid_protection, [inarg1, inarg2]) @uamethod def add_objects_subfolder(self, parent, dir_name): # check if old dir with dir_name exists. if so then delete this dir first try: obj = self.root.get_child( ["0:Objects", ("{}:" + dir_name).format(self.idx)]) self.server.delete_nodes([obj], True) except BadNoMatch: print(DateHelper.get_local_datetime(), "There is no old folder with the name: " + dir_name) folder = self.obj.add_folder(self.idx, dir_name) print(DateHelper.get_local_datetime(), "Add subfolder: " + dir_name) @uamethod def register_opc_tag(self, parent, opctag, variant_type="Float", parent_node=""): # Object "parent_node": try: obj = self.root.get_child( ["0:Objects", ("{}:" + parent_node).format(self.idx)]) except BadNoMatch: print( DateHelper.get_local_datetime(), "register_opc_tag(): OPCUA_server_dir the variables should be assigned to, doesn't exists." ) raise var = ua.Variant(0, strings_to_vartyps(variant_type)) mvar = obj.add_variable(self.idx, opctag.strip(), var) mvar.set_writable() print( DateHelper.get_local_datetime(), "Add variable: " + opctag + " of type " + variant_type + " @node " + parent_node) @uamethod def set_pv_active_power_setpoint(self, parent, setpoint, parent_node=""): try: obj = self.root.get_child( ["0:Objects", ("{}:" + parent_node).format(self.idx)]) except BadNoMatch: print( DateHelper.get_local_datetime(), "set_pv_active_power_setpoint(): assign new value to node failed." ) raise for mvar in obj.get_variables(): if "PV" and "CTRL" in mvar.get_browse_name().Name: variant_type = mvar.get_data_value().Value.VariantType mvar.set_value(clamp(setpoint, 0, 100), variant_type) print( DateHelper.get_local_datetime(), "Set Value of node " + mvar.get_browse_name().Name + " to " + str(clamp(setpoint, 0, 100))) @uamethod def run_online_grid_protection(self, parent, setpoint, parent_node=""): try: obj = self.root.get_child( ["0:Objects", ("{}:" + parent_node).format(self.idx)]) except BadNoMatch: print(DateHelper.get_local_datetime(), "run_online_grid_protection(): Change in On/Off failed.") raise for mvar in obj.get_variables(): if "RUN_ONLINE_GRID_PROTECTION" in mvar.get_browse_name().Name: variant_type = mvar.get_data_value().Value.VariantType mvar.set_value(clamp(setpoint, 0, 1), variant_type) print( DateHelper.get_local_datetime(), "Change status of online grid protection to " + str(clamp(setpoint, 0, 1))) def start(self): self.server.start() print(DateHelper.get_local_datetime(), self.__class__.__name__, " successful started") def stop(self): self.server.stop() print(DateHelper.get_local_datetime(), self.__class__.__name__, " successful stopped")
uri = "http://examples.freeopcua.github.io" idx = server.register_namespace(uri) # Import customobject type server.import_xml('customobject.xml') # get Objects node, this is where we should put our custom stuff objects = server.get_objects_node() # get nodeid of custom object type by : # 1) Use node ID # 2) Or Full path # 3) Or As child from parent nodeid_a = ua.NodeId.from_string('ns=1;i=1002') nodeid_b = server.get_root_node().get_child(["0:Types", "0:ObjectTypes", "0:BaseObjectType", "1:MyObjectType"]).nodeid nodeid_c = server.get_node(ua.ObjectIds.BaseObjectType).get_child(["1:MyObjectType"]).nodeid myobject_type_nodeid = nodeid_a # populating our address space myobj = objects.add_object(idx, "MyObject",) myobj = objects.add_object(idx, "MyCustomObject", myobject_type_nodeid) # starting! server.start() try: while True: time.sleep(1)
class UaModeler(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.ui = Ui_UaModeler() self.ui.setupUi(self) self.setWindowIcon(QIcon(":/network.svg")) # we only show statusbar in case of errors self.ui.statusBar.hide() # load settings, seconds arg is default self.settings = QSettings("FreeOpcUa", "OpcUaModeler") self.server = Server() self.server.set_endpoint( "opc.tcp://0.0.0.0:48400/freeopcua/uamodeler/") self.server.set_server_name("OpcUa Modeler Server") self._new_nodes = [] # the added nodes we will save self.tree_ui = TreeWidget(self.ui.treeView) self.tree_ui.error.connect(self.show_error) self.refs_ui = RefsWidget(self.ui.refView) self.refs_ui.error.connect(self.show_error) self.attrs_ui = AttrsWidget(self.ui.attrView) self.attrs_ui.error.connect(self.show_error) self.idx_ui = NamespaceWidget(self.ui.namespaceView) self.ui.treeView.activated.connect(self.show_refs) self.ui.treeView.clicked.connect(self.show_refs) self.ui.treeView.activated.connect(self.show_attrs) self.ui.treeView.clicked.connect(self.show_attrs) self.resize(int(self.settings.value("main_window_width", 800)), int(self.settings.value("main_window_height", 600))) #self.restoreState(self.settings.value("main_window_state", b"", type="QByteArray")) self.restoreState(self.settings.value("main_window_state", b"")) self.ui.splitterLeft.restoreState( self.settings.value("splitter_left", b"")) self.ui.splitterRight.restoreState( self.settings.value("splitter_right", b"")) self.ui.splitterCenter.restoreState( self.settings.value("splitter_center", b"")) self.server.start() self.tree_ui.set_root_node(self.server.get_root_node()) self.idx_ui.set_node( self.server.get_node(ua.ObjectIds.Server_NamespaceArray)) # fix icon stuff self.ui.actionAddFolder.setIcon(QIcon(":/folder.svg")) self.ui.actionAddObject.setIcon(QIcon(":/object.svg")) self.ui.actionAddObjectType.setIcon(QIcon(":/object_type.svg")) self.ui.actionAddProperty.setIcon(QIcon(":/property.svg")) self.ui.actionAddVariable.setIcon(QIcon(":/variable.svg")) self.ui.actionAddVariableType.setIcon(QIcon(":/variable_type.svg")) # menu self.ui.treeView.addAction(self.ui.actionAddFolder) self.ui.treeView.addAction(self.ui.actionAddObject) self.ui.treeView.addAction(self.ui.actionAddVariable) self.ui.treeView.addAction(self.ui.actionAddProperty) self.ui.treeView.addAction(self.ui.actionAddObjectType) self.ui.treeView.addAction(self.ui.actionAddVariableType) self.ui.treeView.addAction(self.ui.actionAddDataType) # actions self.ui.actionOpen.triggered.connect(self._open) self.ui.actionSave.triggered.connect(self._save) self.ui.actionAddObjectType.triggered.connect(self._add_object_type) self.ui.actionAddObject.triggered.connect(self._add_object) self.ui.actionAddDataType.triggered.connect(self._add_data_type) self.ui.actionAddVariable.triggered.connect(self._add_variable) self.ui.actionAddProperty.triggered.connect(self._add_property) def _open(self): path = QFileDialog.getOpenFileName(self) f = open(path[0], 'r') xml = f.read() print("should read", xml) def _save(self): raise NotImplementedError def _add_node(self, func_name, node_type=None, default_value=None): node = self.tree_ui.get_current_node() if not node: self.show_error("No node selected") raise RuntimeError("No node selected") args, ok = NewNodeDialog.getArgs(self, func_name, self.server, node_type=node_type, default_value=default_value) print("ARGS are", args) if ok: new_node = getattr(node, func_name)(*args) self._new_nodes.append(new_node) self.tree_ui.reload_current() self.show_refs() def _add_object_type(self): return self._add_node("add_object_type") def _add_object(self): return self._add_node("add_object", node_type=self.server.get_node( ua.ObjectIds.BaseObjectType)) def _add_data_type(self): return self._add_node("add_data_type") def _add_variable(self): return self._add_node("add_variable", default_value=9.99) def _add_property(self): return self._add_node("add_property", default_value=1.11) def show_refs(self, idx=None): node = self.get_current_node(idx) if node: self.refs_ui.show_refs(node) def show_attrs(self, idx=None): if not isinstance(idx, QModelIndex): idx = None node = self.get_current_node(idx) if node: self.attrs_ui.show_attrs(node) def show_error(self, msg, level=1): print("showing error: ", msg, level) self.ui.statusBar.show() self.ui.statusBar.setStyleSheet( "QStatusBar { background-color : red; color : black; }") self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(1500, self.ui.statusBar.hide) def get_current_node(self, idx=None): return self.tree_ui.get_current_node(idx) def closeEvent(self, event): self.settings.setValue("main_window_width", self.size().width()) self.settings.setValue("main_window_height", self.size().height()) self.settings.setValue("main_window_state", self.saveState()) self.settings.setValue("splitter_left", self.ui.splitterLeft.saveState()) self.settings.setValue("splitter_right", self.ui.splitterRight.saveState()) self.settings.setValue("splitter_center", self.ui.splitterCenter.saveState()) self.server.stop() event.accept()
class UAServer: def __init__(self,rack : rack_controller): self.rack = rack self._setup_nodes() self._generate_tags() self.ua_server.start() self._generate_subscriptions() Thread(target=self._var_updater, daemon=True).start() def _setup_nodes(self): # Create server instance self.ua_server = Server('./opcua_cache') self.ua_server.set_endpoint('opc.tcp://0.0.0.0:4840/UA/PickByLight') self.ua_server.set_server_name("Pick By Light Server") # idx name will be used later for creating the xml used in data type dictionary # setup our own namespace, not really necessary but should as spec idx_name = 'http://examples.freeopcua.github.io' self.idx = self.ua_server.register_namespace(idx_name) # Set all possible endpoint policies for clients to connect through self.ua_server.set_security_policy([ ua.SecurityPolicyType.NoSecurity, ua.SecurityPolicyType.Basic128Rsa15_SignAndEncrypt, ua.SecurityPolicyType.Basic128Rsa15_Sign, ua.SecurityPolicyType.Basic256_SignAndEncrypt, ua.SecurityPolicyType.Basic256_Sign]) # get Objects node, this is where we should put our custom stuff objects = self.ua_server.get_objects_node() # add a PackMLObjects folder pml_folder = objects.add_folder(self.idx, "PackMLObjects") # Get the base type object types = self.ua_server.get_node(ua.ObjectIds.BaseObjectType) # Create a new type for PackMLObjects PackMLBaseObjectType = types.add_object_type(self.idx, "PackMLBaseObjectType") # Create objects for the pack tags using the above created packMLBasedObjectType self.Admin = pml_folder.add_object('ns=2;s=Admin', "Admin", PackMLBaseObjectType.nodeid) self.Status = pml_folder.add_object('ns=2;s=Status', "Status", PackMLBaseObjectType.nodeid) self.Command = pml_folder.add_object('ns=2;s=Command', "Command", PackMLBaseObjectType.nodeid) # Create an object container for the rack self.RackStatus = self.Status.add_object('ns=2;s=Status.Rack', 'Rack') #BoxesCommonStatus = BoxesStatus.add_object('ns=2;s=Status.Boxes.Common', 'Common') root = self.ua_server.get_root_node() DummyFestoObj = root.add_object("ns=2;s=|var|CECC-LK.Application.Flexstation_globalVariables", "DummyFesto") DummyFestoObj.add_variable("ns=2;s=|var|CECC-LK.Application.Flexstation_globalVariables.FlexStationStatus", "FlexStationStatus", val=0).set_writable() DummyFestoObj.add_variable("ns=2;s=|var|CECC-LK.Application.FBs.stpStopper1.stAppControl.uiOpNo","uiOpNo", val=0).set_writable() def _generate_tags(self): # for all ports generate tags for port_number in self.rack.ports: # Make a folder with the port_number as the name b_obj = self.RackStatus.add_object('ns=2;s=Status.Rack.{}'.format(port_number), str(port_number)) b_obj.add_variable("ns=2;s=Status.Rack.{}.Selected".format(port_number) ,"Selected" , bool()) b_obj.add_variable("ns=2;s=Status.Rack.{}.Activity".format(port_number) ,"Activity" , bool()) b_obj.add_variable("ns=2;s=Status.Rack.{}.ActivityTimestamp".format(port_number) ,"ActivityTimestamp", datetime.fromtimestamp(0)) b_obj.add_variable("ns=2;s=Status.Rack.{}.PickTimestamp".format(port_number) ,"PickTimestamp" , datetime.fromtimestamp(0)) b_obj.add_variable("ns=2;s=Status.Rack.{}.LightState".format(port_number) ,"LightState" , bool()) b_obj.add_variable("ns=2;s=Status.Rack.{}.BoxId".format(port_number) ,"BoxId" , str()) b_obj.add_variable("ns=2;s=Status.Rack.{}.ContentId".format(port_number) ,"ContentId" , str()) b_obj.add_variable("ns=2;s=Status.Rack.{}.ContentCount".format(port_number) ,"ContentCount" , int()) ''' create command tags for clients that does not support ua methods. ''' # create an object in the packml Command object called rack for all the commands. b_obj = self.Command.add_object("ns=2;s=Command.Rack", 'Rack') # Create command tag for triggering the selection b_obj.add_variable("ns=2;s=Command.Rack.Select", 'Select', -1, ua.VariantType.Int16).set_writable() b_obj.add_variable("ns=2;s=Command.Rack.DeSelect", 'DeSelect', -1, ua.VariantType.Int16).set_writable() def _generate_subscriptions(self): # Create UA subscriber node for the box. Set self as handler. sub = self.ua_server.create_subscription(100, self) # Subscribe to the Select tag n = self.ua_server.get_node("ns=2;s=Command.Rack.Select") sub.subscribe_data_change(n) # Subscribe to the Deselect tag n = self.ua_server.get_node("ns=2;s=Command.Rack.DeSelect") sub.subscribe_data_change(n) pass def event_notification(self, event): print("Python: New event. No function implemented", event) def datachange_notification(self, node, val, data): """UA server callback on data change notifications This is a workaround for kepware that does not support UA methods, so instead is has "trigger tags" that when set to true it works like calling a method. TODO make this more dynamic instead of hard coding the attributes. Arguments: node {Node} -- [description] val {[type]} -- [description] data {[type]} -- [description] """ # avoid triggereing it all again when resetting the tags to -1 if val != -1 : # Print info print("New data change event", node, val) # get the node browse name. node_id = node.get_browse_name().Name # If the trigger tag changes to true go in and update the status tag and set the trigger back to false. # Also read description above. if node_id == "Select" : self.rack.select_port(val) node.set_value(-1) elif node_id == "Deselect" : self.rack.select_port(val) node.set_value(-1) def _var_updater(self): while True: sleep(0.1) # for all boxes update tags for port_number, port in self.rack.ports.items(): # get the object in the packml status object using our unique idx node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.Activity".format(port_number)) node.set_value(port.activity) node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.ActivityTimestamp".format(port_number)) node.set_value(port.activity_timestamp) node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.LightState".format(port_number)) node.set_value(port.get_light()) for port_number, box in self.rack.boxes.items(): node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.BoxId".format(port_number)) node.set_value(box.box_id) node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.ContentId".format(port_number)) node.set_value(box.content_id) node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.ContentCount".format(port_number)) node.set_value(box.content_count) for port_number, select_state in self.rack.ports_select_state.items(): node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.Selected".format(port_number)) node.set_value(select_state.selected) node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.PickTimestamp".format(port_number)) node.set_value(select_state.pick_timestamp)
# get Objects node, this is where we should put our custom stuff objects = server.get_objects_node() # Example 1 - create a basic object #------------------------------------------------------------------------------- myobj = objects.add_object(idx, "MyObject") #------------------------------------------------------------------------------- # Example 2 - create a new object type and a instance of the new object type #------------------------------------------------------------------------------- types = server.get_node(ua.ObjectIds.BaseObjectType) object_type_to_derive_from = server.get_root_node().get_child(["0:Types", "0:ObjectTypes", "0:BaseObjectType"]) mycustomobj_type = types.add_object_type(idx, "MyCustomObjectType") mycustomobj_type.add_variable(0, "var_should_be_there_after_instantiate", 1.0) # demonstrates instantiate myobj = objects.add_object(idx, "MyCustomObjectA", mycustomobj_type.nodeid) #------------------------------------------------------------------------------- # Example 3 - import a new object from xml address space and create a instance of the new object type #------------------------------------------------------------------------------- # Import customobject type server.import_xml('customobject.xml') # get nodeid of custom object type by one of the following 3 ways: