Ejemplo n.º 1
1
def conn_opc():
    # OPCサーバに接続
    cl = Client("opc.tcp://192.168.10.5:51110/CogentDataHub/DataAccess")
    # クライアント証明書のapplication_uri
    cl.application_uri = "urn:desktop-i50i89m:Cogent DataHub"
    # policy設定
    print("secPolicy: " + str(secPolicy))
    if secPolicy != policies[0]:  # None以外の場合SecurityPolicyを設定
        mode = ua.MessageSecurityMode.SignAndEncrypt
        pc = getattr(security_policies, 'SecurityPolicy' + secPolicy)
        # 第二引数:クライアント証明書
        cl.set_security(
            pc, "/Users/watarium/PycharmProjects/opcua/OPCUA_CL.der",
            "/Users/watarium/PycharmProjects/opcua/OPCUAClient.pem",
            "/Users/watarium/PycharmProjects/opcua/OPCUAServer.der", mode)

    # 認証設定
    if setCert == certs[1]:  # user/pass
        cl.set_user("admin")
        cl.set_password("1234")
    elif setCert == certs[2]:  # certificate
        cl.load_private_key(
            "/Users/watarium/PycharmProjects/opcua/OPCUAClient.pem")
        cl.load_client_certificate(
            "/Users/watarium/PycharmProjects/opcua/OPCUA_CL.der")
    try:
        # 接続
        print("Policy: {0}, Certificate: {1}".format(secPolicy, setCert))
        print("---------------------Connection start-----------------------")
        cl.connect()
        sleep(5)
        # 情報取得
        ep = cl.get_endpoints()
        print(ep[0].Server.ApplicationUri)

        root = cl.get_root_node()
        print("Objects node is: ", root)

        print(cl.get_namespace_array())
        print(cl.get_namespace_index('urn:win-9hi38ajrojd:Cogent DataHub'))

        #これがうまくいかなかった(2019/06/27)
        #node = cl.get_node('ns=1;s=xxxxx')
        #print(node.get_value())

        #node.set_attribute(ua.AttributeIds.Value, 1)

        # 切断
        cl.disconnect()
        print("-------------------Connection Success!!!--------------------")

    except Exception as e:
        print("---------------------Connection Faild!!---------------------")
        print(e)
        cl.disconnect()
Ejemplo n.º 2
0
 def test_basic256_encrypt_feil(self):
     # FIXME: how to make it feil???
     clt = Client(self.uri_crypto)
     with self.assertRaises(ua.UaError):
         clt.set_security(security_policies.SecurityPolicyBasic256,
                          'examples/certificate-example.der',
                          'examples/private-key-example.pem', None,
                          ua.MessageSecurityMode.None_)
 def test_basic256_encrypt_feil(self):
     # FIXME: how to make it feil???
     clt = Client(self.uri_crypto)
     with self.assertRaises(ua.UaError):
         clt.set_security(security_policies.SecurityPolicyBasic256,
                          'examples/certificate-example.der',
                          'examples/private-key-example.pem',
                          None,
                          ua.MessageSecurityMode.None_
                          )
Ejemplo n.º 4
0
 def test_basic256_encrypt_success(self):
     clt = Client(self.uri_crypto)
     try:
         clt.set_security(security_policies.SecurityPolicyBasic256,
                          'examples/certificate-example.der',
                          'examples/private-key-example.pem', None,
                          ua.MessageSecurityMode.SignAndEncrypt)
         clt.connect()
         self.assertTrue(clt.get_objects_node().get_children())
     finally:
         clt.disconnect()
 def test_basic256_encrypt_success(self):
     clt = Client(self.uri_crypto)
     try:
         clt.set_security(security_policies.SecurityPolicyBasic256,
                          'examples/certificate-example.der',
                          'examples/private-key-example.pem',
                          None,
                          ua.MessageSecurityMode.SignAndEncrypt
                          )
         clt.connect()
         self.assertTrue(clt.get_objects_node().get_children())
     finally:
         clt.disconnect()
Ejemplo n.º 6
0
class UaClient(object):
    """
    OPC-Ua client specialized for the need of GUI client
    return exactly what GUI needs, no customization possible
    """
    def __init__(self):
        self.settings = QSettings()
        self.client = None
        self._connected = False
        self._datachange_sub = None
        self._event_sub = None
        self._subs_dc = {}
        self._subs_ev = {}
        self.security_mode = None
        self.security_policy = None
        self.certificate_path = None
        self.private_key_path = None

    @staticmethod
    def get_endpoints(uri):
        client = Client(uri, timeout=2)
        client.connect_and_get_server_endpoints()
        edps = client.connect_and_get_server_endpoints()
        for i, ep in enumerate(edps, start=1):
            logger.info('Endpoint %s:', i)
            for (n, v) in endpoint_to_strings(ep):
                logger.info('  %s: %s', n, v)
            logger.info('')
        return edps

    def load_security_settings(self, uri):
        self.security_mode = None
        self.security_policy = None
        self.certificate_path = None
        self.private_key_path = None

        mysettings = self.settings.value("security_settings", None)
        if mysettings is None:
            return
        if uri in mysettings:
            mode, policy, cert, key = mysettings[uri]
            self.security_mode = mode
            self.security_policy = policy
            self.certificate_path = cert
            self.private_key_path = key

    def save_security_settings(self, uri):
        mysettings = self.settings.value("security_settings", None)
        if mysettings is None:
            mysettings = {}
        mysettings[uri] = [
            self.security_mode, self.security_policy, self.certificate_path,
            self.private_key_path
        ]
        self.settings.setValue("security_settings", mysettings)

    def get_node(self, nodeid):
        return self.client.get_node(nodeid)

    def connect(self, uri):
        self.disconnect()
        logger.info("Connecting to %s with parameters %s, %s, %s, %s", uri,
                    self.security_mode, self.security_policy,
                    self.certificate_path, self.private_key_path)
        self.client = Client(uri)
        if self.security_mode is not None and self.security_policy is not None:
            self.client.set_security(getattr(
                crypto.security_policies,
                'SecurityPolicy' + self.security_policy),
                                     self.certificate_path,
                                     self.private_key_path,
                                     mode=getattr(ua.MessageSecurityMode,
                                                  self.security_mode))
        self.client.connect()
        self._connected = True
        self.save_security_settings(uri)

    def disconnect(self):
        if self._connected:
            print("Disconnecting from server")
            self._subs_dc = {}
            self._subs_ev = {}
            self._connected = False
            self.client.disconnect()
            self.client = None

    def subscribe_datachange(self, node, handler):
        if not self._datachange_sub:
            self._datachange_sub = self.client.create_subscription(
                500, handler)
        handle = self._datachange_sub.subscribe_data_change(node)
        self._subs_dc[node.nodeid] = handle
        return handle

    def unsubscribe_datachange(self, node):
        self._datachange_sub.unsubscribe(self._subs_dc[node.nodeid])

    def subscribe_events(self, node, handler):
        if not self._event_sub:
            print("subscirbing with handler: ", handler, dir(handler))
            self._event_sub = self.client.create_subscription(500, handler)
        handle = self._event_sub.subscribe_events(node)
        self._subs_ev[node.nodeid] = handle
        return handle

    def unsubscribe_events(self, node):
        self._event_sub.unsubscribe(self._subs_ev[node.nodeid])

    def get_node_attrs(self, node):
        if not isinstance(node, Node):
            node = self.client.get_node(node)
        attrs = node.get_attributes([
            ua.AttributeIds.DisplayName, ua.AttributeIds.BrowseName,
            ua.AttributeIds.NodeId
        ])
        return node, [attr.Value.Value.to_string() for attr in attrs]

    @staticmethod
    def get_children(node):
        descs = node.get_children_descriptions()
        descs.sort(key=lambda x: x.BrowseName)
        return descs
class ClientController:
    def __init__(self, view):
        self.ui = view
        self.client = None
        self._connected = False
        self.address_list = ["opc.tcp://10.42.0.2:4840/OPCUAproject"]
        self.security_mode = None
        self.security_policy = None
        self.certificate_path = None
        self.private_key_path = None
        self.ui.closeEvent = self.closeEvent

        for addr in self.address_list:
            self.ui.addressComboBox.addItem(addr)

        self.tree_ui = TreeWidget(self.ui.treeView)
        self.attrs_ui = AttrsWidget(self.ui.attrView)
        #self.refs_ui = RefsWidget(self.ui.refView)
        self.subscription_window = SubscriptionWindow()
        self.log_window = LogWindow()
        self.datachange_ui = DataChangeUI(self, self.subscription_window)

        #self.ui.treeView.selectionModel().selectionChanged.connect(lambda sel: self.show_refs(sel))
        self.ui.treeView.selectionModel().selectionChanged.connect(
            lambda sel: self.show_attrs(sel))

        # self.ui.endpointsButton.clicked.connect(lambda : self.get_endpoints())
        # self.ui.connSettingsButton.clicked.connect(lambda : self.show_connection_dialog())
        # self.ui.connectButton.clicked.connect(lambda : self.connect())
        # self.ui.disconnectButton.clicked.connect(lambda: self.disconnect())
        # self.ui.readButton.clicked.connect(lambda : self.read_value())
        # self.ui.writeButton.clicked.connect(lambda : self.show_write_dialog())
        # self.ui.showReferencesButton.clicked.connect(lambda : self.show_refs_dialog())
        # self.ui.showSubscriptionsButton.clicked.connect(lambda : self.show_subs_dialog())
        # self.ui.showLogsButton.clicked.connect(lambda : self.show_logs_dialog())

        self.ui.actionQuery_endpoints.triggered.connect(
            lambda: self.get_endpoints())
        self.ui.actionConnection_settings.triggered.connect(
            lambda: self.show_connection_dialog())
        self.ui.actionConnect.triggered.connect(lambda: self.connect())
        self.ui.actionDisconnect.triggered.connect(lambda: self.disconnect())
        self.ui.actionRead.triggered.connect(lambda: self.read_value())
        self.ui.actionWrite.triggered.connect(lambda: self.show_write_dialog())
        self.ui.actionReferences.triggered.connect(
            lambda: self.show_refs_dialog())
        self.ui.actionSubscriptions.triggered.connect(
            lambda: self.show_subs_dialog())
        self.ui.actionLogs.triggered.connect(lambda: self.show_logs_dialog())

    def closeEvent(self, event):
        self.disconnect()

    def get_endpoints(self):

        uri = self.ui.addressComboBox.currentText()
        client = Client(uri, timeout=2)
        try:
            edps = client.connect_and_get_server_endpoints()
            for i, ep in enumerate(edps, start=1):
                self.log_window.ui.logTextEdit.append('Endpoint %s:' % i)
                for (n, v) in endpoint_to_strings(ep):
                    self.log_window.ui.logTextEdit.append('  %s: %s' % (n, v))
                self.log_window.ui.logTextEdit.append('')
        except Exception as ex:
            self.log_window.ui.logTextEdit.append(str(ex))
            raise
        return edps

    def show_connection_dialog(self):
        dia = ConnectionDialog(self, self.ui.addressComboBox.currentText())
        #dia.security_mode = self.security_mode
        #dia.security_policy = self.security_policy
        #dia.certificate_path = self.certificate_path
        #dia.private_key_path = self.private_key_path
        ret = dia.exec_()
        if ret:
            #self.security_mode = dia.security_mode
            #self.security_policy = dia.security_policy
            self.certificate_path = dia.certificate_path
            self.private_key_path = dia.private_key_path

    def show_write_dialog(self):
        node = self.get_current_node()
        if node.get_node_class() == ua.NodeClass.Variable:
            dia = WriteDialog(node, self.log_window.ui.logTextEdit)
            ret = dia.exec_()
        else:
            self.log_window.ui.logTextEdit.append(
                "Only Variable can be written")

    def connect(self):
        self.disconnect()
        uri = self.ui.addressComboBox.currentText()
        self.log_window.ui.logTextEdit.append(
            "Connecting to %s with parameters %s, %s, %s, %s" %
            (uri, self.security_mode, self.security_policy,
             self.certificate_path, self.private_key_path))
        try:
            self.client = Client(uri)
            self.client.application_uri = "urn:opcua:python:client"
            if self.security_mode is not None and self.security_policy is not None:
                self.client.set_security(getattr(
                    crypto.security_policies,
                    'SecurityPolicy' + self.security_policy),
                                         self.certificate_path,
                                         self.private_key_path,
                                         mode=getattr(ua.MessageSecurityMode,
                                                      self.security_mode))
            self.client.connect()
            self._connected = True
        except Exception as ex:
            self.log_window.ui.logTextEdit.append(str(ex))
        try:
            self.client.uaclient._uasocket._thread.isAlive()
            self.tree_ui.set_root_node(self.client.get_root_node())
            self.ui.treeView.setFocus()
        except Exception as ex:
            print("Connection error")

    def _reset(self):
        self.client = None
        self._connected = False
        self.datachange_ui._datachange_sub = {}
        self.datachange_ui._subs_dc = {}

    def disconnect(self):
        try:
            if self._connected:
                self.log_window.ui.logTextEdit.append(
                    "Disconnecting from server")
                self._connected = False
            if self.client:
                if self.datachange_ui._datachange_sub:
                    sub_ids = list(self.datachange_ui._datachange_sub.keys())
                    for sub_id in sub_ids:
                        self.datachange_ui.delete_subscription(sub_id)
                self.client.disconnect()
                self._reset()
        except Exception as ex:
            self.log_window.ui.logTextEdit.append(str(ex))
        finally:
            self.tree_ui.clear()
            #self.refs_ui.clear()
            self.attrs_ui.clear()
            self.datachange_ui.clear()

    def show_attrs(self, selection):
        if isinstance(selection, QItemSelection):
            if not selection.indexes():  # no selection
                return

        node = self.get_current_node()
        if node:
            self.attrs_ui.show_attrs(node)

    '''def show_refs(self, selection):
        if isinstance(selection, QItemSelection):
            if not selection.indexes(): # no selection
                return
        node = self.get_current_node()
        if node:
            self.refs_ui.show_refs(node)'''

    def show_refs_dialog(self):
        self.references_window = ReferencesWindow(self)
        self.references_window.show()

    def show_subs_dialog(self):
        self.subscription_window.show()

    def show_logs_dialog(self):
        self.log_window.show()

    def get_current_node(self, idx=None):
        return self.tree_ui.get_current_node(idx)

    def read_value(self):
        node = self.get_current_node()
        try:
            self.attrs_ui.show_attrs(node)
            if node.get_node_class() == ua.NodeClass.Variable:
                value = node.get_value()
                data = "Node: %s, Value: %s" % (node.get_browse_name(), value)
                self.log_window.ui.logTextEdit.append(data)
        except Exception as ex:
            self.log_window.ui.logTextEdit.append(str(ex))
Ejemplo n.º 8
0
import sys
sys.path.insert(0, "..")

from opcua import Client, ua
from opcua.crypto import security_policies

if __name__ == "__main__":

    client = Client("opc.tcp://*****:*****@localhost:4840/freeopcua/server/") #connect using a user
    try:
        client.connect()

        # Client has a few methods to get proxy to UA nodes that should always be in address space such as Root or Objects
        root = client.get_root_node()
        print("Objects node is: ", root)

        # Node objects have methods to read and write node attributes as well as browse or populate address space
        print("Children of root are: ", root.get_children())

        # get a specific node knowing its node id
        #var = client.get_node(ua.NodeId(1002, 2))
        #var = client.get_node("ns=3;i=2002")
        #print(var)
        policy = uasecurity.get_securitypolicy()
        if server_cert == None:
            print(
                'tls is enabled, but server cert is missing with current configuration'
            )
            sys.exit(-1)
        if private_key == None:
            print(
                'tls is enabled, but private key is missing with current configuration'
            )
            sys.exit(-1)
        #client.load_client_certificate(server_cert)
        #client.load_private_key(private_key)
        client.set_security(getattr(crypto.security_policies,
                                    'SecurityPolicy' + policy),
                            server_cert,
                            private_key,
                            mode=getattr(ua.MessageSecurityMode, mode))

    try:
        client.connect()

        # Client has a few methods to get proxy to UA nodes that should always be in address space such as Root or Objects
        root = client.get_root_node()
        print("Root node is: ", root)
        objects = client.get_objects_node()
        print("Objects node is: ", objects)

        # Node objects have methods to read and write node attributes as well as browse or populate address space
        print("Children of root are: ", root.get_children())
Ejemplo n.º 10
0
class UaClient(object):
    """
    OPC-Ua client specialized for the need of GUI client
    return exactly what GUI needs, no customization possible
    """

    def __init__(self):
        self.settings = QSettings()
        self.client = None
        self._connected = False
        self._datachange_sub = None
        self._event_sub = None
        self._subs_dc = {}
        self._subs_ev = {}
        self.security_mode = None
        self.security_policy = None
        self.certificate_path = None
        self.private_key_path = None

    def _reset(self):
        self.client = None
        self._connected = False
        self._datachange_sub = None
        self._event_sub = None
        self._subs_dc = {}
        self._subs_ev = {}

    @staticmethod
    def get_endpoints(uri):
        client = Client(uri, timeout=2)
        client.connect_and_get_server_endpoints()
        edps = client.connect_and_get_server_endpoints()
        for i, ep in enumerate(edps, start=1):
            logger.info('Endpoint %s:', i)
            for (n, v) in endpoint_to_strings(ep):
                logger.info('  %s: %s', n, v)
            logger.info('')
        return edps

    def load_security_settings(self, uri):
        self.security_mode = None
        self.security_policy = None
        self.certificate_path = None
        self.private_key_path = None

        mysettings = self.settings.value("security_settings", None)
        if mysettings is None:
            return
        if uri in mysettings:
            mode, policy, cert, key = mysettings[uri]
            self.security_mode = mode
            self.security_policy = policy
            self.certificate_path = cert
            self.private_key_path = key

    def save_security_settings(self, uri):
        mysettings = self.settings.value("security_settings", None)
        if mysettings is None:
            mysettings = {}
        mysettings[uri] = [self.security_mode,
                           self.security_policy,
                           self.certificate_path,
                           self.private_key_path]
        self.settings.setValue("security_settings", mysettings)

    def get_node(self, nodeid):
        return self.client.get_node(nodeid)
    
    def connect(self, uri):
        self.disconnect()
        logger.info("Connecting to %s with parameters %s, %s, %s, %s", uri, self.security_mode, self.security_policy, self.certificate_path, self.private_key_path)
        self.client = Client(uri)
        if self.security_mode is not None and self.security_policy is not None:
            self.client.set_security(
                getattr(crypto.security_policies, 'SecurityPolicy' + self.security_policy),
                self.certificate_path,
                self.private_key_path,
                mode=getattr(ua.MessageSecurityMode, self.security_mode)
            )
        self.client.connect()
        self._connected = True
        self.save_security_settings(uri)

    def disconnect(self):
        if self._connected:
            print("Disconnecting from server")
            self._connected = False
            try:
                self.client.disconnect()
            finally:
                self._reset()

    def subscribe_datachange(self, node, handler):
        if not self._datachange_sub:
            self._datachange_sub = self.client.create_subscription(500, handler)
        handle = self._datachange_sub.subscribe_data_change(node)
        self._subs_dc[node.nodeid] = handle
        return handle

    def unsubscribe_datachange(self, node):
        self._datachange_sub.unsubscribe(self._subs_dc[node.nodeid])

    def subscribe_events(self, node, handler):
        if not self._event_sub:
            print("subscirbing with handler: ", handler, dir(handler))
            self._event_sub = self.client.create_subscription(500, handler)
        handle = self._event_sub.subscribe_events(node)
        self._subs_ev[node.nodeid] = handle
        return handle

    def unsubscribe_events(self, node):
        self._event_sub.unsubscribe(self._subs_ev[node.nodeid])

    def get_node_attrs(self, node):
        if not isinstance(node, Node):
            node = self.client.get_node(node)
        attrs = node.get_attributes([ua.AttributeIds.DisplayName, ua.AttributeIds.BrowseName, ua.AttributeIds.NodeId])
        return node, [attr.Value.Value.to_string() for attr in attrs]

    @staticmethod
    def get_children(node):
        descs = node.get_children_descriptions()
        descs.sort(key=lambda x: x.BrowseName)
        return descs
Ejemplo n.º 11
0
class OpcUaClient:
    def __init__(self):
        self.settings = QSettings()
        self.client = None
        self._connected = False
        # Subscriptions
        self._datachange_subs = [
        ]  # list of tuples with subscription and dict with nodeids as keys and handles as values
        self.publishingEnabled = True  # Not necessary
        self.requestedPublishingInterval = 500
        self.publishingIntervals = []
        self.requestedMaxKeepAliveCount = 3000
        self.requestedLifetimeCount = 10000
        self.maxNotificationsPerPublish = 10000
        self.priority = 0
        # Monitored items
        self._client_handle = 0
        self.samplingInterval = self.requestedPublishingInterval
        self.queueSize = 0
        self.discardOldest = True
        self.dataChangeFilter = False
        self.dataChangeTrigger = ua.DataChangeTrigger.StatusValue  # 0 = Status, 1 = StatusValue, 2 = StatusValueTimestamp
        self.deadbandType = ua.DeadbandType.None_  # 0 = None, 1 = Absolute, 2 = Percent
        self.deadbandValue = 0
        self.numericTypes = [
            ua.VariantType.SByte, ua.VariantType.Byte, ua.VariantType.Int16,
            ua.VariantType.UInt16, ua.VariantType.Int32, ua.VariantType.UInt32,
            ua.VariantType.Int64, ua.VariantType.UInt64, ua.VariantType.Float,
            ua.VariantType.Double
        ]
        # Security
        self.security_mode = "None"
        self.security_policy = "None"
        self.certificate_path = ""
        self.private_key_path = ""
        # Custom objects
        self.custom_objects = {}
        self.known_custom_types = [
            "BoilerType", "MotorType", "ValveType", "TempSensorType",
            "LevelIndicatorType", "FlowSensorType"
        ]

    def _reset(self):
        self.client = None
        self._connected = False
        self._datachange_subs = []
        self.custom_objects = {}

    @staticmethod
    def get_endpoints(uri):
        # Create client object and associate url of the server
        client = Client(uri)
        # Connect, ask server for endpoints, and disconnect
        edps = client.connect_and_get_server_endpoints()
        for i, ep in enumerate(edps, start=1):
            logger.info('Endpoint %s:', i)
            for n, v in endpoint_to_strings(ep):
                logger.info('  %s: %s', n, v)
            logger.info('')
        return edps

    def connect(self, uri):
        logger.info("Connecting to %s with parameters %s, %s, %s, %s", uri,
                    self.security_mode, self.security_policy,
                    self.certificate_path, self.private_key_path)
        # Create client object and associate url of the server
        self.client = Client(uri)
        if self.security_mode != "None" and self.security_policy != "None":
            # Set SecureConnection mode
            self.client.set_security(getattr(
                crypto.security_policies,
                'SecurityPolicy' + self.security_policy),
                                     self.certificate_path,
                                     self.private_key_path,
                                     mode=getattr(ua.MessageSecurityMode,
                                                  self.security_mode))
            # self.client.secure_channel_timeout = 10000  # Timeout for the secure channel
            # self.client.session_timeout = 10000  # Timeout for the session
        self.client.application_uri = "urn:example.org:OpcUa:python-client"
        # Open secure channel, create and activate session
        self.client.connect()
        self._connected = True
        self.save_security_settings(uri)

    def disconnect(self):
        if self._connected:
            print("Disconnecting from server")
            self._connected = False
            try:
                # Close session and secure channel
                self.client.disconnect()
            finally:
                self._reset()

    def create_subscription(self, handler):
        # Set subscription parameters
        params = ua.CreateSubscriptionParameters()
        params.PublishingEnabled = self.publishingEnabled
        params.RequestedPublishingInterval = self.requestedPublishingInterval
        params.RequestedMaxKeepAliveCount = self.requestedMaxKeepAliveCount
        params.RequestedLifetimeCount = self.requestedLifetimeCount
        params.MaxNotificationsPerPublish = self.maxNotificationsPerPublish
        params.Priority = self.priority
        datachange_sub = self.client.create_subscription(params, handler)
        self._datachange_subs.append((datachange_sub, {}))
        self.publishingIntervals.append(self.requestedPublishingInterval)

    def create_monitored_items(self, nodes, index):
        monitored_items = []
        if not isinstance(nodes, list):
            nodes = [nodes]
        for node in nodes:
            # Set item to monitor
            rv = ua.ReadValueId()
            rv.NodeId = node.nodeid
            rv.AttributeId = ua.AttributeIds.Value
            # Set monitoring parameters
            mparams = ua.MonitoringParameters()
            self._client_handle += 1
            mparams.ClientHandle = self._client_handle
            mparams.SamplingInterval = self.samplingInterval
            mparams.QueueSize = self.queueSize
            mparams.DiscardOldest = self.discardOldest
            # Create monitored item filter
            if self.dataChangeFilter:
                mfilter = ua.DataChangeFilter()
                mfilter.Trigger = ua.DataChangeTrigger(self.dataChangeTrigger)
                if self.deadbandType == ua.DeadbandType.Absolute:
                    if node.get_data_value(
                    ).Value.VariantType in self.numericTypes:
                        mfilter.DeadbandType = self.deadbandType
                        mfilter.DeadbandValue = self.deadbandValue  # absolute float value or from 0 to 100 for percentage deadband
                    else:
                        self.deadbandType = ua.DeadbandType.None_
                        mfilter.DeadbandType = self.deadbandType
                elif self.deadbandType == ua.DeadbandType.Percent:
                    has_EURange = False
                    if node.get_type_definition(
                    ).Identifier == ua.object_ids.ObjectIds.AnalogItemType:
                        # Get node properties
                        descriptions = node.get_references(
                            ua.ObjectIds.HasProperty,
                            ua.BrowseDirection.Forward, ua.NodeClass.Variable,
                            False)
                        for desc in descriptions:
                            if desc.BrowseName.Name == "EURange" and self.get_node(
                                    desc.NodeId).get_value() is not None:
                                has_EURange = True
                    if has_EURange:
                        mfilter.DeadbandType = self.deadbandType
                        mfilter.DeadbandValue = self.deadbandValue  # absolute float value or from 0 to 100 for percentage deadband
                    else:
                        self.deadbandType = ua.DeadbandType.None_
                        mfilter.DeadbandType = self.deadbandType
            else:
                mfilter = None
            mparams.Filter = mfilter
            # Create monitored item request
            mir = ua.MonitoredItemCreateRequest()
            mir.ItemToMonitor = rv
            mir.MonitoringMode = ua.MonitoringMode.Reporting
            mir.RequestedParameters = mparams
            # Append to list
            monitored_items.append(mir)
        sub, monitored_items_handles = self._datachange_subs[index]
        handles = sub.create_monitored_items(monitored_items)
        for i in range(len(handles)):
            handle = handles[i]
            if type(handle) == ua.StatusCode:
                handle.check()
            monitored_items_handles[nodes[i].nodeid] = handle

    def remove_monitored_item(self, node, index):
        # Unsubscribe to data change using the handle stored while creating monitored item
        # This will remove the corresponding monitored item from subscription
        sub, monitored_items_handles = self._datachange_subs[index]
        sub.unsubscribe(monitored_items_handles[node.nodeid])
        del monitored_items_handles[node.nodeid]

    def delete_subscription(self, index):
        sub, monitored_items_handles = self._datachange_subs[index]
        # Remove all monitored items from subscription
        for handle in monitored_items_handles.values():
            sub.unsubscribe(handle)
        # Delete subscription on server
        sub.delete()
        del self._datachange_subs[index]
        del self.publishingIntervals[index]

    def delete_subscriptions(self):
        for sub, monitored_items_handles in self._datachange_subs:
            # Remove all monitored items from subscription
            for handle in monitored_items_handles.values():
                sub.unsubscribe(handle)
            # Delete subscription on server
            sub.delete()

    def get_node(self, nodeid):
        # Get node using NodeId object or a string representing a NodeId
        return self.client.get_node(nodeid)

    def load_custom_objects(self):
        """
        Function that populates custom_objects dictionary,
        with nodeids of custom objects as keys and
        string representations of their types as values
        """
        # Get Objects folder
        objects_folder = self.client.get_objects_node()
        # Get Organize references to objects inside folder
        descriptions = objects_folder.get_references(
            ua.ObjectIds.Organizes, ua.BrowseDirection.Forward,
            ua.NodeClass.Object, False)
        for desc in descriptions:
            if desc.TypeDefinition == ua.TwoByteNodeId(
                    ua.ObjectIds.FolderType):
                folder_name = desc.BrowseName.Name
                if folder_name == "Actuators" or folder_name == "Sensors":
                    # Get folder node
                    folder_node = self.get_node(desc.NodeId)
                    # Get all objects inside folder
                    objects = folder_node.get_children(ua.ObjectIds.Organizes,
                                                       ua.NodeClass.Object)
                    for obj in objects:
                        # Get HasTypeDefinition references
                        ref = obj.get_references(
                            ua.ObjectIds.HasTypeDefinition,
                            ua.BrowseDirection.Forward,
                            ua.NodeClass.ObjectType, False)[0]
                        custom_type = ref.BrowseName.Name
                        if custom_type in self.known_custom_types:
                            self.custom_objects[obj.nodeid] = custom_type

    def load_security_settings(self, uri):
        mysettings = self.settings.value("security_settings", None)
        if mysettings is not None and uri in mysettings:
            mode, policy, cert, key = mysettings[uri]
            self.security_mode = mode
            self.security_policy = policy
            self.certificate_path = cert
            self.private_key_path = key
        else:
            self.security_mode = "None"
            self.security_policy = "None"
            self.certificate_path = ""
            self.private_key_path = ""

    def save_security_settings(self, uri):
        mysettings = self.settings.value("security_settings", None)
        if mysettings is None:
            mysettings = {}
        mysettings[uri] = [
            self.security_mode, self.security_policy, self.certificate_path,
            self.private_key_path
        ]
        self.settings.setValue("security_settings", mysettings)

    def load_subscription_settings(self, uri):
        mysettings = self.settings.value("subscription_settings", None)
        if mysettings is not None and uri in mysettings:
            pub_interval, max_keepalive_count, lifetime_count, max_notifications, priority = mysettings[
                uri]
            self.requestedPublishingInterval = pub_interval
            self.requestedMaxKeepAliveCount = max_keepalive_count
            self.requestedLifetimeCount = lifetime_count
            self.maxNotificationsPerPublish = max_notifications
            self.priority = priority
        else:
            self.requestedPublishingInterval = 500
            self.requestedMaxKeepAliveCount = 3000
            self.requestedLifetimeCount = 10000
            self.maxNotificationsPerPublish = 10000
            self.priority = 0

    def save_subscription_settings(self, uri):
        mysettings = self.settings.value("subscription_settings", None)
        if mysettings is None:
            mysettings = {}
        mysettings[uri] = [
            self.requestedPublishingInterval, self.requestedMaxKeepAliveCount,
            self.requestedLifetimeCount, self.maxNotificationsPerPublish,
            self.priority
        ]
        self.settings.setValue("subscription_settings", mysettings)

    def load_monitored_items_settings(self, uri):
        mysettings = self.settings.value("monitored_items_settings", None)
        if mysettings is not None and uri in mysettings:
            sampling_interval, queue_size, discard_oldest, data_change_filter, trigger, deadband_type, deadband_value = mysettings[
                uri]
            self.samplingInterval = sampling_interval
            self.queueSize = queue_size
            self.discardOldest = discard_oldest
            self.dataChangeFilter = data_change_filter
            self.dataChangeTrigger = trigger
            self.deadbandType = deadband_type
            self.deadbandValue = deadband_value
        else:
            self.samplingInterval = 250
            self.queueSize = 0
            self.discardOldest = True
            self.dataChangeFilter = False
            self.dataChangeTrigger = ua.DataChangeTrigger.StatusValue
            self.deadbandType = ua.DeadbandType.None_
            self.deadbandValue = 0

    def save_monitored_items_settings(self, uri):
        mysettings = self.settings.value("monitored_items_settings", None)
        if mysettings is None:
            mysettings = {}
        mysettings[uri] = [
            self.samplingInterval, self.queueSize, self.discardOldest,
            self.dataChangeFilter, self.dataChangeTrigger, self.deadbandType,
            self.deadbandValue
        ]
        self.settings.setValue("monitored_items_settings", mysettings)
class OpcUaConnector(object):
    """The connector to OPC UA. This class manages all comms with DCS"""
    def __init__(self, app=None):
        self.app = app
        self._client = None

        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        config = current_app.config
        if config is not None:
            self._server_address = config['OPC_SERVER_ADDRESS']
            self._client_name = config['OPC_CLIENT_NAME']
            self._client_description = config['OPC_CLIENT_DESCRIPTION']
            self._certificate_path = config['OPC_CERTIFICATE_PATH']
            self._private_key_path = config['OPC_PRIVATE_KEY_PATH']
            self._application_uri = config['OPC_APPLICATION_URI']
            self._max_time_out = config['OPC_MAX_TIME_OUT']
            self._client = None

    def _connect(self):
        self._client = Client(self._server_address, self._max_time_out)
        if (self._certificate_path is not None and self._private_key_path is not None):
            self._client.set_security(
                getattr(
                    crypto.security_policies, 'SecurityPolicy' + 'Basic256'),
                self._certificate_path, self._private_key_path,
                mode=getattr(ua.MessageSecurityMode, 'SignAndEncrypt'))
            self._client.application_uri = self._application_uri

        self._client.name = self._client_name
        self._client.description = self._client_description
        self._client.connect()
        # return _client

    def ensure_connection(self):
        if self._client is None:
            self._connect()

    def set_value(self, node_id, value_type_identifier, desired_value):
        """Set value on the OPC UA server. example parameters:
            Node_id=ns=4;s=node_name,
            value_type_identifier 0-25

            see: https://github.com/FreeOpcUa/python-opcua/blob/master/opcua/ua/uatypes.py#L619),
            desired_value could be any value that matches the UA Type
        """
        parsed_value, opc_type = map_to_opcua_type_and_value(
            value_type_identifier, desired_value)
        self.ensure_connection()
        node = self._client.get_node(node_id)
        dv = ua.DataValue(ua.Variant(parsed_value, opc_type))
        node.set_value(dv)

    def get_value(self, node_id):
        self.ensure_connection()
        node = self._client.get_node(node_id)
        value = node.get_value()
        return str(value)

    def disconnect(self):
        if self._client is not None:
            self._client.disconnect()