Ejemplo n.º 1
0
def uasubscribe():
    parser = argparse.ArgumentParser(description="Subscribe to a node and print results")
    add_common_args(parser)
    parser.add_argument("-t",
                        "--eventtype",
                        dest="eventtype",
                        default="datachange",
                        choices=['datachange', 'event'],
                        help="Event type to subscribe to")

    args = parse_args(parser, requirenodeid=False)
    if args.eventtype == "datachange":
        _require_nodeid(parser, args)
    else:
        # FIXME: this is broken, someone may have written i=84 on purpose
        if args.nodeid == "i=84" and args.path == "":
            args.nodeid = "i=2253"

    client = Client(args.url, timeout=args.timeout)
    client.set_security_string(args.security)
    client.connect()
    try:
        node = get_node(client, args)
        handler = SubHandler()
        sub = client.create_subscription(500, handler)
        if args.eventtype == "datachange":
            sub.subscribe_data_change(node)
        else:
            sub.subscribe_events(node)
        embed()
    finally:
        client.disconnect()
    sys.exit(0)
    print(args)
Ejemplo n.º 2
0
class Plant(threading.Thread):
    def __init__(self, ip):
        super().__init__()
        self.client = Client(ip)
        self.objects = self.assign_object()
        self.heights = {'h1': 0, 'h2': 0, 'h3': 0, 'h4': 0}
        self.voltages = {'u1': 0, 'u2': 0}
        self._u = [0, 0]
        self.sample_time = 0.001
        self.daemon = True     ## Que termine de medir cuando termine el programa (debug)
        self.event_measure = threading.Event()

    def assign_object(self):
        self.client.connect()
        return self.client.get_objects_node()

    def get_valve_value(self):
        for i in range(1, 3):
            node = self.objects.get_child(['2:Proceso_Tanques', '2:Valvulas', f'2:Valvula{i}', '2:u'])
            self.voltages[f'u{i}'] = node.get_value() #NoneType object does not support item assig

    def get_heights(self):
        for i in range(1, 5):
            node = self.objects.get_child(['2:Proceso_Tanques', '2:Tanques', f'2:Tanque{i}', '2:h'])
            self.heights[f'h{i}'] = node.get_value() #NoneType object does not support item assig

    def suscribe_alarm(self):
        alarm = self.objects.get_child(['2:Proceso_Tanques', '2:Alarmas', f'2:Alarma_nivel'])
        handler = SubHandler()
        sub = self.client.create_subscription(500, handler)
        handle = sub.subscribe_events(alarm)
        time.sleep(0.1)

    def assign_valve_value(self):
        u1 = self.objects.get_child(['2:Proceso_Tanques', '2:Valvulas', f'2:Valvula1', '2:u'])
        u2 = self.objects.get_child(['2:Proceso_Tanques', '2:Valvulas', f'2:Valvula2', '2:u'])
        u1.set_value(self.u[0])
        u2.set_value(self.u[1])

    @property
    def u(self):
        return self._u

    @u.setter
    def u(self, value):
        if not None in value:
            self._u = list(value)
        else:
            self._u = self._u


    def run(self):
        self.suscribe_alarm()
        while True:
            if sum(self.u) > 0:
                self.assign_valve_value()
                self.u = [0, 0]
            self.event_measure.set() ## Revisar esto porque no se esta cumpliendo
            self.get_heights()
            time.sleep(self.sample_time)
Ejemplo n.º 3
0
def uasubscribe():
    parser = argparse.ArgumentParser(description="Subscribe to a node and print results")
    add_common_args(parser)
    parser.add_argument("-t",
                        "--eventtype",
                        dest="eventtype",
                        default="datachange",
                        choices=['datachange', 'event'],
                        help="Event type to subscribe to")

    args = parser.parse_args()
    if args.nodeid == "i=84" and args.path == "":
        parser.print_usage()
        print("uaread: error: The NodeId or BrowsePath of a variable is required")
        sys.exit(1)
    logging.basicConfig(format="%(levelname)s: %(message)s", level=getattr(logging, args.loglevel))

    client = Client(args.url, timeout=args.timeout)
    client.connect()
    try:
        node = client.get_node(args.nodeid)
        if args.path:
            node = node.get_child(args.path.split(","))
        handler = SubHandler()
        sub = client.create_subscription(500, handler)
        if args.eventtype == "datachange":
            sub.subscribe_data_change(node)
        else:
            sub.subscribe_events(node)
        embed()
    finally:
        client.disconnect()
    sys.exit(0)
    print(args)
Ejemplo n.º 4
0
def uasubscribe():
    parser = argparse.ArgumentParser(
        description="Subscribe to a node and print results")
    add_common_args(parser)
    parser.add_argument("-t",
                        "--eventtype",
                        dest="eventtype",
                        default="datachange",
                        choices=['datachange', 'event'],
                        help="Event type to subscribe to")

    args = parse_args(parser, requirenodeid=False)
    if args.eventtype == "datachange":
        _require_nodeid(parser, args)
    else:
        # FIXME: this is broken, someone may have written i=84 on purpose
        if args.nodeid == "i=84" and args.path == "":
            args.nodeid = "i=2253"

    client = Client(args.url, timeout=args.timeout)
    client.set_security_string(args.security)
    client.connect()
    try:
        node = get_node(client, args)
        handler = SubHandler()
        sub = client.create_subscription(500, handler)
        if args.eventtype == "datachange":
            sub.subscribe_data_change(node)
        else:
            sub.subscribe_events(node)
        embed()
    finally:
        client.disconnect()
    sys.exit(0)
    print(args)
Ejemplo n.º 5
0
def uasubscribe():
    parser = argparse.ArgumentParser(description="Subscribe to a node and print results")
    add_common_args(parser)
    parser.add_argument("-t",
                        "--eventtype",
                        dest="eventtype",
                        default="datachange",
                        choices=['datachange', 'event'],
                        help="Event type to subscribe to")

    args = parse_args(parser, requirenodeid=True)

    client = Client(args.url, timeout=args.timeout)
    client.connect()
    try:
        node = get_node(client, args)
        handler = SubHandler()
        sub = client.create_subscription(500, handler)
        if args.eventtype == "datachange":
            sub.subscribe_data_change(node)
        else:
            sub.subscribe_events(node)
        embed()
    finally:
        client.disconnect()
    sys.exit(0)
    print(args)
Ejemplo n.º 6
0
def main():
    client = Client("opc.tcp://localhost:4840/freeopcua/server/")

    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)
        print("Children of root are: ", root.get_children())

        msclt = SubHandler()
        sub = client.create_subscription(100, msclt)

        ## subscribe to events
        myevent = root.get_child(
            ["0:Types", "0:EventTypes", "0:BaseEventType", "2:ThresholdEvent"])
        print("MyFirstEventType is: ", myevent)
        handle = sub.subscribe_events(obj, myevent)

        myevent2 = root.get_child(
            ["0:Types", "0:EventTypes", "0:BaseEventType"])
        print("MyFirstEventType is: ", myevent2)
        handle = sub.subscribe_events(obj, myevent2)

        while True:
            sleep(0.1)

        sub.unsubscribe(handle)
        sub.delete()
    finally:
        client.disconnect()
Ejemplo n.º 7
0
class OPCUAClient:
    """
    定义opcuaclient
    """
    def __init__(self, url, username='', password=''):
        try:
            self.client = Client(url)  # 初始化OPCUA客户端
            if username != '' and password != '':  # 初始化时如果提供用户名密码则配置
                self.client.activate_session("username", "password")  # 配置用户名密码
            self.client.connect()
        except Exception as e:
            print("OPCUAClient INIT ERROR", e)

    def subscribeTag(self, stringNodeID):
        """
        通过StringNodeID订阅Tag
        """
        tag = self.client.get_node(stringNodeID)  # 获取需要读取的节点tag值
        print('tag节点值:', tag)
        handler = SubHandler()
        subobj = self.client.create_subscription(
            100, handler)  # 返回一个订阅对象第一个参数为发布间隔(毫秒)
        handle = subobj.subscribe_data_change(tag)  # 返回可用于退订的句柄
        return subobj, handle, stringNodeID  # 返回的三个参数可用于取消订阅

    def unsubscribeTag(self, subobj, handle):
        """
        取消订阅
        """
        subobj.unsubscribe(handle)

    def getNodeValue(self, stringNodeID, type=1):
        """
        通过StringNodeID读取节点tag值
        type = 1 获取值
        type = 2 获取DataValue object
        """
        tag = self.client.get_node(stringNodeID)
        return tag.get_value()

    def setNodeValue(self, stringNodeID, value):
        """
        通过StringNodeID设置节点tag值
        """
        tag = self.client.get_node(stringNodeID)
        tag.set_value(value)  # 使用隐含变量类型设置节点值

    def disconnect(self, client):
        """
        断开连接
        """
        return client.disconnect()
Ejemplo n.º 8
0
def plugin_start(handle):
    global loop, t
    _LOGGER.info("opcua_py plugin_start called")

    url = handle['url']['value']
    userName = handle['userName']['value']
    password = handle['password']['value']

    _LOGGER.info('opcua_py: Attempting to connect to %s', url)

    client = Client(url=url)

    if userName:
        _LOGGER.info('opcua_py: Attempting to connect to OPC UA server with username and password.')
        client.set_user(userName)
        client.set_password(password)
    else:
        _LOGGER.info('opcua_py: Attempting to connect anonymously to OPC UA server.')

    client.connect()

    #Need to add some error checking on the connection

    subs = json.loads(handle['subscriptions']['value'])

    subs = subs["subscriptions"]
    _LOGGER.info('opcua_py: Attempting to subscribe to %s', subs)

    nodes = []

    for sub in subs:
        nodes.append(client.get_node(sub))

    handler = SubscriptionHandler()
    # We create a Client Subscription.
    subscription = client.create_subscription(500, handler)

    # We subscribe to data changes for our nodes (variables).
    subscription.subscribe_data_change(nodes)


    def run():
            global loop
            loop.run_forever()


    t = Thread(target=run)

    t.start()
Ejemplo n.º 9
0
class UaClient(object):
    def __init__(self, server_ip):
        self.server_ip = server_ip
        self.client = Client(self.server_ip)
        print('Try to connect', self.server_ip)
        self.client.connect()
        print('Connected!')

        self.root = self.client.get_root_node()
        self.device = self.root.get_child(['0:Objects', '2:device'])

        self.device_obj = Device(self.device)

        self.device_id = self.device.get_child(['2:device_id']).get_value()
        self.location_x = self.device.get_child(['2:location_x'])
        self.location_y = self.device.get_child(['2:location_y'])
        self.direction = self.device.get_child(['2:direction'])
        self.status = self.device.get_child(['2:status'])
        self.network_condition = self.device.get_child(['2:network_condition'])

        handler = SubHandler(self)
        sub = self.client.create_subscription(500, handler)
        sub.subscribe_data_change(self.location_x)
        sub.subscribe_data_change(self.location_y)
        sub.subscribe_data_change(self.direction)
        sub.subscribe_data_change(self.network_condition)
        sub.subscribe_data_change(self.status)

    def go_front(self):
        self.device.call_method('2:go_front')

    def go_back(self):
        self.device.call_method('2:go_back')

    def turn_left(self):
        self.device.call_method('2:turn_left')

    def turn_right(self):
        self.device.call_method('2:turn_right')

    def go_to(self, target_x, target_y):
        self.device.call_method('2:go_to', target_x, target_y)

    def get_status(self):
        return Device(self.device).get_status()

    def disconnect(self):
        self.client.disconnect()
Ejemplo n.º 10
0
def main():
    logging.basicConfig(level=logging.WARN)
    client = Client("opc.tcp://WIN-B3JSS0UOON2:49320")
    try:
        client.connect()

        tag1 = client.get_node("ns=2;s=Channel1.Device1.Tag1")
        tag2 = client.get_node("ns=2;s=Simulation Examples.Functions.Ramp3")
        tag3 = client.get_node("ns=2;s=Simulation Examples.Functions.Sine1")

        tags = [tag1, tag2, tag3]

        handler = SubHandler(tags)
        sub = client.create_subscription(500, handler)

        handles = [
            sub.subscribe_data_change(tag1),
            sub.subscribe_data_change(tag2),
            sub.subscribe_data_change(tag3)
        ]

        sleep(0.1)

        embed()

        print("")
        print("Tag1 is: ", handler.storage[0])
        print("")
        print("Tag2 is: ", handler.storage[1])
        print("")
        print("Tag3 is: ", handler.storage[2])
        print("")

        algorithm = SubHandler.extreme_value_analysis
        flags = list(map(lambda i: algorithm(np.array(i)), handler.storage))

        for i in range(len(handles)):
            if flags[i] == True:
                sub.unsubscribe(handles[i])
                print(tags[i], "is broken!")
            else:
                print(tags[i], "is OK!")

        sub.delete()

    finally:
        client.disconnect()
Ejemplo n.º 11
0
 def subscribe(self):
     global dic
     if __name__ == "__main__":
         logging.basicConfig(level=logging.WARN)
         client = Client("opc.tcp://" + self.host + ":" + self.port)
         try:
             client.connect()
             for i, j in dic.items():
                 for k, l in j.items():
                     ss = client.get_node("ns=2;s=S7-300." + i + "." + k)
                     self.taglist.append(ss)
             print("订阅变量总数为:", len(self.taglist))
         except:
             pass
         handler = SubHandler()
         sub = client.create_subscription(5000, handler)
         handle1 = sub.subscribe_data_change(self.taglist)
Ejemplo n.º 12
0
class OpcuaBase(object):
    def __init__(self, address="opc.tcp://192.168.42.20:4840"):
        # self.client = Client("opc.tcp://100.102.7.5:4840")
        self.address = address
        self.client = Client(self.address)

        self.nodes = {}

    def get_node(self, nodeId):
        if not nodeId in self.nodes:
            self.nodes[nodeId] = self.client.get_node(ua.NodeId(nodeId, 2))
        return self.nodes[nodeId]

    def readValue_polling(self, nodeId, namespace):
        var = self.client.get_node(ua.NodeId(nodeId, namespace))
        return var.get_value()

    def writeBooleanValue(self, nodeId, namespace, value):
        self.get_node(nodeId).set_value(
            ua.Variant(value, ua.VariantType.Boolean))

    def writeFloatValue(self, nodeId, namespace, value):
        var = self.client.get_node(ua.NodeId(nodeId, namespace))
        var.set_value(ua.Variant(value, ua.VariantType.Float))

    def disconnect(self):
        self.client.disconnect()

    def add_subscription(self, AxisNo, AxisType,
                         MeasurementType):  # AxisNo [1...4], AxisType ["Trans","Rot"], MeasurementType ["Vel","Pos"]
        if AxisType == "Rot":
            atype = 0
        if AxisType == "Trans":
            atype = 1
        if MeasurementType == "Pos":
            mtype = 2
        if MeasurementType == "Trans":
            mtype = 3
        nodeId = Axis[AxisNo - 1][atype][mtype][0]
        namespace = Axis[AxisNo - 1][atype][mtype][1]
        var = self.client.get_node(ua.NodeId(nodeId, namespace))
        handler = SubScriptionHandler()
        sub = self.client.create_subscription(50, handler)
        sub.subscribe_data_change(var)
Ejemplo n.º 13
0
def main():
    srv_url = "opc.tcp://127.0.0.1:XXXX/FearFactory/supervision_unit/"
    client = Client(srv_url)
    client.connect()

    root = client.get_root_node()
    objs = client.get_objects_node()

    # Subscribe to the main board
    event_obj = root.get_child("2:MainBoard")
    handler = SubscriptionHandler()
    subscription = client.create_subscription(500, handler)
    event_type = root.get_child(
        ["0:Types", "0:EventTypes", "0:BaseEventType", "2:MainBoardNotif"])
    hilt = subscription.subscribe_events(event_obj, event_type)
    #subscription.unsubscribe(hilt)
    #subscription.delete()

    # Uncomment if you want to interact with server using IPython
    embed()
Ejemplo n.º 14
0
def lambda_handler(event, context):
    """
    Handler for the AWS Lambda function.
    :param event: AWS Lambda uses this parameter to pass in event data to the handler. This
    parameter is usually of the Python dict type. It can also be list, str, int, float, or
    NoneType type.
    :param context: The AWS Lambda event context. To learn more about what is included in
    the context,
    see https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html.
    """

    logger.debug('Handling event: %s', json.dumps(event))

    client = Client(SERVER_URL)

    try:
        client.connect()
        root = client.get_root_node()

        logger.debug("Root node is: %s", root)
        objects = client.get_objects_node()
        logger.debug("Objects node is: %s", objects)

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

        logger.debug('Creating subscription...')
        subscription_handler = SubscriptionHandler()
        subscription = client.create_subscription(500, subscription_handler)
        logger.info('Finished creating subscription to %s', SERVER_URL)

        logger.debug('Subscribing to data changes...')
        variable = root.get_child(["0:Objects", "2:MyObject", "2:MyVariable"])
        handle = subscription.subscribe_data_change(variable)
        logger.info('Subscribed to %s', handle)

        while True:
            time.sleep(1)

    finally:
        client.disconnect()
Ejemplo n.º 15
0
class OpcuaSubClient():
    def __init__(self, sub_handler=SubHandler):
        self.server_uri = "opc.tcp://localhost:4840"
        self.client = Client(self.server_uri)
        self.is_connect = False
        self.sub = None
        self.root = None
        self.sub_handler = sub_handler()
        self.handle = None
        self.connect()

    def connect(self):
        try:
            self.client.connect()
            self.is_connect = True
            self.root = self.client.get_root_node()
            self.sub = self.client.create_subscription(1000, self.sub_handler)
        except Exception as e:
            self.is_connect = False
            raise e

    def dis_connect(self):
        if self.is_connect:
            self.client.disconnect()
            self.is_connect = False
            self.root = None
            self.sub = None

    def subscribe(self, qualified_list):
        val_node = self.root.get_child(qualified_list)
        if val_node:
            self.handle = self.sub.subscribe_data_change(val_node)

    def unsubscribe(self):
        if self.handle:
            self.sub.unsubscribe(self.handle)
Ejemplo n.º 16
0
class UaClient(object):
    """
    OPC-Ua client specialized for the need of GUI client
    return exactly whant GUI needs, no customization possible
    """

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

    def connect(self, uri):
        self.disconnect()
        print("Connecting to ", uri)
        self.client = Client(uri)
        self.client.connect()
        self._connected = True

    def disconnect(self):
        if self._connected:
            print("Disconnecting from server")
            self._subs_dc = {}
            self._subs_ev = {}
            self._connected = False
            self._subscription = None
            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_root_node_and_desc(self):
        node = self.client.get_root_node()
        attrs = node.get_attributes([ua.AttributeIds.DisplayName, ua.AttributeIds.BrowseName, ua.AttributeIds.NodeId, ua.AttributeIds.NodeClass])
        desc = ua.ReferenceDescription()
        desc.DisplayName = attrs[0].Value.Value
        desc.BrowseName = attrs[1].Value.Value
        desc.NodeId = attrs[2].Value.Value
        desc.NodeClass = attrs[3].Value.Value
        desc.TypeDefinition = ua.TwoByteNodeId(ua.ObjectIds.FolderType)
        return node, desc

    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]

    def get_children(self, node):
        descs = node.get_children_descriptions()
        children = []
        for desc in descs:
            children.append((self.client.get_node(desc.NodeId), desc))
        return children

    def get_all_attrs(self, node):
        names = []
        vals = []
        for name, val in ua.AttributeIds.__dict__.items():
            if not name.startswith("_"):
                names.append(name)
                vals.append(val)

        attrs = node.get_attributes(vals)
        res = []
        for idx, name in enumerate(names):
            if attrs[idx].StatusCode.is_good():
                res.append((name, attrs[idx]))
        res.sort()
        return res

    def get_all_refs(self, node):
        return node.get_children_descriptions(refs=ua.ObjectIds.References)
Ejemplo n.º 17
0
class OpcUaConnector(Thread, Connector):
    def __init__(self, gateway, config, connector_type):
        self._connector_type = connector_type
        self.statistics = {'MessagesReceived': 0, 'MessagesSent': 0}
        super().__init__()
        self.__gateway = gateway
        self.__server_conf = config.get("server")
        self.__interest_nodes = []
        self.__available_object_resources = {}
        self.__show_map = self.__server_conf.get("showMap", False)
        self.__previous_scan_time = 0
        for mapping in self.__server_conf["mapping"]:
            if mapping.get("deviceNodePattern") is not None:
                self.__interest_nodes.append(
                    {mapping["deviceNodePattern"]: mapping})
            else:
                log.error(
                    "deviceNodePattern in mapping: %s - not found, add property deviceNodePattern to processing this mapping",
                    dumps(mapping))
        if "opc.tcp" not in self.__server_conf.get("url"):
            self.__opcua_url = "opc.tcp://" + self.__server_conf.get("url")
        else:
            self.__opcua_url = self.__server_conf.get("url")
        self.client = Client(
            self.__opcua_url,
            timeout=self.__server_conf.get("timeoutInMillis", 4000) / 1000)
        if self.__server_conf["identity"].get("type") == "cert.PEM":
            try:
                ca_cert = self.__server_conf["identity"].get("caCert")
                private_key = self.__server_conf["identity"].get("privateKey")
                cert = self.__server_conf["identity"].get("cert")
                security_mode = self.__server_conf["identity"].get(
                    "mode", "SignAndEncrypt")
                policy = self.__server_conf["security"]
                if cert is None or private_key is None:
                    log.exception(
                        "Error in ssl configuration - cert or privateKey parameter not found"
                    )
                    raise RuntimeError(
                        "Error in ssl configuration - cert or privateKey parameter not found"
                    )
                security_string = policy + ',' + security_mode + ',' + cert + ',' + private_key
                if ca_cert is not None:
                    security_string = security_string + ',' + ca_cert
                self.client.set_security_string(security_string)

            except Exception as e:
                log.exception(e)
        if self.__server_conf["identity"].get("username"):
            self.client.set_user(
                self.__server_conf["identity"].get("username"))
            if self.__server_conf["identity"].get("password"):
                self.client.set_password(
                    self.__server_conf["identity"].get("password"))

        self.setName(
            self.__server_conf.get(
                "name", 'OPC-UA ' +
                ''.join(choice(ascii_lowercase)
                        for _ in range(5))) + " Connector")
        self.__opcua_nodes = {}
        self._subscribed = {}
        self.__sub = None
        self.__sub_handler = SubHandler(self)
        self.data_to_send = []
        self.__stopped = False
        self.__connected = False
        self.daemon = True

    def is_connected(self):
        return self.__connected

    def open(self):
        self.__stopped = False
        self.start()
        log.info("Starting OPC-UA Connector")

    def run(self):
        while not self.__connected:
            try:
                self.client.connect()
                try:
                    self.client.load_type_definitions()
                except Exception as e:
                    log.debug(e)
                    log.debug("Error on loading type definitions.")
                log.debug(self.client.get_namespace_array()[-1])
                log.debug(
                    self.client.get_namespace_index(
                        self.client.get_namespace_array()[-1]))
            except ConnectionRefusedError:
                log.error(
                    "Connection refused on connection to OPC-UA server with url %s",
                    self.__server_conf.get("url"))
                time.sleep(10)
            except OSError:
                log.error(
                    "Connection refused on connection to OPC-UA server with url %s",
                    self.__server_conf.get("url"))
                time.sleep(10)
            except Exception as e:
                log.debug("error on connection to OPC-UA server.")
                log.error(e)
                time.sleep(10)
            else:
                self.__connected = True
                log.info("OPC-UA connector %s connected to server %s",
                         self.get_name(), self.__server_conf.get("url"))
        self.__initialize_client()
        while not self.__stopped:
            try:
                time.sleep(.1)
                self.__check_connection()
                if not self.__connected and not self.__stopped:
                    self.client.connect()
                    self.__initialize_client()
                    log.info("Reconnected to the OPC-UA server - %s",
                             self.__server_conf.get("url"))
                elif not self.__stopped:
                    if self.__server_conf.get(
                            "disableSubscriptions", False
                    ) and time.time(
                    ) * 1000 - self.__previous_scan_time > self.__server_conf.get(
                            "scanPeriodInMillis", 60000):
                        self.scan_nodes_from_config()
                        self.__previous_scan_time = time.time() * 1000
                    # giusguerrini, 2020-09-24: Fix: flush event set and send all data to platform,
                    # so data_to_send doesn't grow indefinitely in case of more than one value change
                    # per cycle, and platform doesn't lose events.
                    # NOTE: possible performance improvement: use a map to store only one event per
                    # variable to reduce frequency of messages to platform.
                    while self.data_to_send:
                        self.__gateway.send_to_storage(self.get_name(),
                                                       self.data_to_send.pop())
                if self.__stopped:
                    self.close()
                    break
            except (KeyboardInterrupt, SystemExit):
                self.close()
                raise
            except FuturesTimeoutError:
                self.__check_connection()
            except Exception as e:
                log.error(
                    "Connection failed on connection to OPC-UA server with url %s",
                    self.__server_conf.get("url"))
                log.exception(e)
                self.client = Client(
                    self.__opcua_url,
                    timeout=self.__server_conf.get("timeoutInMillis", 4000) /
                    1000)
                self._subscribed = {}
                self.__available_object_resources = {}
                time.sleep(10)

    def __check_connection(self):
        try:
            node = self.client.get_root_node()
            node.get_children()
            if not self.__server_conf.get("disableSubscriptions", False) and (
                    not self.__connected or not self.subscribed):
                self.__sub = self.client.create_subscription(
                    self.__server_conf.get("subCheckPeriodInMillis", 500),
                    self.__sub_handler)
            self.__connected = True
        except ConnectionRefusedError:
            self.__connected = False
            self._subscribed = {}
            self.__available_object_resources = {}
            self.__sub = None
        except OSError:
            self.__connected = False
            self._subscribed = {}
            self.__available_object_resources = {}
            self.__sub = None
        except FuturesTimeoutError:
            self.__connected = False
            self._subscribed = {}
            self.__available_object_resources = {}
            self.__sub = None
        except AttributeError:
            self.__connected = False
            self._subscribed = {}
            self.__available_object_resources = {}
            self.__sub = None
        except Exception as e:
            self.__connected = False
            self._subscribed = {}
            self.__available_object_resources = {}
            self.__sub = None
            log.exception(e)

    def close(self):
        self.__stopped = True
        if self.__connected:
            self.client.disconnect()
        self.__connected = False
        log.info('%s has been stopped.', self.get_name())

    def get_name(self):
        return self.name

    def on_attributes_update(self, content):
        log.debug(content)
        try:
            for server_variables in self.__available_object_resources[
                    content["device"]]['variables']:
                for attribute in content["data"]:
                    for variable in server_variables:
                        if attribute == variable:
                            try:
                                server_variables[variable].set_value(
                                    content["data"][variable])
                            except Exception:
                                server_variables[variable].set_attribute(
                                    ua.AttributeIds.Value,
                                    ua.DataValue(content["data"][variable]))
        except Exception as e:
            log.exception(e)

    def server_side_rpc_handler(self, content):
        try:
            rpc_method = content["data"].get("method")
            for method in self.__available_object_resources[
                    content["device"]]['methods']:
                if rpc_method is not None and method.get(
                        rpc_method) is not None:
                    arguments_from_config = method["arguments"]
                    arguments = content["data"].get(
                        "params") if content["data"].get(
                            "params") is not None else arguments_from_config
                    try:
                        if isinstance(arguments, list):
                            result = method["node"].call_method(
                                method[rpc_method], *arguments)
                        elif arguments is not None:
                            try:
                                result = method["node"].call_method(
                                    method[rpc_method], arguments)
                            except ua.UaStatusCodeError as e:
                                if "BadTypeMismatch" in str(e) and isinstance(
                                        arguments, int):
                                    result = method["node"].call_method(
                                        method[rpc_method], float(arguments))
                        else:
                            result = method["node"].call_method(
                                method[rpc_method])

                        self.__gateway.send_rpc_reply(
                            content["device"], content["data"]["id"], {
                                content["data"]["method"]: result,
                                "code": 200
                            })
                        log.debug("method %s result is: %s",
                                  method[rpc_method], result)
                    except Exception as e:
                        log.exception(e)
                        self.__gateway.send_rpc_reply(content["device"],
                                                      content["data"]["id"], {
                                                          "error": str(e),
                                                          "code": 500
                                                      })
                else:
                    log.error("Method %s not found for device %s", rpc_method,
                              content["device"])
                    self.__gateway.send_rpc_reply(
                        content["device"], content["data"]["id"], {
                            "error": "%s - Method not found" % (rpc_method),
                            "code": 404
                        })
        except Exception as e:
            log.exception(e)

    def __initialize_client(self):
        self.__opcua_nodes["root"] = self.client.get_objects_node()
        self.__opcua_nodes["objects"] = self.client.get_objects_node()
        self.scan_nodes_from_config()
        self.__previous_scan_time = time.time() * 1000
        log.debug('Subscriptions: %s', self.subscribed)
        log.debug("Available methods: %s", self.__available_object_resources)

    def scan_nodes_from_config(self):
        try:
            if self.__interest_nodes:
                for device_object in self.__interest_nodes:
                    for current_device in device_object:
                        try:
                            device_configuration = device_object[
                                current_device]
                            devices_info_array = self.__search_general_info(
                                device_configuration)
                            for device_info in devices_info_array:
                                if device_info is not None and device_info.get(
                                        "deviceNode") is not None:
                                    self.__search_nodes_and_subscribe(
                                        device_info)
                                    self.__save_methods(device_info)
                                    self.__search_attribute_update_variables(
                                        device_info)
                                else:
                                    log.error(
                                        "Device node is None, please check your configuration."
                                    )
                                    log.debug(
                                        "Current device node is: %s",
                                        str(
                                            device_configuration.get(
                                                "deviceNodePattern")))
                                    break
                        except BrokenPipeError:
                            log.debug("Broken Pipe. Connection lost.")
                        except OSError:
                            log.debug("Stop on scanning.")
                        except FuturesTimeoutError:
                            self.__check_connection()
                        except Exception as e:
                            log.exception(e)
                log.debug(self.__interest_nodes)
        except Exception as e:
            log.exception(e)

    def __search_nodes_and_subscribe(self, device_info):
        sub_nodes = []
        information_types = {
            "attributes": "attributes",
            "timeseries": "telemetry"
        }
        for information_type in information_types:
            for information in device_info["configuration"][information_type]:
                information_key = information["key"]
                config_path = TBUtility.get_value(information["path"],
                                                  get_tag=True)
                information_path = self._check_path(config_path,
                                                    device_info["deviceNode"])
                information["path"] = '${%s}' % information_path
                information_nodes = []
                self.__search_node(device_info["deviceNode"],
                                   information_path,
                                   result=information_nodes)
                for information_node in information_nodes:
                    if information_node is not None:
                        try:
                            information_value = information_node.get_value()
                        except:
                            log.error("Err get_value: %s",
                                      str(information_node))
                            continue
                        log.debug(
                            "Node for %s \"%s\" with path: %s - FOUND! Current values is: %s",
                            information_type, information_key,
                            information_path, str(information_value))
                        if device_info.get("uplink_converter") is None:
                            configuration = {
                                **device_info["configuration"], "deviceName":
                                device_info["deviceName"],
                                "deviceType":
                                device_info["deviceType"]
                            }
                            if device_info["configuration"].get(
                                    'converter') is None:
                                converter = OpcUaUplinkConverter(configuration)
                            else:
                                converter = TBModuleLoader.import_module(
                                    self._connector_type, configuration)
                            device_info["uplink_converter"] = converter
                        else:
                            converter = device_info["uplink_converter"]
                        self.subscribed[information_node] = {
                            "converter": converter,
                            "path": information_path,
                            "config_path": config_path
                        }
                        if not device_info.get(
                                information_types[information_type]):
                            device_info[
                                information_types[information_type]] = []
                        converted_data = converter.convert(
                            (config_path, information_path), information_value)
                        self.statistics['MessagesReceived'] = self.statistics[
                            'MessagesReceived'] + 1
                        self.data_to_send.append(converted_data)
                        self.statistics['MessagesSent'] = self.statistics[
                            'MessagesSent'] + 1
                        log.debug("Data to ThingsBoard: %s", converted_data)
                        if not self.__server_conf.get("disableSubscriptions",
                                                      False):
                            sub_nodes.append(information_node)
                    else:
                        log.error(
                            "Node for %s \"%s\" with path %s - NOT FOUND!",
                            information_type, information_key,
                            information_path)
        if not self.__server_conf.get("disableSubscriptions", False):
            if self.__sub is None:
                self.__sub = self.client.create_subscription(
                    self.__server_conf.get("subCheckPeriodInMillis", 500),
                    self.__sub_handler)
            if sub_nodes:
                self.__sub.subscribe_data_change(sub_nodes)
                log.debug("Added subscription to nodes: %s", str(sub_nodes))

    def __save_methods(self, device_info):
        try:
            if self.__available_object_resources.get(
                    device_info["deviceName"]) is None:
                self.__available_object_resources[
                    device_info["deviceName"]] = {}
            if self.__available_object_resources[
                    device_info["deviceName"]].get("methods") is None:
                self.__available_object_resources[
                    device_info["deviceName"]]["methods"] = []
            if device_info["configuration"].get("rpc_methods", []):
                node = device_info["deviceNode"]
                for method_object in device_info["configuration"][
                        "rpc_methods"]:
                    method_node_path = self._check_path(
                        method_object["method"], node)
                    methods = []
                    self.__search_node(node,
                                       method_node_path,
                                       True,
                                       result=methods)
                    for method in methods:
                        if method is not None:
                            node_method_name = method.get_display_name().Text
                            self.__available_object_resources[
                                device_info["deviceName"]]["methods"].append({
                                    node_method_name:
                                    method,
                                    "node":
                                    node,
                                    "arguments":
                                    method_object.get("arguments")
                                })
                        else:
                            log.error(
                                "Node for method with path %s - NOT FOUND!",
                                method_node_path)
        except Exception as e:
            log.exception(e)

    def __search_attribute_update_variables(self, device_info):
        try:
            if device_info["configuration"].get("attributes_updates", []):
                node = device_info["deviceNode"]
                device_name = device_info["deviceName"]
                if self.__available_object_resources.get(device_name) is None:
                    self.__available_object_resources[device_name] = {}
                if self.__available_object_resources[device_name].get(
                        "variables") is None:
                    self.__available_object_resources[device_name][
                        "variables"] = []
                for attribute_update in device_info["configuration"][
                        "attributes_updates"]:
                    attribute_path = self._check_path(
                        attribute_update["attributeOnDevice"], node)
                    attribute_nodes = []
                    self.__search_node(node,
                                       attribute_path,
                                       result=attribute_nodes)
                    for attribute_node in attribute_nodes:
                        if attribute_node is not None:
                            self.__available_object_resources[device_name][
                                "variables"].append({
                                    attribute_update["attributeOnThingsBoard"]:
                                    attribute_node
                                })
                        else:
                            log.error(
                                "Attribute update node with path \"%s\" - NOT FOUND!",
                                attribute_path)
        except Exception as e:
            log.exception(e)

    def __search_general_info(self, device):
        result = []
        match_devices = []
        self.__search_node(self.__opcua_nodes["root"],
                           TBUtility.get_value(device["deviceNodePattern"],
                                               get_tag=True),
                           result=match_devices)
        for device_node in match_devices:
            if device_node is not None:
                result_device_dict = {
                    "deviceName": None,
                    "deviceType": None,
                    "deviceNode": device_node,
                    "configuration": deepcopy(device)
                }
                name_pattern_config = device["deviceNamePattern"]
                name_expression = TBUtility.get_value(name_pattern_config,
                                                      get_tag=True)
                if "${" in name_pattern_config and "}" in name_pattern_config:
                    log.debug("Looking for device name")
                    device_name_from_node = ""
                    if name_expression == "$DisplayName":
                        device_name_from_node = device_node.get_display_name(
                        ).Text
                    elif name_expression == "$BrowseName":
                        device_name_from_node = device_node.get_browse_name(
                        ).Name
                    elif name_expression == "$NodeId.Identifier":
                        device_name_from_node = str(
                            device_node.nodeid.Identifier)
                    else:
                        name_path = self._check_path(name_expression,
                                                     device_node)
                        device_name_node = []
                        self.__search_node(device_node,
                                           name_path,
                                           result=device_name_node)
                        device_name_node = device_name_node[0]
                        if device_name_node is not None:
                            device_name_from_node = device_name_node.get_value(
                            )
                    if device_name_from_node == "":
                        log.error(
                            "Device name node not found with expression: %s",
                            name_expression)
                        return None
                    full_device_name = name_pattern_config.replace(
                        "${" + name_expression + "}",
                        str(device_name_from_node)).replace(
                            name_expression, str(device_name_from_node))
                else:
                    full_device_name = name_expression
                result_device_dict["deviceName"] = full_device_name
                log.debug("Device name: %s", full_device_name)
                if device.get("deviceTypePattern"):
                    device_type_expression = TBUtility.get_value(
                        device["deviceTypePattern"], get_tag=True)
                    if "${" in device_type_expression and "}" in device_type_expression:
                        type_path = self._check_path(device_type_expression,
                                                     device_node)
                        device_type_node = []
                        self.__search_node(device_node,
                                           type_path,
                                           result=device_type_node)
                        device_type_node = device_type_node[0]
                        if device_type_node is not None:
                            device_type = device_type_node.get_value()
                            full_device_type = device_type_expression.replace(
                                "${" + device_type_expression + "}",
                                device_type).replace(device_type_expression,
                                                     device_type)
                        else:
                            log.error(
                                "Device type node not found with expression: %s",
                                device_type_expression)
                            full_device_type = "default"
                    else:
                        full_device_type = device_type_expression
                    result_device_dict["deviceType"] = full_device_type
                    log.debug("Device type: %s", full_device_type)
                else:
                    result_device_dict["deviceType"] = "default"
                result.append(result_device_dict)
            else:
                log.error(
                    "Device node not found with expression: %s",
                    TBUtility.get_value(device["deviceNodePattern"],
                                        get_tag=True))
        return result

    #
    # get fullpath of node as string
    #
    # this is verry slow
    # path = '\\.'.join(char.split(":")[1] for char in node.get_path(200000, True))
    # i think we don't need \\.
    #
    def get_node_path(self, node):
        ID = node.nodeid.Identifier
        if ID == 85:
            return 'Root.Objects'  # this is Root
        if type(ID) == int:
            ID = node.get_browse_name(
            ).Name  # for int Identifer we take browsename
        return 'Root.Objects.' + ID

    def __search_node(self,
                      current_node,
                      fullpath,
                      search_method=False,
                      result=None):
        if result is None:
            result = []
        try:
            if regex.match(r"ns=\d*;[isgb]=.*", fullpath, regex.IGNORECASE):
                if self.__show_map:
                    log.debug("Looking for node with config")
                node = self.client.get_node(fullpath)
                if node is None:
                    log.warning("NODE NOT FOUND - using configuration %s",
                                fullpath)
                else:
                    log.debug("Found in %s", node)
                    result.append(node)
            else:
                fullpath_pattern = regex.compile(fullpath)
                full1 = fullpath.replace('\\\\.', '.')
                #current_node_path = '\\.'.join(char.split(":")[1] for char in current_node.get_path(200000, True))
                current_node_path = self.get_node_path(current_node)
                # we are allways the parent
                child_node_parent_class = current_node.get_node_class()
                new_parent = current_node
                for child_node in current_node.get_children():
                    new_node_class = child_node.get_node_class()
                    # this will not change you can do it outside th loop
                    # basis Description of node.get_parent() function, sometime child_node.get_parent() return None
                    #new_parent = child_node.get_parent()
                    #if (new_parent is None):
                    #    child_node_parent_class = current_node.get_node_class()
                    #else:
                    #    child_node_parent_class = child_node.get_parent().get_node_class()
                    #current_node_path = '\\.'.join(char.split(":")[1] for char in current_node.get_path(200000, True))
                    #new_node_path = '\\\\.'.join(char.split(":")[1] for char in child_node.get_path(200000, True))
                    new_node_path = self.get_node_path(child_node)
                    if child_node_parent_class == ua.NodeClass.View and new_parent is not None:
                        parent_path = self.get_node_path(new_parent)
                        #parent_path = '\\.'.join(char.split(":")[1] for char in new_parent.get_path(200000, True))
                        fullpath = fullpath.replace(current_node_path,
                                                    parent_path)
                    nnp1 = new_node_path.replace('\\\\.', '.')
                    nnp2 = new_node_path.replace('\\\\', '\\')
                    if self.__show_map:
                        log.debug("SHOW MAP: Current node path: %s",
                                  new_node_path)
                    regex_fullmatch = regex.fullmatch(fullpath_pattern,  nnp1) or \
                                      nnp2 == full1 or \
                                      nnp2 == fullpath or \
                                      nnp1 == full1
                    if regex_fullmatch:
                        if self.__show_map:
                            log.debug(
                                "SHOW MAP: Current node path: %s - NODE FOUND",
                                nnp2)
                        result.append(child_node)
                    else:
                        regex_search = fullpath_pattern.fullmatch(nnp1, partial=True) or \
                                          nnp2 in full1 or \
                                          nnp1 in full1
                        if regex_search:
                            if self.__show_map:
                                log.debug(
                                    "SHOW MAP: Current node path: %s - NODE FOUND",
                                    new_node_path)
                            if new_node_class == ua.NodeClass.Object:
                                if self.__show_map:
                                    log.debug("SHOW MAP: Search in %s",
                                              new_node_path)
                                self.__search_node(child_node,
                                                   fullpath,
                                                   result=result)
                            elif new_node_class == ua.NodeClass.Variable:
                                log.debug("Found in %s", new_node_path)
                                result.append(child_node)
                            elif new_node_class == ua.NodeClass.Method and search_method:
                                log.debug("Found in %s", new_node_path)
                                result.append(child_node)
        except CancelledError:
            log.error(
                "Request during search has been canceled by the OPC-UA server."
            )
        except BrokenPipeError:
            log.error("Broken Pipe. Connection lost.")
        except OSError:
            log.debug("Stop on scanning.")
        except Exception as e:
            log.exception(e)

    def _check_path(self, config_path, node):
        if regex.match(r"ns=\d*;[isgb]=.*", config_path, regex.IGNORECASE):
            return config_path
        if re.search(r"^root", config_path.lower()) is None:
            node_path = self.get_node_path(node)
            #node_path = '\\\\.'.join(char.split(":")[1] for char in node.get_path(200000, True))
            if config_path[-3:] != '\\.':
                information_path = node_path + '\\\\.' + config_path.replace(
                    '\\', '\\\\')
            else:
                information_path = node_path + config_path.replace(
                    '\\', '\\\\')
        else:
            information_path = config_path
        result = information_path[:]
        return result

    @property
    def subscribed(self):
        return self._subscribed
Ejemplo n.º 18
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
Ejemplo n.º 19
0
                               password=password)

    listdb = client_db.get_list_database()
    client_db.create_database(mydb)
    client_db.switch_database(mydb)

    client_ua = Client(url)
    try:
        client_ua.set_user(ua_username)
        client_ua.set_password(ua_password)
        client_ua.connect()
        print('Client Connected')
        for i in nodes:
            myvar.append(client_ua.get_node(i))
        handler = SubHandler()
        sub = client_ua.create_subscription(ua_period, handler)
        handle = sub.subscribe_data_change(myvar)
        print('Subscribe data_change with period {} ms'.format(ua_period))
        #        time.sleep(5)
        input("Press Enter to continue...")
        for i in handle:
            sub.unsubscribe(i)
            print('Unsubscribe handle: ', i)
        print('Start deleting Sub')
        sub.delete()

    finally:
        try:
            client_db.close()
            client_ua.disconnect()
        except concurrent.futures._base.TimeoutError:
Ejemplo n.º 20
0
        print("New event notification", event)
        # To print only the notification message
        #print("Write whatever you want here", event.Message.Text)


if __name__ == "__main__":

    client = Client("opc.tcp://localhost:4840/freeopcua/server/")
    try:
        client.connect()

        root = client.get_root_node()
        print("Objects node is: ", root)
        # Now getting a variable node using its browse path
        obj = root.get_child(["0:Objects", "2:MyObject"])
        print("MyObject is: ", obj)

        # Get the custom event type
        myevent = root.get_child(["0:Types", "0:EventTypes", "0:BaseEventType", "2:MyFirstEvent"])
        print("MyFirstEventType is: ", myevent)

        msclt = SubHandler()
        sub = client.create_subscription(100, msclt)
        handle = sub.subscribe_events(obj, myevent)

        #embed()
        #sub.unsubscribe(handle)
        #sub.delete()
    finally:
client.disconnect()
def run():
    logger.info("Modular Input mi_opcua_subscription command: %s" % sys.argv)
    if len(sys.argv) > 1:
        try:
            if sys.argv[1] == "--scheme":
                do_scheme()
            elif sys.argv[1] == "--validate-arguments":
                validate_arguments()
            elif sys.argv[1] == "--test":
                test()
            else:
                usage()
        except Exception as ex:
            logger.critical(ex)
    else:
        logger.info("Modular Input mi_opcua_subscription Starts data collection.")
        
        configs = get_config()
        stanza = configs["name"]
        # server_uri = configs["server_uri"]
        # sessionKey = configs["session_key"]
        # userName = "******"   # make this modular input as application context only.
        patterns = configs["measures"].split(":")
        tout = configs["connection_timeout"].strip()
        timeout = 1 if len(tout) <= 0 else int(tout)
        ct = configs["collect_duration"].strip()
        duration = 1000 if len(ct) <=0 else int(ct)
        
        conn = configs["connection"]   ## "opc.tcp://ec2-54-190-162-94.us-west-2.compute.amazonaws.com:49320"

        if configs.has_key("username"):
            username = configs["username"].strip()
            if len(username)>0:
                password = configs["password"].strip()
                conn = "%s?username=%s&password=%s" % (conn, username, password)
    
        client = Client(conn, timeout=timeout)
        
        try:
            client.connect()
            measures = []
            root = client.get_root_node()
            
            node.collect_measures(measures, patterns, root)
            
            subscribers = []
            for m in measures:
                try:
                    subscribers.append(m[len(m)-1])
                except:
                    logger.warn("The node of %s is invalid to subscribe." % m)
                    
            handler = SubHandler(stanza)
            sub = client.create_subscription(duration, handler)
            dchandle = sub.subscribe_data_change(subscribers)
       
            def signal_handler(signal, frame):
                logger.info('Press Ctrl+C')
                
                if signal in [signal.SIGABRT, signal.SIGINT, signal.SIGQUIT, signal.SIGTERM]:
                    sub.unsubscribe(dchandle)
                    sub.delete()
                    client.disconnect()

            signal.signal(signal.SIGINT, signal_handler)
            signal.signal(signal.SIGABRT, signal_handler)
            signal.signal(signal.SIGTERM, signal_handler)
            signal.signal(signal.SIGQUIT, signal_handler)

            signal.pause()
                            
        except Exception as ex:
            logger.critical(ex)
        finally:
            sub.unsubscribe(dchandle)
            sub.delete()
            client.disconnect()
            
            logger.info("---- end of sub opc ua ----")
Ejemplo n.º 22
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.º 23
0
class UaClient(object):
    """
    OPC-Ua client specialized for the need of GUI client
    return exactly whant GUI needs, no customization possible
    """
    def __init__(self):
        self.client = None
        self._connected = False
        self._subscription = None

    def connect(self, uri):
        self.disconnect()
        print("Connecting to ", uri)
        self.client = Client(uri)
        self.client.connect()
        self._connected = True
        print("Connected, root is: ", self.client.get_root_node())
        print(self.get_root_attrs())

    def disconnect(self):
        if self._connected:
            print("Disconnecting from server")
            self._connected = False
            self._subscription = None
            self.client.disconnect()
            self.client = None

    def subscribe(self, node, handler):
        if not self._subscription:
            self._subscription = self.client.create_subscription(500, handler)
        self._subscription.subscribe_data_change(node)

    def get_root_attrs(self):
        return self.get_node_attrs(self.client.get_root_node())

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

    def get_children(self, node):
        descs = node.get_children_descriptions()
        children = []
        for desc in descs:
            children.append([self.client.get_node(desc.NodeId), desc.DisplayName.to_string(), desc.BrowseName.to_string(), desc.NodeId.to_string()])
        return children

    def get_all_attrs(self, node):
        names = []
        vals = []
        for name, val in ua.AttributeIds.__dict__.items():
            if not name.startswith("_"):
                names.append(name)
                vals.append(val)

        attrs = node.get_attributes(vals)
        res = {}
        for idx, name in enumerate(names):
            if attrs[idx].StatusCode.is_good():
                res[name] = attrs[idx].Value.Value
        return res

    def get_all_refs(self, node):
        return node.get_children_descriptions(refs=ObjectIds.References)
Ejemplo n.º 24
0
        # gettting our namespace idx

        #uri = "http://examples.freeopcua.github.io"
        #idx = client.get_namespace_index(uri)

        # Now getting a variable node using its browse path
        myvar = root.get_child([
            "0:Objects", "{}:MyObject".format(idx), "{}:MyVariable".format(idx)
        ])
        obj = root.get_child(["0:Objects", "{}:MyObject".format(idx)])
        print("myvar is: ", myvar)

        # subscribing to a variable node
        handler = SubHandler()
        sub = client.create_subscription(500, handler)
        handle = sub.subscribe_data_change(myvar)
        time.sleep(0.1)

        # we can also subscribe to events from server
        sub.subscribe_events()
        # sub.unsubscribe(handle)
        # sub.delete()

        # calling a method on server
        res = obj.call_method("{}:multiply".format(idx), 3, "klk")
        print("method result is: ", res)

        embed()
    finally:
        client.disconnect()
Ejemplo n.º 25
0
class OpcClient():
    """A simplified OpClient.

    This is a opc client that can be leveraged to
    subscribe to the OPC data change notifications.
    
    You should interact with the client using
    * add_notification_handler
    * subscribe_variable
    * unsubscribe_variable

    So typically:
    ```
    # setup client
    cl = OpcClient(...)
    # define handler
    def handler(update):
        # data update : {'node': <node>, 'timestamp': <datetime>, 'value': <value>, 'data': <data>}
        # do something with update here
    # add handler
    cl.add_notification_handler(handler)
    # subscribe to variable
    cl.subscribe_variable(cl.get_node("ns=3;i=2002"))

    time.sleep(100)
    cl.disconnect()
    ```

    *Note*
    Make sure to call disconnect before shutting down in
    order to ensure a clean close.

    See: https://github.com/FreeOpcUa/python-opcua

    Attributes
    ----------
    _address : str
        The connection string address
    _address_obfuscated : str
        The connection string address obfuscating a potnetial password
    _client : OPCLibClient
        The opc lib client
    _subscription : ua.Subscription
        The ua subscription handle that can be used
        to create new subscritions or unsubscribe
    _sub_handles : dict
        A dictionary mapping ua.Node variables to
        subscription handles to be able to unsubscribe
        from them again
    _handlers : list
        A list of handler functions
    """
    def __init__(self, host, port, path='/', username=None, password=None):
        """Create a new OpClient.

        This will create a new opc client that can be
        leveraged to subscribe to the OPC data change
        notifications.

        Parameters
        ----------
        host : str
            The host name of the opc server.
        port : int
            The port of the opc server.
        path : str
            The path to add to the server as base
        username : str|None
            A username to use for authorization.
        password : str|None
            A password to use for authorization.
        """

        self._client = None
        self._subscription = None
        self._sub_handles = {}
        self._handlers = []

        # setup authorization
        auth = ''
        if username is not None:
            auth = '{}:{}@'.format(username, password)

        # define address
        self._address = self._address_obfuscated = "opc.tcp://{}{}:{}{}".format(
            auth, host, port, path)
        if username is not None and password is not None:
            self._address_obfuscated = self._address.replace(password, '***')

        Logger.trace('Created OpcClient',
                     fields={'address': self._address_obfuscated})

        # setup client
        self.init_client()
        # setup subscriptions
        self.init_subscriptions()

    def init_client(self):
        """Initialize the client.

        This will connect to the client using
        the address. This is required to be
        called before anything else interacting
        with the opc server is done.
        """
        try:
            self._client = OPCLibClient(self._address)
            self._client.connect()
            self._client.load_type_definitions()
            self.namespace = self._client.get_namespace_array()
            Logger.trace('Connection established')
        except Exception as e:
            Logger.error('Failed connecting to address "{}"'.format(
                self._address_obfuscated))
            Logger.error('{}'.format(e))
            raise e

    def log_info(self):
        root = self._client.get_root_node()
        objects = self._client.get_objects_node()
        children = root.get_children()
        # print '{}:{}'.format(namespace[children[1].nodeid.NamespaceIndex], children[1].nodeid.Identifier)
        # print self._client.get_node("ns=0;i=86")
        Logger.debug("Retrieved Client Info",
                     fields={
                         'root': root,
                         'objects': objects,
                         'children': children,
                         'namespace': self.namespace
                     })

    def full_uri(self, node):
        """Resolve the full uri of a ua.Node.

        Parameters
        ----------
        node : ua.Node
            A node from the OPC interface.

        Returns
        -------
        str :
            The namespace prefixed full uri of the entity.
        """
        return '{}:{}'.format(self.namespace[node.nodeid.NamespaceIndex],
                              node.nodeid.Identifier)

    def get_by_uri(self, uri):
        """Resolve the full uri to a ua.Node.

        Parameters
        ----------
        uri : str
            The uri to the ua.Node.

        Returns
        -------
        ua.Node :
            The resolved node.
        """
        ns_match = None
        for ns in self.namespace:
            if '{}:'.format(ns) in uri:
                ns_match = ns
                break
        if ns_match is None:
            raise RuntimeError('Namespace of "{}" not available'.format(uri))
        ns_idx = self._client.get_namespace_index(ns_match)
        identifier = uri.replace('{}:'.format(ns_match), '')
        try:
            int(identifier)
            is_int = True
        except:
            is_int = False

        substituted = 'ns={};{}={}'.format(ns_idx, 'i' if is_int else 's',
                                           identifier)
        return self._client.get_node(substituted)

    def init_subscriptions(self):
        """Initialize the subscriptions.

        This will initialize a subscription handler
        and afterwards will be ready to subscribe to
        specific variables.
        """
        if self._client is None:
            raise RuntimeError('Client not initialized yet.')

        self._subscription = self._client.create_subscription(500, self)
        Logger.trace('Base Subscription established')

    def subscribe_variable(self, variable):
        """Subscribe to a OPC variable.

        This will subscribe the client to
        the given variable and any data change
        notification will be published.

        Parameters
        ----------
        variable : ua.Node
            The ua node, e.g. client.get_node(ua.NodeId(1002, 2)) or
            client.get_node("ns=3;i=2002")
        """
        if self._subscription is None:
            raise RuntimeError('Subscriptions not initialized yet.')

        if variable in self._sub_handles.keys():
            Logger.info('Already subscribed to "{}"'.format(variable))
            return
        self._sub_handles[variable] = self._subscription.subscribe_data_change(
            variable)

    def unsubscribe_variable(self, variable):
        """Unsubscribe from a OPC variable.

        This will unsubscribe the client from
        the given variable.

        Parameters
        ----------
        variable : ua.Node
            The ua node, e.g. client.get_node(ua.NodeId(1002, 2)) or
            client.get_node("ns=3;i=2002")
        """
        if self._subscription is None:
            raise RuntimeError('Subscriptions not initialized yet.')

        if variable not in self._sub_handles.keys():
            Logger.info('Not subscribed to "{}"'.format(variable))
            return
        self._subscription.unsubscribe(self._sub_handles[variable])
        del self._sub_handles[variable]

    def disconnect(self):
        """Disconnect the client.
        """
        if self._client is None:
            return
        try:
            self._client.disconnect()
        except Exception:
            pass

    def datachange_notification(self, node, value, data):
        """Receiver from the OPC client.

        This gets called by OPC client on subscription
        notification.

        Parameter
        ---------
        node : ua.Node
            The node from which we received the data.
        value : any
            The value notification
        data : any
            The data of the notification
        """
        timestamp = datetime.now()
        if hasattr(data, 'MonitoredItemNotification') and \
                hasattr(data.MonitoredItemNotification, 'SourceTimestamp'):
            timestamp = data.MonitoredItemNotification.SourceTimestamp
        Logger.debug('OpcClient: Received data change notification',
                     fields={
                         'node': node,
                         'value': value,
                         'data': data,
                         'timestamp': timestamp.isoformat()
                     })
        # send update to handlers
        update = {
            'node': node,
            'value': value,
            'data': data,
            'timestamp': timestamp
        }
        for hdl in self._handlers:
            hdl(update)

    def add_notification_handler(self, handler):
        """Add a handler function.

        This handler `def handler(update)` will be
        called upon reception of a notification from
        the OPC Client. The update will have the
        following data:
        ```{
            'node': <node>,
            'value': <value>,
            'data': <data>,
            'timestamp': <timestamp>
        }```
        """
        self._handlers.append(handler)
Ejemplo n.º 26
0
class ServerConnect():
    # WRONG_INPUT_STATE = 0
    # SEND_ERRORS = False  # whether to send error to OPC server or just show them in console
    # USE_ACTIVE_STATE = False
    # STRIP_ACCENTS = True  # whether to remove accents before comparing recognized text and possible choices
    # ALLOW_INTERRUPTIONS = False  # whether the user can interupt TTS playback
    #
    # MICROPHONE_WAIT_TIMEOUT = 5  # time to wait for any non-zero audio from mic
    # LISTENING_START_TIMEOUT = 5  # time to start speaking after recognition is ran
    # PHRASE_TIMEOUT = 4  # maximum length of phrase before listening is cut off
    # CALIBRATION_TIME = 1  # time to spend calibrating the microphone bgr energy levels

    def __init__(self, serverAdress, gain: int = 1.0):
        # instantiate client object; make sure address and port are correct
        self.client = Client(serverAdress)
        # self.shouldProcessInput = True
        # self.LANG = 'cs'
        # self.recognizer = sr.Recognizer()
        # self.fast_recognizer = sr.Recognizer()
        # self.fast_recognizer.non_speaking_duration = 0.05
        # self.fast_recognizer.pause_threshold = 0.15
        # self.recText = RawNLParser()
        # self.lastRecognitionFailed = False
        # self.repeatChoices = False

    def connect(self):
        self.client.connect()  # connect to server
        root = self.client.nodes.root  # get the root entity
        print("Connected to server and successfully retrieved the root.")

        # Retreive some objects and variables
        dataObj = root.get_child(["0:Objects", "4:DATA"])

        # a horse
        horse = dataObj.get_child("4:horse")

        # mic_active is the "You can now try recognizing speech" variable
        self.mic_active = horse.get_child("4:request")

        # the string where responses (errors and such) should be sent
        self.response_string = horse.get_child("4:response")

        # the state change request variable
        self.request = horse.get_child(["4:next_state_choice", "4:request"])
        # self.request.set_value(True)
        # the number of the state to be changed to
        self.request_state_num = horse.get_child(
            ["4:next_state_choice", "4:state_num"])

        # the variable with next state choices
        self.next_state_possibilities = horse.get_child(
            "4:next_state_possibilities")
        # self.client.load_type_definitions()

        # the variable with the current state
        self.actual_state_number = horse.get_child(
            ["4:actual_state", "4:number"])

        self.sub = self.client.create_subscription(100,
                                                   self)  # create subscription
        self.handle = self.sub.subscribe_data_change(self.mic_active)

    def send_state(self, state_num):
        """
        Changes state to the specified number and sets "request" to True.
        """
        dt = ua.DataValue(ua.Variant(state_num, ua.VariantType.Int16))
        self.request_state_num.set_value(dt)
        self.request.set_value(True)

    # def __extract_directive(self, string):
    #     result = self.hint_directive_re.split(string)
    #     if len(result) > 1:
    #         return result[0], result[1]
    #     else:
    #         return result[0], ""

    def disconnect(self):
        try:
            self.sub.unsubscribe(self.handle)  # cancel subscription
            self.sub.delete()
        except AttributeError:
            pass  # not subscribed, yet
        except Exception:
            print("Error trying to unsubscribe from the mic_active variable!")
        self.client.disconnect()
Ejemplo n.º 27
0
def run():
    logger.debug("Modular Input mi_opcua_event command: %s" % sys.argv)
    if len(sys.argv) > 1:
        try:
            if sys.argv[1] == "--scheme":
                do_scheme()
            elif sys.argv[1] == "--validate-arguments":
                validate_arguments()
            elif sys.argv[1] == "--test":
                test()
            else:
                usage()
        except Exception as ex:
            logger.critical(ex)
    else:
        logger.debug("Modular Input mi_opcua_event Starts data collection.")
        
        configs = get_config()
        logger.debug("Configuration: %s" % configs)
        stanza = configs["name"]
        # server_uri = configs["server_uri"]
        # sessionKey = configs["session_key"]
        # userName = "******"   # make this modular input as application context only.

        """
        wevts = configs["events"].strip()
        if len(wevts) <= 0:
            wevts = ["Objects", "Server"]
        else:
            wevts = wevts.split(":")
            
        patterns = configs["event_types"].strip()
        if len(patterns) <= 0:
            patterns = ["*"]
        else:
            patterns = patterns.split(":")
        """
            
        tout = configs["connection_timeout"].strip()
        timeout = 1 if len(tout) <= 0 else int(tout)

        cdur = configs["collect_duration"].strip()
        duration = 1000 if len(cdur) <= 0 else int(cdur)
        
        conn = configs["connection"]   ## "opc.tcp://ec2-54-190-162-94.us-west-2.compute.amazonaws.com:49320"
        if configs.has_key("username"):
            username = configs["username"].strip()
            if len(username)>0:
                password = configs["password"].strip()
                conn = "%s?username=%s&password=%s" % (conn, username, password)
    
        client = Client(conn, timeout=timeout)
        
        try:
            client.connect()
            #root = client.get_root_node()
            #m = node.get_child(root, wevts)
            #measures = []
            #node.collect_measures(measures, wevts, root)
                    
            handler = SubHandler(stanza)
            sub = client.create_subscription(duration, handler)
            h = sub.subscribe_events()
        
            """
            handles = []
            
            for evt in measures:
                try:
                    h = sub.subscribe_events(evt[len(evt)-1])
                    handles.append(h)
                except Exception as ex:
                    logger.warn(ex)
            """    
       
            def signal_handler(signal, frame):
                logger.info('Press Ctrl+C')
                
                if signal in [signal.SIGABRT, signal.SIGINT, signal.SIGQUIT, signal.SIGTERM]:
                    #[sub.unsubscribe(h) for h in handles]
                    sub.unsubscribe(h)
                    sub.delete()
                    client.disconnect()

            signal.signal(signal.SIGINT, signal_handler)
            signal.signal(signal.SIGABRT, signal_handler)
            signal.signal(signal.SIGTERM, signal_handler)
#            signal.signal(signal.SIGQUIT, signal_handler)

#            signal.pause()
                            
        except Exception as ex:
            logger.critical(ex)
        finally:
            logger.info("---- end of sub opc ua event ----")
Ejemplo n.º 28
0
class OpcUaConnector(Thread, Connector):
    def __init__(self, gateway, config, connector_type):
        self.__connector_type = connector_type
        self.statistics = {'MessagesReceived': 0, 'MessagesSent': 0}
        super().__init__()
        self.__gateway = gateway
        self.__server_conf = config.get("server")
        self.__interest_nodes = []
        self.__available_object_resources = {}
        for mapping in self.__server_conf["mapping"]:
            if mapping.get("deviceNodePattern") is not None:
                self.__interest_nodes.append(
                    {mapping["deviceNodePattern"]: mapping})
            else:
                log.error(
                    "deviceNodePattern in mapping: %s - not found, add property deviceNodePattern to processing this mapping",
                    dumps(mapping))
        if "opc.tcp" not in self.__server_conf.get("url"):
            opcua_url = "opc.tcp://" + self.__server_conf.get("url")
        else:
            opcua_url = self.__server_conf.get("url")
        self.client = Client(
            opcua_url,
            timeout=self.__server_conf.get("timeoutInMillis", 4000) / 1000)
        if self.__server_conf["identity"]["type"] == "cert.PEM":
            try:
                ca_cert = self.__server_conf["identity"].get("caCert")
                private_key = self.__server_conf["identity"].get("privateKey")
                cert = self.__server_conf["identity"].get("cert")
                security_mode = self.__server_conf["identity"].get(
                    "mode", "SignAndEncrypt")
                policy = self.__server_conf["security"]
                if cert is None or private_key is None:
                    log.exception(
                        "Error in ssl configuration - cert or privateKey parameter not found"
                    )
                    raise
                security_string = policy + ',' + security_mode + ',' + cert + ',' + private_key
                if ca_cert is not None:
                    security_string = security_string + ',' + ca_cert
                self.client.set_security_string(security_string)

            except Exception as e:
                log.exception(e)
        if self.__server_conf["identity"].get("username"):
            self.client.set_user(
                self.__server_conf["identity"].get("username"))
            if self.__server_conf["identity"].get("password"):
                self.client.set_password(
                    self.__server_conf["identity"].get("password"))

        self.setName(
            self.__server_conf.get(
                "name", 'OPC-UA Default ' +
                ''.join(choice(ascii_lowercase)
                        for _ in range(5))) + " Connector")
        self.__opcua_nodes = {}
        self._subscribed = {}
        self.data_to_send = []
        self.__sub_handler = SubHandler(self)
        self.__stopped = False
        self.__connected = False
        self.daemon = True

    def is_connected(self):
        return self.__connected

    def open(self):
        self.__stopped = False
        self.start()
        log.info("Starting OPC-UA Connector")

    def run(self):
        while not self.__connected:
            try:
                self.__connected = self.client.connect()
                self.client.load_type_definitions()
                log.debug(self.client.get_namespace_array()[-1])
                log.debug(
                    self.client.get_namespace_index(
                        self.client.get_namespace_array()[-1]))
            except ConnectionRefusedError:
                log.error(
                    "Connection refused on connection to OPC-UA server with url %s",
                    self.__server_conf.get("url"))
                time.sleep(10)
            except Exception as e:
                log.debug("error on connection to OPC-UA server.")
                log.error(e)
                time.sleep(10)
            else:
                self.__connected = True
                log.info("OPC-UA connector %s connected to server %s",
                         self.get_name(), self.__server_conf.get("url"))
        self.__opcua_nodes["root"] = self.client.get_root_node()
        self.__opcua_nodes["objects"] = self.client.get_objects_node()
        sub = self.client.create_subscription(
            self.__server_conf.get("scanPeriodInMillis", 500),
            self.__sub_handler)
        self.__search_name(self.__opcua_nodes["objects"], 2)
        self.__search_tags(self.__opcua_nodes["objects"], 2, sub)
        log.debug('Subscriptions: %s', self.subscribed)

        log.debug("Available methods: %s", self.__available_object_resources)
        while True:
            try:
                time.sleep(1)
                if self.data_to_send:
                    self.__gateway.send_to_storage(self.get_name(),
                                                   self.data_to_send.pop())
                if self.__stopped:
                    break
            except (KeyboardInterrupt, SystemExit):
                self.close()
                raise
            except Exception as e:
                self.close()
                log.exception(e)

    def close(self):
        self.__stopped = True
        self.client.disconnect()
        self.__connected = False
        log.info('%s has been stopped.', self.get_name())

    def get_name(self):
        return self.name

    def on_attributes_update(self, content):
        log.debug(content)
        try:
            for server_variables in self.__available_object_resources[
                    content["device"]]['variables']:
                for attribute in content["data"]:
                    for variable in server_variables:
                        if attribute == variable:
                            server_variables[variable].set_value(
                                content["data"][variable])
        except Exception as e:
            log.exception(e)

    def server_side_rpc_handler(self, content):
        try:
            for method in self.__available_object_resources[
                    content["device"]]['methods']:
                rpc_method = content["data"].get("method")
                if rpc_method is not None and method.get(
                        rpc_method) is not None:
                    arguments = content["data"].get("params")
                    if type(arguments) is list:
                        result = method["node"].call_method(
                            method[rpc_method], *arguments)
                    elif arguments is not None:
                        result = method["node"].call_method(
                            method[rpc_method], arguments)
                    else:
                        result = method["node"].call_method(method[rpc_method])

                    self.__gateway.send_rpc_reply(
                        content["device"], content["data"]["id"],
                        {content["data"]["method"]: result})

                    log.debug("method %s result is: %s", method[rpc_method],
                              result)
        except Exception as e:
            log.exception(e)

    def __search_name(self, node, recursion_level):
        try:
            for childId in node.get_children():
                ch = self.client.get_node(childId)
                current_var_path = '.'.join(
                    x.split(":")[1] for x in ch.get_path(20000, True))
                if self.__interest_nodes:
                    if ch.get_node_class() == ua.NodeClass.Object:
                        for interest_node in self.__interest_nodes:
                            for int_node in interest_node:
                                subrecursion_level = recursion_level
                                if subrecursion_level != recursion_level + len(
                                        interest_node[int_node]
                                    ["deviceNamePattern"].split("\\.")):
                                    if ch.get_display_name().Text in TBUtility.get_value(interest_node[int_node]["deviceNamePattern"], get_tag=True).split('.') or \
                                            re.search(TBUtility.get_value(interest_node[int_node]["deviceNodePattern"], get_tag=True), ch.get_display_name().Text):
                                        self.__search_name(
                                            ch, subrecursion_level + 1)
                                else:
                                    return
                    elif ch.get_node_class() == ua.NodeClass.Variable:
                        try:
                            for interest_node in self.__interest_nodes:
                                for int_node in interest_node:
                                    if interest_node[int_node].get(
                                            "deviceName") is None:
                                        try:
                                            name_pattern = TBUtility.get_value(
                                                interest_node[int_node]
                                                ["deviceNamePattern"],
                                                get_tag=True)
                                            log.debug(current_var_path)
                                            device_name_node = re.search(
                                                name_pattern.split('\\.')[-1],
                                                current_var_path)
                                            if device_name_node is not None:
                                                device_name = ch.get_value()
                                                if "${" + name_pattern + "}" in interest_node[
                                                        int_node][
                                                            "deviceNamePattern"]:
                                                    full_device_name = interest_node[
                                                        int_node][
                                                            "deviceNamePattern"].replace(
                                                                "${" +
                                                                name_pattern +
                                                                "}",
                                                                device_name)
                                                elif device_name in interest_node[
                                                        int_node][
                                                            "deviceNamePattern"]:
                                                    full_device_name = interest_node[
                                                        int_node][
                                                            "deviceNamePattern"].replace(
                                                                name_pattern,
                                                                device_name)
                                                else:
                                                    log.error(
                                                        "Name pattern not found."
                                                    )
                                                    break
                                                interest_node[int_node][
                                                    "deviceName"] = full_device_name
                                                if self.__available_object_resources.get(
                                                        full_device_name
                                                ) is None:
                                                    self.__available_object_resources[
                                                        full_device_name] = {
                                                            'methods': [],
                                                            'variables': []
                                                        }
                                                if not self.__gateway.get_devices(
                                                ).get(full_device_name):
                                                    self.__gateway.add_device(
                                                        full_device_name,
                                                        {"connector": None})
                                                self.__gateway.update_device(
                                                    full_device_name,
                                                    "connector", self)
                                            else:
                                                try:
                                                    if re.search(
                                                            int_node.split(
                                                                '\\.')
                                                        [recursion_level - 2],
                                                            ch.
                                                            get_display_name(
                                                            ).Text):
                                                        self.__search_name(
                                                            ch,
                                                            recursion_level +
                                                            1)
                                                except IndexError:
                                                    if re.search(
                                                            int_node.split(
                                                                '\\.')[-1],
                                                            ch.
                                                            get_display_name(
                                                            ).Text):
                                                        self.__search_name(
                                                            ch,
                                                            recursion_level +
                                                            1)

                                        except Exception as e:
                                            log.exception(e)
                                    else:
                                        break
                        except BadWaitingForInitialData:
                            pass
                elif not self.__interest_nodes:
                    log.error(
                        "Nodes in mapping not found, check your settings.")
        except Exception as e:
            log.exception(e)

    def __search_tags(self, node, recursion_level, sub=None):
        try:
            for childId in node.get_children():
                ch = self.client.get_node(childId)
                current_var_path = '.'.join(
                    x.split(":")[1] for x in ch.get_path(20000, True))
                if self.__interest_nodes:
                    if ch.get_node_class() == ua.NodeClass.Object:
                        for interest_node in self.__interest_nodes:
                            for int_node in interest_node:
                                try:
                                    name_to_check = int_node.split('\\.')[
                                        recursion_level -
                                        1] if '\\.' in int_node else int_node
                                    name_to_check = int_node.split(
                                        '.'
                                    )[recursion_level -
                                      1] if '.' in int_node else name_to_check
                                except IndexError:
                                    name_to_check = int_node.split(
                                        '\\.'
                                    )[-1] if '\\.' in int_node else int_node
                                    name_to_check = int_node.split(
                                        '.'
                                    )[-1] if '.' in int_node else name_to_check
                                if re.search(name_to_check,
                                             ch.get_display_name().Text):
                                    try:
                                        methods = ch.get_methods()
                                        for method in methods:
                                            self.__available_object_resources[
                                                interest_node[int_node]
                                                ["deviceName"]][
                                                    "methods"].append({
                                                        method.get_display_name(
                                                        ).Text:
                                                        method,
                                                        "node":
                                                        ch
                                                    })
                                    except Exception as e:
                                        log.exception(e)
                                for tag in interest_node[int_node][
                                        "timeseries"] + interest_node[
                                            int_node]["attributes"]:
                                    subrecursion_level = recursion_level
                                    if subrecursion_level != recursion_level + len(
                                            tag["path"].split("\\.")):
                                        self.__search_tags(
                                            ch, subrecursion_level + 1, sub)
                                    else:
                                        return
                                self.__search_tags(ch, recursion_level + 1,
                                                   sub)
                    elif ch.get_node_class() == ua.NodeClass.Variable:
                        try:
                            for interest_node in self.__interest_nodes:
                                for int_node in interest_node:
                                    if interest_node[int_node].get(
                                            "attributes_updates"):
                                        try:
                                            for attribute_update in interest_node[
                                                    int_node][
                                                        "attributes_updates"]:
                                                if attribute_update[
                                                        "attributeOnDevice"] == ch.get_display_name(
                                                        ).Text:
                                                    self.__available_object_resources[
                                                        interest_node[int_node]
                                                        ["deviceName"]][
                                                            'variables'].append({
                                                                attribute_update["attributeOnThingsBoard"]:
                                                                ch,
                                                            })
                                        except Exception as e:
                                            log.exception(e)
                                    name_to_check = int_node.split(
                                        '\\.'
                                    )[-1] if '\\.' in int_node else int_node
                                    name_to_check = int_node.split(
                                        '.'
                                    )[-1] if '.' in int_node else name_to_check
                                    if re.search(
                                            name_to_check.replace('$', ''),
                                            current_var_path):
                                        tags = []
                                        if interest_node[int_node].get(
                                                "attributes"):
                                            tags.extend(interest_node[int_node]
                                                        ["attributes"])
                                        if interest_node[int_node].get(
                                                "timeseries"):
                                            tags.extend(interest_node[int_node]
                                                        ["timeseries"])
                                        for tag in tags:
                                            target = TBUtility.get_value(
                                                tag["path"], get_tag=True)
                                            try:
                                                tag_name_for_check = target.split(
                                                    '\\.'
                                                )[recursion_level -
                                                  1] if '\\.' in target else target
                                                tag_name_for_check = target.split(
                                                    '.'
                                                )[recursion_level -
                                                  1] if '.' in target else tag_name_for_check
                                            except IndexError:
                                                tag_name_for_check = target.split(
                                                    '\\.'
                                                )[-1] if '\\.' in target else target
                                                tag_name_for_check = target.split(
                                                    '.'
                                                )[-1] if '.' in target else tag_name_for_check
                                            current_node_name = ch.get_display_name(
                                            ).Text
                                            if current_node_name == tag_name_for_check:
                                                sub.subscribe_data_change(ch)
                                                if interest_node[int_node].get(
                                                        "uplink_converter"
                                                ) is None:
                                                    if interest_node[
                                                            int_node].get(
                                                                'converter'
                                                            ) is None:
                                                        converter = OpcUaUplinkConverter(
                                                            interest_node[
                                                                int_node])
                                                    else:
                                                        converter = TBUtility.check_and_import(
                                                            self.
                                                            __connector_type,
                                                            interest_node[
                                                                int_node]
                                                            ['converter'])
                                                    interest_node[int_node][
                                                        "uplink_converter"] = converter
                                                else:
                                                    converter = interest_node[
                                                        int_node][
                                                            "uplink_converter"]
                                                self.subscribed[ch] = {
                                                    "converter": converter,
                                                    "path": current_var_path
                                                }
                                    else:
                                        return
                        except BadWaitingForInitialData:
                            pass
                    elif not self.__interest_nodes:
                        log.error(
                            "Nodes in mapping not found, check your settings.")
        except Exception as e:
            log.exception(e)

    @property
    def subscribed(self):
        return self._subscribed
Ejemplo n.º 29
0
class UaClient(object):
    """
    OPC-Ua client specialized for the need of GUI client
    return exactly whant GUI needs, no customization possible
    """
    def __init__(self):
        self.client = None
        self._connected = False
        self._subscription = None

    def connect(self, uri):
        self.disconnect()
        print("Connecting to ", uri)
        self.client = Client(uri)
        self.client.connect()
        self._connected = True
        print("Connected, root is: ", self.client.get_root_node())
        print(self.get_root_attrs())

    def disconnect(self):
        if self._connected:
            print("Disconnecting from server")
            self._connected = False
            self._subscription = None
            self.client.disconnect()
            self.client = None

    def subscribe(self, node, handler):
        if not self._subscription:
            self._subscription = self.client.create_subscription(500, handler)
        self._subscription.subscribe_data_change(node)

    def get_root_attrs(self):
        return self.get_node_attrs(self.client.get_root_node())

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

    def get_children(self, node):
        descs = node.get_children_descriptions()
        children = []
        for desc in descs:
            children.append([
                self.client.get_node(desc.NodeId),
                desc.DisplayName.to_string(),
                desc.BrowseName.to_string(),
                desc.NodeId.to_string()
            ])
        return children

    def get_all_attrs(self, node):
        names = []
        vals = []
        for name, val in ua.AttributeIds.__dict__.items():
            if not name.startswith("_"):
                names.append(name)
                vals.append(val)

        attrs = node.get_attributes(vals)
        res = {}
        for idx, name in enumerate(names):
            if attrs[idx].StatusCode.is_good():
                res[name] = attrs[idx].Value.Value
        return res

    def get_all_refs(self, node):
        return node.get_children_descriptions(refs=ObjectIds.References)
Ejemplo n.º 30
0
class Client_opc():

    def __init__(self, cert_path, server_path, policy, mode, AggrObject, handle_dict):
        self.cert_path = cert_path #certificates path
        self.server_path = server_path
        self.policy = policy
        self.mode = mode
        self.AggrObject = AggrObject
        self.handle_dict = handle_dict


    #istantiating Client calling "Client" constructor into stack opcua, set name and calling set_security_string method in the stack
    def client_instantiate(self):
        self.client = Client(self.server_path) #instaniate client
        self.client.name = "AggregationClient"
        if ((self.policy != "None") and (self.mode != "None")):
            #this method take a string as input that contains policy, mode, client certificate path and private key path. The endpoint that satisfies this characteristichs is choosed
            self.client.set_security_string(self.policy+","+self.mode+","+self.cert_path+"client_certificate.der,"+self.cert_path+"client_private_key.pem") #SecurityPolicy, Mode, Certificate path, Private key path


    #This method call the "connect" method in the stack. This method creates secure channel, create the session and activate it
    def secure_channel_and_session_activation(self):
        #params requested from the client. Server can set another value based on its requirements
        self.client.secure_channel_timeout = 10000
        self.client.session_timeout = 10000
        try:
            self.client.connect() #create secure channel and session; activate session
            print("Client instantiated; secure channel and session created; session activated ")
        except: 
            #if exception occures, disconnect the client
            self.client.disconnect()


    #This method disconnect the client from the server, closing session and secure channel
    def disconnect(self):
        self.client.disconnect()


    #This method is called when we want only to read Data
    def readData(self,node_id, polling_dict):
        #Get node
        node = self.client.get_node(node_id) #Client.py stack function
        #Get values
        value = node.get_data_value() #Node.py stack function
        print(f"Polling Service readed value : {value} ")
        #Set readed values in the local variables
        AggrVar = self.AggrObject.get_variables()
        for var in AggrVar: 
            for key in polling_dict:
                remote_node = self.client.get_node(polling_dict[key])
                if(remote_node == node and str(var.nodeid) == key):
                    var.set_value(value)
                    

    '''This method is our stack method revisitation to set our parameter values'''
    #This method is used in the "subscribe" method to create the filter for making the monitored item request
    def set_datachange_filter(self, deadband_val, deadbandtype=1):
        deadband_filter = ua.DataChangeFilter()
        deadband_filter.Trigger = ua.DataChangeTrigger(1)  # send notification when status or value change
        deadband_filter.DeadbandType = deadbandtype #type = 0 -> notification every change; type = 1 -> absolute deadband_val is considered; type = 2 -> percent deadband_val is considered
        deadband_filter.DeadbandValue = deadband_val
        return deadband_filter


    '''This method is our stack method revisitation to set our parameter values'''
    #This method is called in the "subscribe" method for creating the monitored items for the nodes passed. 
    def create_monitored_item(self, subscription, nodes , sampling_interval, client_handle, filter=None, queuesize = 0, discard_oldest = True, attr=ua.AttributeIds.Value):
        is_list = True
        if isinstance(nodes, Iterable):
            nodes = list(nodes)
        else:
            nodes = [nodes]
            is_list = False
        mirs = []
        for node in nodes:
            mir = self.make_monitored_item_request(subscription, node, attr, sampling_interval, client_handle, filter, queuesize, discard_oldest) #making monitored item request
            mirs.append(mir)

        mids = subscription.create_monitored_items(mirs)
        if is_list:
            return mids
        if type(mids[0]) == ua.StatusCode:
            mids[0].check()
        return mids[0] #return a list of handles (monitored item ids)


    '''This method is our stack method revisitation to set our parameter values'''
    #This method sets our params obtained from the conf file and make the monitored item request
    def make_monitored_item_request(self, subscription, node, attr, sampling_interval, client_handle, filter, queuesize, discard_oldest):
        rv = ua.ReadValueId()
        rv.NodeId = node.nodeid
        rv.AttributeId = attr
        mparams = ua.MonitoringParameters()
        with subscription._lock:
            subscription._client_handle = client_handle
            mparams.ClientHandle = subscription._client_handle
        mparams.SamplingInterval = sampling_interval
        mparams.QueueSize = queuesize
        mparams.DiscardOldest = discard_oldest
        if filter:
            mparams.Filter = filter
        mir = ua.MonitoredItemCreateRequest() #stack request
        mir.ItemToMonitor = rv
        mir.MonitoringMode = ua.MonitoringMode.Reporting
        mir.RequestedParameters = mparams
        return mir


    #This method is called when we want only to subscribe to Data. It takes as input sub infos and mon_item infos from conf file
    def subscribe(self, monitored_nodes, sub_infos):
            #Create the handlers
            handler = []
            for i in range(len(sub_infos)):
                handler.append(SubHandler(self.AggrObject, self.handle_dict))
            #Creating a subscription for ech 'sub_infos' element in the config file (different types of subscriptions -> different parameters)
            sub = []
            sub_index_list = []
            for i in range(len(monitored_nodes)):
                sub_index_list.append(monitored_nodes[i]["subIndex"])
            for i in range(len(sub_infos)):
                if(i in sub_index_list):
                    #Set sub parameters
                    params = ua.CreateSubscriptionParameters()
                    params.RequestedPublishingInterval = sub_infos[i]['requested_publish_interval']
                    params.RequestedLifetimeCount = sub_infos[i]['requested_lifetime_count']
                    params.RequestedMaxKeepAliveCount = sub_infos[i]['requested_max_keepalive_timer']
                    params.MaxNotificationsPerPublish = sub_infos[i]['max_notif_per_publish']
                    params.PublishingEnabled = sub_infos[i]['publishing_enabled']
                    params.Priority = sub_infos[i]['priority']
                    #Create the subscription
                    sub.append(self.client.create_subscription(params, handler[i]))
            #handle will contains mon_item_ids 
            handle = []
            Aggr_key = []
            for key in self.handle_dict:
                Aggr_key.append(key)
            for i in range(len(monitored_nodes)):                     
                filter = self.set_datachange_filter(monitored_nodes[i]['deadbandval'], monitored_nodes[i]['deadbandtype']) #Set filter from config parameters setted in the config file
                handle.append(self.create_monitored_item(sub[monitored_nodes[i]['subIndex']], self.client.get_node(monitored_nodes[i]['nodeTomonitor']),  monitored_nodes[i]['sampling_interval'] ,self.handle_dict[Aggr_key[i]], filter, monitored_nodes[i]['queue_size'], monitored_nodes[i]['discard_oldest'])) #handle = list of monitored items ids
            #handler.datachange_notification is called when a value of the monitored nodes has changed
            return sub, handle
    

    #This method take as input the subscription list and handle list of monitored items that we want to delete
    def delete_monit_items(self, sub, handle):
       for i in range(len(sub)):
            for mid in handle:
                try:
                    #stack function called on the subscription
                    sub[i].unsubscribe(mid) #unsubscribe to data_change/events of the selected monitored items (handle -> list of monitored items ids)
                except ua.uaerrors._auto.BadMonitoredItemIdInvalid: 
                    #This except is added because we call the unsubscribe stack method (delete monitored_item) for every subscription, but the monitored item is present only in one of them                        #So, in the other subscriptions, the BadMonitoredItemInvalid is raised, but we want to ignore this error
                    pass
    


    #This method takes as input the subscriptions list and delete them
    def delete_sub(self, sub):
        try:
            for i in range(len(sub)):
                sub[i].delete() #Stack method call on the subscription(this method delete every monitored item in the subscription and delete the subscription)
        except Exception:
            print("An Error was occured in client.delete function!")
Ejemplo n.º 31
0
            args=(node, val))  # Se realiza la descarga por un thread
        thread_handler.start()

    def event_notification(self, event):
        global evento_alarma
        evento_alarma = event
        #print(event)


eventos = rootNode.get_child(
    ["0:Types", "0:EventTypes", "0:BaseEventType",
     "2:Alarma_nivel"])  # TIPO DE EVENTO
obj_evento = objectsNode.get_child(
    ['2:Proceso_Tanques', '2:Alarmas', '2:Alarma_nivel'])  # OBJETO EVENTO
handler_event = SubHandler()
sub_event = client.create_subscription(100,
                                       handler_event)  #Subscripción al evento
handle_event = sub_event.subscribe_events(obj_evento, eventos)

#########################################################################


def funcion_guardado(mem_pd, T_init, T_now):
    global extension
    nombre = f"{T_init} - {T_now}{extension}"
    if extension == '.csv':
        mem_pd.to_csv(nombre)
    elif extension == '.txt':
        mem_npy = mem_pd.to_numpy()
        np.savetxt(nombre, mem_npy, fmt='%s')
    elif extension == '.npy':
        mem_npy = mem_pd.to_numpy()
class Cliente():
    def __init__(self, direccion, suscribir_eventos, SubHandler):
        self.direccion = direccion
        self.client = Client(direccion)
        self.alturas = {'H1': 0, 'H2': 0, 'H3':0, 'H4':0}
        self.temperaturas = {'T1': 0, 'T2': 0, 'T3':0, 'T4':0}
        self.valvulas = {'valvula1':0, 'valvula2':0}
        self.razones = {'razon1':0, 'razon2': 0}
        self.subscribir_eventos = suscribir_eventos
        self.periodo = 100 # cantidad de milisegundos para revisar las variables subscritas
        self.SubHandlerClass = SubHandler

    def Instanciacion(self):
        self.root = self.client.get_root_node()
        self.objects = self.client.get_objects_node()
        self.Tanques = self.objects.get_child(['2:Proceso_Tanques','2:Tanques'])
        self.Valvulas = self.objects.get_child(['2:Proceso_Tanques', '2:Valvulas'])
        self.Razones = self.objects.get_child(['2:Proceso_Tanques', '2:Razones'])


        # Obtención de las alturas
        self.alturas['H1'] = self.Tanques.get_child(['2:Tanque1', '2:h'])
        self.alturas['H2'] = self.Tanques.get_child(['2:Tanque2', '2:h'])
        self.alturas['H3'] = self.Tanques.get_child(['2:Tanque3', '2:h'])
        self.alturas['H4'] = self.Tanques.get_child(['2:Tanque4', '2:h'])

        # Obtención de temperaturas
        self.temperaturas['T1'] = self.Tanques.get_child(['2:Tanque1', '2:T'])
        self.temperaturas['T2'] = self.Tanques.get_child(['2:Tanque2', '2:T'])
        self.temperaturas['T3'] = self.Tanques.get_child(['2:Tanque3', '2:T'])
        self.temperaturas['T4'] = self.Tanques.get_child(['2:Tanque4', '2:T'])

        # Obtención de los pumps
        self.valvulas['valvula1'] = self.Valvulas.get_child(['2:Valvula1', '2:u'])
        self.valvulas['valvula2'] = self.Valvulas.get_child(['2:Valvula2', '2:u'])

        # Obtención de los switches
        self.razones['razon1'] = self.Razones.get_child(['2:Razon1', '2:gamma'])
        self.razones['razon2'] = self.Razones.get_child(['2:Razon2', '2:gamma'])

        # Evento (alarma en este caso)
        if self.subscribir_eventos:
            self.myevent = self.root.get_child(["0:Types", "0:EventTypes", "0:BaseEventType", "2:Alarma_nivel"])#Tipo de evento
            self.obj_event = self.objects.get_child(['2:Proceso_Tanques', '2:Alarmas', '2:Alarma_nivel'])#Objeto Evento
            self.handler_event = self.SubHandlerClass()
            self.sub_event = self.client.create_subscription(self.periodo, self.handler_event)#Subscripción al evento
            self.handle_event = self.sub_event.subscribe_events(self.obj_event, self.myevent)


    def subscribir_cv(self): # Subscripción a las variables controladas
        self.handler_cv = self.SubHandlerClass()
        self.sub_cv = self.client.create_subscription(self.periodo, self.handler_cv)
        for key, var in self.alturas.items():
            self.sub_cv.subscribe_data_change(var)
        for key, var in self.temperaturas.items():
            self.sub_cv.subscribe_data_change(var)


    def subscribir_mv(self): # Subscripación a las variables manipuladas
        self.handler_mv = self.SubHandlerClass()
        self.sub_mv = self.client.create_subscription(self.periodo, self.handler_mv)
        for key, var in self.valvulas.items():
            self.sub_mv.subscribe_data_change(var)
        for key, var in self.razones.items():
            self.sub_mv.subscribe_data_change(var)


    def conectar(self):
            self.client.connect()
            self.objects = self.client.get_objects_node()
            print('Cliente OPCUA se ha conectado')
            self.Instanciacion()

            #self.client.disconnect()
            #print('Cliente no se ha podido conectar')



#cliente = Cliente("opc.tcp://localhost:4840/freeopcua/server/", suscribir_eventos=True, SubHandlerClass=SubHandler)
#cliente.conectar()
#cliente.subscribir_mv() # Se subscribe a las variables manipuladas
Ejemplo n.º 33
0
class Plant(threading.Thread):
    def __init__(self, ip):
        super().__init__()
        self.client = Client(ip)
        self.objects = self.assign_object()
        self.heights = {'h1': 0, 'h2': 0, 'h3': 0, 'h4': 0}
        self._u = [0, 0]
        self.sample_time = 0.001
        self.daemon = True  ## Que termine de medir cuando termine el programa (debug)
        self.event_measure = threading.Event()

    def assign_object(self):
        """Conecta el cliente y retorna el objeto donde se encuentra la planta en el servidor"""

        self.client.connect()
        return self.client.get_objects_node()

    def get_heights(self):
        """Obtiene las alturas y las almacena en un diccionario con indices h1, h2, h3, h4"""

        for i in range(1, 5):
            node = self.objects.get_child([
                '2:Parametros', f'2:Altura {i}'
            ])  ## '2:Proceso_Tanques', '2:Tanques', f'2:Tanque{i}', '2:h'
            self.heights[f'h{i}'] = node.get_value(
            )  #NoneType object does not support item assig

    def get_show_heights(self):
        return [x for x in self.heights.values()]

    def suscribe_alarm(self):
        """Suscribe la alarma que esta overwrited en la clase SubHandler"""

        alarm = self.objects.get_child(
            ['2:Proceso_Tanques', '2:Alarmas', f'2:Alarma_nivel'])
        handler = SubHandler()
        sub = self.client.create_subscription(500, handler)
        handle = sub.subscribe_events(alarm)
        time.sleep(0.1)

    def assign_valve_value(self):
        """Constantemente, asigna las variablaes almacenadas en el atributo self.u, a la planta"""

        u1 = self.objects.get_child([
            '2:Parametros', '2: Válvula 1'
        ])  ## '2:Proceso_Tanques', '2:Valvulas', f'2:Valvula1', '2:u'
        u2 = self.objects.get_child([
            '2:Parametros', '2: Válvula 2'
        ])  ## '2:Proceso_Tanques', '2:Valvulas', f'2:Valvula2', '2:u'
        u1.set_value(self.u[0])
        u2.set_value(self.u[1])

    @property
    def u(self):
        return self._u

    @u.setter
    def u(self, value):
        if not None in value:
            self._u = list(value)
        else:
            self._u = self._u

    def run(self):
        # self.suscribe_alarm()  // no hay alarma en simulacion
        while True:
            if sum(self.u) > 0:
                self.assign_valve_value()
                self.u = [0, 0]
            self.event_measure.set(
            )  ## Revisar esto porque no se esta cumpliendo
            self.get_heights()
            time.sleep(self.sample_time)
Ejemplo n.º 34
0
        print("New event recived: ", event)


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)

        # Now getting a variable node using its browse path
        obj = root.get_child(["0:Objects", "2:MyObject"])
        print("MyObject is: ", obj)

        myevent = root.get_child(["0:Types", "0:EventTypes", "0:BaseEventType", "2:MyFirstEvent"])
        print("MyFirstEventType is: ", myevent)

        msclt = SubHandler()
        sub = client.create_subscription(100, msclt)
        handle = sub.subscribe_events(obj, myevent)

        embed()
        sub.unsubscribe(handle)
        sub.delete()
    finally:
        client.disconnect()
Ejemplo n.º 35
0
class OpcProtocol():
    '''
    OPC Protocol settings
    '''
    def string_to_node_type(self, type='string'):
        if type == 'string':
            return ua.NodeIdType.String
        elif type == 'numeric':
            return ua.NodeIdType.Numeric
        else:
            return ua.NodeIdType.ByteString

    def __del__(self):
        self.Disconnect()

    def __init__(self, server_name):
        self.server_name = server_name

        namespaces = VAR.OPC_SERVERS[server_name]["namespaces"]

        # Get OPC UA node type
        for namespace in namespaces.keys():
            nodes = VAR.OPC_SERVERS[server_name]["namespaces"][namespace]["nodes"]
            for node in nodes:
                type = nodes[node]["opc_type"]
                nodes[node]["opc_type"] = self.string_to_node_type(type)

        self.Connect()

    def Connect(self):
        '''
        For creating connection to OPC UA Server
        '''
        server = VAR.OPC_SERVERS[self.server_name]["opc_server"]
        namespaces = VAR.OPC_SERVERS[self.server_name]["namespaces"]
        
        self.client = Client(server)
        try:
            self.client.connect()
            
            for namespace in namespaces.keys():
                VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["index"] = self.client.get_namespace_index(namespace)

        except Exception as e:
            print('Connect error:', e)
        finally:
            self.firstrun()


    def remove_subscribe(self):
        namespaces = VAR.OPC_SERVERS[self.server_name]["namespaces"]
        for namespace in namespaces.keys():
            nodes = VAR.OPC_SERVERS[self.server_name]['namespaces'][namespace]["nodes"]
            for node in nodes.keys():
                VAR.OPC_SERVERS[self.server_name]['namespaces'][namespace]["nodes"][node]["subscribe"].unsubscribe(
                    VAR.OPC_SERVERS[self.server_name]['namespaces'][namespace]["nodes"][node]["handler"]
                )
                VAR.OPC_SERVERS[self.server_name]['namespaces'][namespace]["nodes"][node]["subscribe"].delete()
        return True


    def Disconnect(self):
        '''
        Disconnect from OPC UA Server
        '''
        try:
            self.remove_subscribe()
            self.client.disconnect()
        except Exception as e:
            print('Disconnect error:', e)
        return "disconnect done"

    def create_node(self, node, namespace, type):
        return ua.NodeId(identifier=node, namespaceidx=namespace, nodeidtype=type)

    def firstrun(self):
        '''
        When OPC UA Server connection has been established, do this once
        '''
        try:
            if VAR.FIRST_RUN:
                namespaces = VAR.OPC_SERVERS[self.server_name]["namespaces"]

                for namespace in namespaces.keys():
                    index = VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["index"]
                    nodes = VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["nodes"]
                    for node in nodes.keys():
                        type = VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["nodes"][node]["opc_type"]
                        nodeid = self.create_node(node, index, type)
                        VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["nodes"][node]["opc_nodeid"] = nodeid

                        this_node = self.client.get_node(nodeid)
                        VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["nodes"][node]["opc_variable"] = this_node

                        value = this_node.get_value()

                        VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["nodes"][node]["value"] = value
                        VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["nodes"][node]["timestamp"] = str(datetime.datetime.utcnow())

                        VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["nodes"][node]["handler"] = NodeHandler(self.server_name, namespace)
                        VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["nodes"][node]["subscribe"] = self.client.create_subscription(
                            100,
                            VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["nodes"][node]["handler"]
                        )
                        VAR.OPC_SERVERS[self.server_name]["namespaces"][namespace]["nodes"][node]["subscribe"].subscribe_data_change(this_node)
        except Exception as e:
            print('firstRun error:', e)
        finally:
            VAR.FIRST_RUN = False

    def reset(self):
        self.remove_subscribe()
        VAR.FIRST_RUN = True
        self.firstrun()
Ejemplo n.º 36
0
class OpcUaConnector(Thread, Connector):
    def __init__(self, gateway, config, connector_type):
        self._connector_type = connector_type
        self.statistics = {'MessagesReceived': 0, 'MessagesSent': 0}
        super().__init__()
        self.__gateway = gateway
        self.__server_conf = config.get("server")
        self.__interest_nodes = []
        self.__available_object_resources = {}
        self.__show_map = self.__server_conf.get("showMap", False)
        self.__previous_scan_time = 0
        for mapping in self.__server_conf["mapping"]:
            if mapping.get("deviceNodePattern") is not None:
                self.__interest_nodes.append(
                    {mapping["deviceNodePattern"]: mapping})
            else:
                log.error(
                    "deviceNodePattern in mapping: %s - not found, add property deviceNodePattern to processing this mapping",
                    dumps(mapping))
        if "opc.tcp" not in self.__server_conf.get("url"):
            opcua_url = "opc.tcp://" + self.__server_conf.get("url")
        else:
            opcua_url = self.__server_conf.get("url")
        self.client = Client(
            opcua_url,
            timeout=self.__server_conf.get("timeoutInMillis", 4000) / 1000)
        if self.__server_conf["identity"]["type"] == "cert.PEM":
            try:
                ca_cert = self.__server_conf["identity"].get("caCert")
                private_key = self.__server_conf["identity"].get("privateKey")
                cert = self.__server_conf["identity"].get("cert")
                security_mode = self.__server_conf["identity"].get(
                    "mode", "SignAndEncrypt")
                policy = self.__server_conf["security"]
                if cert is None or private_key is None:
                    log.exception(
                        "Error in ssl configuration - cert or privateKey parameter not found"
                    )
                    raise
                security_string = policy + ',' + security_mode + ',' + cert + ',' + private_key
                if ca_cert is not None:
                    security_string = security_string + ',' + ca_cert
                self.client.set_security_string(security_string)

            except Exception as e:
                log.exception(e)
        if self.__server_conf["identity"].get("username"):
            self.client.set_user(
                self.__server_conf["identity"].get("username"))
            if self.__server_conf["identity"].get("password"):
                self.client.set_password(
                    self.__server_conf["identity"].get("password"))

        self.setName(
            self.__server_conf.get(
                "name", 'OPC-UA ' +
                ''.join(choice(ascii_lowercase)
                        for _ in range(5))) + " Connector")
        self.__opcua_nodes = {}
        self._subscribed = {}
        self.data_to_send = []
        self.__sub_handler = SubHandler(self)
        self.__stopped = False
        self.__connected = False
        self.daemon = True

    def is_connected(self):
        return self.__connected

    def open(self):
        self.__stopped = False
        self.start()
        log.info("Starting OPC-UA Connector")

    def run(self):
        while not self.__connected:
            try:
                self.__connected = self.client.connect()
                try:
                    self.client.load_type_definitions()
                except Exception as e:
                    log.debug(e)
                    log.debug("Error on loading type definitions.")
                log.debug(self.client.get_namespace_array()[-1])
                log.debug(
                    self.client.get_namespace_index(
                        self.client.get_namespace_array()[-1]))
            except ConnectionRefusedError:
                log.error(
                    "Connection refused on connection to OPC-UA server with url %s",
                    self.__server_conf.get("url"))
                time.sleep(10)
            except OSError:
                log.error(
                    "Connection refused on connection to OPC-UA server with url %s",
                    self.__server_conf.get("url"))
                time.sleep(10)
            except Exception as e:
                log.debug("error on connection to OPC-UA server.")
                log.error(e)
                time.sleep(10)
            else:
                self.__connected = True
                log.info("OPC-UA connector %s connected to server %s",
                         self.get_name(), self.__server_conf.get("url"))
        self.__opcua_nodes["root"] = self.client.get_objects_node()
        self.__opcua_nodes["objects"] = self.client.get_objects_node()
        if not self.__server_conf.get("disableSubscriptions", False):
            self.__sub = self.client.create_subscription(
                self.__server_conf.get("subCheckPeriodInMillis", 500),
                self.__sub_handler)
        else:
            self.__sub = False
        self.__scan_nodes_from_config()
        self.__previous_scan_time = time.time() * 1000
        log.debug('Subscriptions: %s', self.subscribed)
        log.debug("Available methods: %s", self.__available_object_resources)
        while not self.__stopped:
            try:
                time.sleep(.1)
                self.__check_connection()
                if not self.__connected and not self.__stopped:
                    self.client.connect()
                elif not self.__stopped:
                    if self.__server_conf.get(
                            "disableSubscriptions", False
                    ) and time.time(
                    ) * 1000 - self.__previous_scan_time > self.__server_conf.get(
                            "scanPeriodInMillis", 60000):
                        self.__scan_nodes_from_config()
                        self.__previous_scan_time = time.time() * 1000

                    if self.data_to_send:
                        self.__gateway.send_to_storage(self.get_name(),
                                                       self.data_to_send.pop())
                if self.__stopped:
                    self.close()
                    break
            except (KeyboardInterrupt, SystemExit):
                self.close()
                raise
            except ConnectionRefusedError:
                log.error(
                    "Connection refused on connection to OPC-UA server with url %s",
                    self.__server_conf.get("url"))
                time.sleep(10)
            except Exception as e:
                self.close()
                log.exception(e)

    def __check_connection(self):
        try:
            node = self.client.get_root_node()
            node.get_children()
            self.__connected = True
        except ConnectionRefusedError:
            self.__connected = False
            self._subscribed = {}
            self.__sub = None
        except OSError:
            self.__connected = False
            self._subscribed = {}
            self.__sub = None
        except TimeoutError:
            self.__connected = False
            self._subscribed = {}
            self.__sub = None
        except AttributeError:
            self.__connected = False
            self._subscribed = {}
            self.__sub = None
        except Exception as e:
            self.__connected = False
            self._subscribed = {}
            self.__sub = None
            log.exception(e)

    def close(self):
        self.__stopped = True
        if self.__connected:
            self.client.disconnect()
        self.__connected = False
        log.info('%s has been stopped.', self.get_name())

    def get_name(self):
        return self.name

    def on_attributes_update(self, content):
        log.debug(content)
        try:
            for server_variables in self.__available_object_resources[
                    content["device"]]['variables']:
                for attribute in content["data"]:
                    for variable in server_variables:
                        if attribute == variable:
                            server_variables[variable].set_value(
                                content["data"][variable])
        except Exception as e:
            log.exception(e)

    def server_side_rpc_handler(self, content):
        try:
            for method in self.__available_object_resources[
                    content["device"]]['methods']:
                rpc_method = content["data"].get("method")
                if rpc_method is not None and method.get(
                        rpc_method) is not None:
                    arguments_from_config = method["arguments"]
                    arguments = content["data"].get(
                        "params") if content["data"].get(
                            "params") is not None else arguments_from_config
                    try:
                        if type(arguments) is list:
                            result = method["node"].call_method(
                                method[rpc_method], *arguments)
                        elif arguments is not None:
                            result = method["node"].call_method(
                                method[rpc_method], arguments)
                        else:
                            result = method["node"].call_method(
                                method[rpc_method])

                        self.__gateway.send_rpc_reply(
                            content["device"], content["data"]["id"], {
                                content["data"]["method"]: result,
                                "code": 200
                            })
                        log.debug("method %s result is: %s",
                                  method[rpc_method], result)
                    except Exception as e:
                        log.exception(e)
                        self.__gateway.send_rpc_reply(content["device"],
                                                      content["data"]["id"], {
                                                          "error": str(e),
                                                          "code": 500
                                                      })
                else:
                    log.error("Method %s not found for device %s", rpc_method,
                              content["device"])
                    self.__gateway.send_rpc_reply(
                        content["device"], content["data"]["id"], {
                            "error": "%s - Method not found" % (rpc_method),
                            "code": 404
                        })
        except Exception as e:
            log.exception(e)

    def __scan_nodes_from_config(self):
        try:
            if self.__interest_nodes:
                for device_object in self.__interest_nodes:
                    for current_device in device_object:
                        try:
                            device_configuration = device_object[
                                current_device]
                            devices_info_array = self.__search_general_info(
                                device_configuration)
                            for device_info in devices_info_array:
                                if device_info is not None and device_info.get(
                                        "deviceNode") is not None:
                                    self.__search_nodes_and_subscribe(
                                        device_info)
                                    self.__save_methods(device_info)
                                    self.__search_attribute_update_variables(
                                        device_info)
                                else:
                                    log.error(
                                        "Device node is None, please check your configuration."
                                    )
                                    log.debug(
                                        "Current device node is: %s",
                                        str(
                                            device_configuration.get(
                                                "deviceNodePattern")))
                                    break
                        except Exception as e:
                            log.exception(e)
                log.debug(self.__interest_nodes)
        except Exception as e:
            log.exception(e)

    def __search_nodes_and_subscribe(self, device_info):
        information_types = {
            "attributes": "attributes",
            "timeseries": "telemetry"
        }
        for information_type in information_types:
            for information in device_info["configuration"][information_type]:
                information_key = information["key"]
                config_path = TBUtility.get_value(information["path"],
                                                  get_tag=True)
                information_path = self._check_path(config_path,
                                                    device_info["deviceNode"])
                information["path"] = '${%s}' % information_path
                information_nodes = []
                self.__search_node(device_info["deviceNode"],
                                   information_path,
                                   result=information_nodes)
                for information_node in information_nodes:
                    if information_node is not None:
                        information_value = information_node.get_value()
                        log.debug(
                            "Node for %s \"%s\" with path: %s - FOUND! Current values is: %s",
                            information_type, information_key,
                            information_path, str(information_value))
                        if device_info.get("uplink_converter") is None:
                            configuration = {
                                **device_info["configuration"], "deviceName":
                                device_info["deviceName"],
                                "deviceType":
                                device_info["deviceType"]
                            }
                            if device_info["configuration"].get(
                                    'converter') is None:
                                converter = OpcUaUplinkConverter(configuration)
                            else:
                                converter = TBUtility.check_and_import(
                                    self._connector_type, configuration)
                            device_info["uplink_converter"] = converter
                        else:
                            converter = device_info["uplink_converter"]
                        self.subscribed[information_node] = {
                            "converter": converter,
                            "path": information_path,
                            "config_path": config_path
                        }
                        if not device_info.get(
                                information_types[information_type]):
                            device_info[
                                information_types[information_type]] = []
                        converted_data = converter.convert(
                            (config_path, information_path), information_value)
                        self.statistics['MessagesReceived'] += 1
                        self.data_to_send.append(converted_data)
                        self.statistics['MessagesSent'] += 1
                        if self.__sub is None:
                            self.__sub = self.client.create_subscription(
                                self.__server_conf.get(
                                    "subCheckPeriodInMillis", 500),
                                self.__sub_handler)
                        if self.__sub:
                            self.__sub.subscribe_data_change(information_node)
                        log.debug("Added subscription to node: %s",
                                  str(information_node))
                        log.debug("Data to ThingsBoard: %s", converted_data)
                    else:
                        log.error(
                            "Node for %s \"%s\" with path %s - NOT FOUND!",
                            information_type, information_key,
                            information_path)

    def __save_methods(self, device_info):
        try:
            if self.__available_object_resources.get(
                    device_info["deviceName"]) is None:
                self.__available_object_resources[
                    device_info["deviceName"]] = {}
            if self.__available_object_resources[
                    device_info["deviceName"]].get("methods") is None:
                self.__available_object_resources[
                    device_info["deviceName"]]["methods"] = []
            if device_info["configuration"].get("rpc_methods"):
                node = device_info["deviceNode"]
                for method_object in device_info["configuration"][
                        "rpc_methods"]:
                    method_node_path = self._check_path(
                        method_object["method"], node)
                    methods = []
                    self.__search_node(node,
                                       method_node_path,
                                       True,
                                       result=methods)
                    for method in methods:
                        if method is not None:
                            node_method_name = method.get_display_name().Text
                            self.__available_object_resources[
                                device_info["deviceName"]]["methods"].append({
                                    node_method_name:
                                    method,
                                    "node":
                                    node,
                                    "arguments":
                                    method_object.get("arguments")
                                })
                        else:
                            log.error(
                                "Node for method with path %s - NOT FOUND!",
                                method_node_path)
        except Exception as e:
            log.exception(e)

    def __search_attribute_update_variables(self, device_info):
        try:
            if device_info["configuration"].get("attributes_updates"):
                node = device_info["deviceNode"]
                device_name = device_info["deviceName"]
                if self.__available_object_resources.get(device_name) is None:
                    self.__available_object_resources[device_name] = {}
                if self.__available_object_resources[device_name].get(
                        "variables") is None:
                    self.__available_object_resources[device_name][
                        "variables"] = []
                for attribute_update in device_info["configuration"][
                        "attributes_updates"]:
                    attribute_path = self._check_path(
                        attribute_update["attributeOnDevice"], node)
                    attribute_nodes = []
                    self.__search_node(node,
                                       attribute_path,
                                       result=attribute_nodes)
                    for attribute_node in attribute_nodes:
                        if attribute_node is not None:
                            self.__available_object_resources[device_name][
                                "variables"].append({
                                    attribute_update["attributeOnThingsBoard"]:
                                    attribute_node
                                })
                        else:
                            log.error(
                                "Attribute update node with path \"%s\" - NOT FOUND!",
                                attribute_path)
        except Exception as e:
            log.exception(e)

    def __search_general_info(self, device):
        result = []
        match_devices = []
        self.__search_node(self.__opcua_nodes["root"],
                           TBUtility.get_value(device["deviceNodePattern"],
                                               get_tag=True),
                           result=match_devices)
        for device_node in match_devices:
            if device_node is not None:
                result_device_dict = {
                    "deviceName": None,
                    "deviceType": None,
                    "deviceNode": device_node,
                    "configuration": deepcopy(device)
                }
                name_pattern_config = device["deviceNamePattern"]
                name_expression = TBUtility.get_value(name_pattern_config,
                                                      get_tag=True)
                if "${" in name_pattern_config and "}" in name_pattern_config:
                    log.debug("Looking for device name")
                    name_path = self._check_path(name_expression, device_node)
                    device_name_node = []
                    self.__search_node(device_node,
                                       name_path,
                                       result=device_name_node)
                    device_name_node = device_name_node[0]
                    if device_name_node is not None:
                        device_name_from_node = device_name_node.get_value()
                        full_device_name = name_pattern_config.replace(
                            "${" + name_expression + "}",
                            str(device_name_from_node)).replace(
                                name_expression, str(device_name_from_node))
                    else:
                        log.error(
                            "Device name node not found with expression: %s",
                            name_expression)
                        return
                else:
                    full_device_name = name_expression
                result_device_dict["deviceName"] = full_device_name
                log.debug("Device name: %s", full_device_name)
                if device.get("deviceTypePattern"):
                    device_type_expression = TBUtility.get_value(
                        device["deviceTypePattern"], get_tag=True)
                    if "${" in device_type_expression and "}" in device_type_expression:
                        type_path = self._check_path(device_type_expression,
                                                     device_node)
                        device_type_node = []
                        self.__search_node(device_node,
                                           type_path,
                                           result=device_type_node)
                        device_type_node = device_type_node[0]
                        if device_type_node is not None:
                            device_type = device_type_node.get_value()
                            full_device_type = device_type_expression.replace(
                                "${" + device_type_expression + "}",
                                device_type).replace(device_type_expression,
                                                     device_type)
                        else:
                            log.error(
                                "Device type node not found with expression: %s",
                                device_type_expression)
                            full_device_type = "default"
                    else:
                        full_device_type = device_type_expression
                    result_device_dict["deviceType"] = full_device_type
                    log.debug("Device type: %s", full_device_type)
                else:
                    result_device_dict["deviceType"] = "default"
                result.append(result_device_dict)
            else:
                log.error(
                    "Device node not found with expression: %s",
                    TBUtility.get_value(device["deviceNodePattern"],
                                        get_tag=True))
        return result

    def __search_node(self,
                      current_node,
                      fullpath,
                      search_method=False,
                      result=[]):
        fullpath_pattern = regex.compile(fullpath)
        try:
            for child_node in current_node.get_children():
                new_node = self.client.get_node(child_node)
                new_node_path = '\\\\.'.join(
                    char.split(":")[1]
                    for char in new_node.get_path(200000, True))
                if self.__show_map:
                    log.debug("SHOW MAP: Current node path: %s", new_node_path)
                new_node_class = new_node.get_node_class()
                # regex_fullmatch = re.fullmatch(fullpath, new_node_path.replace('\\\\.', '.')) or new_node_path.replace('\\\\', '\\') == fullpath
                regex_fullmatch = regex.fullmatch(fullpath_pattern, new_node_path.replace('\\\\.', '.')) or \
                                  new_node_path.replace('\\\\', '\\') == fullpath.replace('\\\\', '\\') or \
                                  new_node_path.replace('\\\\', '\\') == fullpath
                regex_search = fullpath_pattern.fullmatch(new_node_path.replace('\\\\.', '.'), partial=True) or \
                                  new_node_path.replace('\\\\', '\\') in fullpath.replace('\\\\', '\\')
                # regex_search = re.search(new_node_path, fullpath.replace('\\\\', '\\'))
                if regex_fullmatch:
                    if self.__show_map:
                        log.debug(
                            "SHOW MAP: Current node path: %s - NODE FOUND",
                            new_node_path.replace('\\\\', '\\'))
                    result.append(new_node)
                elif regex_search:
                    if self.__show_map:
                        log.debug(
                            "SHOW MAP: Current node path: %s - NODE FOUND",
                            new_node_path)
                    if new_node_class == ua.NodeClass.Object:
                        if self.__show_map:
                            log.debug("SHOW MAP: Search in %s", new_node_path)
                        self.__search_node(new_node, fullpath, result=result)
                    elif new_node_class == ua.NodeClass.Variable:
                        log.debug("Found in %s", new_node_path)
                        result.append(new_node)
                    elif new_node_class == ua.NodeClass.Method and search_method:
                        log.debug("Found in %s", new_node_path)
                        result.append(new_node)
        except Exception as e:
            log.exception(e)

    def _check_path(self, config_path, node):
        if re.search("^root", config_path.lower()) is None:
            node_path = '\\\\.'.join(
                char.split(":")[1] for char in node.get_path(200000, True))
            if config_path[-3:] != '\\.':
                information_path = node_path + '\\\\.' + config_path.replace(
                    '\\', '\\\\')
            else:
                information_path = node_path + config_path.replace(
                    '\\', '\\\\')
        else:
            information_path = config_path
        return information_path[:]

    @property
    def subscribed(self):
        return self._subscribed
Ejemplo n.º 37
0
def main():
    client = Client("opc.tcp://localhost:4840/freeopcua/server/")

    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)
        print("Children of root are: ", root.get_children())

        server_namespace = "http://examples.freeopcua.github.io"
        idx = client.get_namespace_index(server_namespace)

        # Now getting a variable node using its browse path
        obj = root.get_child(["0:Objects", "2:MyObject"])
        print("My Object object is: ", obj)

        ## simply read variables, properties, and arrays
        myvar = root.get_child(
            ["0:Objects", "2:MyObject", "2:MyFirstVariable"])
        print("myvar is: ", myvar.get_value())
        myvar.set_value(3.9)  # if the var on the server is writable
        print("myvar is: ", myvar.get_value())

        myprop = root.get_child(
            ["0:Objects", "2:MyObject", "2:MyFirstVariable"])
        print("myprop is: ", myprop.get_value())
        myprop.set_value(3.9)  # if the var on the server is writable
        print("myprop is: ", myprop.get_value())

        ## subscribe to variables change
        subscribed_variables_dict = dict()
        subscribed_variables = list()

        for var in VARS_NAMES:
            myvar = root.get_child(
                ["0:Objects", "2:ChargeController", "2:" + str(var)])
            subscribed_variables.append(myvar)
            subscribed_variables_dict[str(myvar)] = str(
                myvar.get_browse_name().to_string())

        msclt = SubHandler()
        sub = client.create_subscription(100, msclt)
        for var in subscribed_variables:
            handle = sub.subscribe_data_change(var)

        ## subscribe to events
        myevent = root.get_child([
            "0:Types", "0:EventTypes", "0:BaseEventType", "2:LowBatteryEvent"
        ])
        print("MyFirstEventType is: ", myevent)

        handle = sub.subscribe_events(obj, myevent)

        ## methods

        while True:
            sleep(1)

        sub.unsubscribe(handle)
        sub.delete()
    finally:
        client.disconnect()
Ejemplo n.º 38
0
class MyPlc:
    area = {'I': 0x81, 'Q': 0x82, 'M': 0x83, 'D': 0x84}
    szs = {'x': 1, 'X': 1, 'b': 1, 'B': 1, 'w': 2, 'W': 2, 'd': 4, 'D': 4}

    def __init__(self, ip='192.168.0.1'):
        self.ip = ip
        self.INByteArray = bytearray([0, 0])
        self.MKByteArray = bytearray([0, 0])
        self.threadStatus = False
        self.varsdict = {}
        self.threads = {}
        self.plc = PlcClient()
        self.subNodes = []
        self.subNodesD = {}
        self.keysDict = {}
        self.inNodes = {}

    def get_db(self, server_id):
        self.db_server = Server.query.get(server_id)
        self.connections()

    def connections(self):
        self.opc_ns_uri = self.db_server.server_namespace
        self.ep_url = 'opc.tcp://' + self.db_server.server_endpoint_url
        self.opclient = Client(self.ep_url)
        try:
            self.plc.connect(self.ip, 0, 1)
            # pass
        except Exception:
            self.conn_stat = "Could not connect to PLC"
        else:
            self.conn_stat = "PLC Connected Successfully"

        self.opclient.connect()
        self.root = self.opclient.get_root_node()
        self.idx = self.opclient.get_namespace_index(
            self.db_server.server_namespace)
        self.set_tags(self.db_server.server_objects)
        for key, val in self.varsdict.items():
            if re.search("^(M|m)([\d]+).[\d]*$", key) is not None:
                self.subNodes.append(val['obj'])
                self.subNodesD[key] = val
            else:
                self.inNodes[key] = val
        self.run_threads()
        handler = SubHandler(self)
        sub = self.opclient.create_subscription(200, handler)
        handle = sub.subscribe_data_change(self.subNodes)
        time.sleep(0.1)

    def set_tags(self, objs):
        for obj in objs:
            try:
                self.make_tag_dict(obj, obj.object_variables)
            except Exception:
                self.make_tags_dict(obj.object_variables)
            finally:
                for var in obj.object_variables:
                    self.keysDict[var.variable_name] = var.variable_address

    def make_tag_dict(self, obj, allvars):
        for var in allvars:
            self.varsdict[var.variable_address] = {
                'obj':
                self.root.get_child([
                    "0:Objects", "{}:{}".format(self.idx, obj.object_name),
                    "{}:{}".format(self.idx, var.variable_name)
                ]),
                'type':
                var.variable_type
            }

    def kill_threads(self):
        self.threadStatus = False

    def run_threads(self):
        self.threadStatus = True
        self.threads['update_server'] = threading.Thread(
            target=self.updateInputs)
        self.threads['update_server'].start()

    def getInputs(self):
        while self.threadStatus:
            self.INByteArray = self.plc.read_area(areas['PE'], 0, 0, 2)
            # self.INByteArray = bytearray([ randint(0,7), randint(0,7) ])
            time.sleep(.1)

    # def get_bool(_bytearray, byte_index, bool_index):
    def updateInputs(self):
        while self.threadStatus:
            for key, val in self.inNodes.items():
                self.update_server_vars(key)
                time.sleep(.01)

    def writetoPLC(self, value, node):
        key = self.keysDict[node.get_browse_name().to_string().split(':')[1]]
        self.write_to_plc(key, value)

    '''
        Get Data from the PLC and Update OPC Server variables
    '''

    def update_server_vars(self, addr_key):
        addr = addr_key.split('.')
        # Works with Boolean values from a Data Block
        if len(addr) == 3 and addr[0][0] == 'D':
            DBn = int(addr[0][2:])
            DBt = addr[1][2]
            byt = int(addr[1][3:])
            bit = int(addr[2])
            reading = self.plc.read_area(MyPlc.area['D'], DBn, byt, szs[DBt])
            if DBt == 'X' or DBt == 'x':
                self.varsdict[addr_key]['obj'].set_value(
                    get_bool(reading, 0, bit))
                # return get_bool( reading, 0, bit )
            else:
                self.varsdict[addr_key]['obj'].set_value(reading)
                # return reading

        # Works with other data types from a Data Block
        elif len(addr) == 2 and addr[0][0] == 'D':
            DBn = int(addr[0][2:])
            DBt = addr[1][2]
            byt = int(addr[1][3:])
            reading = self.plc.read_area(MyPlc.area['D'], DBn, byt, szs[DBt])
            if DBt == 'W' or DBt == 'w':
                self.varsdict[addr_key]['obj'].set_value(get_int(reading, 0))
                # return get_int(reading,0)
            elif DBt == 'D' or DBt == 'd':
                self.varsdict[addr_key]['obj'].set_value(get_real(reading, 0))
                # return get_real(reading,0)
            else:
                self.varsdict[addr_key]['obj'].set_value(reading)

        # Works with boolean values from Inputs,Merkels and Outputs
        elif len(addr) == 2:
            byt = int(addr[0][1:])
            bit = int(addr[1])
            reading = self.plc.read_area(MyPlc.area[addr[0][0]], 0, byt, 1)
            self.varsdict[addr_key]['obj'].set_value(get_bool(reading, 0, bit))
            # return get_bool(reading,0,bit)

        # Works with other data types from Inputs,Merkels ot Outputs eg MW2
        elif len(addr) == 1:
            byt = int(addr[0][2:])
            typ = addr[0][1]
            reading = self.plc.read_area(MyPlc.area[addr[0][0]], 0, byt, 2)
            if typ == 'w' or typ == 'W':
                self.varsdict[addr_key]['obj'].set_value(get_int(reading, 0))
                # return get_int(reading, 0)
            elif typ == 'd' or typ == 'D':
                self.varsdict[addr_key]['obj'].set_value(get_real(reading, 0))
                # return get_real(reading, 0)
            else:
                self.varsdict[addr_key]['obj'].set_value(reading)
                # return reading

    '''
        WRITE DATA TO PLC FROM SERVER
    '''

    def write_to_plc(self, addr_key, value):
        addr = addr_key.split('.')
        print("New data change on {} : {}".format(addr_key, value))

        # Works with Boolean values from a Data Block
        if len(addr) == 3 and addr[0][0] == 'D':
            DBn = int(addr[0][2:])
            DBt = addr[1][2]
            byt = int(addr[1][3:])
            bit = int(addr[2])
            reading = self.plc.read_area(MyPlc.area['D'], DBn, byt,
                                         MyPlc.szs[DBt])
            if DBt == 'X' or DBt == 'x':
                set_bool(reading, 0, bit, value)
            self.plc.write_area(MyPlc.area['D'], DBn, byt, reading)

        # Works with other data types from a Data Block
        elif len(addr) == 2 and addr[0][0] == 'D':
            DBn = int(addr[0][2:])
            DBt = addr[1][2]
            byt = int(addr[1][3:])
            reading = self.plc.read_area(MyPlc.area['D'], DBn, byt,
                                         MyPlc.szs[DBt])
            if DBt == 'W' or DBt == 'w':
                set_int(reading, 0, value)
            elif DBt == 'D' or DBt == 'd':
                set_real(reading, 0, value)
            self.plc.write_area(MyPlc.area['D'], DBn, byt, reading)

        # Works with boolean values from Inputs,Merkels ot Outputs
        elif len(addr) == 2:
            byt = int(addr[0][1:])
            bit = int(addr[1])
            reading = self.plc.read_area(MyPlc.area[addr[0][0]], 0, byt, 1)
            set_bool(reading, 0, bit, value)
            self.plc.write_area(MyPlc.area[addr[0][0]], 0, byt, reading)

        # Works with other data types from Inputs,Merkels ot Outputs eg MW2
        elif len(addr) == 1:
            byt = int(addr[0][2:])
            typ = addr[0][1]
            reading = self.plc.read_area(MyPlc.area[addr[0][0]], 0, byt, 2)
            if typ == 'w' or typ == 'W':
                set_int(reading, 0, value)
            elif typ == 'd' or typ == 'D':
                set_real(reading, 0, value)
            else:
                set_data(value)
            self.plc.write_area(MyPlc.area[addr[0][0]], 0, byt, reading)
Ejemplo n.º 39
0
class UaClient(object):
    """
    OPC-Ua client specialized for the need of GUI client
    return exactly whant GUI needs, no customization possible
    """

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

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

    def connect(self, uri):
        self.disconnect()
        print("Connecting to ", uri)
        self.client = Client(uri)
        self.client.connect()
        self._connected = True

    def disconnect(self):
        if self._connected:
            print("Disconnecting from server")
            self._subs_dc = {}
            self._subs_ev = {}
            self._connected = False
            self._subscription = None
            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]

    def get_children(self, node):
        descs = node.get_children_descriptions()
        descs.sort(key=lambda x: x.BrowseName)
        return descs
Ejemplo n.º 40
0
        myfloat = client.get_node("ns=4;s=Float")
        mydouble = client.get_node("ns=4;s=Double")
        myint64 = client.get_node("ns=4;s=Int64")
        myuint64 = client.get_node("ns=4;s=UInt64")
        myint32 = client.get_node("ns=4;s=Int32")
        myuint32 = client.get_node("ns=4;s=UInt32")

        var = client.get_node(ua.NodeId("Random1", 5))
        print("var is: ", var)
        print("value of var is: ", var.get_value())
        var.set_value(ua.Variant([23], ua.VariantType.Double))
        print("setting float value")
        myfloat.set_value(ua.Variant(1.234, ua.VariantType.Float))
        print("reading float value: ", myfloat.get_value())

        handler = SubHandler()
        sub = client.create_subscription(500, handler)
        handle = sub.subscribe_data_change(var)

        device = objects.get_child(["2:MyObjects", "2:MyDevice"])
        method = device.get_child("2:MyMethod")
        result = device.call_method(method, ua.Variant("sin"), ua.Variant(180, ua.VariantType.Double))
        print("Mehtod result is: ", result)

        #embed()
        sub.unsubscribe(handle)
        sub.delete()
        #client.close_session()
    finally:
        client.disconnect()
Ejemplo n.º 41
0
class OPCPLC(PLC):
    """PLC con comunicación OPC UA.

    Args::
    address (str): Dirección IP (o nombre) del controlador.
    port (int): Puerto de conexión.
    interval (float): Intervalo de actualización en segundos.

    Attributes:
    subscription: Grupo al que se suscriben las variables.
    handler: Manejador de las actualizaciones de los valores.
    objects: Nodo de objetos.
    tagbynodeid (Tag{}): Diccionario de variables por identificador de nodo.
    client: Cliente OPC UA.
    opctype (VariantType{}): Principales tipos de datos OPC.
    
    """
    opctype={
        1:ua.VariantType.Boolean,
        2:ua.VariantType.SByte,
        3:ua.VariantType.Byte,
        4:ua.VariantType.Int16,
        5:ua.VariantType.UInt16,
        6:ua.VariantType.Int32,
        7:ua.VariantType.UInt32,
        8:ua.VariantType.Int64,
        9:ua.VariantType.UInt64,
        10:ua.VariantType.Float,
        11:ua.VariantType.Double,
        12:ua.VariantType.String,
        13:ua.VariantType.DateTime}

    class Memory(PLC.Memory):
        ''' Representacióne un área de memoria.

        No usada en OPC.

        Args:
        plc (PLC): Controlador al que pertenece.

        Attributes:
        tag (tag{}): Diccionario de variables ordenadas por nombre.
        tagbyaddress (tag{}): Diccionario de variables ordenadas por dirección.

        '''

        class Tag(PLC.Memory.Tag):
            ''' Variable

            Args:
            memory (Memory): Memoria a la que pertenece (no usada en OPC).
            key (str): Nombre.
            description (str): Descripción.
            address: Dirección. Se pasa la ruta hasta el nodo con el carácter '\' como separación.
                Los nodos vienen precedidos del tipo en forma de entero, separados por dos puntos.
                Por ejemplo, una dirección podria ser "2:Data\2:Static\2:Scalar\2:Variable".
                Para más información de una estructura en particular, una vez conectado
                llamar al método print_tree().
            
            Attributes:
            node: Nodo OPC asociado.
            type: Tipo de dato.
            value: Valor.
            subscriptor (Subcriptor[]): Objetos suscritos a los cambios.
            
            '''

            def __init__(self, memory:PLC.Memory, key:str, description:str="", address=None):
                self.node=None
                self.type=None
                super().__init__(memory,key,description,address)

            def opcsubscribe(self):
                ''' Suscripción al nodo OPC.

                '''
                plc=self.memory.plc
                address=self.address.split("\\")
                self.node=plc.objects.get_child(address)
                self.type=int(self.node.get_data_type().Identifier)
                plc.tagbynodeid[self.node.nodeid.Identifier]=self
                plc.subscription.subscribe_data_change(self.node)
                self.node.get_value()

            def set(self,value):
                ''' Modifica o asigna el valor de una variable.

                Args:
                value: Nuevo valor de la variable.

                '''
                try:
                    if self.type==1:
                        self.node.set_value(ua.Variant(bool(value),OPCPLC.opctype[self.type])) 
                    if self.type>=2 and self.type<=9:
                        self.node.set_value(ua.Variant(int(value),OPCPLC.opctype[self.type]))
                    if self.type>=10 and self.type<=11:
                        self.node.set_value(ua.Variant(float(value),OPCPLC.opctype[self.type]))
                    if self.type==12:
                        self.node.set_value(ua.Variant(str(value),OPCPLC.opctype[self.type]))
                    if self.type==13:
                        self.node.set_value(ua.Variant(datetime.strptime(value,"%Y-%m-%d %H:%M:%S"),OPCPLC.opctype[self.type]))

                    self.__update(value)
                except Exception as e:
                    printexception(e,"Error in assignment. Tag="+self.key+", Value="+value)


    def __init__(self, address:str, port:int=502, interval:float=3):
        super().__init__()
        self.address=address
        self.port=port
        self.interval=interval
        self.handler=OPCPLC.Handler(self)
        self.subscription=None
        self.objects=None
        self.tagbynodeid={}
        self.client = Client("opc.tcp://"+self.address+":"+str(self.port)+"/")
        self.create("")

    def connect(self):
        ''' Conexión con el controlador

        '''
        try:
            self.client.connect()
            self.objects=self.client.get_objects_node()
            self.subscription=self.client.create_subscription(self.interval, self.handler)
            for key_memory in self.memory:
                memory=self.get(key_memory)
                for key_tag in memory:
                    memory.get(key_tag).opcsubscribe()
            self.connected=True
        except Exception as e:
            printexception(e,"Error connecting to OPC server")
        
    def __tree(self, root, level:int=0):
        ''' Recursión para imprimir el árbol de nodos.

        Args:
        root: nodo raíz en la recursión.
        level (int): Nivel de recursión.

        '''        
        nodes=root.get_children()
        for node in nodes:
            node2=self.client.get_node(node.nodeid)
            name=node2.get_browse_name().to_string()
            print(('   '*level)+name)
            self.tree(node, level+1)

            
    def print_tree(self):
        ''' Imprime la estructura de nodos.

        '''
        self.__tree(self.client.get_objects_node())


    class Handler(object):
        ''' Manejador de los cambios en los valores de los nodos.

        Args:
        plc (PLC): Controlador.

        '''
        
        def __init__(self,plc):
            self.plc=plc

        def datachange_notification(self, node, val, data):
            ''' Método llamado cuando cambia el valor de un nodo.

            Args:
            node: Nodo.
            val: Valor.
            data: Datos.

            '''
            self.plc.tagbynodeid[node.nodeid.Identifier].update(val)