def conn_opc(): # OPCサーバに接続 cl = Client("opc.tcp://192.168.10.5:51110/CogentDataHub/DataAccess") # クライアント証明書のapplication_uri cl.application_uri = "urn:desktop-i50i89m:Cogent DataHub" # policy設定 print("secPolicy: " + str(secPolicy)) if secPolicy != policies[0]: # None以外の場合SecurityPolicyを設定 mode = ua.MessageSecurityMode.SignAndEncrypt pc = getattr(security_policies, 'SecurityPolicy' + secPolicy) # 第二引数:クライアント証明書 cl.set_security( pc, "/Users/watarium/PycharmProjects/opcua/OPCUA_CL.der", "/Users/watarium/PycharmProjects/opcua/OPCUAClient.pem", "/Users/watarium/PycharmProjects/opcua/OPCUAServer.der", mode) # 認証設定 if setCert == certs[1]: # user/pass cl.set_user("admin") cl.set_password("1234") elif setCert == certs[2]: # certificate cl.load_private_key( "/Users/watarium/PycharmProjects/opcua/OPCUAClient.pem") cl.load_client_certificate( "/Users/watarium/PycharmProjects/opcua/OPCUA_CL.der") try: # 接続 print("Policy: {0}, Certificate: {1}".format(secPolicy, setCert)) print("---------------------Connection start-----------------------") cl.connect() sleep(5) # 情報取得 ep = cl.get_endpoints() print(ep[0].Server.ApplicationUri) root = cl.get_root_node() print("Objects node is: ", root) print(cl.get_namespace_array()) print(cl.get_namespace_index('urn:win-9hi38ajrojd:Cogent DataHub')) #これがうまくいかなかった(2019/06/27) #node = cl.get_node('ns=1;s=xxxxx') #print(node.get_value()) #node.set_attribute(ua.AttributeIds.Value, 1) # 切断 cl.disconnect() print("-------------------Connection Success!!!--------------------") except Exception as e: print("---------------------Connection Faild!!---------------------") print(e) cl.disconnect()
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()
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
# password = base64.b64decode(psw).decode() myvar = [] client_db = InfluxDBClient(host=host, port=port, username=username, 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')
def startLogging(ip, username, password, rate, path): print("Starting") print(ip) print(username) print(password) print(rate) print(path) url = "opc.tcp://192.168.1.20:4840" client = Client(url) #KUKA_OPC_UA_Logger_GUI.gui.setEntry("Logging Status","Logging Started") #KUKA_OPC_UA_Logger_GUI.startbutton = "Logging Active" print("try session connect") client.set_user("opcuaoperator") client.set_password("kuka") print("session success") client.connect() print("Client Connected to KUKA OPC Server") lograte = 0.1 while True: now = time.strftime('%d-%m-%Y %H:%M:%S') # Force in X Direction variablename = "ForceinX" variableid = client.get_node( "ns=5;s=MotionDeviceSystem.ProcessData.R1.System.$config.FX_FT") variabledata = variableid.get_value() print(variablename) print(variabledata) myFile = open("E:/test.csv", 'w') with myFile: writer = csv.writer(myFile) writer.writerows([now, now]) with open("E:/" + variablename + ".csv", "a") as log: log.write("{0},{1}\n".format(now, str(variabledata))) # Force in Y Direction variablename = "ForceinY" variableid = client.get_node( "ns=5;s=MotionDeviceSystem.ProcessData.R1.System.$config.FY_FT") variabledata = variableid.get_value() print(variablename) print(variabledata) myFile = open("E:/test.csv", 'w') with myFile: writer = csv.writer(myFile) writer.writerows([now, now]) with open("E:/" + variablename + ".csv", "a") as log: log.write("{0},{1}\n".format(now, str(variabledata))) # Force in Z Direction variablename = "ForceinZ" variableid = client.get_node( "ns=5;s=MotionDeviceSystem.ProcessData.R1.System.$config.FZ_FT") variabledata = variableid.get_value() print(variablename) print(variabledata) myFile = open("E:/test.csv", 'w') with myFile: writer = csv.writer(myFile) writer.writerows([now, now]) with open("E:/" + variablename + ".csv", "a") as log: log.write("{0},{1}\n".format(now, str(variabledata))) # Torque in X Direction variablename = "TorqueinX" variableid = client.get_node( "ns=5;s=MotionDeviceSystem.ProcessData.R1.System.$config.TX_FT") variabledata = variableid.get_value() print(variablename) print(variabledata) myFile = open("E:/test.csv", 'w') with myFile: writer = csv.writer(myFile) writer.writerows([now, now]) with open("E:/" + variablename + ".csv", "a") as log: log.write("{0},{1}\n".format(now, str(variabledata))) # Torque in X Direction variablename = "TorqueinY" variableid = client.get_node( "ns=5;s=MotionDeviceSystem.ProcessData.R1.System.$config.TY_FT") variabledata = variableid.get_value() print(variablename) print(variabledata) myFile = open("E:/test.csv", 'w') with myFile: writer = csv.writer(myFile) writer.writerows([now, now]) with open("E:/" + variablename + ".csv", "a") as log: log.write("{0},{1}\n".format(now, str(variabledata))) # Torque in X Direction variablename = "TorqueinZ" variableid = client.get_node( "ns=5;s=MotionDeviceSystem.ProcessData.R1.System.$config.TZ_FT") variabledata = variableid.get_value() print(variablename) print(variabledata) myFile = open("E:/test.csv", 'w') with myFile: writer = csv.writer(myFile) writer.writerows([now, now]) with open("E:/" + variablename + ".csv", "a") as log: log.write("{0},{1}\n".format(now, str(variabledata))) time.sleep(lograte)
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
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
class OPCUAClient: def __init__(self, server: str, username='', password='', reconnect_interval=1000): self.server = server self.username = username self.password = password self.client = Client(self.server) self.client.set_user(username) self.client.set_password(password) self.connection_status = False self.connectivity_thread = None self.reconnect_interval = reconnect_interval self.connected_once = False self.stop_flag = False self.stopped = True def connect(self): self.connectivity_thread = threading.Thread( target=self.__connectivity_routine) self.stopped = False self.connectivity_thread.start() sleep(1) def disconnect(self): logging.info('Disconnecting to OPC UA server %s ...' % self.server) self.stop_flag = True self.client.disconnect() while not self.stopped: sleep(0.1) logging.info('Disconnected from OPC UA server %s' % self.server) def __single_connect(self): logging.info('Connecting to OPC UA server %s ...' % self.server) try: self.client.connect() logging.info('Connection to OPC UA server %s established' % self.server) sleep(1) self.connected_once = True except Exception as exc: logging.warning('Connection to OPC UA server %s failed' % self.server, exc_info=exc) def __connectivity_routine(self): while True: if self.stop_flag: self.stopped = True return self.check_connection() if not self.connection_status: self.__single_connect() sleep(self.reconnect_interval / 1000) def check_connection(self): logging.debug('Checking connection status to OPCA UA server %s ...' % self.server) try: self.client.get_node(ua.NodeId(2259, 0)).get_data_value() logging.debug('Connection to OPCA UA server %s persists' % self.server) self.connection_status = True except Exception as exc: logging.warning( 'Connection to OPCA UA server %s does NOT persist' % self.server) self.connection_status = False sleep(1) def get_connection_status(self): return self.connection_status def get_url(self): return self.server def get_server_obj(self): return self.client
from opcua import Client import time import mysql.connector import datetime use_crypto = True url = "opc.tcp://192.168.0.101:4840" client = Client(url) client._username = "******" client._password = "******" client.set_user("OpcUaClient") client.set_password("123456789") client.connect() print('Client connected') while (True): R = client.get_node("ns=2;s=/Channel/Parameter/R") R_value = R.get_value() print(R_value) Date_Time = datetime.datetime.now() aaCurr = client.get_node("ns=2;s=/Channel/MachineAxis/aaCurr") aaCurr_value = aaCurr.get_value() print(aaCurr_value) actParts = client.get_node("ns=2;s=/Channel/State/actParts") actParts_value = actParts.get_value() print(actParts_value) DB100 = client.get_node("ns=2;s=/Plc/DB100.DBW")
from opcua import Client, ua url = "opc.tcp://127.0.0.1:4840" client = Client(url) client.set_user("user1") client.set_password("pw1") client.set_security_string("Basic256Sha256,SignAndEncrypt,cert.pem,key.pem") client.application_uri = "urn:example.org:FreeOpcUa:python-opcua" client.connect() print(f"Connected to: {url}") servicelevel_node = client.get_node("ns=0;i=2267") servicelevel_node_value = servicelevel_node.get_value() print(servicelevel_node_value) client.disconnect()
class CustomClient(object): def __init__(self, server_endpoint, namespace, enable_cert, client_cert_path, client_key_path, auth_name=None, auth_password=None, debug_print=False, client_request_timeout=4): self.NAMESPACE = namespace self.DEBUG_MODE_PRINT = debug_print self.client = Client(server_endpoint, client_request_timeout) if auth_name is not None and auth_password is not None: self.client.set_user(auth_name) self.client.set_password(auth_password) if enable_cert: self.client.set_security_string("Basic256Sha256,SignAndEncrypt," + client_cert_path + "," + client_key_path) # TODO experimental( cf. client.py @line 60) # self.client.session_timeout = 10*1000 # 30h = 30*60*60*1000 # self.client.secure_channel_timeout = 10*1000 # 30h self.root = None self.idx = None def start(self): try: self.client.connect() except ConnectionError as er: print(DateHelper.get_local_datetime(), er) raise # sys.exit(1) except Exception as ex: print(DateHelper.get_local_datetime(), ex) raise # sys.exit(1) # Now getting root variable node using its browse path self.root = self.client.get_root_node() uri = self.NAMESPACE self.idx = self.client.get_namespace_index(uri) def stop(self): try: self.client.disconnect() except Exception as ex: print("Couldn't stop OPC Client because of: ", ex) def get_server_vars(self, child): # TODO raise TimeOutError when called after subscription was set up, (cf. ua_client.py: send_request) try: obj = self.root.get_child( ["0:Objects", ("{}:" + child).format(self.idx)]) # print(obj.get_browse_name()) # print(obj.get_variables()) except BadNoMatch: return None return obj.get_variables() def create_dir_on_server(self, child): # get object node objects_node = self.client.get_objects_node() # add new folder "child" first for method in objects_node.get_methods(): # print(method.get_browse_name().Name) if "ADD_NEW_OBJECTS_FOLDER" in method.get_browse_name().Name: objects_node.call_method(method, child) def register_variables_to_server(self, child, file_path): # get object node objects_node = self.client.get_objects_node() # get tags of variables and register them serverside in folder "child" mtagfile = open(file_path, 'r') tags_pf_output = format_textfile(mtagfile.readlines()) mtagfile.close() # VARIANT A for method in objects_node.get_methods(): # print(method.get_browse_name().Name) if "ADD_OPC_TAG" in method.get_browse_name().Name: for i in tags_pf_output: opctag, typ = i.split() opctag, typ = opctag.strip(), int(typ) # call method to register var objects_node.call_method(method, opctag, numbers_to_typestrings(typ), child) # VARIANT B # for i in tags_pf_output: # opctag, typ = i.split() # opctag, typ = opctag.strip(), int(typ) # # # # register vars at server # mvar = folder.add_variable(self.idx, opctag.strip(), ua.Variant(0, numbers_to_vartyps(typ))) # mvar.set_writable() # # # Test # # dv = DataValue() # # dv.Value = ua.Variant(1,numbers_to_vartyps(typ)) # # mvar.set_value(dv) @staticmethod def set_vars(observed_nodes_list, ctrl_list, value_list): """ Set new value for node. :param observed_nodes_list: list of nodes, the client subscribed to :param ctrl_list: list of nodes to update :param value_list: list of values to assign """ i = 0 for ctrl in ctrl_list: for var in observed_nodes_list: if var.nodeid == ctrl.nodeid: try: variant_type = var.get_data_value().Value.VariantType var.set_value(value_list[i], variant_type) break except Exception as ex: if type(ex).__name__ in TimeoutError.__name__: print( DateHelper.get_local_datetime(), 'TimeOutError ignored while set var in OPCClient' ) pass else: print(DateHelper.get_local_datetime(), ex) raise i += 1 # region subscription def _subscribe(self, dir_name, sub_handler, subscription, subscription_handle, list_of_nodes_to_subscribe, already_subscribed_nodes, sub_interval): """ Make a subscription for list of nodes and return handle for subscription :param dir_name: subfolder, which contains the requested nodes :param sub_handler: SubHandler which will call the update_data function :param subscription: subscription object :param subscription_handle: handle can used to unsubscribe :param list_of_nodes_to_subscribe: list of nodes/customVars :param already_subscribed_nodes: list of nodes which already within subscription :param sub_interval: time interval the subscribed node is checked (in ms) :return subscription: :return subscription_handle :return subscribed_nodes """ if subscription is not None: self._unsubscribe(subscription, subscription_handle) already_subscribed_nodes = [] all_server_nodes = self.get_server_vars(dir_name) for node in all_server_nodes: for var in list_of_nodes_to_subscribe: if node.nodeid == var.nodeid: already_subscribed_nodes.append(node) # make subscription subscription = self.client.create_subscription(sub_interval, sub_handler) subscription_handle = subscription.subscribe_data_change( already_subscribed_nodes) return subscription, subscription_handle, already_subscribed_nodes # will raise TimeoutError() - why? --> use self.subscription.delete() instead @staticmethod def _unsubscribe(self, subscription, subscription_handle): if subscription_handle is not None: # self.stop() # self.start() # self.subscription.delete() subscription.unsubscribe(subscription_handle)
"ba/wago/opcua/plc3/plcsub", ] mqttTopicSubscribeData = [ "ba/wago/opcua/plc1/plcpub", "ba/wago/opcua/plc2/plcpub", "ba/wago/opcua/plc3/plcpub", ] mqttPublishPvSuffix = os.getenv( "MQTT_PUBLISH_PV_SUFFIX" ) # Published every sample, other tags are pulished on data change logging.warning("HMI: Evn: OpcUaServer: " + opcUaServer + ", OpcUaIdPrefix" + opcUaIdPrefix + ", MqttBroker: " + mqttBroker) # OPC UA opcClient = Client("opc.tcp://" + opcUaServer + ":4840", timeout=3) opcClient.set_user(opcUaServerUsername) opcClient.set_password(opcUaServerPassword) # MQTT mqttClient = mqtt.Client() mqttClient.on_connect = on_mqtt_connect mqttClient.on_disconnect = on_mqtt_disconnect mqttClient.on_message = on_received_mqtt_message # Ensure disconnecting on program close try: # Tries to reconnect every 10 seconds logging.warning("HMI: Waiting 10s for e!cockpit to start") time.sleep(10) while True: try: logging.warning("HMI: Connecting to Opc.")
""" Client to subscription. It will receive events from server """ def datachange_notification(self, node, val, data): print("Python: New data change event", node, val) def event_notification(self, event): print("Python: New event", event) if __name__ == "__main__": #from IPython import embed #logging.basicConfig(level=logging.DEBUG) client = Client("opc.tcp://192.168.10.10:4840/") client.set_user('admin') client.set_password('ca895987') client.set_security_string( "Basic256Sha256,SignAndEncrypt,opcua_client.der,opcua_client.pem") client.application_uri = "urn:example.org:FreeOpcUa:python-opcua" i = 0 try: client.connect() while i < 5: ua_LevelMaximum = client.get_node(