Пример #1
0
 def setup_nodes(self):
     """
     Set up some nodes as defined by spec
     """
     uries = ["http://opcfoundation.org/UA/"]
     ns_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
     ns_node.set_value(uries)
Пример #2
0
    def __init__(self, cacheFile=None):
        self.logger = logging.getLogger(__name__)

        self.server_callback_dispatcher = CallbackDispatcher()

        self.endpoints = []
        self._channel_id_counter = 5
        self.allow_remote_admin = True
        self.disabled_clock = False  # for debugging we may want to disable clock that writes too much in log
        self._known_servers = {}  # used if we are a discovery server

        self.aspace = AddressSpace()
        self.attribute_service = AttributeService(self.aspace)
        self.view_service = ViewService(self.aspace)
        self.method_service = MethodService(self.aspace)
        self.node_mgt_service = NodeManagementService(self.aspace)

        self.load_standard_address_space(cacheFile)

        self.loop = utils.ThreadLoop()
        self.asyncio_transports = []
        self.subscription_service = SubscriptionService(self.loop, self.aspace)

        self.history_manager = HistoryManager(self)

        # create a session to use on server side
        self.isession = InternalSession(self, self.aspace, self.subscription_service, "Internal", user=User.Admin)

        self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
        self.setup_nodes()
Пример #3
0
    def create_custom_data_type(self,
                                idx,
                                name,
                                basetype=ua.ObjectIds.BaseDataType,
                                properties=None,
                                description=None):
        if properties is None:
            properties = []

        if isinstance(basetype, Node):
            base_t = basetype
        elif isinstance(basetype, ua.NodeId):
            base_t = Node(self.iserver.isession, basetype)
        else:
            base_t = Node(self.iserver.isession, ua.NodeId(basetype))

        custom_t = base_t.add_data_type(idx, name, description)
        for prop in properties:
            datatype = None
            if len(prop) > 2:
                datatype = prop[2]
            custom_t.add_property(idx,
                                  prop[0],
                                  ua.get_default_value(prop[1]),
                                  varianttype=prop[1],
                                  datatype=datatype)

        return custom_t
Пример #4
0
def _copy_node(server, parent_nodeid, rdesc, nodeid, recursive):
    addnode = ua.AddNodesItem()
    addnode.RequestedNewNodeId = nodeid
    addnode.BrowseName = rdesc.BrowseName
    addnode.ParentNodeId = parent_nodeid
    addnode.ReferenceTypeId = rdesc.ReferenceTypeId
    addnode.TypeDefinition = rdesc.TypeDefinition
    addnode.NodeClass = rdesc.NodeClass

    node_to_copy = Node(server, rdesc.NodeId)
    
    attrObj = getattr(ua, rdesc.NodeClass.name + "Attributes")
    _read_and_copy_attrs(node_to_copy, attrObj(), addnode)
    
    res = server.add_nodes([addnode])[0]

    added_nodes = [res.AddedNodeId]
        
    if recursive:
        descs = node_to_copy.get_children_descriptions()
        for desc in descs:
            nodes = _copy_node(server, res.AddedNodeId, desc, nodeid=ua.NodeId(namespaceidx=desc.NodeId.NamespaceIndex), recursive=True)
            added_nodes.extend(nodes)

    return added_nodes
Пример #5
0
    def _create_custom_type(self, idx, name, basetype, properties, variables,
                            methods):
        if isinstance(basetype, Node):
            base_t = basetype
        elif isinstance(basetype, ua.NodeId):
            base_t = Node(self.iserver.isession, basetype)
        else:
            base_t = Node(self.iserver.isession, ua.NodeId(basetype))

        custom_t = base_t.add_object_type(idx, name)
        for prop in properties:
            datatype = None
            if len(prop) > 2:
                datatype = prop[2]
            custom_t.add_property(idx,
                                  prop[0],
                                  ua.get_default_value(prop[1]),
                                  varianttype=prop[1],
                                  datatype=datatype)
        for variable in variables:
            datatype = None
            if len(variable) > 2:
                datatype = variable[2]
            custom_t.add_variable(idx,
                                  variable[0],
                                  ua.get_default_value(variable[1]),
                                  varianttype=variable[1],
                                  datatype=datatype)
        for method in methods:
            custom_t.add_method(idx, method[0], method[1], method[2],
                                method[3])

        return custom_t
Пример #6
0
    def __init__(self, shelffile=None, user_manager=None, session_cls=None):
        self.logger = logging.getLogger(__name__)

        self.server_callback_dispatcher = CallbackDispatcher()

        self.endpoints = []
        self._channel_id_counter = 5
        self.disabled_clock = False  # for debugging we may want to disable clock that writes too much in log
        self._local_discovery_service = None # lazy-loading

        self.aspace = AddressSpace()
        self.attribute_service = AttributeService(self.aspace)
        self.view_service = ViewService(self.aspace)
        self.method_service = MethodService(self.aspace)
        self.node_mgt_service = NodeManagementService(self.aspace)

        self.load_standard_address_space(shelffile)

        self.loop = None
        self.asyncio_transports = []
        self.subscription_service = SubscriptionService(self.aspace)

        self.history_manager = HistoryManager(self)
        self.user_manager = user_manager

        # create a session to use on server side
        self.session_cls = session_cls or InternalSession
        self.isession = self.session_cls(self, self.aspace, \
          self.subscription_service, "Internal", user=UserManager.User.Admin)

        self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
        self._address_space_fixes()
        self.setup_nodes()
Пример #7
0
def _copy_node(server, parent_nodeid, rdesc, nodeid, recursive):
    addnode = ua.AddNodesItem()
    addnode.RequestedNewNodeId = nodeid
    addnode.BrowseName = rdesc.BrowseName
    addnode.ParentNodeId = parent_nodeid
    addnode.ReferenceTypeId = rdesc.ReferenceTypeId
    addnode.TypeDefinition = rdesc.TypeDefinition
    addnode.NodeClass = rdesc.NodeClass

    node_to_copy = Node(server, rdesc.NodeId)

    attrObj = getattr(ua, rdesc.NodeClass.name + "Attributes")
    _read_and_copy_attrs(node_to_copy, attrObj(), addnode)

    res = server.add_nodes([addnode])[0]

    added_nodes = [res.AddedNodeId]

    if recursive:
        descs = node_to_copy.get_children_descriptions()
        for desc in descs:
            nodes = _copy_node(
                server,
                res.AddedNodeId,
                desc,
                nodeid=ua.NodeId(namespaceidx=desc.NodeId.NamespaceIndex),
                recursive=True)
            added_nodes.extend(nodes)

    return added_nodes
Пример #8
0
 def setup_nodes(self):
     """
     Set up some nodes as defined by spec
     """
     uries = ["http://opcfoundation.org/UA/"]
     ns_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
     ns_node.set_value(uries)
Пример #9
0
 def start(self):
     self.logger.info("starting internal server")
     for edp in self.endpoints:
         self._known_servers[edp.Server.ApplicationUri] = ServerDesc(edp.Server)
     self.loop.start()
     Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_State)).set_value(0, ua.VariantType.Int32)
     Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_StartTime)).set_value(datetime.utcnow())
     if not self.disabled_clock:
         self._set_current_time()
Пример #10
0
 def start(self):
     self.logger.info("starting internal server")
     self.loop = utils.ThreadLoop()
     self.loop.start()
     self.subscription_service.set_loop(self.loop)
     serverState = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_State))
     serverState.set_value(ua.uaprotocol_auto.ServerState.Running, ua.VariantType.Int32)
     Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_StartTime)).set_value(datetime.utcnow())
     if not self.disabled_clock:
         self._set_current_time()
Пример #11
0
    def create_custom_event_type(self, idx, name, baseetype=ua.ObjectIds.BaseEventType, properties=[]):

        if isinstance(baseetype, Node):
            base_event = baseetype
        elif isinstance(baseetype, ua.NodeId):
            base_event = Node(self.iserver.isession, baseetype)
        else:
            base_event = Node(self.iserver.isession, ua.NodeId(baseetype))

        custom_event = base_event.add_subtype(idx, name)
        for property in properties:
            custom_event.add_property(idx, property[0], ua.Variant(None, property[1]))

        return custom_event
Пример #12
0
    def create_custom_event_type(self, idx, name, baseetype=ua.ObjectIds.BaseEventType, properties=[]):

        if isinstance(baseetype, Node):
            base_event = baseetype
        elif isinstance(baseetype, ua.NodeId):
            base_event = Node(self.iserver.isession, baseetype)
        else:
            base_event = Node(self.iserver.isession, ua.NodeId(baseetype))

        custom_event = base_event.add_subtype(idx, name)
        for property in properties:
            custom_event.add_property(idx, property[0], ua.Variant(None, property[1]))

        return custom_event
Пример #13
0
    def __init__(self, shelffile=None):
        self.logger = logging.getLogger(__name__)

        self.server_callback_dispatcher = CallbackDispatcher()

        self.endpoints = []
        self._channel_id_counter = 5
        self.allow_remote_admin = True
        self.disabled_clock = False  # for debugging we may want to disable clock that writes too much in log
        self._known_servers = {}  # used if we are a discovery server

        self.aspace = AddressSpace()
        self.attribute_service = AttributeService(self.aspace)
        self.view_service = ViewService(self.aspace)
        self.method_service = MethodService(self.aspace)
        self.node_mgt_service = NodeManagementService(self.aspace)

        self.load_standard_address_space(shelffile)

        self.loop = utils.ThreadLoop()
        self.asyncio_transports = []
        self.subscription_service = SubscriptionService(self.loop, self.aspace)

        self.history_manager = HistoryManager(self)

        # create a session to use on server side
        self.isession = InternalSession(self, self.aspace, self.subscription_service, "Internal", user=User.Admin)

        self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
        self.setup_nodes()
Пример #14
0
def sub_monitored_items_creation(sub, monitored_items):
	params = ua.CreateMonitoredItemsParameters()
	params.SubscriptionId = sub.subscription_id
	params.ItemsToCreate = monitored_items
	params.TimestampsToReturn = ua.TimestampsToReturn.Both

	# insert monitored item into map to avoid notification arrive before result return
	# server_handle is left as None in purpose as we don't get it yet.
	with sub._lock:
		for mi in monitored_items:
			data = SubscriptionItemData()
			data.client_handle = mi.RequestedParameters.ClientHandle
			data.node = Node(sub.server, mi.ItemToMonitor.NodeId)
			data.attribute = mi.ItemToMonitor.AttributeId
			#TODO: Either use the filter from request or from response. Here it uses from request, in modify it uses from response
			data.mfilter = mi.RequestedParameters.Filter
			sub._monitoreditems_map[mi.RequestedParameters.ClientHandle] = data
	results = sub.server.create_monitored_items(params)
	mids = []
	# process result, add server_handle, or remove it if failed
	with sub._lock:
		for idx, result in enumerate(results):
			mi = params.ItemsToCreate[idx]
			if not result.StatusCode.is_good():
				del sub._monitoreditems_map[mi.RequestedParameters.ClientHandle]
				mids.append(result.StatusCode)
				continue
			data = sub._monitoreditems_map[mi.RequestedParameters.ClientHandle]
			data.server_handle = result.MonitoredItemId
			mids.append(result.MonitoredItemId)
	return mids, results
Пример #15
0
def browse_tests(client, logger):

    nid, subPostfixNodeIdHierarchical, subNodeIdNonHierarchical, parentNid = browseSubTree

    # Hierarchical referenced node
    childrenNids = list()
    for bn in subPostfixNodeIdHierarchical:
        childrenNids.append('ns=1;s=' + bn)
    print("Browsing children of node {} expecting nodes {}".format(
        nid, childrenNids))
    n1 = client.get_node(nid)
    # Get all children of a node. By default hierarchical references and all node classes are returned.
    children = n1.get_children(
    )  # <=> n1.get_children(refs=33) for HierarchicalReferences
    # Checking number of children and their associated ids
    logger.add_test(
        'Browse Test - number of children for Node {}. Expecting {} == {}'.
        format(nid, len(childrenNids), len(children)),
        len(childrenNids) == len(children))
    # There shall not be backward references
    node = Node(sUri, parentNid)
    logger.add_test(
        'Browse Test - parent {} is not in browsed children'.format(parentNid),
        node not in children)
    # Checking forward references
    for childNid in childrenNids:
        print(childNid)
        node = Node(sUri, childNid)
        logger.add_test(
            'Browse Test - child {} retrieved in browsed children'.format(
                childNid), node in children)

    nonHierarchicalNids = list(subNodeIdNonHierarchical)
    nonHierChildren = n1.get_children(refs=32)  #NonHierarchicalReferences
    print("Non hier children: " + str(nonHierChildren))
    # Checking number of children and their associated ids
    logger.add_test(
        'Browse Test - number of non hierarchical children for Node {}. Expecting {} == {}'
        .format(nid, len(nonHierarchicalNids), len(nonHierChildren)),
        len(nonHierarchicalNids) == len(nonHierChildren))
    # Checking forward references
    for childNid in nonHierarchicalNids:
        print(childNid)
        node = Node(sUri, childNid)
        logger.add_test('Browse Test - non hierarchical child ' + childNid,
                        node in nonHierChildren)
Пример #16
0
def copy_node(parent, node, nodeid=None, recursive=True):
    """
    Copy a node or node tree as child of parent node
    """
    rdesc = _rdesc_from_node(parent, node)

    if nodeid is None:
        nodeid = ua.NodeId(namespaceidx=node.nodeid.NamespaceIndex)
    added_nodeids = _copy_node(parent.server, parent.nodeid, rdesc, nodeid,
                               recursive)
    return [Node(parent.server, nid) for nid in added_nodeids]
Пример #17
0
 def set_value(node_name: str, node: Node, value: bool) -> None:
     """
     节点赋值
     :param node_name:
     :param node:
     :param value: True -> 停机,False -> 复位
     :return: None
     """
     try:
         node.set_attribute(ua.AttributeIds.Value,
                            ua.DataValue(variant=ua.Variant(value)))
     except BadNodeIdUnknown as b:
         msg = '写入{}状态信息失败, 错误信息:节点不存在!'.format(node_name)
         print(msg)
         logging.warning(msg)
         raise RuntimeError("写入 {} 状态信息失败: 节点不存在!".format(node_name))
     except Exception as e:
         msg = '写入{}状态信息失败!未知错误:{}'.format(node_name, e)
         print(msg)
         logging.warning(msg)
         raise RuntimeError("写入 {} 状态信息失败!未知错误:{}".format(node_name, e))
Пример #18
0
def create_monitored_items(sub, dirty_nodes, attr):
	mirs = []
	for dirty_node in dirty_nodes:
		try:
			node_var = Node(sub.server, NodeId().from_string(dirty_node["node"]))
			rv = ua.ReadValueId()
			rv.NodeId = node_var.nodeid
			rv.AttributeId = attr
			# rv.IndexRange //We leave it null, then the entire array is returned
			mparams = ua.MonitoringParameters()
			with sub._lock:
				sub._client_handle += 1
				mparams.ClientHandle = sub._client_handle
			mparams.SamplingInterval = dirty_node["samplingInterval"]
			mparams.QueueSize = dirty_node["queueSize"]
			mparams.DiscardOldest = dirty_node["queueDiscardOldest"] == "True"
			
			if dirty_node["filter"] != "None":
				try:
					mfilter = DataChangeFilter()
					#DataChangeTrigger(0) = Status, DataChangeTrigger(1) = StatusValue, DataChangeTrigger(2) = StatusValueTimestamp
					mfilter.Trigger = DataChangeTrigger[dirty_node["filter"]["Trigger"]]
					# DeadbandType(0) = None, DeadbandType(1) = Absolute, DeadbandType(2) = Percent
					mfilter.DeadbandType = DeadbandType[dirty_node["filter"]["DeadbandType"]]
					mfilter.DeadbandValue = dirty_node["filter"]["DeadbandValue"]
				except:
					mfilter = None
					print(f"\n\nWARNING: Can't apply filter on node {dirty_node['node']}")
			else:
				mfilter = None
			
			if mfilter:
				mparams.Filter = mfilter	
			
			mir = ua.MonitoredItemCreateRequest()
			mir.ItemToMonitor = rv
			mir.MonitoringMode = ua.MonitoringMode.Disabled if dirty_node["monitoringMode"] == "Disabled" else ua.MonitoringMode.Sampling if dirty_node["monitoringMode"] == "Sampling" else ua.MonitoringMode.Reporting
			mir.RequestedParameters = mparams
			mirs.append(mir)
		except:
			print("\nUnable to create monitored item for node {dirty_node['node']}")		
		
	mids, results = sub_monitored_items_creation(sub, mirs)
	
	for i, r in enumerate(results):
		if dirty_node["samplingInterval"] != r.RevisedSamplingInterval or dirty_node["queueSize"] != r.RevisedQueueSize:
			print(f"\nServer has changed monitored item properties for node {dirty_node['node']}")
			print(f"Monitored item id: {r.MonitoredItemId}")
			print(f"Revised SamplingInterval: {r.RevisedSamplingInterval}")
			print(f"Revised QueueSize: {r.RevisedQueueSize}")
			print(f"Filter Result: {r.FilterResult}\n")
		
	return mids	
Пример #19
0
    def __init__(self):
        self.logger = logging.getLogger(__name__)
        self.endpoints = []
        self._channel_id_counter = 5
        self.allow_remote_admin = True
        self.disabled_clock = False  # for debugging we may want to disable clock that writes too much in log
        self._known_servers = {}  # used if we are a discovery server

        self.aspace = AddressSpace()
        self.attribute_service = AttributeService(self.aspace)
        self.view_service = ViewService(self.aspace)
        self.method_service = MethodService(self.aspace)
        self.node_mgt_service = NodeManagementService(self.aspace)
        # import address space from code generated from xml
        standard_address_space.fill_address_space(self.node_mgt_service)  
        # import address space from save db to disc
        #standard_address_space.fill_address_space_from_disk(self.aspace)  

        # import address space directly from xml, this has preformance impact so disabled
        #importer = xmlimporter.XmlImporter(self.node_mgt_service)
        #importer.import_xml("/home/olivier/python-opcua/schemas/Opc.Ua.NodeSet2.xml")

        self.loop = utils.ThreadLoop()
        self.subscription_service = SubscriptionService(self.loop, self.aspace)

        # create a session to use on server side
        self.isession = InternalSession(self, self.aspace, self.subscription_service, "Internal", user=User.Admin)
        self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
        uries = ["http://opcfoundation.org/UA/"]
        ns_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
        ns_node.set_value(uries)
Пример #20
0
    def _create_custom_type(self, idx, name, basetype, properties, variables, methods):
        if isinstance(basetype, Node):
            base_t = basetype
        elif isinstance(basetype, ua.NodeId):
            base_t = Node(self.iserver.isession, basetype)
        else:
            base_t = Node(self.iserver.isession, ua.NodeId(basetype))

        custom_t = base_t.add_object_type(idx, name)
        for property in properties:
            datatype = None
            if len(property) > 2:
                datatype = property[2]
            custom_t.add_property(idx, property[0], None, varianttype=property[1], datatype=datatype)
        for variable in variables:
            datatype = None
            if len(variable) > 2:
                datatype = variable[2]
            custom_t.add_variable(idx, variable[0], None, varianttype=variable[1], datatype=datatype)
        for method in methods:
            custom_t.add_method(idx, method[0], method[1], method[2], method[3])

        return custom_t
Пример #21
0
class InternalServer(object):
    def __init__(self, shelffile=None):
        self.logger = logging.getLogger(__name__)

        self.server_callback_dispatcher = CallbackDispatcher()

        self.endpoints = []
        self._channel_id_counter = 5
        self.allow_remote_admin = True
        self.disabled_clock = False  # for debugging we may want to disable clock that writes too much in log
        self._known_servers = {}  # used if we are a discovery server

        self.certificate = None
        self.private_key = None

        self.aspace = AddressSpace()
        self.attribute_service = AttributeService(self.aspace)
        self.view_service = ViewService(self.aspace)
        self.method_service = MethodService(self.aspace)
        self.node_mgt_service = NodeManagementService(self.aspace)

        self.load_standard_address_space(shelffile)

        self.loop = None
        self.asyncio_transports = []
        self.subscription_service = SubscriptionService(self.aspace)

        self.history_manager = HistoryManager(self)

        self.user_manager = default_user_manager  # defined at the end of this file

        # create a session to use on server side
        self.isession = InternalSession(self,
                                        self.aspace,
                                        self.subscription_service,
                                        "Internal",
                                        user=User.Admin)

        self.current_time_node = Node(
            self.isession,
            ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
        self._address_space_fixes()
        self.setup_nodes()

    def setup_nodes(self):
        """
        Set up some nodes as defined by spec
        """
        uries = ["http://opcfoundation.org/UA/"]
        ns_node = Node(self.isession,
                       ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
        ns_node.set_value(uries)

    def load_standard_address_space(self, shelffile=None):
        if (shelffile is not None) and (os.path.isfile(shelffile)
                                        or os.path.isfile(shelffile + ".db")):
            # import address space from shelf
            self.aspace.load_aspace_shelf(shelffile)
        else:
            # import address space from code generated from xml
            standard_address_space.fill_address_space(self.node_mgt_service)
            # import address space directly from xml, this has performance impact so disabled
            # importer = xmlimporter.XmlImporter(self.node_mgt_service)
            # importer.import_xml("/path/to/python-opcua/schemas/Opc.Ua.NodeSet2.xml", self)

            # if a cache file was supplied a shelve of the standard address space can now be built for next start up
            if shelffile:
                self.aspace.make_aspace_shelf(shelffile)

    def _address_space_fixes(self):
        """
        Looks like the xml definition of address space has some error. This is a good place to fix them
        """

        it = ua.AddReferencesItem()
        it.SourceNodeId = ua.NodeId(ua.ObjectIds.BaseObjectType)
        it.ReferenceTypeId = ua.NodeId(ua.ObjectIds.Organizes)
        it.IsForward = False
        it.TargetNodeId = ua.NodeId(ua.ObjectIds.ObjectTypesFolder)
        it.TargetNodeClass = ua.NodeClass.Object

        it2 = ua.AddReferencesItem()
        it2.SourceNodeId = ua.NodeId(ua.ObjectIds.BaseDataType)
        it2.ReferenceTypeId = ua.NodeId(ua.ObjectIds.Organizes)
        it2.IsForward = False
        it2.TargetNodeId = ua.NodeId(ua.ObjectIds.DataTypesFolder)
        it2.TargetNodeClass = ua.NodeClass.Object

        results = self.isession.add_references([it, it2])

    def load_address_space(self, path):
        """
        Load address space from path
        """
        self.aspace.load(path)

    def dump_address_space(self, path):
        """
        Dump current address space to path
        """
        self.aspace.dump(path)

    def start(self):
        self.logger.info("starting internal server")
        for edp in self.endpoints:
            self._known_servers[edp.Server.ApplicationUri] = ServerDesc(
                edp.Server)
        self.loop = utils.ThreadLoop()
        self.loop.start()
        self.subscription_service.set_loop(self.loop)
        Node(self.isession,
             ua.NodeId(ua.ObjectIds.Server_ServerStatus_State)).set_value(
                 0, ua.VariantType.Int32)
        Node(self.isession,
             ua.NodeId(ua.ObjectIds.Server_ServerStatus_StartTime)).set_value(
                 datetime.utcnow())
        if not self.disabled_clock:
            self._set_current_time()

    def stop(self):
        self.logger.info("stopping internal server")
        self.isession.close_session()
        if self.loop:
            self.loop.stop()
            self.loop = None
        self.subscription_service.set_loop(None)
        self.history_manager.stop()

    def _set_current_time(self):
        self.current_time_node.set_value(datetime.utcnow())
        self.loop.call_later(1, self._set_current_time)

    def get_new_channel_id(self):
        self._channel_id_counter += 1
        return self._channel_id_counter

    def add_endpoint(self, endpoint):
        self.endpoints.append(endpoint)

    def get_endpoints(self, params=None, sockname=None):
        self.logger.info("get endpoint")
        if sockname:
            # return to client the ip address it has access to
            edps = []
            for edp in self.endpoints:
                edp1 = copy(edp)
                url = urlparse(edp1.EndpointUrl)
                url = url._replace(netloc=sockname[0] + ":" + str(sockname[1]))
                edp1.EndpointUrl = url.geturl()
                edps.append(edp1)
            return edps
        return self.endpoints[:]

    def find_servers(self, params):
        if not params.ServerUris:
            return [desc.Server for desc in self._known_servers.values()]
        servers = []
        for serv in self._known_servers.values():
            serv_uri = serv.Server.ApplicationUri.split(":")
            for uri in params.ServerUris:
                uri = uri.split(":")
                if serv_uri[:len(uri)] == uri:
                    servers.append(serv.Server)
                    break
        return servers

    def register_server(self, server, conf=None):
        appdesc = ua.ApplicationDescription()
        appdesc.ApplicationUri = server.ServerUri
        appdesc.ProductUri = server.ProductUri
        # FIXME: select name from client locale
        appdesc.ApplicationName = server.ServerNames[0]
        appdesc.ApplicationType = server.ServerType
        appdesc.DiscoveryUrls = server.DiscoveryUrls
        # FIXME: select discovery uri using reachability from client network
        appdesc.GatewayServerUri = server.GatewayServerUri
        self._known_servers[server.ServerUri] = ServerDesc(appdesc, conf)

    def register_server2(self, params):
        return self.register_server(params.Server,
                                    params.DiscoveryConfiguration)

    def create_session(self, name, user=User.Anonymous, external=False):
        return InternalSession(self,
                               self.aspace,
                               self.subscription_service,
                               name,
                               user=user,
                               external=external)

    def enable_history_data_change(self,
                                   node,
                                   period=timedelta(days=7),
                                   count=0):
        """
        Set attribute Historizing of node to True and start storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(True))
        node.set_attr_bit(ua.AttributeIds.AccessLevel,
                          ua.AccessLevel.HistoryRead)
        node.set_attr_bit(ua.AttributeIds.UserAccessLevel,
                          ua.AccessLevel.HistoryRead)
        self.history_manager.historize_data_change(node, period, count)

    def disable_history_data_change(self, node):
        """
        Set attribute Historizing of node to False and stop storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(False))
        node.unset_attr_bit(ua.AttributeIds.AccessLevel,
                            ua.AccessLevel.HistoryRead)
        node.unset_attr_bit(ua.AttributeIds.UserAccessLevel,
                            ua.AccessLevel.HistoryRead)
        self.history_manager.dehistorize(node)

    def enable_history_event(self, source, period=timedelta(days=7), count=0):
        """
        Set attribute History Read of object events to True and start storing data for history
        """
        event_notifier = source.get_event_notifier()
        if ua.EventNotifier.SubscribeToEvents not in event_notifier:
            raise ua.UaError("Node does not generate events", event_notifier)

        if ua.EventNotifier.HistoryRead not in event_notifier:
            event_notifier.add(ua.EventNotifier.HistoryRead)
            source.set_event_notifier(event_notifier)

        self.history_manager.historize_event(source, period, count)

    def disable_history_event(self, source):
        """
        Set attribute History Read of node to False and stop storing data for history
        """
        source.unset_attr_bit(ua.AttributeIds.EventNotifier,
                              ua.EventNotifier.HistoryRead)
        self.history_manager.dehistorize(source)

    def subscribe_server_callback(self, event, handle):
        """
        Create a subscription from event to handle
        """
        self.server_callback_dispatcher.addListener(event, handle)

    def unsubscribe_server_callback(self, event, handle):
        """
        Remove a subscription from event to handle
        """
        self.server_callback_dispatcher.removeListener(event, handle)

    def set_attribute_value(self,
                            nodeid,
                            datavalue,
                            attr=ua.AttributeIds.Value):
        """
        directly write datavalue to the Attribute, bypasing some checks and structure creation
        so it is a little faster
        """
        self.aspace.set_attribute_value(nodeid, ua.AttributeIds.Value,
                                        datavalue)

    def set_user_manager(self, user_manager):
        """
        set up a function which that will check for authorize users. Input function takes username
        and password as paramters and returns True of user is allowed access, False otherwise.
        """
        self.user_manager = user_manager

    def check_user_token(self, isession, token):
        """
        unpack the username and password for the benefit of the user defined user manager
        """
        userName = token.UserName
        passwd = token.Password

        # decrypt password is we can
        if str(token.EncryptionAlgorithm) != "None":
            if use_crypto == False:
                return False
            try:
                if token.EncryptionAlgorithm == "http://www.w3.org/2001/04/xmlenc#rsa-1_5":
                    raw_pw = uacrypto.decrypt_rsa15(self.private_key, passwd)
                elif token.EncryptionAlgorithm == "http://www.w3.org/2001/04/xmlenc#rsa-oaep":
                    raw_pw = uacrypto.decrypt_rsa_oaep(self.private_key,
                                                       passwd)
                else:
                    self.logger.warning(
                        "Unknown password encoding '{0}'".format(
                            token.EncryptionAlgorithm))
                    return False
                length = unpack_from('<I', raw_pw)[0] - len(isession.nonce)
                passwd = raw_pw[4:4 + length]
                passwd = passwd.decode('utf-8')
            except Exception as exp:
                self.logger.warning("Unable to decrypt password")
                return False

        # call user_manager
        return self.user_manager(self, isession, userName, passwd)
Пример #22
0
class InternalServer(object):

    def __init__(self, shelffile=None, parent=None):
        self.logger = logging.getLogger(__name__)

        self._parent = parent
        self.server_callback_dispatcher = CallbackDispatcher()

        self.endpoints = []
        self._channel_id_counter = 5
        self.disabled_clock = False  # for debugging we may want to disable clock that writes too much in log
        self._local_discovery_service = None # lazy-loading

        self.aspace = AddressSpace()
        self.attribute_service = AttributeService(self.aspace)
        self.view_service = ViewService(self.aspace)
        self.method_service = MethodService(self.aspace)
        self.node_mgt_service = NodeManagementService(self.aspace)

        self.load_standard_address_space(shelffile)

        self.loop = None
        self.asyncio_transports = []
        self.subscription_service = SubscriptionService(self.aspace)

        self.history_manager = HistoryManager(self)

        # create a session to use on server side
        self.isession = InternalSession(self, self.aspace, \
          self.subscription_service, "Internal", user=UserManager.User.Admin)

        self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
        self._address_space_fixes()
        self.setup_nodes()

    @property
    def user_manager(self):
        return self._parent.user_manager

    @property
    def thread_loop(self):
        if self.loop is None:
            raise Exception("InternalServer stopped: async threadloop is not running.")
        return self.loop

    @property
    def local_discovery_service(self):
        if self._local_discovery_service is None:
            self._local_discovery_service = LocalDiscoveryService(parent = self)
            for edp in self.endpoints:
                srvDesc = LocalDiscoveryService.ServerDescription(edp.Server)
                self._local_discovery_service.add_server_description(srvDesc)
        return self._local_discovery_service

    def setup_nodes(self):
        """
        Set up some nodes as defined by spec
        """
        uries = ["http://opcfoundation.org/UA/"]
        ns_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
        ns_node.set_value(uries)

    def load_standard_address_space(self, shelffile=None):
        if (shelffile is not None) and (os.path.isfile(shelffile) or os.path.isfile(shelffile+".db")):
            # import address space from shelf
            self.aspace.load_aspace_shelf(shelffile)
        else:
            # import address space from code generated from xml
            standard_address_space.fill_address_space(self.node_mgt_service)
            # import address space directly from xml, this has performance impact so disabled
            # importer = xmlimporter.XmlImporter(self.node_mgt_service)
            # importer.import_xml("/path/to/python-opcua/schemas/Opc.Ua.NodeSet2.xml", self)

            # if a cache file was supplied a shelve of the standard address space can now be built for next start up
            if shelffile:
                self.aspace.make_aspace_shelf(shelffile)

    def _address_space_fixes(self):
        """
        Looks like the xml definition of address space has some error. This is a good place to fix them
        """

        it = ua.AddReferencesItem()
        it.SourceNodeId = ua.NodeId(ua.ObjectIds.BaseObjectType)
        it.ReferenceTypeId = ua.NodeId(ua.ObjectIds.Organizes)
        it.IsForward = False
        it.TargetNodeId = ua.NodeId(ua.ObjectIds.ObjectTypesFolder)
        it.TargetNodeClass = ua.NodeClass.Object

        it2 = ua.AddReferencesItem()
        it2.SourceNodeId = ua.NodeId(ua.ObjectIds.BaseDataType)
        it2.ReferenceTypeId = ua.NodeId(ua.ObjectIds.Organizes)
        it2.IsForward = False
        it2.TargetNodeId = ua.NodeId(ua.ObjectIds.DataTypesFolder)
        it2.TargetNodeClass = ua.NodeClass.Object

        results = self.isession.add_references([it, it2])
 
    def load_address_space(self, path):
        """
        Load address space from path
        """
        self.aspace.load(path)

    def dump_address_space(self, path):
        """
        Dump current address space to path
        """
        self.aspace.dump(path)

    def start(self):
        self.logger.info("starting internal server")
        self.loop = utils.ThreadLoop()
        self.loop.start()
        self.subscription_service.set_loop(self.loop)
        Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_State)).set_value(0, ua.VariantType.Int32)
        Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_StartTime)).set_value(datetime.utcnow())
        if not self.disabled_clock:
            self._set_current_time()

    def stop(self):
        self.logger.info("stopping internal server")
        self.isession.close_session()
        if self.loop:
            self.loop.stop()
            self.loop = None
        self.subscription_service.set_loop(None)
        self.history_manager.stop()

    def is_running(self):
        return self.loop is not None

    def _set_current_time(self):
        self.current_time_node.set_value(datetime.utcnow())
        self.loop.call_later(1, self._set_current_time)

    def get_new_channel_id(self):
        self._channel_id_counter += 1
        return self._channel_id_counter

    def add_endpoint(self, endpoint):
        self.endpoints.append(endpoint)

    def get_endpoints(self, params=None, sockname=None):
        self.logger.info("get endpoint")
        if sockname:
            # return to client the ip address it has access to
            edps = []
            for edp in self.endpoints:
                edp1 = copy(edp)
                url = urlparse(edp1.EndpointUrl)
                url = url._replace(netloc=sockname[0] + ":" + str(sockname[1]))
                edp1.EndpointUrl = url.geturl()
                edps.append(edp1)
            return edps
        return self.endpoints[:]

    def create_session(self, name, user=UserManager.User.Anonymous, external=False):
        return InternalSession(self, self.aspace, self.subscription_service, name, user=user, external=external)

    def enable_history_data_change(self, node, period=timedelta(days=7), count=0):
        """
        Set attribute Historizing of node to True and start storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(True))
        node.set_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.HistoryRead)
        node.set_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.HistoryRead)
        self.history_manager.historize_data_change(node, period, count)

    def disable_history_data_change(self, node):
        """
        Set attribute Historizing of node to False and stop storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(False))
        node.unset_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.HistoryRead)
        node.unset_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.HistoryRead)
        self.history_manager.dehistorize(node)

    def enable_history_event(self, source, period=timedelta(days=7), count=0):
        """
        Set attribute History Read of object events to True and start storing data for history
        """
        event_notifier = source.get_event_notifier()
        if ua.EventNotifier.SubscribeToEvents not in event_notifier:
            raise ua.UaError("Node does not generate events", event_notifier)

        if ua.EventNotifier.HistoryRead not in event_notifier:
            event_notifier.add(ua.EventNotifier.HistoryRead)
            source.set_event_notifier(event_notifier)

        self.history_manager.historize_event(source, period, count)

    def disable_history_event(self, source):
        """
        Set attribute History Read of node to False and stop storing data for history
        """
        source.unset_attr_bit(ua.AttributeIds.EventNotifier, ua.EventNotifier.HistoryRead)
        self.history_manager.dehistorize(source)

    def subscribe_server_callback(self, event, handle):
        """
        Create a subscription from event to handle
        """
        self.server_callback_dispatcher.addListener(event, handle)

    def unsubscribe_server_callback(self, event, handle):
        """
        Remove a subscription from event to handle
        """
        self.server_callback_dispatcher.removeListener(event, handle)

    def set_attribute_value(self, nodeid, datavalue, attr=ua.AttributeIds.Value):
        """
        directly write datavalue to the Attribute, bypasing some checks and structure creation
        so it is a little faster
        """
        self.aspace.set_attribute_value(nodeid, ua.AttributeIds.Value, datavalue)
Пример #23
0
class InternalServer(object):

    def __init__(self):
        self.logger = logging.getLogger(__name__)
        self.endpoints = []
        self._channel_id_counter = 5
        self.allow_remote_admin = True
        self.disabled_clock = False  # for debugging we may want to disable clock that writes too much in log
        self._known_servers = {}  # used if we are a discovery server

        self.aspace = AddressSpace()
        self.attribute_service = AttributeService(self.aspace)
        self.view_service = ViewService(self.aspace)
        self.method_service = MethodService(self.aspace)
        self.node_mgt_service = NodeManagementService(self.aspace)
        # import address space from code generated from xml
        standard_address_space.fill_address_space(self.node_mgt_service)  
        # import address space from save db to disc
        #standard_address_space.fill_address_space_from_disk(self.aspace)  

        # import address space directly from xml, this has preformance impact so disabled
        #importer = xmlimporter.XmlImporter(self.node_mgt_service)
        #importer.import_xml("/home/olivier/python-opcua/schemas/Opc.Ua.NodeSet2.xml")

        self.loop = utils.ThreadLoop()
        self.subscription_service = SubscriptionService(self.loop, self.aspace)

        # create a session to use on server side
        self.isession = InternalSession(self, self.aspace, self.subscription_service, "Internal", user=User.Admin)
        self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
        uries = ["http://opcfoundation.org/UA/"]
        ns_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
        ns_node.set_value(uries)

    def load_address_space(self, path):
        self.aspace.load(path)

    def dump_address_space(self, path):
        self.aspace.dump(path)

    def start(self):
        self.logger.info("starting internal server")
        for edp in self.endpoints:
            self._known_servers[edp.Server.ApplicationUri] = ServerDesc(edp.Server)
        self.loop.start()
        Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_State)).set_value(0)
        Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_StartTime)).set_value(datetime.now())
        if not self.disabled_clock:
            self._set_current_time()

    def stop(self):
        self.logger.info("stopping internal server")
        self.loop.stop()

    def _set_current_time(self):
        self.current_time_node.set_value(datetime.now())
        self.loop.call_later(1, self._set_current_time)

    def get_new_channel_id(self):
        self._channel_id_counter += 1
        return self._channel_id_counter

    def add_endpoint(self, endpoint):
        self.endpoints.append(endpoint)

    def get_endpoints(self, params=None, sockname=None):
        self.logger.info("get endpoint")
        if sockname:
            #return to client the ip address it has access to
            edps = []
            for edp in self.endpoints:
                edp1 = copy(edp)
                url = urlparse(edp1.EndpointUrl)
                url = url._replace(netloc=sockname[0] + ":" + str(sockname[1]))
                edp1.EndpointUrl = url.geturl()
                edps.append(edp1)
            return edps
        return self.endpoints[:]

    def find_servers(self, params):
        if not params.ServerUris:
            return [desc.Server for desc in self._known_servers.values()] 
        servers = []
        for serv in self._known_servers.values():
            serv_uri = serv.Server.ApplicationUri.split(":")
            for uri in params.ServerUris:
                uri = uri.split(":")
                if serv_uri[:len(uri)] == uri:
                    servers.append(serv.Server)
                    break
        return servers

    def register_server(self, server, conf=None):
        appdesc = ua.ApplicationDescription()
        appdesc.ApplicationUri = server.ServerUri
        appdesc.ProductUri = server.ProductUri
        appdesc.ApplicationName = server.ServerNames[0]  # FIXME: select name from client locale
        appdesc.ApplicationType = server.ServerType
        appdesc.GatewayServerUri = server.GatewayServerUri
        appdesc.DiscoveryUrls = server.DiscoveryUrls  # FIXME: select discovery uri using reachability from client network
        self._known_servers[server.ServerUri] = ServerDesc(appdesc, conf)

    def register_server2(self, params):
        return self.register_server(params.Server, params.DiscoveryConfiguration)

    def create_session(self, name, user=User.Anonymous, external=False):
        return InternalSession(self, self.aspace, self.subscription_service, name, user=user, external=external)
Пример #24
0
class InternalServer(object):

    def __init__(self, shelffile=None, user_manager=None, session_cls=None):
        self.logger = logging.getLogger(__name__)

        self.server_callback_dispatcher = CallbackDispatcher()

        self.endpoints = []
        self._channel_id_counter = 5
        self.disabled_clock = False  # for debugging we may want to disable clock that writes too much in log
        self._local_discovery_service = None # lazy-loading

        self.aspace = AddressSpace()
        self.attribute_service = AttributeService(self.aspace)
        self.view_service = ViewService(self.aspace)
        self.method_service = MethodService(self.aspace)
        self.node_mgt_service = NodeManagementService(self.aspace)

        self.load_standard_address_space(shelffile)

        self.loop = None
        self.asyncio_transports = []
        self.subscription_service = SubscriptionService(self.aspace)

        self.history_manager = HistoryManager(self)
        self.user_manager = user_manager

        # create a session to use on server side
        self.session_cls = session_cls or InternalSession
        self.isession = self.session_cls(self, self.aspace, \
          self.subscription_service, "Internal", user=UserManager.User.Admin)

        self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
        self._address_space_fixes()
        self.setup_nodes()

    @property
    def thread_loop(self):
        if self.loop is None:
            raise Exception("InternalServer stopped: async threadloop is not running.")
        return self.loop

    @property
    def local_discovery_service(self):
        if self._local_discovery_service is None:
            self._local_discovery_service = LocalDiscoveryService(parent = self)
            for edp in self.endpoints:
                srvDesc = LocalDiscoveryService.ServerDescription(edp.Server)
                self._local_discovery_service.add_server_description(srvDesc)
        return self._local_discovery_service

    def setup_nodes(self):
        """
        Set up some nodes as defined by spec
        """
        uries = ["http://opcfoundation.org/UA/"]
        ns_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
        ns_node.set_value(uries)

    def load_standard_address_space(self, shelffile=None):
        if (shelffile is not None) and (os.path.isfile(shelffile) or os.path.isfile(shelffile+".db")):
            # import address space from shelf
            self.aspace.load_aspace_shelf(shelffile)
        else:
            # import address space from code generated from xml
            standard_address_space.fill_address_space(self.node_mgt_service)
            # import address space directly from xml, this has performance impact so disabled
            # importer = xmlimporter.XmlImporter(self.node_mgt_service)
            # importer.import_xml("/path/to/python-opcua/schemas/Opc.Ua.NodeSet2.xml", self)

            # if a cache file was supplied a shelve of the standard address space can now be built for next start up
            if shelffile:
                self.aspace.make_aspace_shelf(shelffile)

    def _address_space_fixes(self):
        """
        Looks like the xml definition of address space has some error. This is a good place to fix them
        """

        it = ua.AddReferencesItem()
        it.SourceNodeId = ua.NodeId(ua.ObjectIds.BaseObjectType)
        it.ReferenceTypeId = ua.NodeId(ua.ObjectIds.Organizes)
        it.IsForward = False
        it.TargetNodeId = ua.NodeId(ua.ObjectIds.ObjectTypesFolder)
        it.TargetNodeClass = ua.NodeClass.Object

        it2 = ua.AddReferencesItem()
        it2.SourceNodeId = ua.NodeId(ua.ObjectIds.BaseDataType)
        it2.ReferenceTypeId = ua.NodeId(ua.ObjectIds.Organizes)
        it2.IsForward = False
        it2.TargetNodeId = ua.NodeId(ua.ObjectIds.DataTypesFolder)
        it2.TargetNodeClass = ua.NodeClass.Object

        results = self.isession.add_references([it, it2])

        params = ua.WriteParameters()
        for nodeid in (ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerRead,
                     ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryReadData,
                     ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryReadEvents,
                     ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerWrite,
                     ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryUpdateData,
                     ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryUpdateEvents,
                     ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerMethodCall,
                     ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerBrowse,
                     ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerRegisterNodes,
                     ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerTranslateBrowsePathsToNodeIds,
                     ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerNodeManagement,
                     ua.ObjectIds.Server_ServerCapabilities_OperationLimits_MaxMonitoredItemsPerCall):
            attr = ua.WriteValue()
            attr.NodeId = ua.NodeId(nodeid)
            attr.AttributeId = ua.AttributeIds.Value
            attr.Value = ua.DataValue(ua.Variant(10000, ua.VariantType.UInt32), ua.StatusCode(ua.StatusCodes.Good))
            attr.Value.ServerTimestamp = datetime.utcnow()
            params.NodesToWrite.append(attr)
        result = self.isession.write(params)
        result[0].check()


    def load_address_space(self, path):
        """
        Load address space from path
        """
        self.aspace.load(path)

    def dump_address_space(self, path):
        """
        Dump current address space to path
        """
        self.aspace.dump(path)

    def start(self):
        self.logger.info("starting internal server")
        self.loop = utils.ThreadLoop()
        self.loop.start()
        self.subscription_service.set_loop(self.loop)
        serverState = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_State))
        serverState.set_value(ua.uaprotocol_auto.ServerState.Running, ua.VariantType.Int32)
        Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_StartTime)).set_value(datetime.utcnow())
        if not self.disabled_clock:
            self._set_current_time()

    def stop(self):
        self.logger.info("stopping internal server")
        self.isession.close_session()
        self.subscription_service.set_loop(None)
        self.history_manager.stop()
        if self.loop:
            self.loop.stop()
            # wait for ThreadLoop to finish before proceeding
            self.loop.join()
            self.loop.close()
            self.loop = None

    def is_running(self):
        return self.loop is not None

    def _set_current_time(self):
        self.current_time_node.set_value(datetime.utcnow())
        self.loop.call_later(1, self._set_current_time)

    def get_new_channel_id(self):
        self._channel_id_counter += 1
        return self._channel_id_counter

    def add_endpoint(self, endpoint):
        self.endpoints.append(endpoint)

    def get_endpoints(self, params=None, sockname=None):
        self.logger.info("get endpoint")
        if sockname:
            # return to client the ip address it has access to
            edps = []
            for edp in self.endpoints:
                edp1 = copy(edp)
                url = urlparse(edp1.EndpointUrl)
                url = url._replace(netloc=sockname[0] + ":" + str(sockname[1]))
                edp1.EndpointUrl = url.geturl()
                edps.append(edp1)
            return edps
        return self.endpoints[:]

    def create_session(self, name, user=UserManager.User.Anonymous):
        return self.session_cls(self, self.aspace, self.subscription_service, name, user=user)

    def enable_history_data_change(self, node, period=timedelta(days=7), count=0):
        """
        Set attribute Historizing of node to True and start storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(True))
        node.set_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.HistoryRead)
        node.set_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.HistoryRead)
        self.history_manager.historize_data_change(node, period, count)

    def disable_history_data_change(self, node):
        """
        Set attribute Historizing of node to False and stop storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(False))
        node.unset_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.HistoryRead)
        node.unset_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.HistoryRead)
        self.history_manager.dehistorize(node)

    def enable_history_event(self, source, period=timedelta(days=7), count=0):
        """
        Set attribute History Read of object events to True and start storing data for history
        """
        event_notifier = source.get_event_notifier()
        if ua.EventNotifier.SubscribeToEvents not in event_notifier:
            raise ua.UaError("Node does not generate events", event_notifier)

        if ua.EventNotifier.HistoryRead not in event_notifier:
            event_notifier.add(ua.EventNotifier.HistoryRead)
            source.set_event_notifier(event_notifier)

        self.history_manager.historize_event(source, period, count)

    def disable_history_event(self, source):
        """
        Set attribute History Read of node to False and stop storing data for history
        """
        source.unset_attr_bit(ua.AttributeIds.EventNotifier, ua.EventNotifier.HistoryRead)
        self.history_manager.dehistorize(source)

    def subscribe_server_callback(self, event, handle):
        """
        Create a subscription from event to handle
        """
        self.server_callback_dispatcher.addListener(event, handle)

    def unsubscribe_server_callback(self, event, handle):
        """
        Remove a subscription from event to handle
        """
        self.server_callback_dispatcher.removeListener(event, handle)

    def set_attribute_value(self, nodeid, datavalue, attr=ua.AttributeIds.Value):
        """
        directly write datavalue to the Attribute, bypasing some checks and structure creation
        so it is a little faster
        """
        self.aspace.set_attribute_value(nodeid, ua.AttributeIds.Value, datavalue)
Пример #25
0
 def get_node(self, nodeid):
     """
     Get node using NodeId object or a string representing a NodeId
     """
     return Node(self.bclient, nodeid)
Пример #26
0
class InternalServer(object):
    def __init__(self, shelffile=None):
        self.logger = logging.getLogger(__name__)

        self.server_callback_dispatcher = CallbackDispatcher()

        self.endpoints = []
        self._channel_id_counter = 5
        self.allow_remote_admin = True
        self.disabled_clock = False  # for debugging we may want to disable clock that writes too much in log
        self._known_servers = {}  # used if we are a discovery server

        self.aspace = AddressSpace()
        self.attribute_service = AttributeService(self.aspace)
        self.view_service = ViewService(self.aspace)
        self.method_service = MethodService(self.aspace)
        self.node_mgt_service = NodeManagementService(self.aspace)

        self.load_standard_address_space(shelffile)

        self.loop = utils.ThreadLoop()
        self.asyncio_transports = []
        self.subscription_service = SubscriptionService(self.loop, self.aspace)

        self.history_manager = HistoryManager(self)

        # create a session to use on server side
        self.isession = InternalSession(self,
                                        self.aspace,
                                        self.subscription_service,
                                        "Internal",
                                        user=User.Admin)

        self.current_time_node = Node(
            self.isession,
            ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
        self._address_space_fixes()
        self.setup_nodes()

    def setup_nodes(self):
        """
        Set up some nodes as defined by spec
        """
        uries = ["http://opcfoundation.org/UA/"]
        ns_node = Node(self.isession,
                       ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
        ns_node.set_value(uries)

    def load_standard_address_space(self, shelffile=None):
        if shelffile is not None and os.path.isfile(shelffile):
            # import address space from shelf
            self.aspace.load_aspace_shelf(shelffile)
        else:
            # import address space from code generated from xml
            standard_address_space.fill_address_space(self.node_mgt_service)
            # import address space directly from xml, this has performance impact so disabled
            # importer = xmlimporter.XmlImporter(self.node_mgt_service)
            # importer.import_xml("/path/to/python-opcua/schemas/Opc.Ua.NodeSet2.xml", self)

            # if a cache file was supplied a shelve of the standard address space can now be built for next start up
            if shelffile:
                self.aspace.make_aspace_shelf(shelffile)

    def _address_space_fixes(self):
        """
        Looks like the xml definition of address space has some error. This is a good place to fix them
        """

        it = ua.AddReferencesItem()
        it.SourceNodeId = ua.NodeId(ua.ObjectIds.BaseObjectType)
        it.ReferenceTypeId = ua.NodeId(ua.ObjectIds.Organizes)
        it.IsForward = False
        it.TargetNodeId = ua.NodeId(ua.ObjectIds.ObjectTypesFolder)
        it.TargetNodeClass = ua.NodeClass.Object

        results = self.isession.add_references([it])

    def load_address_space(self, path):
        """
        Load address space from path
        """
        self.aspace.load(path)

    def dump_address_space(self, path):
        """
        Dump current address space to path
        """
        self.aspace.dump(path)

    def start(self):
        self.logger.info("starting internal server")
        for edp in self.endpoints:
            self._known_servers[edp.Server.ApplicationUri] = ServerDesc(
                edp.Server)
        self.loop.start()
        Node(self.isession,
             ua.NodeId(ua.ObjectIds.Server_ServerStatus_State)).set_value(
                 0, ua.VariantType.Int32)
        Node(self.isession,
             ua.NodeId(ua.ObjectIds.Server_ServerStatus_StartTime)).set_value(
                 datetime.utcnow())
        if not self.disabled_clock:
            self._set_current_time()

    def stop(self):
        self.logger.info("stopping internal server")
        self.isession.close_session()
        self.loop.stop()
        self.history_manager.stop()

    def _set_current_time(self):
        self.current_time_node.set_value(datetime.utcnow())
        self.loop.call_later(1, self._set_current_time)

    def get_new_channel_id(self):
        self._channel_id_counter += 1
        return self._channel_id_counter

    def add_endpoint(self, endpoint):
        self.endpoints.append(endpoint)

    def get_endpoints(self, params=None, sockname=None):
        self.logger.info("get endpoint")
        if sockname:
            # return to client the ip address it has access to
            edps = []
            for edp in self.endpoints:
                edp1 = copy(edp)
                url = urlparse(edp1.EndpointUrl)
                url = url._replace(netloc=sockname[0] + ":" + str(sockname[1]))
                edp1.EndpointUrl = url.geturl()
                edps.append(edp1)
            return edps
        return self.endpoints[:]

    def find_servers(self, params):
        if not params.ServerUris:
            return [desc.Server for desc in self._known_servers.values()]
        servers = []
        for serv in self._known_servers.values():
            serv_uri = serv.Server.ApplicationUri.split(":")
            for uri in params.ServerUris:
                uri = uri.split(":")
                if serv_uri[:len(uri)] == uri:
                    servers.append(serv.Server)
                    break
        return servers

    def register_server(self, server, conf=None):
        appdesc = ua.ApplicationDescription()
        appdesc.ApplicationUri = server.ServerUri
        appdesc.ProductUri = server.ProductUri
        # FIXME: select name from client locale
        appdesc.ApplicationName = server.ServerNames[0]
        appdesc.ApplicationType = server.ServerType
        appdesc.DiscoveryUrls = server.DiscoveryUrls
        # FIXME: select discovery uri using reachability from client network
        appdesc.GatewayServerUri = server.GatewayServerUri
        self._known_servers[server.ServerUri] = ServerDesc(appdesc, conf)

    def register_server2(self, params):
        return self.register_server(params.Server,
                                    params.DiscoveryConfiguration)

    def create_session(self, name, user=User.Anonymous, external=False):
        return InternalSession(self,
                               self.aspace,
                               self.subscription_service,
                               name,
                               user=user,
                               external=external)

    def enable_history_data_change(self,
                                   node,
                                   period=timedelta(days=7),
                                   count=0):
        """
        Set attribute Historizing of node to True and start storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(True))
        node.set_attr_bit(ua.AttributeIds.AccessLevel,
                          ua.AccessLevel.HistoryRead)
        node.set_attr_bit(ua.AttributeIds.UserAccessLevel,
                          ua.AccessLevel.HistoryRead)
        self.history_manager.historize_data_change(node, period, count)

    def disable_history_data_change(self, node):
        """
        Set attribute Historizing of node to False and stop storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(False))
        node.unset_attr_bit(ua.AttributeIds.AccessLevel,
                            ua.AccessLevel.HistoryRead)
        node.unset_attr_bit(ua.AttributeIds.UserAccessLevel,
                            ua.AccessLevel.HistoryRead)
        self.history_manager.dehistorize(node)

    def enable_history_event(self, source, period=timedelta(days=7), count=0):
        """
        Set attribute History Read of object events to True and start storing data for history
        """
        event_notifier = source.get_event_notifier()
        if ua.EventNotifier.SubscribeToEvents not in event_notifier:
            raise ua.UaError("Node does not generate events", event_notifier)

        if ua.EventNotifier.HistoryRead not in event_notifier:
            event_notifier.add(ua.EventNotifier.HistoryRead)
            source.set_event_notifier(event_notifier)

        self.history_manager.historize_event(source, period, count)

    def disable_history_event(self, source):
        """
        Set attribute History Read of node to False and stop storing data for history
        """
        source.unset_attr_bit(ua.AttributeIds.EventNotifier,
                              ua.EventNotifier.HistoryRead)
        self.history_manager.dehistorize(source)

    def subscribe_server_callback(self, event, handle):
        """
        Create a subscription from event to handle
        """
        self.server_callback_dispatcher.addListener(event, handle)

    def unsubscribe_server_callback(self, event, handle):
        """
        Remove a subscription from event to handle
        """
        self.server_callback_dispatcher.removeListener(event, handle)
Пример #27
0
 def get_node(self, nodeid):
     """
     Get a specific node using NodeId object or a string representing a NodeId
     """
     return Node(self.iserver.isession, nodeid)
Пример #28
0
class InternalServer(object):

    def __init__(self, cacheFile=None):
        self.logger = logging.getLogger(__name__)

        self.server_callback_dispatcher = CallbackDispatcher()

        self.endpoints = []
        self._channel_id_counter = 5
        self.allow_remote_admin = True
        self.disabled_clock = False  # for debugging we may want to disable clock that writes too much in log
        self._known_servers = {}  # used if we are a discovery server

        self.aspace = AddressSpace()
        self.attribute_service = AttributeService(self.aspace)
        self.view_service = ViewService(self.aspace)
        self.method_service = MethodService(self.aspace)
        self.node_mgt_service = NodeManagementService(self.aspace)

        if cacheFile and path.isfile(cacheFile):
            # import address space from shelve
            self.aspace.load(cacheFile)
        else:
            # import address space from code generated from xml
            standard_address_space.fill_address_space(self.node_mgt_service)
            # import address space directly from xml, this has preformance impact so disabled
            # importer = xmlimporter.XmlImporter(self.node_mgt_service)
            # importer.import_xml("/path/to/python-opcua/schemas/Opc.Ua.NodeSet2.xml", self)

            if cacheFile:
                self.aspace.dump(cacheFile)

        self.loop = utils.ThreadLoop()
        self.asyncio_transports = []
        self.subscription_service = SubscriptionService(self.loop, self.aspace)

        self.history_manager = HistoryManager(self)

        # create a session to use on server side
        self.isession = InternalSession(self, self.aspace, self.subscription_service, "Internal", user=User.Admin)
        self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
        uries = ["http://opcfoundation.org/UA/"]
        ns_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
        ns_node.set_value(uries)

    def load_address_space(self, path):
        self.aspace.load(path)

    def dump_address_space(self, path):
        self.aspace.dump(path)

    def start(self):
        self.logger.info("starting internal server")
        for edp in self.endpoints:
            self._known_servers[edp.Server.ApplicationUri] = ServerDesc(edp.Server)
        self.loop.start()
        Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_State)).set_value(0)
        Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_StartTime)).set_value(datetime.utcnow())
        if not self.disabled_clock:
            self._set_current_time()

    def stop(self):
        self.logger.info("stopping internal server")
        self.loop.stop()
        self.history_manager.stop()

    def _set_current_time(self):
        self.current_time_node.set_value(datetime.utcnow())
        self.loop.call_later(1, self._set_current_time)

    def get_new_channel_id(self):
        self._channel_id_counter += 1
        return self._channel_id_counter

    def add_endpoint(self, endpoint):
        self.endpoints.append(endpoint)

    def get_endpoints(self, params=None, sockname=None):
        self.logger.info("get endpoint")
        if sockname:
            # return to client the ip address it has access to
            edps = []
            for edp in self.endpoints:
                edp1 = copy(edp)
                url = urlparse(edp1.EndpointUrl)
                url = url._replace(netloc=sockname[0] + ":" + str(sockname[1]))
                edp1.EndpointUrl = url.geturl()
                edps.append(edp1)
            return edps
        return self.endpoints[:]

    def find_servers(self, params):
        if not params.ServerUris:
            return [desc.Server for desc in self._known_servers.values()]
        servers = []
        for serv in self._known_servers.values():
            serv_uri = serv.Server.ApplicationUri.split(":")
            for uri in params.ServerUris:
                uri = uri.split(":")
                if serv_uri[:len(uri)] == uri:
                    servers.append(serv.Server)
                    break
        return servers

    def register_server(self, server, conf=None):
        appdesc = ua.ApplicationDescription()
        appdesc.ApplicationUri = server.ServerUri
        appdesc.ProductUri = server.ProductUri
        # FIXME: select name from client locale
        appdesc.ApplicationName = server.ServerNames[0]
        appdesc.ApplicationType = server.ServerType
        appdesc.DiscoveryUrls = server.DiscoveryUrls
        # FIXME: select discovery uri using reachability from client network
        appdesc.GatewayServerUri = server.GatewayServerUri
        self._known_servers[server.ServerUri] = ServerDesc(appdesc, conf)

    def register_server2(self, params):
        return self.register_server(params.Server, params.DiscoveryConfiguration)

    def create_session(self, name, user=User.Anonymous, external=False):
        return InternalSession(self, self.aspace, self.subscription_service, name, user=user, external=external)

    def enable_history_data_change(self, node, period=timedelta(days=7), count=0):
        """
        Set attribute Historizing of node to True and start storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(True))
        node.set_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.HistoryRead)
        node.set_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.HistoryRead)
        self.history_manager.historize_data_change(node, period, count)

    def disable_history_data_change(self, node):
        """
        Set attribute Historizing of node to False and stop storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(False))
        node.unset_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.HistoryRead)
        node.unset_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.HistoryRead)
        self.history_manager.dehistorize(node)

    def enable_history_event(self, source, period=timedelta(days=7), count=0):
        """
        Set attribute History Read of object events to True and start storing data for history
        """
        event_notifier = source.get_event_notifier()
        if ua.EventNotifier.SubscribeToEvents not in event_notifier:
            raise ua.UaError("Node does not generate events", event_notifier)

        if ua.EventNotifier.HistoryRead not in event_notifier:
            event_notifier.append(ua.EventNotifier.HistoryRead)
            source.set_event_notifier(event_notifier)

        self.history_manager.historize_event(source, period, count)

    def disable_history_event(self, source):
        """
        Set attribute History Read of node to False and stop storing data for history
        """
        source.unset_attr_bit(ua.AttributeIds.EventNotifier, ua.EventNotifier.HistoryRead)
        self.history_manager.dehistorize(source)

    def subscribe_server_callback(self, event, handle):
        """
        Create a subscription from event to handle
        """
        self.server_callback_dispatcher.addListener(event, handle)

    def unsubscribe_server_callback(self, event, handle):
        """
        Remove a subscription from event to handle
        """
        self.server_callback_dispatcher.removeListener(event, handle)
Пример #29
0
class InternalServer(object):

    def __init__(self, cacheFile = None):
        self.logger = logging.getLogger(__name__)
        self.endpoints = []
        self._channel_id_counter = 5
        self.allow_remote_admin = True
        self.disabled_clock = False  # for debugging we may want to disable clock that writes too much in log
        self._known_servers = {}  # used if we are a discovery server

        self.aspace = AddressSpace()
        self.attribute_service = AttributeService(self.aspace)
        self.view_service = ViewService(self.aspace)
        self.method_service = MethodService(self.aspace)
        self.node_mgt_service = NodeManagementService(self.aspace)

        if cacheFile and path.isfile(cacheFile):
            # import address space from shelve
            self.aspace.load(cacheFile)
        else:
            # import address space from code generated from xml
            standard_address_space.fill_address_space(self.node_mgt_service)
            # import address space directly from xml, this has preformance impact so disabled
            #importer = xmlimporter.XmlImporter(self.node_mgt_service)
            #importer.import_xml("/path/to/python-opcua/schemas/Opc.Ua.NodeSet2.xml")

            if cacheFile:
                self.aspace.dump(cacheFile)

        self.loop = utils.ThreadLoop()
        self.asyncio_transports = []
        self.subscription_service = SubscriptionService(self.loop, self.aspace)

        self.history_manager = HistoryManager(self)

        # create a session to use on server side
        self.isession = InternalSession(self, self.aspace, self.subscription_service, "Internal", user=User.Admin)
        self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
        uries = ["http://opcfoundation.org/UA/"]
        ns_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
        ns_node.set_value(uries)

    def load_address_space(self, path):
        self.aspace.load(path)

    def dump_address_space(self, path):
        self.aspace.dump(path)

    def start(self):
        self.logger.info("starting internal server")
        for edp in self.endpoints:
            self._known_servers[edp.Server.ApplicationUri] = ServerDesc(edp.Server)
        self.loop.start()
        Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_State)).set_value(0)
        Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_StartTime)).set_value(datetime.utcnow())
        if not self.disabled_clock:
            self._set_current_time()

    def stop(self):
        self.logger.info("stopping internal server")
        self.loop.stop()
        self.history_manager.stop()

    def _set_current_time(self):
        self.current_time_node.set_value(datetime.utcnow())
        self.loop.call_later(1, self._set_current_time)

    def get_new_channel_id(self):
        self._channel_id_counter += 1
        return self._channel_id_counter

    def add_endpoint(self, endpoint):
        self.endpoints.append(endpoint)

    def get_endpoints(self, params=None, sockname=None):
        self.logger.info("get endpoint")
        if sockname:
            #return to client the ip address it has access to
            edps = []
            for edp in self.endpoints:
                edp1 = copy(edp)
                url = urlparse(edp1.EndpointUrl)
                url = url._replace(netloc=sockname[0] + ":" + str(sockname[1]))
                edp1.EndpointUrl = url.geturl()
                edps.append(edp1)
            return edps
        return self.endpoints[:]

    def find_servers(self, params):
        if not params.ServerUris:
            return [desc.Server for desc in self._known_servers.values()]
        servers = []
        for serv in self._known_servers.values():
            serv_uri = serv.Server.ApplicationUri.split(":")
            for uri in params.ServerUris:
                uri = uri.split(":")
                if serv_uri[:len(uri)] == uri:
                    servers.append(serv.Server)
                    break
        return servers

    def register_server(self, server, conf=None):
        appdesc = ua.ApplicationDescription()
        appdesc.ApplicationUri = server.ServerUri
        appdesc.ProductUri = server.ProductUri
        appdesc.ApplicationName = server.ServerNames[0]  # FIXME: select name from client locale
        appdesc.ApplicationType = server.ServerType
        appdesc.GatewayServerUri = server.GatewayServerUri
        appdesc.DiscoveryUrls = server.DiscoveryUrls  # FIXME: select discovery uri using reachability from client network
        self._known_servers[server.ServerUri] = ServerDesc(appdesc, conf)

    def register_server2(self, params):
        return self.register_server(params.Server, params.DiscoveryConfiguration)

    def create_session(self, name, user=User.Anonymous, external=False):
        return InternalSession(self, self.aspace, self.subscription_service, name, user=user, external=external)

    def enable_history_data_change(self, node, period=timedelta(days=7), count=0):
        """
        Set attribute Historizing of node to True and start storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(True))
        node.set_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.HistoryRead)
        node.set_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.HistoryRead)
        self.history_manager.historize_data_change(node, period, count)

    def disable_history_data_change(self, node):
        """
        Set attribute Historizing of node to False and stop storing data for history
        """
        node.set_attribute(ua.AttributeIds.Historizing, ua.DataValue(False))
        node.unset_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.HistoryRead)
        node.unset_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.HistoryRead)
        self.history_manager.dehistorize(node)

    def enable_history_event(self, source, period=timedelta(days=7)):
        """
        Set attribute History Read of object events to True and start storing data for history
        """
        # to historize events of an object, first check if object supports events
        source_event_notifier = source.get_attribute(ua.AttributeIds.EventNotifier)
        if source_event_notifier.Value.Value & 1 == 1:  # check bit 0
            # if it supports events, turn on bit 2 (enables history read)
            source.set_attr_bit(ua.AttributeIds.EventNotifier, 2)
            # send the object to history manager
            self.history_manager.historize_event(source, period)

    def disable_history_event(self, source):
        """
        Set attribute History Read of node to False and stop storing data for history
        """
        source.unset_attr_bit(ua.AttributeIds.EventNotifier, 2)
        self.history_manager.dehistorize(source)