def uawrite(): parser = argparse.ArgumentParser(description="Write attribute of a node, per default write value of node") add_common_args(parser) parser.add_argument("-a", "--attribute", dest="attribute", type=int, #default="VALUE", #choices=['VALUE', 'NODEID', 'BROWSENAME', 'ERROR', 'CRITICAL'], default=ua.AttributeIds.Value, help="Set attribute to read") parser.add_argument("-l", "--list", "--array", dest="array", default="guess", choices=["guess", "true", "false"], help="Value is an array") parser.add_argument("-t", "--datatype", dest="datatype", default="guess", choices=["guess", 'byte', 'sbyte', 'nodeid', 'expandednodeid', 'qualifiedname', 'browsename', 'string', 'float', 'double', 'int16', 'int32', "int64", 'uint16', 'uint32', 'uint64', "bool", "string", 'datetime', 'bytestring', 'xmlelement', 'statuscode', 'localizedtext'], help="Data type to return") parser.add_argument("value", help="Value to be written", metavar="VALUE") args = parser.parse_args() if args.nodeid == "i=84" and args.path == "" and args.attribute == ua.AttributeIds.Value: parser.print_usage() print("uaread: error: A NodeId or BrowsePath 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(",")) val = _val_to_variant(args.value, args) node.set_attribute(args.attribute, ua.DataValue(val)) finally: client.disconnect() sys.exit(0) print(args)
def uals(): parser = argparse.ArgumentParser(description="Browse OPC-UA node and print result") add_common_args(parser) parser.add_argument("-l", dest="long_format", const=3, nargs="?", type=int, help="use a long listing format") parser.add_argument("-d", "--depth", default=1, type=int, help="Browse depth") args = parse_args(parser) if args.long_format is None: args.long_format = 1 client = Client(args.url, timeout=args.timeout) _configure_client_with_args(client, args) client.connect() try: node = get_node(client, args) print("Browsing node {0} at {1}\n".format(node, args.url)) if args.long_format == 0: _lsprint_0(node, args.depth - 1) elif args.long_format == 1: _lsprint_1(node, args.depth - 1) else: _lsprint_long(node, args.depth - 1) finally: client.disconnect() sys.exit(0) print(args)
def uaclient(): parser = argparse.ArgumentParser(description="Connect to server and start python shell. root and objects nodes are available. Node specificed in command line is available as mynode variable") add_common_args(parser) parser.add_argument("-c", "--certificate", help="set client certificate") parser.add_argument("-k", "--private_key", help="set client private key") args = parse_args(parser) client = Client(args.url, timeout=args.timeout) _configure_client_with_args(client, args) if args.certificate: client.load_client_certificate(args.certificate) if args.private_key: client.load_private_key(args.private_key) client.connect() try: root = client.get_root_node() objects = client.get_objects_node() mynode = get_node(client, args) embed() finally: client.disconnect() sys.exit(0)
def test_find_servers2(self): client = Client(self.discovery.endpoint.geturl()) client.connect() try: servers = client.find_servers() new_app_uri1 = "urn:freeopcua:python:server:test_discovery1" self.srv.application_uri = new_app_uri1 self.srv.register_to_discovery(self.discovery.endpoint.geturl(), period=0) new_app_uri2 = "urn:freeopcua:python:test_discovery2" self.srv.application_uri = new_app_uri2 self.srv.register_to_discovery(self.discovery.endpoint.geturl(), period=0) time.sleep(0.1) # let server register registration new_servers = client.find_servers() self.assertEqual(len(new_servers) - len(servers) , 2) self.assertFalse(new_app_uri1 in [s.ApplicationUri for s in servers]) self.assertFalse(new_app_uri2 in [s.ApplicationUri for s in servers]) self.assertTrue(new_app_uri1 in [s.ApplicationUri for s in new_servers]) self.assertTrue(new_app_uri2 in [s.ApplicationUri for s in new_servers]) # now do a query with filer new_servers = client.find_servers(["urn:freeopcua:python:server"]) self.assertEqual(len(new_servers) - len(servers) , 0) self.assertTrue(new_app_uri1 in [s.ApplicationUri for s in new_servers]) self.assertFalse(new_app_uri2 in [s.ApplicationUri for s in new_servers]) # now do a query with filer new_servers = client.find_servers(["urn:freeopcua:python"]) self.assertEqual(len(new_servers) - len(servers) , 2) self.assertTrue(new_app_uri1 in [s.ApplicationUri for s in new_servers]) self.assertTrue(new_app_uri2 in [s.ApplicationUri for s in new_servers]) finally: client.disconnect()
def wrapper(self): try: client = Client(URL) client.connect() func(self, client) finally: client.disconnect()
def test_nocrypto(self): clt = Client(self.uri_no_crypto) clt.connect() try: clt.get_objects_node().get_children() finally: clt.disconnect()
def test_find_servers2(self): client = Client(self.discovery.endpoint.geturl()) client.connect() try: servers = client.find_servers() # Use 2 different RegistrationServices, as it does not allow duplicate registrations. with RegistrationService() as regService1, RegistrationService() as regService2: # Register to server with uri1 new_app_uri1 = "urn:freeopcua:python:server:test_discovery1" self.srv.application_uri = new_app_uri1 regService1.register_to_discovery(self.srv, self.discovery.endpoint.geturl(), period=0) # Register to server with uri2 new_app_uri2 = "urn:freeopcua:python:test_discovery2" self.srv.application_uri = new_app_uri2 regService2.register_to_discovery(self.srv, self.discovery.endpoint.geturl(), period=0) # Check for 2 registrations time.sleep(0.1) # let server register registration new_servers = client.find_servers() self.assertEqual(len(new_servers) - len(servers) , 2) self.assertFalse(new_app_uri1 in [s.ApplicationUri for s in servers]) self.assertFalse(new_app_uri2 in [s.ApplicationUri for s in servers]) self.assertTrue(new_app_uri1 in [s.ApplicationUri for s in new_servers]) self.assertTrue(new_app_uri2 in [s.ApplicationUri for s in new_servers]) # now do a query with filter new_servers = client.find_servers(["urn:freeopcua:python:server"]) self.assertEqual(len(new_servers) - len(servers) , 0) self.assertTrue(new_app_uri1 in [s.ApplicationUri for s in new_servers]) self.assertFalse(new_app_uri2 in [s.ApplicationUri for s in new_servers]) # now do a query with filter new_servers = client.find_servers(["urn:freeopcua:python"]) self.assertEqual(len(new_servers) - len(servers) , 2) self.assertTrue(new_app_uri1 in [s.ApplicationUri for s in new_servers]) self.assertTrue(new_app_uri2 in [s.ApplicationUri for s in new_servers]) finally: client.disconnect()
def uaread(): parser = argparse.ArgumentParser(description="Read attribute of a node, per default reads value of a node") add_common_args(parser) parser.add_argument("-a", "--attribute", dest="attribute", type=int, default=ua.AttributeIds.Value, help="Set attribute to read") parser.add_argument("-t", "--datatype", dest="datatype", default="python", choices=['python', 'variant', 'datavalue'], help="Data type to return") args = parse_args(parser, requirenodeid=True) client = Client(args.url, timeout=args.timeout) client.set_security_string(args.security) client.connect() try: node = get_node(client, args) attr = node.get_attribute(args.attribute) if args.datatype == "python": print(attr.Value.Value) elif args.datatype == "variant": print(attr.Value) else: print(attr) finally: client.disconnect() sys.exit(0) print(args)
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)
def uals(): parser = argparse.ArgumentParser(description="Browse OPC-UA node and print result") add_common_args(parser) #parser.add_argument("-l", #dest="long_format", #default=ua.AttributeIds.Value, #help="use a long listing format") parser.add_argument("-d", "--depth", default=1, type=int, help="Browse depth") args = parser.parse_args() 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(",")) print("Browsing node {} at {}\n".format(node, args.url)) _lsprint(client, node.nodeid, args.depth - 1) finally: client.disconnect() sys.exit(0) print(args)
def uahistoryread(): parser = argparse.ArgumentParser(description="Read history of a node") add_common_args(parser) parser.add_argument( "--starttime", default="", help="Start time, formatted as YYYY-MM-DD [HH:MM[:SS]]. Default: current time" ) parser.add_argument( "--endtime", default="", help="End time, formatted as YYYY-MM-DD [HH:MM[:SS]]. Default: current time" ) args = parse_args(parser, requirenodeid=True) client = Client(args.url, timeout=args.timeout) client.set_security_string(args.security) client.connect() try: node = get_node(client, args) starttime = str_to_datetime(args.starttime) endtime = str_to_datetime(args.endtime) print( "Reading raw history of node {} at {}; start at {}, end at {}\n".format(node, args.url, starttime, endtime) ) print_history(node.read_raw_history(starttime, endtime)) finally: client.disconnect() sys.exit(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)
def uaclient(): parser = argparse.ArgumentParser(description="Connect to server and start python shell. root and objects nodes are available. Node specificed in command line is available as mynode variable") add_common_args(parser) parser.add_argument("-c", "--certificate", help="set client certificate") parser.add_argument("-k", "--private_key", help="set client private key") args = parser.parse_args() logging.basicConfig(format="%(levelname)s: %(message)s", level=getattr(logging, args.loglevel)) client = Client(args.url, timeout=args.timeout) client.connect() if args.certificate: client.load_certificate(args.certificate) if args.private_key: client.load_certificate(args.private_key) try: root = client.get_root_node() objects = client.get_objects_node() mynode = client.get_node(args.nodeid) if args.path: mynode = mynode.get_child(args.path.split(",")) embed() finally: client.disconnect() sys.exit(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)
def run(): configs = get_configs() patterns = configs["measures"].split(":") tout = configs["connection_timeout"].strip() timeout = 1 if len(tout) <= 0 else int(tout) client = Client(configs["connection"], timeout=timeout) try: client.connect() measures = [] root = client.get_root_node() collect_measures(measures, patterns, root) for x in root.get_children(): print x.get_browse_name().Name for m in measures: print m time.sleep(30) except Exception as ex: print ex finally: client.disconnect()
def uahistoryread(): parser = argparse.ArgumentParser(description="Read history of a node") add_common_args(parser) parser.add_argument("--starttime", default="", help="Start time, formatted as YYYY-MM-DD [HH:MM[:SS]]. Default: current time") parser.add_argument("--endtime", default="", help="End time, formatted as YYYY-MM-DD [HH:MM[:SS]]. Default: current time") args = parser.parse_args() if args.nodeid == "i=84" and args.path == "": parser.print_usage() print("uahistoryread: error: A NodeId or BrowsePath 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(",")) starttime = str_to_datetime(args.starttime) endtime = str_to_datetime(args.endtime) print("Reading raw history of node {} at {}; start at {}, end at {}\n".format(node, args.url, starttime, endtime)) print_history(node.read_raw_history(starttime, endtime)) finally: client.disconnect() sys.exit(0)
class TestClient(unittest.TestCase, CommonTests): ''' Run common tests on client side Of course we need a server so we start a server in another process using python Process module Tests that can only be run on client side must be defined here ''' @classmethod def setUpClass(self): # start our own server self.srv = Server() self.srv.set_endpoint('opc.tcp://localhost:%d' % port_num1) add_server_methods(self.srv) self.srv.start() # start client self.clt = Client('opc.tcp://localhost:%d' % port_num1) self.clt.connect() self.opc = self.clt @classmethod def tearDownClass(self): self.clt.disconnect() # stop the server in its own process self.srv.stop() def test_service_fault(self): request = ua.ReadRequest() request.TypeId = ua.FourByteNodeId(999) # bad type! with self.assertRaises(Exception): self.clt.bclient._send_request(request)
def test_basic256(self): clt = Client(self.uri_crypto) try: clt.set_security_string("Basic256,Sign,examples/example-certificate.der,examples/example-private-key.pem") clt.connect() self.assertTrue(clt.get_objects_node().get_children()) finally: clt.disconnect()
def test_basic128Rsa15_encrypt(self): clt = Client(self.uri_crypto) try: clt.set_security_string("Basic128Rsa15,SignAndEncrypt,examples/certificate-example.der,examples/private-key-example.pem") clt.connect() self.assertTrue(clt.get_objects_node().get_children()) finally: clt.disconnect()
class HelloClient: def __init__(self, endpoint): self.client = Client(endpoint) def __enter__(self): self.client.connect() return self.client def __exit__(self, exc_type, exc_val, exc_tb): self.client.disconnect()
def opcua_init(request): client = Client( request.get('url', 'opc.tcp://localhost:4841'), timeout=request.get('timeout', 10) ) client.set_security_string(request.get('security', '')) client.connect() return client
def test_basic256_encrypt_success(self): clt = Client(self.uri_crypto) try: clt.set_security(security_policies.SecurityPolicyBasic256, 'examples/certificate-example.der', 'examples/private-key-example.pem', None, ua.MessageSecurityMode.SignAndEncrypt ) clt.connect() self.assertTrue(clt.get_objects_node().get_children()) finally: clt.disconnect()
def test_discovery(self): client = Client(self.discovery.endpoint.geturl()) client.connect() servers = client.find_servers() new_app_uri = "urn:freeopcua:python:server::test_discovery" self.srv.application_uri = new_app_uri self.srv.register_to_discovery(self.discovery.endpoint.geturl(), 1) time.sleep(0.1) # let server register registration new_servers = client.find_servers() self.assertEqual(len(new_servers) - len(servers) , 1) self.assertFalse(new_app_uri in [s.ApplicationUri for s in servers]) self.assertTrue(new_app_uri in [s.ApplicationUri for s in new_servers]) client.disconnect()
class ServerC(object): def __init__(self): self._server = None self._client = None self.nodes = None self.get_node = None self.get_namespace_array = None def start_server(self, endpoint): self._server = UAServer() self._server.endpoint = 48400 # enpoint not supported yet #self._server.endpoint = endpoint self._server.start() #self._server.set_server_name("OpcUa Modeler Server") time.sleep(0.2) self._client = Client(endpoint) self._client.connect() self.nodes = self._client.nodes self.get_node = self._client.get_node self.get_namespace_array = self._client.get_namespace_array # now remove freeopcua namespace, not necessary when modeling and # ensures correct idx for exported nodesets ns_node = self._client.get_node(ua.NodeId(ua.ObjectIds.Server_NamespaceArray)) nss = ns_node.get_value() #ns_node.set_value(nss[1:]) def stop_server(self): if self._server is not None: self._client.disconnect() self._client = None self._server.stop() time.sleep(0.2) self._server = None self.get_node = None self.get_namespace_array = None def import_xml(self, path): return self._client.import_xml(path) def export_xml(self, nodes, uris, path): exp = XmlExporter(self._client) exp.build_etree(nodes, uris=uris) exp.write_xml(path)
def uaread(): parser = argparse.ArgumentParser(description="Read attribute of a node, per default reads value of a node") add_common_args(parser) parser.add_argument("-a", "--attribute", dest="attribute", type=int, #default="VALUE", #choices=['VALUE', 'NODEID', 'BROWSENAME', 'ERROR', 'CRITICAL'], default=ua.AttributeIds.Value, help="Set attribute to read") parser.add_argument("-t", "--datatype", dest="datatype", default="python", choices=['python', 'variant', 'datavalue'], help="Data type to return") args = parser.parse_args() if args.nodeid == "i=84" and args.path == "" and args.attribute == ua.AttributeIds.Value: parser.print_usage() print("uaread: error: A NodeId or BrowsePath 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(",")) attr = node.get_attribute(args.attribute) if args.datatype == "python": print(attr.Value.Value) elif args.datatype == "variant": print(attr.Value) else: print(attr) finally: client.disconnect() sys.exit(0) print(args)
def uawrite(): parser = argparse.ArgumentParser(description="Write attribute of a node, per default write value of node") add_common_args(parser) parser.add_argument("-a", "--attribute", dest="attribute", type=int, default=ua.AttributeIds.Value, help="Set attribute to read") parser.add_argument("-l", "--list", "--array", dest="array", default="guess", choices=["guess", "true", "false"], help="Value is an array") parser.add_argument("-t", "--datatype", dest="datatype", default="guess", choices=["guess", 'byte', 'sbyte', 'nodeid', 'expandednodeid', 'qualifiedname', 'browsename', 'string', 'float', 'double', 'int16', 'int32', "int64", 'uint16', 'uint32', 'uint64', "bool", "string", 'datetime', 'bytestring', 'xmlelement', 'statuscode', 'localizedtext'], help="Data type to return") parser.add_argument("value", help="Value to be written", metavar="VALUE") args = parse_args(parser, requirenodeid=True) client = Client(args.url, timeout=args.timeout) _configure_client_with_args(client, args) client.connect() try: node = get_node(client, args) val = _val_to_variant(args.value, args) node.set_attribute(args.attribute, ua.DataValue(val)) finally: client.disconnect() sys.exit(0) print(args)
def uahistoryread(): parser = argparse.ArgumentParser(description="Read history of a node") add_common_args(parser) parser.add_argument("--starttime", default=None, help="Start time, formatted as YYYY-MM-DD [HH:MM[:SS]]. Default: current time - one day") parser.add_argument("--endtime", default=None, help="End time, formatted as YYYY-MM-DD [HH:MM[:SS]]. Default: current time") parser.add_argument("-e", "--events", action="store_true", help="Read event history instead of data change history") parser.add_argument("-l", "--limit", type=int, default=10, help="Maximum number of notfication to return") args = parse_args(parser, requirenodeid=True) client = Client(args.url, timeout=args.timeout) _configure_client_with_args(client, args) client.connect() try: node = get_node(client, args) starttime = str_to_datetime(args.starttime, datetime.utcnow() - timedelta(days=1)) endtime = str_to_datetime(args.endtime, datetime.utcnow()) print("Reading raw history of node {0} at {1}; start at {2}, end at {3}\n".format(node, args.url, starttime, endtime)) if args.events: evs = node.read_event_history(starttime, endtime, numvalues=args.limit) for ev in evs: print(ev) else: print_history(node.read_raw_history(starttime, endtime, numvalues=args.limit)) finally: client.disconnect() sys.exit(0)
def uageneratestructs(): parser = argparse.ArgumentParser(description="Generate a Python module from the xml structure definition (.bsd)") add_common_args(parser, require_node=True) parser.add_argument("-o", "--output", dest="output_path", required=True, type=str, default=None, help="The python file to be generated.", ) args = parse_args(parser, requirenodeid=True) client = Client(args.url, timeout=args.timeout) _configure_client_with_args(client, args) client.connect() try: node = get_node(client, args) generators, _ = client.load_type_definitions([node]) generators[0].save_to_file(args.output_path, True) finally: client.disconnect() sys.exit(0)
def test_context_manager(self): """ Context manager calls connect() and disconnect() """ state = [0] def increment_state(self, *args, **kwargs): state[0] += 1 # create client and replace instance methods with dummy methods client = Client('opc.tcp://dummy_address:10000') client.connect = increment_state.__get__(client) client.disconnect = increment_state.__get__(client) assert state[0] == 0 with client: # test if client connected self.assertEqual(state[0], 1) # test if client disconnected self.assertEqual(state[0], 2)
class CommunicationManager(): def __init__(self, swtid="001", configObject=None): self.swtID = swtid self.mqttClient = None self.opcClient = None self.__stopFlag = False self.__valueQueue = queue.Queue() self.__startMQTTThread = Thread(target=self.__MQTT_startClient, args=(), name="StartMqttClient") self.__startOpcuaThread = None self.__startOpcuaWrite = None self.__nodeList = ["Wrong", "Entries"] self.__combinedNuelleData = NuelleData() self.Station5APresent = [False] ######### MQTT Methods ########### def __on_message(self, mqttc, obj, msg): # statt topic wahrscheinlich topic+fieldname, als Payload Feld6-8 aus den einzelnen topics (10 verschiedene features insg) #print(msg.topic + msg.payload.decode()) self.__valueQueue.put( (msg.topic, msg.payload.decode()) ) #msg.payload is bytes, use "decode()" turn it into string. do not use str() def MQTT_CreateClient(self, url, port, timeout): self.mqttClient = mqtt.Client() self.mqttClient.on_message = self.__on_message self.mqttClient.connect(url, port, timeout) def MQTT_subscribeToTopic(self, topics): for topic in topics: self.mqttClient.subscribe(topic, 0) def MQTT_startClient(self): self.__startMQTTThread = Thread(target=self.__MQTT_startClient, args=(), name="StartMqttClient") self.__startMQTTThread.start() def __MQTT_startClient(self): self.mqttClient.loop_forever() def MQTT_stopClient(self): self.__MQTT_stopClient() def __MQTT_stopClient(self): try: self.mqttClient.disconnect() logging.info('Disconnected successfully') except: logging.error('Disconnect from MQTT Broker failed') self.__startMQTTThread.join() ######### OPC UA Methods ########### def OPCUA_createClient(self, url): self.opcClient = Client(url) self.opcClient.connect() print("OPC UA Client is now connected to " + url) def OPCUA_subscribe(self, nodeList): self.__nodeList = nodeList self.__startOpcuaThread = Thread(target=self.__OPCUA_subscribe, args=(), name="StartOPCUAClient") self.__startOpcuaThread.start() def OPCUA_write(self, nodeIDtoWrite, valueToWrite): print("OPC UA write to ") print(nodeIDtoWrite) print(" with value: ") print(valueToWrite) #self.__startOpcuaWriteThread = Thread(target=self.__OPCUA_write, args=(nodeIDtoWrite, valueToWrite), # name="WriteToOPCUAClient"+str(nodeIDtoWrite)) #self.__startOpcuaWriteThread.start() #self.__startOpcuaWriteThread.join() def __OPCUA_write(self, nodeID, value): var = self.opcClient.get_node(nodeID) var.set_attribute(ua.AttributeIds.Value, ua.DataValue(value)) def __OPCUA_subscribe(self): handler = SubHandler(self.__valueQueue, self.Station5APresent) self.__subscription = self.opcClient.create_subscription(50, handler) for i in range(len(self.__nodeList)): node = self.opcClient.get_node(self.__nodeList[i]) self.__subscription.subscribe_data_change(node) def OPCUA_stopClient(self): self.__OPCUA_stopClient() def __OPCUA_stopClient(self): try: self.__subscription.delete() self.opcClient.disconnect() print('Disconnected successfully') except: print('Disconnect from opc ua server failed') ########## Handle Data Collection, Combination and Retrieving ########### def __addToNuelleData(self, ValueName, newValue): if ValueName == 'esp32mag': #print(newValue) newValue = list(newValue.split(",")) if (newValue[1] == self.swtID): # print(newValue) self.__combinedNuelleData.combinedData[0] = float( newValue[5]) #feld 6 xmag self.__combinedNuelleData.combinedData[1] = float( newValue[6]) #feld 7 ymag self.__combinedNuelleData.combinedData[2] = float( newValue[7]) #feld 8 zmag self.__combinedNuelleData.combinedData[3] = newValue[ 4] #timestamp elif ValueName == 'StringNodeId(ns=3;s="DB_OPC_UA"."IMS_5A_M0009682"."I_Eingaenge"."I_IMS5A_IL")': self.__combinedNuelleData.combinedData[5] = newValue elif ValueName == 'StringNodeId(ns=3;s="DB_OPC_UA"."IMS_5A_M0009682"."I_Eingaenge"."I_IMS5A_B4")': self.__combinedNuelleData.combinedData[6] = newValue else: # pass print("Warnung - Unbekannte Variable erhalten: " + newValue + " - " + ValueName) def getDataSnapshot(self): return self.__combinedNuelleData.combinedData def __insertVariables(self): while not self.__stopFlag: if (not self.__valueQueue.empty()): queueContent = self.__valueQueue.get() self.__addToNuelleData(queueContent[0], queueContent[1]) self.__valueQueue.task_done() def startCollectingData(self): for i in range(20): self.__insertVariablesThread = Thread( target=self.__insertVariables, args=(), name="insertVariables{0}".format(i)) self.__insertVariablesThread.start() def stopCollectionData(self): self.__stopFlag = True self.__insertVariablesThread.join() def writeStation(self, address, value): self.OPCUA_write(address, value) def resetStation(self, number): for address in StationLightNode[number].values(): self.OPCUA_write(address, False) print(address, "False") def endofProgramm(self): # for LightDict in StationLightNode[1:]: # self.OPCUA_write(LightDict['IDofGreen'], True) # self.OPCUA_write(LightDict['IDofOrange'], False) # self.OPCUA_write(LightDict['IDofRed'], False) # print("Writes Done") # time.sleep(2) self.stopCollectionData() print("Stoped Collecting") self.OPCUA_stopClient() print("Stoped OPCUA") self.MQTT_stopClient() print("Stoped MQTT") print("Stopped!")
class AgentOPCUA(Agent): """Defines an Agent communicating via OPCUA.""" def __init__(self, hyperparams): """Initializes the agent. Args: hyperparams: Dictionary of hyperparameters. """ Agent.__init__(self, hyperparams) self.x0 = None self.dt = self._hyperparams['dt'] self.scaler = self._hyperparams['scaler'] self.action_scaler = self._hyperparams['action_scaler'] self.actuator_overrides = self._hyperparams['override_actuator'] self.sensor_overrides = self._hyperparams['override_sensor'] self.signals = self._hyperparams['send_signal'] self.sensors = self._hyperparams['opc_ua_states_include'] self.actuators = self.u_data_types self.client = None self.pool = ThreadPool(len(self.sensors)) self.debug = False def __init_opcua(self): if self.client is not None: # Close existing connection try: self.client.disconnect() except ua.uaerrors.UaError: pass self.client = Client(self._hyperparams['opc-ua_server']) self.client.connect() try: # Get Nodes self.opcua_vars = {} for sensor in (self.sensors + self.actuators): self.opcua_vars[sensor] = self.__get_node(sensor.value) for signal in self.signals: self.opcua_vars[signal['signal']] = self.__get_node( signal['signal']) except Exception: # Close connection in case of error self.close() raise def __get_node(self, sensor): browse_name = sensor.split(',') try: return self.client.get_objects_node().get_child(browse_name) except ua.uaerrors.BadNoMatch: logging.critical("Node not found: '%s'" % (sensor)) raise def transform(self, sensor, sensor_data): """Scales sates according to the scaler.""" data_idx = self._x_data_idx[sensor] return (sensor_data - self.scaler.mean_[data_idx]) / self.scaler.scale_[data_idx] def inverse_transform(self, actuator, actuator_data): """Inverse actions according to the scaler.""" data_idx = self._u_data_idx[actuator] return actuator_data * self.action_scaler.scale_[ data_idx] + self.action_scaler.mean_[data_idx] def read_sensor(self, sensor): """Reads an OPCUA sensor. Args: sensor: Sensor identifier (as specified in hyperparams file) Returns: sensor_data: Array of sensor readings. """ sensor_data = self.opcua_vars[sensor].get_value() if np.isscalar(sensor_data): # Wrap scalars into single element arrays sensor_data = [sensor_data] return self.transform(sensor, np.asarray(sensor_data)) def write_actuator(self, actuator, data): """Sets an OPCUA actuator. Args: actuator: Actuator identifier (as specified in hyperparams file) data: Value to set the actuator to. Arrays of length one are unboxed to a scalar. """ if len(data) == 1: data = data.item() data = ua.Variant(self.inverse_transform(actuator, data), ua.VariantType.Float) try: self.opcua_vars[actuator].set_data_value(data) except ua.uaerrors._auto.BadTypeMismatch: logging.critical( "Failed to write %r to %r of type %r" % (data, actuator, self.opcua_vars[actuator].get_data_type())) raise def reset(self, cond): """Reset the agent for a particular experiment condition. Args: condition: An index into hyperparams['reset_conditions']. """ if not self.debug: input('Press Enter to confirm reset') def sample(self, policy, condition, save=True, noisy=True, reset_cond=None, **kwargs): """Performs agent reset and rolls out given policy to collect a sample. Args: policy: A Policy object. condition: Which condition setup to run. save: Whether or not to store the trial into the samples. noisy: Whether or not to use noise during sampling. reset_cond: The initial condition to reset the agent into. Returns: sample: A Sample object. """ # Get a new sample sample = Sample(self) sample_ok = False while not sample_ok: if not self.debug: self.reset(reset_cond) self.__init_opcua() if noisy: noise = generate_noise(self.T, self.dU, self._hyperparams) else: noise = None # Execute policy over a time period of [0,T] start = time.time() for t in range(self.T): # Read sensors and store sensor data in sample def store_sensor(sensor): sample.set(sensor, self.read_sensor(sensor), t) self.pool.map(store_sensor, self.sensors) # Override sensors for override in self.sensor_overrides: if override['condition'](t): sensor = override['sensor'] sample.set(sensor, override['value'](sample, t), t) print('X_%02d' % t, sample.get_X(t)) # Get action U_t = policy.act(sample.get_X(t), sample.get_obs(t), t, noise) # Override actuators for override in self.actuator_overrides: if override['condition'](t): actuator = override['actuator'] U_t[self._u_data_idx[actuator]] = np.copy( override['value']) # Send signals self.send_signals(t) # Perform action for actuator in self._u_data_idx: self.write_actuator(actuator, U_t[self._u_data_idx[actuator]]) sample.set(ACTION, U_t, t) print('U_%02d' % t, U_t) # Check if agent is keeping up sleep_time = start + (t + 1) * self.dt - time.time() if sleep_time < 0: logging.critical("Agent can't keep up. %fs behind." % sleep_time) elif sleep_time < self.dt / 2: logging.warning( "Agent may not keep up (%.0f percent busy)" % (((self.dt - sleep_time) / self.dt) * 100)) # Wait for next timestep if sleep_time > 0 and not self.debug: time.sleep(sleep_time) if save: self._samples[condition].append(sample) self.finalize_sample() sample_ok = self.debug or input('Continue?') == 'y' if not sample_ok: print('Repeating') return sample def finalize_sample(self): """Adds additional waiting time to allow agent to reset. Sends final signals.""" if not self.debug: time.sleep(10) self.send_signals(self.T) def send_signals(self, t): """Sends edge-controlled OPCUA signals.""" if not self.debug: for signal in self.signals: if signal['condition'](t): self.send_signal(signal, True) thread.start_new_thread(self.send_signal, (signal, False, 2)) def send_signal(self, signal, value, sleep=0): """Sends an edge-controlled OPCUA signal.""" if sleep > 0: time.sleep(sleep) opcua_var = self.opcua_vars[signal['signal']] print("Signal", signal['signal'], value) opcua_var.set_data_value(ua.Variant(value, ua.VariantType.Boolean)) def close(self): """Releases any resources the agent may hold.""" if self.client is not None: self.client.disconnect()
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)
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 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): try: self.client.connect() self.objects = self.client.get_objects_node() # print('Cliente OPCUA se ha conectado') self.Instanciacion() except: self.client.disconnect() print('Cliente no se ha podido conectar')
class omronNx: def __init__(self, config_json, qt_main_ui, time_update): self._qt_main_ui = qt_main_ui self._config_json = config_json self.time_update = time_update self.PLC = plc.PLC(config_json, qt_main_ui, self) self.connect_addres = None self.opc_ua_client = None self.Time = 0 self.F = 20 self.Drivers = MPoll.MotorsPoll(config_json, qt_main_ui, self) self.is_stop = False self.is_opcua_connected = False self.is_started_drivers = False self.read_config() self.create_opc_client() self.init_ui_signals() self.count_update = 0 def init_ui_signals(self): self._qt_main_ui.ConnectToOmronBtn.clicked.connect(self.connect) def create_opc_client(self): self.opc_ua_client = Client( self.connect_addres ) def connect(self): try: self.opc_ua_client.connect() self.add_to_log_box("connect to : {}".format(self.connect_addres)) self.is_opcua_connected = True except Exception as e: self.is_opcua_connected = True self.add_to_log_box("connection error : {}".format(str(e))) #self.PLC._set_alarm_on(); def update(self): self.Drivers.update() self.view_update() self.PLC.update() pass def view_update(self): self._qt_main_ui.ferq_lab.display(self.F) pass def read_config(self): try: self.connect_addres = self._config_json["network"][0]["opc_addr"] except Exception as e: self.add_to_log_box(str(e)) def get_value(self, cmd): pass def set_value(self, node, value): try : node = self.opc_ua_client.get_node(node) node.set_attribute(ua.AttributeIds.Value, ua.DataValue(value)) except Exception as e: self.add_to_log_box("set_value error : {}".format(str(e))) pass def add_to_log_box(self, text): tmp_text = "" #self._qt_main_ui.log_box.text self._qt_main_ui.log_box.setText(tmp_text + "\n" +text) pass
class ScheduleCTRLWORD(object): """ RuleBasic定义 """ def __init__(self, AName): ''' :param tagID: 要采集的变量名称 :param src: 数据源,为dict类型 ''' self._redispool = redis.ConnectionPool( host=constant.REDIS_HOST, password=constant.REDIS_PASSWORD) self._name = AName self._ls1ctrlword = 0 self._lq1pv = 40 self._ld1pv = 50 self._ls2ctrlword = 0 self._lq2pv = 49 self._ld2pv = 40 self._kt1pv = 30 self._kt2pv = 30 self._kt1vopen = 50 self._kt2vopen = 50 self._ls1_run = 0 self._ls1_stop = 0 self._lqt1_run = 0 self._lqt1_stop = 0 self._ld1_run = 0 self._ld1_stop = 0 self._ls2_run = 0 self._ls2_stop = 0 self._lqt2_run = 0 self._lqt2_stop = 0 self._ld2_run = 0 self._ld2_stop = 0 self._ls1_wd = 10 self._ls2_wd = 10 self._ls1_net = 1 self._ls2_net = 1 self._connected = False self._client = None self._nodels1 = None self._nodeld1pv = None self._nodelq1pv = None self._nodels2 = None self._nodeld2pv = None self._nodelq2pv = None self._nodekt1pv = None self._nodekt2pv = None self._nodekt1vpv = None self._nodekt2vpv = None # self.INI_CTRL_WORD() def INI_CTRL_WORD(self): # client = Client('opc.tcp://127.0.0.1:49320') self.connect() # self._nodels1 = self._client.get_node('ns = 2;s = SCADA.DO.TSET1') # # self._nodeld1pv = self._client.get_node('ns = 2;s = SCADA.DO.LD1SET') # # self._nodelq1pv = self._client.get_node('ns = 2;s = SCADA.DO.LQ1SET') # # self._nodels2 = self._client.get_node('ns = 2;s = SCADA.DO.TSET2') # # self._nodeld2pv = self._client.get_node('ns = 2;s = SCADA.DO.LD2SET') # # self._nodelq2pv = self._client.get_node('ns = 2;s = SCADA.DO.LQ2SET') # # self._nodekt1pv = self._client.get_node('ns = 2;s = SCADA.DO.KT1SET') # # self._nodekt2pv = self._client.get_node('ns = 2;s = SCADA.DO.KT2SET') # # self._nodekt1vpv = self._client.get_node('ns = 2;s = SCADA.DO.SDF1SET') # # self._nodekt2vpv = self._client.get_node('ns = 2;s = SCADA.DO.SDF2SET') self._nodels1 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.KG2_KG1_Lighting.H_P_Man_Ang_x.H_P_Man_Ang_038' ) self._nodeld1pv = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.JN_x.JN_2') self._nodelq1pv = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.JN_x.JN_0') self._nodels2 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.KG2_KG1_Lighting.H_P_Man_Ang_x.H_P_Man_Ang_039' ) self._nodeld2pv = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.JN_x.JN_3') self._nodelq2pv = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.JN_x.JN_1') self._nodek1p1 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.H_P_Pid_Set_X.H_P_Pid_Set_28') self._nodek2p2 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.H_P_Pid_Set_X.H_P_Pid_Set_35') self._nodek3p3 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.H_P_Pid_Set_X.H_P_Pid_Set_42') self._nodek4p4 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.H_P_Pid_Set_X.H_P_Pid_Set_49') self._nodek5p5 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.H_P_Pid_Set_X.H_P_Pid_Set_56') def Write_LS1_CTRLWord(self): # client = Client('opc.tcp://127.0.0.1:49320') try: self.connect() ls1ctrl = self.GetCtrlWord(self._ls1_wd, self._ls1_run, self._ls1_stop, self._ld1_run, self._ld1_stop, self._lqt1_run, self._lqt1_stop) self._nodels1.set_value( ua.DataValue(ua.Variant(ls1ctrl, ua.VariantType.Int16))) except Exception as err: print(err) pass def Equip_LS1Control(self, AEquip, AType): # client = Client('opc.tcp://127.0.0.1:49320') try: self.connect() self._ls1_run = 0 self._ls1_stop = 0 self._ld1_run = 0 self._ld1_stop = 0 self._lqt1_run = 0 self._lqt1_stop = 0 if ((AEquip == "LS1") and (AType == "RUN")): self._ls1_run = 1 elif ((AEquip == "LS1") and (AType == "STOP")): self._ls1_stop = 1 elif ((AEquip == "LD1") and (AType == "RUN")): self._ld1_run = 1 elif ((AEquip == "LD1") and (AType == "STOP")): self._ld1_stop = 1 elif ((AEquip == "LQT1") and (AType == "RUN")): self._lqt1_run = 1 elif ((AEquip == "LQT1") and (AType == "STOP")): self._lqt1_stop = 1 ls1ctrl = self.GetCtrlWord(int(100), self._ls1_run, self._ls1_stop, self._ld1_run, self._ld1_stop, self._lqt1_run, self._lqt1_stop) self._nodels1.set_value( ua.DataValue(ua.Variant(ls1ctrl, ua.VariantType.Int16))) except Exception as err: print(err) pass def Write_LS1_Params(self, AEquipment, AValue): # client = Client('opc.tcp://127.0.0.1:49320') try: self.connect() if (AEquipment == "LD1"): self._ld1pv = int(AValue) self._nodeld1pv.set_value( ua.DataValue( ua.Variant(10 * int(self._ld1pv), ua.VariantType.UInt16))) elif (AEquipment == "LQ1"): self._lq1pv = int(AValue) self._nodelq1pv.set_value( ua.DataValue( ua.Variant(10 * int(self._lq1pv), ua.VariantType.UInt16))) # self._nodekt1pv.set_value(ua.DataValue(ua.Variant(10*int(self._kt1pv),ua.VariantType.UInt16))) # self._nodekt2pv.set_value(ua.DataValue(ua.Variant(10*int(self._kt2pv),ua.VariantType.UInt16))) # self._nodekt1vpv.set_value(ua.DataValue(ua.Variant(10*int(self._kt1vopen),ua.VariantType.UInt16))) # self._nodekt2vpv.set_value(ua.DataValue(ua.Variant(10*int(self._kt2vopen),ua.VariantType.UInt16))) except Exception as err: print(err) pass def Equip_LS2Control(self, AEquip, AType): # client = Client('opc.tcp://127.0.0.1:49320') try: self.connect() self._ls2_run = 0 self._ls2_stop = 0 self._ld2_run = 0 self._ld2_stop = 0 self._lqt2_run = 0 self._lqt2_stop = 0 if ((AEquip == "LS2") and (AType == "RUN")): self._ls2_run = 1 elif ((AEquip == "LS2") and (AType == "STOP")): self._ls2_stop = 1 elif ((AEquip == "LD2") and (AType == "RUN")): self._ld2_run = 1 elif ((AEquip == "LD2") and (AType == "STOP")): self._ld2_stop = 1 elif ((AEquip == "LQT2") and (AType == "RUN")): self._lqt2_run = 1 elif ((AEquip == "LQT2") and (AType == "STOP")): self._lqt2_stop = 1 ls2ctrl = self.GetCtrlWord(int(100), self._ls2_run, self._ls2_stop, self._ld2_run, self._ld2_stop, self._lqt2_run, self._lqt2_stop) self._nodels2.set_value( ua.DataValue(ua.Variant(ls2ctrl, ua.VariantType.Int16))) except Exception as err: print(err) pass def Write_LS2_Params(self, AEquipment, AValue): # client = Client('opc.tcp://127.0.0.1:49320') try: self.connect() if (AEquipment == "LD2"): self._ld2pv = int(AValue) self._nodeld2pv.set_value( ua.DataValue( ua.Variant(10 * int(self._ld2pv), ua.VariantType.Int16))) elif (AEquipment == "LQ2"): self._lq2pv = int(AValue) self._nodelq2pv.set_value( ua.DataValue( ua.Variant(10 * int(self._lq2pv), ua.VariantType.Int16))) # self._nodekt1pv.set_value(ua.DataValue(ua.Variant(10*int(self._kt1pv),ua.VariantType.UInt16))) # self._nodekt2pv.set_value(ua.DataValue(ua.Variant(10*int(self._kt2pv),ua.VariantType.UInt16))) # self._nodekt2vpv.set_value(ua.DataValue(ua.Variant(10*int(self._kt2vopen),ua.VariantType.UInt16))) # self._nodekt1vpv.set_value(ua.DataValue(ua.Variant(10*int(self._kt1vopen),ua.VariantType.UInt16))) except Exception as err: print(err) pass def connect(self): self.disconnect() self._client = Client('opc.tcp://127.0.0.1:49320') self._client.connect() # self._nodels1 = self._client.get_node('ns = 2;s = SCADA.DO.TSET1') # self._nodeld1pv = self._client.get_node('ns = 2;s = SCADA.DO.LD1SET') # self._nodelq1pv = self._client.get_node('ns = 2;s = SCADA.DO.LQ1SET') # self._nodels2 = self._client.get_node('ns = 2;s = SCADA.DO.TSET2') # self._nodeld2pv = self._client.get_node('ns = 2;s = SCADA.DO.LD2SET') # self._nodelq2pv = self._client.get_node('ns = 2;s = SCADA.DO.LQ2SET') # self._nodekt1pv = self._client.get_node('ns = 2;s = SCADA.DO.KT1SET') # self._nodekt2pv = self._client.get_node('ns = 2;s = SCADA.DO.KT2SET') # self._nodekt1vpv = self._client.get_node('ns = 2;s = SCADA.DO.SDF1SET') # self._nodekt2vpv = self._client.get_node('ns = 2;s = SCADA.DO.SDF2SET') self._nodels1 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.KG2_KG1_Lighting.H_P_Man_Ang_x.H_P_Man_Ang_038' ) self._nodeld1pv = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.JN_x.JN_2') self._nodelq1pv = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.JN_x.JN_0') self._nodels2 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.KG2_KG1_Lighting.H_P_Man_Ang_x.H_P_Man_Ang_039' ) self._nodeld2pv = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.JN_x.JN_3') self._nodelq2pv = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.JN_x.JN_1') self._nodek1p1 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.H_P_Pid_Set_X.H_P_Pid_Set_28') self._nodek2p2 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.H_P_Pid_Set_X.H_P_Pid_Set_35') self._nodek3p3 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.H_P_Pid_Set_X.H_P_Pid_Set_42') self._nodek4p4 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.H_P_Pid_Set_X.H_P_Pid_Set_49') self._nodek5p5 = self._client.get_node( 'ns = 2;s = PLC.KG1.Global.H_P_Pid_Set_X.H_P_Pid_Set_56') self._connected = True def disconnect(self): if self._connected: print("Disconnecting from server") self._connected = False try: self._client.disconnect() finally: self._reset() def _reset(self): self.client = None self._connected = False def Write_LS2_CTRLWord(self): # client = Client('opc.tcp://127.0.0.1:49320') try: self.connect() ls2ctrl = self.GetCtrlWord(self._ls2_wd, self._ls2_run, self._ls2_stop, self._ld2_run, self._ld2_stop, self._lqt2_run, self._lqt2_stop) # self._nodels2 = self._client.get_node('ns = 2;s = SCADA.DO.TSET2') self._nodels2.set_value( ua.DataValue(ua.Variant(ls2ctrl, ua.VariantType.Int16))) except Exception as err: print(err) pass def GetCtrlWord(self, AOutTemp, ALSRun, ALSSTOP, ALDRun, ALDSTOP, ALQT_T1_RUN, ALQT_T1_STOP): if int(AOutTemp) > 30: int_num = int(AOutTemp) else: int_num = int(AOutTemp) bin_num = bin(int_num) slow = str(bin_num)[2:] if len(slow) == 1: slow = '0000000' + slow elif len(slow) == 2: slow = '000000' + slow elif len(slow) == 3: slow = '00000' + slow elif len(slow) == 4: slow = '0000' + slow elif len(slow) == 5: slow = '000' + slow elif len(slow) == 6: slow = '00' + slow elif len(slow) == 7: slow = '0' + slow shigh = '' # 第8位 if ALSRun == 1: shigh = '01' # 第9位 elif ALSSTOP == 1: shigh = '10' elif (ALSRun == 0) and (ALSSTOP == 0): shigh = '00' if ALDRun == 1: shigh = "01" + shigh elif ALDSTOP == 1: shigh = '10' + shigh elif (ALDRun == 0) and (ALDSTOP == 0): shigh = '00' + shigh # 第12位 if ALQT_T1_RUN == 1: shigh = '01' + shigh elif ALQT_T1_STOP == 1: shigh = '10' + shigh elif (ALQT_T1_RUN == 0) and (ALQT_T1_RUN == 0): shigh = '00' + shigh shigh = '00' + shigh print("字符串" + shigh + slow + ":整型:" + str(int(shigh + slow, 2))) return int(shigh + slow, 2) def Write_LS_INIWORD(self, AEquip, AWD): # client = Client('opc.tcp://127.0.0.1:49320') try: self.connect() lsctrl = self.GetCtrlWord(int(AWD), 0, 0, 0, 0, 0, 0) if AEquip == "LS1": # self._nodels1 = self._client.get_node('ns = 2;s = SCADA.DO.TSET1') self._nodels1.set_value( ua.DataValue(ua.Variant(lsctrl, ua.VariantType.Int16))) elif AEquip == "LS2": # self._nodels2 = self._client.get_node('ns = 2;s = SCADA.DO.TSET2') self._nodels2.set_value( ua.DataValue(ua.Variant(lsctrl, ua.VariantType.Int16))) except Exception as err: print(err) pass def GetFaultCtrlWord(self, AOutTemp, AFault): if int(AOutTemp) > 30: int_num = int(AOutTemp) else: int_num = int(AOutTemp) bin_num = bin(int_num) slow = str(bin_num)[2:] if len(slow) == 1: slow = '0000000' + slow elif len(slow) == 2: slow = '000000' + slow elif len(slow) == 3: slow = '00000' + slow elif len(slow) == 4: slow = '0000' + slow elif len(slow) == 5: slow = '000' + slow elif len(slow) == 6: slow = '00' + slow elif len(slow) == 7: slow = '0' + slow shigh = '000000' if AFault == 1: shigh = '1' + shigh else: shigh = '0' + shigh print("字符串" + shigh + slow + ":整型:" + str(int(shigh + slow, 2))) return int(shigh + slow, 2) def Write_LS_FaultReset(self, AEquipment): # client = Client('opc.tcp://127.0.0.1:49320') try: self.connect() if (AEquipment == "LS1"): lsctrl = self.GetFaultCtrlWord(100, 1) self._nodels1.set_value( ua.DataValue(ua.Variant(int(lsctrl), ua.VariantType.Int16))) time.sleep(5) lsctrl = self.GetFaultCtrlWord(100, 0) self._nodels1.set_value( ua.DataValue(ua.Variant(int(lsctrl), ua.VariantType.Int16))) elif (AEquipment == "LS2"): lsctrl = self.GetFaultCtrlWord(100, 1) self._nodels2.set_value( ua.DataValue(ua.Variant(int(lsctrl), ua.VariantType.UInt16))) time.sleep(5) lsctrl = self.GetFaultCtrlWord(100, 0) self._nodels2.set_value( ua.DataValue(ua.Variant(int(lsctrl), ua.VariantType.UInt16))) except Exception as err: print(err) pass
# encoding=utf-8 import sys, time sys.path.insert(0, "..") from opcua import Client if __name__ == "__main__": # client = Client("opc.tcp://127.0.0.1:4840") # client = Client("opc.tcp://127.0.0.1:4840/freeopcua/server/") client = Client("opc.tcp://127.0.0.1:7766") #connect using a user try: res = 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) children = root.get_children() # Node objects have methods to read and write node attributes as well as browse or populate address space print("Children of root are: ", root.get_children()) # get a specific node knowing its node id # var = client.get_node(ua.NodeId(1002, 2)) # var = client.get_node("ns=3;i=2002") # print(var) # var.get_data_value() # get value of node as a DataValue object # var.get_value() # get value of node as a python builtin # var.set_value(ua.Variant([23], ua.VariantType.Int64)) #set node value using explicit data type # var.set_value(3.9) # set node value using implicit data type
def config_setup(): data = {} configdict = dict() # OPC UA Initialisation while True: opcdata = GUI.opc_initialise() a = list() for num, val in opcdata.items(): a.append(val) OPCname = str(a[0]) OPCurl = str(a[1]) client = Client(OPCurl) try: # Authentication requires copy of certificate and private key in local system. # need to add full path of private key and certificate file as parameters (not available at the moment) # client.set_security_string(security_algorithm , authentication_mode , path_of_certificate , path_of_private_key)) -> syntax # client.set_security_string("Basic256Sha256,SignAndEncrypt,server_cert.der,server_key.pem") # need to add cert and key path client.connect() opclist.append(client) DB.get_opc(client) GUI.opc_pop() configdict.update({"OPC Server Name": OPCname}) configdict.update({"OPC Server URL": OPCurl}) break except: # Connecting to OPC UA Server without authentication try: client.connect() opclist.append(client) DB.get_opc(client) GUI.opc_pop() configdict.update({"OPC Server Name": OPCname}) configdict.update({"OPC Server URL": OPCurl}) break except: GUI.opc_error() # MySQL Initialisation while True: sqldata = GUI.sql_initialise() a = list() for num, val in sqldata.items(): a.append(val) sqlhost = str(a[0]) sqluser = str(a[1]) sqlpwd = str(a[2]) dbname = str(a[3]) try: mydb = mysql.connector.connect(host=sqlhost, user=sqluser, passwd=sqlpwd, database=dbname) mycursor = mydb.cursor() GUI.sql_pop1() configdict.update({"SQL Host": sqlhost}) configdict.update({"SQL Username": sqluser}) configdict.update({"SQL Password": sqlpwd}) configdict.update({"Database Name": dbname}) DB.get_db(mydb) MYSQL_list.append(mydb) break except: try: mydb = mysql.connector.connect(host=sqlhost, user=sqluser, passwd=sqlpwd) mycursor = mydb.cursor() db = "CREATE DATABASE " + dbname db = str(db) mycursor.execute(db) mydb = mysql.connector.connect(host=sqlhost, user=sqluser, passwd=sqlpwd, database=dbname) mycursor = mydb.cursor() GUI.sql_pop2() configdict.update({"SQL Host": sqlhost}) configdict.update({"SQL Username": sqluser}) configdict.update({"SQL Password": sqlpwd}) configdict.update({"Database Name": dbname}) DB.get_db(mydb) MYSQL_list.append(mydb) break except: GUI.sql_error() # Mainflux API initialization while True: mainflux_data = GUI.flux_initialise() a = list() for num, val in mainflux_data.items(): a.append(val) flux_ip = str(a[0]) flux_port = str(a[1]) flux_email = str(a[2]) flux_pwd = str(a[3]) try: token = DB.get_token(flux_ip, flux_port, flux_email, flux_pwd) GUI.flux_pop() configdict.update({"Mainflux IP": flux_ip}) configdict.update({"Mainflux Port": flux_port}) configdict.update({"Mainflux Email": flux_email}) configdict.update({"Mainflux Password": flux_pwd}) break except: GUI.flux_error() data['Settings'] = [] data['Settings'].append(configdict) dir_path = os.path.dirname(os.path.realpath(__file__)) dir_path = str(dir_path) configpath = dir_path + "\config.json" configpath = str(configpath) with open(configpath, 'w') as f: json.dump(data, f, indent=4)
def test_get_endpointr(self): client = Client("opc.tcp://" + os.environ['TEST_IP'] + ":" + os.environ['TEST_PORT']) client.connect() endpoints = client.get_endpoints() self.assertEqual(len(endpoints), 4) client.disconnect()
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()
class PluginConsoleTool(cmd.Cmd): intro = ''' Welcome to the (opcua plugin tool) shell. Type help or ? to list commands.\n ''' prompt = '(opcua plugin tool) > ' def __init__(self): super(PluginConsoleTool, self).__init__() self.server_uri = "opc.tcp://localhost:4840" self.opcua = None self.node = None def do_plugin_list(self, arg): try: code, data = self.node.call_method('2:get_plugin_list') if code == '0': result = json.loads(data) if result['Error']: print(result['Error']) else: print(result['Success']) else: print(code, data) except Exception as e: print(repr(e)) def do_start_plugin(self, arg): args = arg.split() if len(args) == 1: try: code, data = self.node.call_method('2:start_plugin', args[0]) if code == '0': result = json.loads(data) if result['Error']: print(result['Error']) else: print(result['Success']) else: print(code, data) except Exception as e: print(repr(e)) else: print('Error input. example : start_plugin MqttPlugin') def do_stop_plugin(self, arg): args = arg.split() if len(args) == 1: try: code, data = self.node.call_method('2:stop_plugin', args[0]) if code == '0': result = json.loads(data) if result['Error']: print(result['Error']) else: print(result['Success']) else: print(code, data) except Exception as e: print(repr(e)) else: print('Error input. example : stop_plugin MqttPlugin') def do_getcfg(self, arg): args = arg.split() if len(args) == 3: dirname = os.path.realpath(args[2]) if os.path.isdir(dirname): try: code, data = self.node.call_method('2:getcfg', args[0], args[1]) if code == '0': result = json.loads(data) if result['Error']: print(result['Error']) else: with open( os.path.join( dirname, result['Success']['filename']), "w") as f: f.write(result['Success']['data']) print('saved file to %s' % os.path.join( dirname, result['Success']['filename'])) else: print(code, data) except Exception as e: print(repr(e)) else: print( 'folder not exist, please enter the correct directory used to store files' ) else: print('Error input. example : getcfg mqttplugin json /home/test/') def do_setcfg(self, arg): args = arg.split() if len(args) == 3: if os.path.isfile(os.path.realpath(args[2])): fp = os.path.realpath(args[2]) s = '' with open(fp, 'r') as f: s = f.read() try: code, data = self.node.call_method('2:setcfg', args[0], args[1], s) if code == '0': result = json.loads(data) if result['Error']: print(result['Error']) else: print(result['Success']) else: print(code, data) except Exception as e: print(repr(e)) else: print( 'source file not exist, please enter the correct path to upload' ) else: print( 'Error input. example : setcfg mqttplugin json /home/test/t.json' ) def do_call(self, arg): args = arg.split() if len(args) > 1: plugin_name = args[0:1][0] method_name = args[1:2][0] params = args[2:] if plugin_name == 'manager': print("manager plugin not allow call_method in console tools") return plugin_node = None try: plugin_node = self.root.get_child( ["0:Objects", "2:" + plugin_name]) except BaseException: print('Cannot find {0}, please check the plugin is started.'. format(plugin_name)) if plugin_node: methods = plugin_node.get_methods() func = None for m in methods: if m.get_display_name().Text == method_name: func = m if func: try: result = plugin_node.call_method(func, *params) print(result) except BaseException: pass else: print('object has not method ({0}).'.format(method_name)) else: print('example : call KvPlugin put key value') def do_tree(self, arg): args = arg.split() if len(args) == 1: plugin_name = args[0] if plugin_name == 'manager': print("manager plugin operation is not supported") return plugin_node = None try: plugin_node = self.root.get_child( ["0:Objects", "2:" + plugin_name]) except BaseException: print('Cannot find {0}, please check the plugin is started.'. format(plugin_name)) if plugin_node: listtree(plugin_node, tab=0) else: print('example : tree KvPlugin') def do_exit(self, arg): print('GOOD BAY') return True def preloop(self): self.opcua = Client(self.server_uri) try: self.opcua.connect() except BaseException: self.bye('Connect opcua server failed. %s' % self.server_uri) self.root = self.opcua.get_root_node() try: self.node = self.root.get_child(["0:Objects", "2:ManagerPlugin"]) except BaseException: self.bye( 'Cannot find the ManagerPlugin node, maybe the Manager plugin not started.' ) def postloop(self): if self.opcua: self.opcua.disconnect() def default(self, line): print('Unknown command, please try help') def bye(self, msg): print(msg) print('Application exit') if self.opcua: try: self.opcua.disconnect() except BaseException: pass exit(1)
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"]["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.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.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 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")) self.client = Client( self.__opcua_url, timeout=self.__server_conf.get("timeoutInMillis", 4000) / 1000) 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 FuturesTimeoutError: 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 isinstance(arguments, 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 __initialize_client(self): 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) 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 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 None 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=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) 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 = 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('\\\\', '\\') 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 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 = '\\\\.'.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 TankSystem: def __init__(self): self.client = None self.objects_node = None self.root_node = None self.connected = False self.sub_handler = SubHandler() self.max_size = 600 self.past_values = { 'time': collections.deque(maxlen=self.max_size), 'tank_1': collections.deque(maxlen=self.max_size), 'tank_2': collections.deque(maxlen=self.max_size), 'tank_3': collections.deque(maxlen=self.max_size), 'tank_4': collections.deque(maxlen=self.max_size), 'valve_1': collections.deque(maxlen=self.max_size), 'valve_2': collections.deque(maxlen=self.max_size), } self.seconds = time.time() self.start_time = time.time() self.logging_time = 1 def connect(self): if not self.connected: # self.client = Client('opc.tcp://192.168.1.23:4840/freeopcua/server/') self.client = Client( 'opc.tcp://192.168.1.23:4840/freeopcua/server/') self.client.connect() self.objects_node = self.client.get_objects_node() self.connected = True self.log_values() self.root_node = self.client.get_root_node() myevent = self.root_node.get_child([ '0:Types', '0:EventTypes', '0:BaseEventType', '2:Alarma_nivel' ]) obj = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Alarmas', '2:Alarma_nivel']) sub = self.client.create_subscription(100, self.sub_handler) handle = sub.subscribe_events(obj, myevent) # sub.unsubscribe(handle) # sub.delete() def disconnect(self): if self.connected: self.connected = False self.client.disconnect() self.client = None self.objects_node = None self.past_values = { 'time': collections.deque(maxlen=self.max_size), 'tank_1': collections.deque(maxlen=self.max_size), 'tank_2': collections.deque(maxlen=self.max_size), 'tank_3': collections.deque(maxlen=self.max_size), 'tank_4': collections.deque(maxlen=self.max_size), 'valve_1': collections.deque(maxlen=self.max_size), 'valve_2': collections.deque(maxlen=self.max_size), } @property def tank_1(self): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Tanques', '2:Tanque1', '2:h']) value = node.get_value() return value @property def tank_2(self): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Tanques', '2:Tanque2', '2:h']) value = node.get_value() return value @property def tank_3(self): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Tanques', '2:Tanque3', '2:h']) value = node.get_value() return value @property def tank_4(self): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Tanques', '2:Tanque4', '2:h']) value = node.get_value() return value @property def valve_1(self): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Valvulas', '2:Valvula1', '2:u']) value = node.get_value() return value @valve_1.setter def valve_1(self, value): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Valvulas', '2:Valvula1', '2:u']) node.set_value(value) @property def valve_2(self): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Valvulas', '2:Valvula2', '2:u']) value = node.get_value() return value @valve_2.setter def valve_2(self, value): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Valvulas', '2:Valvula2', '2:u']) node.set_value(value) @property def gamma_1(self): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Razones', '2:Razon1', '2:gamma']) value = node.get_value() return value @gamma_1.setter def gamma_1(self, value): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Razones', '2:Razon1', '2:gamma']) node.set_value(value) @property def gamma_2(self): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Razones', '2:Razon2', '2:gamma']) value = node.get_value() return value @gamma_2.setter def gamma_2(self, value): node = self.objects_node.get_child( ['2:Proceso_Tanques', '2:Razones', '2:Razon2', '2:gamma']) node.set_value(value) def log_values(self): if self.connected: self.seconds = time.time() self.past_values['time'].append( round(time.time() - self.start_time, 3)) self.past_values['tank_1'].append(round(self.tank_1, 3)) self.past_values['tank_2'].append(round(self.tank_2, 3)) self.past_values['tank_3'].append(round(self.tank_3, 3)) self.past_values['tank_4'].append(round(self.tank_4, 3)) self.past_values['valve_1'].append(round(self.valve_1, 3)) self.past_values['valve_2'].append(round(self.valve_2, 3))
class Subscriber(): """Create a service to monitor OPC nodes. """ def __init__(self, callback, **params): """Instantiate an the base class OPC client. Arguments callback (func): Function to call on node value changes. params (dict): Configuration parameters to start service. The dictionary should contain: endpoint (str): OPC server address uri (str): the namespace for the nodes obj (str): the parent object node of the nodes nodes (dict): Keys are the name of the nodes to monitor. The values are dictionaries: "respond": node to respond watchdog (optional) (str): the name of the node used for the watchdog """ self._callback = callback self._params = params def _connect(self, endpoint): """Conncect to the OPC UA server. Arguments endpoint (str): OPC server address """ self._client = Client(endpoint) self._client.connect() def _get_nodes(self, idx, obj, names): """Get links to the OPC nodes. Arguments idx (int): Namespace index obj (str): Object name names (list): List of string of node names returns (list): List of Nodes """ idx = self._client.get_namespace_index(idx) root = self._client.get_root_node() nodes = [root.get_child(self._get_path(idx, obj, n)) for n in names] return nodes def _get_path(self, idx, obj, name): """Make a browse path list from the namespace index and object and node name. Arguments idx (int): Namespace index obj (str): Object name name (str): Name of node Return (list) browse path """ bp = ["0:Objects", f"{idx}:{obj}", f"{idx}:{name}"] return bp def _get_name(self, node): """ Get the name of the node from the mapping. Arguments node (node): Node object return (str) name associated with node """ return [k for k, v in self._map.items() if v == node][0] def _create_node_map(self): """Create a map between node names and Node objects for fast lookup. """ # Get all the nodes defined in the parameters dictionary. names = list(self._params["nodes"].keys())\ + [v["respond"] for k, v in self._params["nodes"].items()] if "watchdog" in self._params: names += [ self._params["watchdog"]["controller"], self._params["watchdog"]["instrument"] ] nodes = self._get_nodes(self._params["uri"], self._params["obj"], names) return {k: v for k, v in zip(names, nodes)} def _get_monitor_nodes(self): """Get the nodes to be monitored. """ names = list(self._params["nodes"].keys()) if "watchdog" in self._params: names += [self._params["watchdog"]["controller"]] return self._get_nodes(self._params["uri"], self._params["obj"], names) def _update_watchdog(self, val): """Update the watchdog. This is handled at the subscription service level and not instrument to reduce CPU overhead. Arguments val (?): The value to return to the watchdog tag. """ # self.respond(self._params["watchdog"]["instrument"], val) def respond(self, node, value): """Write a value to the node. Arguments node (str): String associated with node (see self._map) value (varries): value to write """ self._map[node].set_value(value) def datachange_notification(self, node, val, data): """This method is called on subscribed node changes. see https://python-opcua.readthedocs.io/en/latest/subscription.html """ # If the node is the watchdog node, then update without # calling instrument method to reduce CPU cycles. if "watchdog" in self._params: if node == self._map[self._params["watchdog"]["controller"]]: self._update_watchdog(val) else: name = self._get_name(node) # Call the instrument callback with the node information: # desired run command, # callback to the respond method with the node as parameter self._callback( command=self._params["nodes"][name]["command"], parameters=val, callback=lambda x: self.respond( self._params["nodes"][name]["respond"], x), ) def run(self): """Connect to client, and subscribe to nodes. """ self._connect(self._params["endpoint"]) self._map = self._create_node_map() sub = self._client.create_subscription(1000, self) nodes = self._get_monitor_nodes() handle = sub.subscribe_data_change(nodes) logger.info("OPC subscription started")
def event_notification(self, event): print("Python: New event", event) if __name__ == "__main__": logging.basicConfig(level=logging.WARN) #logger = logging.getLogger("KeepAlive") #logger.setLevel(logging.DEBUG) #Set according to the OPC UA network #client = Client("opc.tcp://127.0.0.1:12686/AI4.0-Ontology-Example") client = Client("opc.tcp://192.168.1.7:12686/AI4.0-Ontology-Example") try: client.connect() client.load_type_definitions() # load definition of server specific structures/extension objects # Client has a few methods to get proxy to UA nodes that should always be in address space such as Root or Objects root = client.get_root_node() print("Root node is: ", root) objects = client.get_objects_node() print("Objects node is: ", objects) # Node objects have methods to read and write node attributes as well as browse or populate address space print("Children of root are: ", root.get_children()) ###States state0Node = client.get_node("ns=2;s=A-I4.0-Ontology/Metal-Separation-Process/States/State 0") state0_value = state0Node.get_value() state1Node = client.get_node("ns=2;s=A-I4.0-Ontology/Metal-Separation-Process/States/State 1")
class microKWKKcom(object): variables_location = ["0:Objects", "4:PLC1", "4:GVL_OPC_Variablen"] devices = { "CHP_H_W_Q_M___": "4:QthChp", "CHP_H_W_PT_M___": "4:PthChp", "CHP_H_W_VF_M___": "4:VdotChp", "CHP_H_W_T_M__FL_": "4:TflChp", "CHP_H_W_T_M__RL_": "4:TrlChp", "CHP_H_W_dT_M___": "4:VHmChp", "CHP_H_E_PE_M___": "4:PelChp", "CHP_H_F_VF_M___": "4:VdotFuel", "CHP_H_F_IMP_M___": "4:VdotFuelImp", "CHP_H_W_B_O___": "4:OnChp", "CHP_H_E_B_O___": "4:OnVoltageChp", "CHP_H_E_Q_M__FL_": "4:QelChpIn", "CHP_H_E_Q_M__RL_": "4:QelChpOut", "ADCM_C_W_Q_M_LT__": "4:QthAdcmLt", "ADCM_C_W_PT_M_LT__": "4:PthAdcmLt", "ADCM_C_W_VF_M_LT__": "4:VdotAdcmLt", "ADCM_C_W_T_M_LT_FL_": "4:TflAdcmLt", "ADCM_C_W_T_M_LT_RL_": "4:TrlAdcmLt", "ADCM_C_W_dT_M_LT__": "4:VHmAdcmLt", "ADCM_C_W_Q_M_MT__": "4:QthAdcmMt", "ADCM_C_W_PT_M_MT__": "4:PthAdcmMt", "ADCM_C_W_VF_M_MT__": "4:VdotAdcmMt", "ADCM_C_W_T_M_MT_FL_": "4:TflAdcmMt", "ADCM_C_W_T_M_MT_RL_": "4:TrlAdcmMt", "ADCM_C_W_dT_M_MT__": "4:VHmAdcmMt", "ADCM_C_W_Q_M_HT__": "4:QthAdcmHt", "ADCM_C_W_PT_M_HT__": "4:PthAdcmHt", "ADCM_C_W_VF_M_HT__": "4:VdotAdcmHt", "ADCM_C_W_T_M_HT_FL_": "4:TflAdcmHt", "ADCM_C_W_T_M_HT_RL_": "4:TrlAdcmHt", "ADCM_C_W_dT_M_HT__": "4:VHmAdcmHt", "ADCM_C_E_PE_M___": "4:PelAdcm", "ADCM_C_W_B_O___": "4:OnAdcm", "ADCM_C_W_TSET_O_LT__": "4:TsetAdcm", "ADCM_C_W_VSET_M_MT__": "4:VAdcmCt", "RevHP_HC_W_Q_M_LT__": "4:QthCcmLt", "RevHP_HC_W_PT_M_LT__": "4:PthCcmLt", "RevHP_HC_W_VF_M_LT__": "4:VdotCcmLt", "RevHP_HC_W_T_M_LT_FL_": "4:TflCcmLt", "RevHP_HC_W_T_M_LT_RL_": "4:TrlCcmLt", "RevHP_HC_W_dT_M_LT__": "4:VHmCcmLt", "RevHP_HC_W_Q_M_MT__": "4:QthCcmCkd", "RevHP_HC_W_PT_M_MT__": "4:PthCcmCkd", "RevHP_HC_W_VF_M_MT__": "4:VdotCcmCkd", "RevHP_HC_W_T_M_MT_FL_": "4:TflCcmCkd", "RevHP_HC_W_T_M_MT_RL_": "4:TrlCcmCkd", "RevHP_HC_W_dT_M_MT__": "4:VHmCcmCkd", "RevHP_HC_E_PE_M___": "4:PelCcm", "RevHP_HC_W_B_O___": "4:OnCcm", "RevHP_C_W_B_O___": "4:CoolingCcm", "OC_HC_B_Q_M___": "4:QthCt", "OC_HC_B_PT_M___": "4:PthCt", "OC_HC_B_VF_M___": "4:VdotCt", "OC_HC_B_T_M__FL_": "4:TrlCt", "OC_HC_B_T_M__RL_": "4:TflCt", "OC_HC_B_dT_M___": "4:VHmCt", "OC_HC_E_PE_M___": "4:PelCt", "OC_HC_B_B_O___": "4:OnCt", "OC_HC_B_PSET_O___": "4:VsetCt", "OC_HC_E_B_O___": "4:ModeCt", "LOAD_HC_W_Q_M___": "4:QthLoad", "LOAD_HC_W_PT_M___": "4:PthLoad", "LOAD_HC_W_VF_M___": "4:VdotLoad", "LOAD_HC_W_T_M__FL_": "4:TflLoad", "LOAD_HC_W_T_M__RL_": "4:TrlLoad", "LOAD_HC_W_dT_M___": "4:VHmLoad", "PU_HC_B_B_O_MT__": "4:OnP5AdcmMt", "PU_HC_W_B_O_LT_RevHp_": "4:OnP6CcmLt", "PU_HC_W_B_O_MT_RevHp_": "4:OnP7CcmMt", "PU_H_W_B_O__MX_": "4:OnP8HtesCtes", "PU_H_W_B_O_MT_HTES_": "4:OnP11Htes", "PU_H_W_B_O_IT_HTES_": "4:OnP12Htes", "PU_H_W_B_O_HT_RevHP_": "4:OnP13RevHpW2", "HTES_H_W_T_M_IT_1_": "4:HT01", "HTES_H_W_T_M_IT_2_": "4:HT02", "HTES_H_W_T_M_IT_3_": "4:HT03", "HTES_H_W_T_M_IT_4_": "4:HT04", "HTES_H_W_T_M_IT_5_": "4:HT05", "HTES_H_W_T_M_IT_6_": "4:HT06", "HTES_H_W_T_M_IT_7_": "4:HT07", "HTES_H_W_T_M_IT_8_": "4:HT08", "HTES_H_W_T_M_IT_9_": "4:HT09", "CTES_C_W_T_M_IT_1_": "4:CT01", "CTES_C_W_T_M_IT_2_": "4:CT02", "CTES_C_W_T_M_IT_3_": "4:CT03", "CTES_C_W_T_M_IT_4_": "4:CT04", "COIL_H_W_B_O_IT__": "4:OnCoil", "COIL_H_E_PE_M___": "4:PelCoil", "ASL_H_W_B_O_IT_FL_": "4:LeftAsl", "ASL_H_W_B_O_IT_RL_": "4:RightAsl", "ASL_H_W_T_M_IT_FL_": "4:AslTcl", "SV_HC_W_B_O__FL_": "4:OpenSo1", "SV_HC_W_B_O__RL_": "4:OpenSo2", "MV_HC_W_B_O_FL_1_": "4:OpenMv1", "MV_HC_W_B_O_FL_2_": "4:OpenMv2", "MV_HC_W_B_O_RL_1_": "4:CloseMv1", "MV_HC_W_B_O_RL_2_": "4:CloseMv2", "AUX_HC_E_PE_M___": "4:PelAux", "AUX_HC_A_T_M___": "4:Tamb", "KWKK_SPStime": "4:SPSzeit", "KWKK_SPSrun": "4:SPSrun", "KWKK_CtrlMode": "4:OpModeAuto", "NotAusAktiv": "4:NotAusAktiv", "Optimal_Mode": "4:Optimal_Mode" } def __init__(self, server_address=None, server_port=None): self.server_address = server_address self.server_port = server_port self.client = Client("opc.tcp://" +str(self.server_address) + ":" + \ str(self.server_port)) self.client.connect() self.root = self.client.get_root_node() def __del__(self): self.client.disconnect() def set_value(self, device="", value=""): """ Assign a value to the specified device listed on the dictionary (use labview name) These values have to match the data type set on the PLC (SPS). eg. float, UInt16, etc. The SPS can recieve either a variant or a datavalue variable, but it seems to accept more the Datavalue as in Set_Value, therefore its better to send it this way. Refer to uatypes.py for more information regarding variant types. the Timestamp also on uatypes.py has to be set to 0 or none. https://github.com/FreeOpcUa/python-opcua/issues/9 """ child = self.root.get_child(self.variables_location + \ [self.devices[str(device)]]) if isinstance(value, float): dv = ua.DataValue(ua.Variant(float(value), ua.VariantType.Float)) elif isinstance(value, bool): dv = ua.DataValue(ua.Variant(bool(value), ua.VariantType.Boolean)) else: print( 'At the moment Bool and Float variant types are accepted, for adding' 'an extra type please refer to microkwkkcom.py document') child.set_value(dv) value = child.get_value() return {device: value} def get_value(self, device=""): """ Retrieve the value from the listed device contained on the dictionary """ child = self.root.get_child(self.variables_location + \ [self.devices[str(device)]]) value = child.get_value() return {device: value} def get_all_values(self): """ Retrieve the value from the listed device contained on the dictionary """ values = {} for device in self.devices: values.update(self.get_value(device=device)) return values
class OPCUAServer(object): """ Each instance of this class manages a connection to its own OPC UA server. Methods are called to get node data from the server. """ def __init__(self, name, endPointAddress, nameSpaceUri=None, browseRootNodeIdentifier=None): # ---------- Setup ----------- self.name = name self.logger = logging.getLogger(self.name) self.endPointAddress = endPointAddress self.nameSpaceUri = nameSpaceUri self.nameSpaceIndex = None self.browseRootNodeIdentifier = browseRootNodeIdentifier self.rootNodeId = None self.client = Client(self.endPointAddress, timeout=2) self.sub = None self.subscriptions = {} # ---------------------------- def check_connection(self): """ Check if a connection has been established before or if connection thread is running. If either fails, try to (re)connect. """ if self.client.uaclient._uasocket is None: self.connect() elif self.client.uaclient._uasocket._thread is None: self.connect() elif not self.client.uaclient._uasocket._thread.is_alive(): self.connect() def connect(self): """ Connect to OPC UA server. If fails clean up session and socket, and raise exception. """ try: self.logger.info("Connecting to " + self.name + ".") self.client.connect() self.update_namespace_and_root_node_id() except socket.timeout: self.logger.info(self.name + " socket timed out.") try: self.logger.info("Cleaning up session and socket.") self.client.uaclient.disconnect() except AttributeError: pass self.logger.info("Socket and session cleaned up.") raise TimeoutError(self.name + " timed out.") def update_namespace_and_root_node_id(self): """ Update rootNodeId and nameSpaceIndex. If no namespace given, sets root node (id: i=84) as root node. """ if self.nameSpaceUri and self.browseRootNodeIdentifier: nsArray = self.client.get_namespace_array() index = nsArray.index(self.nameSpaceUri) if index > 0: nodeId = "ns={};".format(index) + self.browseRootNodeIdentifier else: nodeId = self.browseRootNodeIdentifier else: nodeId = "i=84" index = None self.rootNodeId = nodeId self.nameSpaceIndex = index return def get_node_path(self, nodeId): """ Create node path from node id for current server settings. Attempts to create a path of node from rootNode. Only works for folderly like string node ids. Example: "ns=2;s=node1.node2.node3.node4" """ identifierType = self.rootNodeId.split(";")[-1].split("=")[0] if (identifierType == "s") and ("." in self.rootNodeId): rootNodeName = self.rootNodeId.lower().split(".")[-1] nodePath = nodeId.lower().split(rootNodeName)[-1] nodePath = nodePath.replace(".", "", 1).replace(".", "/") else: nodePath = nodeId.split("=")[-1] return nodePath def get_node(self, nodeId=""): """ Returns node from nodeId or identifier. If no namespace given in nodeId, assumes the namespace to namespace given for the server in settings.py. Only the ns set for the server in servers.json is accessible via browsing. """ self.check_connection() if nodeId == "": nodeId = self.rootNodeId elif self.nameSpaceIndex is None: nodeId = nodeId elif nodeId[:3] == "ns=": identifier = nodeId.split(";")[-1] if self.nameSpaceIndex == 0: nodeId = identifier else: nodeId = f"ns={self.nameSpaceIndex};{identifier}" else: nodeId = f"ns={self.nameSpaceIndex};{nodeId}" return self.client.get_node(nodeId) async def get_variable_nodes(self, node, nodeClass=2, variableList=None, depth=0, maxDepth=10): """ Eats a list of node object(s). Recursively finds nodes under given nodes that have given nodeClass. Returns node objects in a list. """ if variableList is None: variableList = [] depth += 1 if depth >= maxDepth: return variableList nodes = node.get_children() params = ua.ReadParameters() for node in nodes: rv = ua.ReadValueId() rv.NodeId = node.nodeid rv.AttributeId = ua.AttributeIds.NodeClass params.NodesToRead.append(rv) results = [] if len(params.NodesToRead) > 0: results, readTime = await self.read(params) for i in range(len(results)): if nodeClass == results[i].Value.Value: variableList.append(nodes[i]) await self.get_variable_nodes(node=nodes[i], nodeClass=nodeClass, variableList=variableList, depth=depth) return variableList def subscribe_variable(self, nodeId): if self.sub is None: handler = self self.sub = self.client.create_subscription(100, handler) node = self.get_node(nodeId) if 2 == node.get_attribute(ua.AttributeIds.NodeClass).Value.Value: return self.sub.subscribe_data_change(node) else: return None def datachange_notification(self, node, value, data): self.subscriptions[node.nodeid.to_string()] = data.monitored_item.Value async def read_node_attribute(self, nodeId, attribute): """ Read node attribute based on given arguments. Giving correct dataType for value and node speeds up the write operation. Arguments Example nodeId: Target nodeId "ns=2;i=2" attribute: Target attribute of node "Value" Results OPCUAVar: OPC UA variable object <object> readTime: Time taken for read (ns) 12345678 """ rv = ua.ReadValueId() if nodeId == "": rv.NodeId = ua.NodeId.from_string(server.rootNodeId) else: rv.NodeId = ua.NodeId.from_string(nodeId) rv.AttributeId = ua.AttributeIds[attribute] params = ua.ReadParameters() params.NodesToRead.append(rv) result, readTime = await self.read(params) if attribute == "Value": return result[0], readTime else: return result[0] async def set_node_attribute(self, nodeId, attribute, value, dataType=None): """ Sets node attribute based on given arguments. Giving correct dataType for value and node speeds up the write operation. Arguments Example nodeId: Target nodeId "ns=2;i=2" attribute: Target attribute of node "Value" value: Value for the attribute 1234 dataType: Data type of value "Int32" Results boolean: Indicates success True writeTime: Time taken for write (ns) 12345678 """ attr = ua.WriteValue() if nodeId == "": attr.NodeId = ua.NodeId.from_string(self.rootNodeId) else: attr.NodeId = ua.NodeId.from_string(nodeId) attr.AttributeId = ua.AttributeIds[attribute] if attribute == "Description": dataValue = ua.LocalizedText(value) else: if dataType is None: variantType = self.variant_type_finder(value, nodeId) else: variantType = ua.VariantType[dataType] dataValue = ua.Variant(value, variantType) attr.Value = ua.DataValue(dataValue) params = ua.WriteParameters() params.NodesToWrite.append(attr) result, writeTime = await self.write(params) if attribute == "Value": return result[0].is_good(), writeTime else: return result[0].is_good() def add_node(self, name, nodeId, parentId, value=None, writable=True): """ Adds a node to OPC UA server. If value given, adds a variable node, else, a folder node. Requires server admin powers in server servers.json, for example endPointAddress: "opc.tcp://[email protected]:4840/freeopcua/server/". """ self.check_connection() if self.nameSpaceIndex is not None: index = self.nameSpaceIndex elif nodeId[:3] == "ns=": index = nodeId.split("=")[1][0] else: index = 0 browseName = f"{index}:{name}" parentNode = self.get_node(parentId) if value is None: node = parentNode.add_folder(nodeId, browseName) result = { "name": node.get_display_name().to_string(), "nodeId": node.nodeid.to_string(), } else: node = parentNode.add_variable(nodeId, browseName, value) attribute = node.get_attribute(ua.AttributeIds.Value) result = { "name": node.get_display_name().to_string(), "nodeId": node.nodeid.to_string(), "value": attribute.Value.Value, "dataType": attribute.Value.VariantType.name, "sourceTimestamp": attribute.SourceTimestamp, "statusCode": attribute.StatusCode.name } if writable is True: node.set_writable() return result def delete_node(self, nodeId, recursive=True): """ Recursively deletes node and it's subnodes unless recursive=False. Requires admins. Doesn't raise errors if deleting is unsuccessful. """ self.check_connection() node = self.get_node(nodeId) result = self.client.delete_nodes([node], recursive) result[1][0].check() return result[1][0].is_good() async def read(self, params): """ Reads from OPC UA server params == ua.ReadParameters() that are properly set up. Returns result object and time it took to read from OPC UA server. """ self.check_connection() start = time.time_ns() result = self.client.uaclient.read(params) readTime = time.time_ns() - start return result, readTime async def write(self, params): """ Writes to OPC UA server params == ua.WriteParameters() that are properly set up. Returns result object and time it took to read from OPC UA server. """ self.check_connection() start = time.time_ns() result = self.client.uaclient.write(params) writeTime = time.time_ns() - start return result, writeTime def variant_type_finder(self, value, nodeId): """ Attempts to find variant type of given value. If not found, retrieves variant type of node from OPC UA server. """ valueType = type(value) if isinstance(valueType, datetime.datetime): variantType = ua.uatypes.VariantType.DateTime elif valueType == bool: variantType = ua.uatypes.VariantType.Boolean elif valueType == str: variantType = ua.uatypes.VariantType.String elif valueType == int or valueType == float: node = self.get_node(nodeId) self.check_connection() variantType = node.get_data_type_as_variant_type() else: raise ValueError("Unsupported datatype") return variantType
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
def uacall(): parser = argparse.ArgumentParser(description="Call method of a node") add_common_args(parser) parser.add_argument( "-m", "--method", dest="method", type=int, default=None, help= "Set method to call. If not given then (single) method of the selected node is used." ) parser.add_argument("-M", "--method-name", dest="method_name", type=str, default=None, help="Set name of method to call. Overrides --method") parser.add_argument("-l", "--list", "--array", dest="array", default="guess", choices=["guess", "true", "false"], help="Value is an array") parser.add_argument("-t", "--datatype", dest="datatype", default="guess", choices=[ "guess", 'byte', 'sbyte', 'nodeid', 'expandednodeid', 'qualifiedname', 'browsename', 'string', 'float', 'double', 'int16', 'int32', "int64", 'uint16', 'uint32', 'uint64', "bool", "string", 'datetime', 'bytestring', 'xmlelement', 'statuscode', 'localizedtext' ], help="Data type to return") parser.add_argument("value", help="Value to use for call to method, if any", nargs="?", metavar="VALUE") args = parse_args(parser, requirenodeid=True) client = Client(args.url, timeout=args.timeout) _configure_client_with_args(client, args) client.connect() try: node = get_node(client, args) # val must be a tuple in order to enable method calls without arguments if (args.value is None): val = () #empty tuple else: val = (_val_to_variant(args.value, args), ) # tuple with one element # determine method to call: Either explicitly given or automatically select the method of the selected node. methods = node.get_methods() method_id = None #print( "methods=%s" % (methods) ) if (args.method_name is not None): method_id = args.method_name elif (args.method is None): if (len(methods) == 0): raise ValueError( "No methods in selected node and no method given") elif (len(methods) == 1): method_id = methods[0] else: raise ValueError( "Selected node has {0:d} methods but no method given. Provide one of {1!s}" .format(*(methods))) else: for m in methods: if (m.nodeid.Identifier == args.method): method_id = m.nodeid break if (method_id is None): # last resort: method_id = ua.NodeId( identifier=args.method) #, namespaceidx=? )#, nodeidtype=?): ) #print( "method_id=%s\nval=%s" % (method_id,val) ) result_variants = node.call_method(method_id, *val) print("resulting result_variants={0!s}".format(result_variants)) finally: client.disconnect() sys.exit(0) print(args)
def datachange_notification(self, node, val, data): try: logger.debug( "handler: New data change event on fhs server: NewValAvailable=%s", val) # GET SOME VALUES FROM THIS SERVER logger.debug("handler: connecting to DTZ master Server") this_client = Client("opc.tcp://0.0.0.0:4840/freeopcua/server") this_client.connect() this_client_root = this_client.get_root_node() self.demonstrator_busy = this_client_root.get_child( ["0:Objects", "2:DTZMasterController", "2:DemonstratorBusy"]) # GET SOME VALUES FROM FHS SERVER logger.debug("handler: connecting to FHS Server") # handler_client_fhs = Client(global_url_pseudo_fhs_server) # Testing with pseudo FH server handler_client_fhs = Client(global_url_fhs_server) # Original handler_client_fhs.connect() handler_root_fhs = handler_client_fhs.get_root_node() # handler_desired_shelf = handler_client_fhs.get_node("ns=2;i=3") # Testing with pseudo FH server handler_desired_shelf = handler_client_fhs.get_node( "ns=6;s=::AsGlobalPV:ShelfNumber") # Original # GET VALUES FROM PANDA SERVER logger.debug("handler: connecting to Panda Server") handler_client_panda = Client(global_url_panda_server) handler_client_panda.connect() handler_root_panda = handler_client_panda.get_root_node() self.handler_panda_moving = handler_root_panda.get_child( ["0:Objects", "2:PandaRobot", "2:RobotMoving"]) # GET VALUES FROM PIXTEND SERVER logger.debug("handler: connecting to Pixtend Server") handler_client_pixtend = Client(global_url_pixtend_server) handler_client_pixtend.connect() handler_root_pixtend = handler_client_pixtend.get_root_node() self.handler_belt_moving = handler_root_pixtend.get_child( ["0:Objects", "2:ConveyorBelt", "2:ConBeltMoving"]) # data = NewValueAvailable demoBusy = self.demonstrator_busy.get_value() exit = "NewValAvailable is {}, demonstratorBusy is {}".format( val, demoBusy) if val is True and demoBusy is False: logger.debug("handler: global_demonstrator_busy: " + str(demoBusy) + ". NewValAvailable: " + str(val) + ". ShelfNumber: " + str(handler_desired_shelf.get_value()) + ".") ############# LOAD STORAGE DATA ############# # [1][2][3] # [4][5][6] # [7][8][9] with open("./dtz_storage", "r", encoding="utf-8") as in_file: for in_line in in_file: self.storage.append(in_line) # IS THE STORAGE EMPTY? self.storage[handler_desired_shelf.get_value() - 1] = "1" #if self.storage[handler_desired_shelf.get_value() - 1] is "0": # commented because of problems with demonstrator if False: exit = "Shelf empty - error!" else: self.demonstrator_busy.set_value(True) # METHOD CALLS move_panda_thread = threading.Thread( name='move_panda_thread', target=self.move_robot_core, args=( "SO", handler_desired_shelf.get_value(), )) move_panda_thread.daemon = True move_panda_thread.start() move_panda_thread.join() # logger.debug("p_moved %s", self.panda_moved) if self.panda_moved is True: move_belt_thread = threading.Thread( name='move_belt_thread', target=self.move_belt_core, args=( "left", 0.55, )) move_belt_thread.daemon = True move_belt_thread.start() self.storage[handler_desired_shelf.get_value() - 1] = "0" move_belt_thread.join() if not self.belt_moved: logger.debug("Error - Belt not moved") exit = "Error - Belt not moved" else: logger.debug("Error - Panda not moved") exit = "Error - Panda not moved" ############# SAVE STORAGE DATA ############# # [1][2][3] # [4][5][6] # [7][8][9] with open("./dtz_storage", "w", encoding="utf-8") as out_file: for out_line in self.storage: out_file.write(str(out_line)) logger.debug("handler: disconnect from fhs server") handler_client_fhs.disconnect() logger.debug("handler: disconnect from panda server") handler_client_panda.disconnect() logger.debug("handler: disconnect from pixtend server") handler_client_pixtend.disconnect() this_client.disconnect() except Exception as e: logger.debug("handler: Catched Exception: " + str(e)) try: logger.debug( "handler: trying to disconnect from pixtend server") handler_client_pixtend.disconnect() except: logger.debug("handler: pixtend server was disconnected") pass try: logger.debug("handler: trying to disconnect from panda server") handler_client_panda.disconnect() except: logger.debug("handler: panda server was disconnected") pass try: logger.debug("handler: trying to disconnect from fhs server") handler_client_fhs.disconnect() except: logger.debug("handler: fhs server was disconnected") pass return "handler: Error: " + str(e) logger.debug( "handler: exiting datachange_notification. return message: %s", exit) return exit
#!usr/bin/env python #-*- coding:utf-8 _*- """ @author:zengguang @file: client2.py @time: 2021/2/1 14:05 """ from opcua import Client, ua url = "opc.tcp://127.0.0.1:12345/" # url = "opc.tcp://127.0.0.1:12346/test" c = Client(url) try: c.connect() # root = c.find_servers() root = c.get_node('ns=2;i=11').get_value() print(root) # print("\r\nBrower:") # brower_child2(root.get_child(["0:Objects"]), -1, ["Server"]) except Exception as e: print("Client Exception:", e) finally: c.disconnect()
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() 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['methods'][content["device"]]: 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: if re.search(int_node.split('\\.')[recursion_level-2], ch.get_display_name().Text): self.__search_name(ch, recursion_level+1) 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) device_name_node = re.search(name_pattern.split('.')[-1], current_var_path) if device_name_node is not None: device_name = ch.get_value() full_device_name = interest_node[int_node]["deviceNamePattern"].replace("${"+name_pattern+"}", device_name) 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) except Exception as e: log.exception(e) 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: if re.search(int_node.split('\\.')[recursion_level-2], 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) 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) if re.search(int_node.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) if ch.get_display_name().Text == target: 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} 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 PubSubServer: def __init__(self, uri, nid_configuration, nid_start_stop, nid_status): self.uri = uri self.client = Client(self.uri) self.client.application_uri = "urn:S2OPC:localhost" self.nid_configuration = nid_configuration self.nid_start_stop = nid_start_stop self.nid_status = nid_status # Connect to the Pub/Sub server. Shall be called before other methods def connect(self): self.client.connect() print('Connected') self.nodeConfiguration =self.client.get_node(self.nid_configuration) self.nodeStartStop = self.client.get_node(self.nid_start_stop) self.nodeStatus = self.client.get_node(self.nid_status) # Is connected to Pub/Sub server def isConnected(self): try: self.nodeStatus.get_value() return True except: return False # Disconnect to the Pub/Sub server def disconnect(self): self.client.disconnect() print('Disconnected') def __setStartStop(self, value): try: # Set value and wait until value changes or timeout expires self.nodeStartStop.set_value(ua.Variant(value, ua.VariantType.Byte)) status = 2 if value else 0 timeout = PUBSUBSERVER_TIMEOUT_MAX while self.getStatus() != status and timeout > 0: sleep(PUBSUBSERVER_TIMEOUT_STEP) timeout = timeout - PUBSUBSERVER_TIMEOUT_STEP except e: print('Client not connected to PubSubServer') # Is Pub/Sub module started def isStart(self): try: return bool(self.nodeStartStop.get_value()) except: print('Client not connected to PubSubServer') return False # Start the Pub/Sub module # Wait until status changes or timeout expires def start(self): self.__setStartStop(1) # Stop the Pub/Sub module # Wait until status changes or timeout expires def stop(self): self.__setStartStop(0) # Get the Pub/Sub module status: # - 0 : not running # - 2 : is running def getStatus(self): try: return self.nodeStatus.get_value() except: print('Client not connected to PubSubServer') return 0 # Set the Pub/Sub module configuration # Value is a XML in a string def setConfiguration(self, value): try: self.nodeConfiguration.set_value(ua.Variant(value, ua.VariantType.String)) except: print('Client not connected to PubSubServer') # Get the Pub/Sub module configuration as XML string def getConfiguration(self): try: return self.nodeConfiguration.get_value() except: print('Client not connected to PubSubServer') return None # Get value. Nid is a string def getValue(self, nid): node = self.client.get_node(nid) return node.get_value() # Set value. # - nid is a string. # - varianttype is a builtintype from ua package # - value type depends of varianttype def setValue(self, nid, varianttype, value): node = self.client.get_node(nid) node.set_value(value=value, varianttype=varianttype)
from opcua import Client from opcua import ua # client = Client("opc.tcp://10.19.3.49:49320/AGVkanban.fx3u") # try: # client.connect() # # except OSError as e: # print(e) # # print(client.get_node("ns=2;s=AGVkanban.fx3u." + "7号车当前动作指令").get_value()) client1 = Client("opc.tcp://127.0.0.1:49320") client1.connect() client1.disconnect() try: client1.disconnect() except Exception as e: pass client1.connect() nodeId = {} nodeId[1] = 'ns=2;s=shougonghanjieAGVbaojing.FX3U.shougonghanjieAGV' # 好像拼音写错了 nodeId[2] = 'ns=2;s=jiaobizhuanxiangAGVbaojing.FX3U.jiaobizhuangxiangAGV' # 好像和 新萨瓦尼尼 1 2 颠倒了 nodeId[3] = 'ns=2;s=sawanini1houdaoAGVbaojing.FX3U.sawanini1houdaoAGV' nodeId[4] = 'ns=2;s=houbanAGVbaojing.FX3U.houbanAGV'
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": self.__set_auth_settings_by_cert() if self.__server_conf["identity"].get("username"): self.__set_auth_settings_by_username() 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(.2) 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) if self.__server_conf["identity"].get("type") == "cert.PEM": self.__set_auth_settings_by_cert() if self.__server_conf["identity"].get("username"): self.__set_auth_settings_by_username() self._subscribed = {} self.__available_object_resources = {} time.sleep(10) def __set_auth_settings_by_cert(self): 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) def __set_auth_settings_by_username(self): 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")) 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") # firstly check if a method is not service if rpc_method == 'set' or rpc_method == 'get': full_path = '' args_list = [] try: args_list = content['data']['params'].split(';') if 'ns' in content['data']['params']: full_path = ';'.join([ item for item in (args_list[0:-1] if rpc_method == 'set' else args_list) ]) else: full_path = args_list[0].split('=')[-1] except IndexError: log.error('Not enough arguments. Expected min 2.') self.__gateway.send_rpc_reply( content['device'], content['data']['id'], { content['data']['method']: 'Not enough arguments. Expected min 2.', 'code': 400 }) node_list = [] self.__search_node(current_node=content['device'], fullpath=full_path, result=node_list) node = None try: node = node_list[0] except IndexError: self.__gateway.send_rpc_reply( content['device'], content['data']['id'], { content['data']['method']: 'Node didn\'t find!', 'code': 500 }) if rpc_method == 'get': self.__gateway.send_rpc_reply( content['device'], content['data']['id'], { content['data']['method']: node.get_value(), 'code': 200 }) else: try: value = args_list[2].split('=')[-1] node.set_value(value) self.__gateway.send_rpc_reply(content['device'], content['data']['id'], { 'success': 'true', 'code': 200 }) except ValueError: log.error('Method SET take three arguments!') self.__gateway.send_rpc_reply( content['device'], content['data']['id'], { 'error': 'Method SET take three arguments!', 'code': 400 }) except ua.UaStatusCodeError: log.error('Write method doesn\'t allow!') self.__gateway.send_rpc_reply( content['device'], content['data']['id'], { 'error': 'Write method doesn\'t allow!', 'code': 400 }) 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: if self.get_node_path( attribute_node) == attribute_path: 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) if len(device_name_node) == 0: log.warn( "Device name node - not found, skipping device..." ) continue 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 @cached(cache=TTLCache(maxsize=1000, ttl=10 * 60)) def get_node_path(self, node: Node): return '\\.'.join(node.get_browse_name().Name for node in node.get_path(200000)) 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
def run(): logger.info("Modular Input mi_opcua 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 Starts data collection.") configs = get_config() stanza = configs["name"] patterns = configs["measures"].split(":") tout = configs["connection_timeout"].strip() spec = configs.get("metrics_spec", "n.a.").strip() timeout = 1 if len(tout) <= 0 else int(tout) 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) mi.init_stream(sys.stdout) try: logger.info("Start connecting OPC Server [%s]." % conn) client.connect() logger.info("OPC Server [%s] is connected." % conn) measures = [] root = client.get_root_node() node.collect_measures(measures, patterns, root) md = {} try: jm = os.path.join(ua.data_dir(), spec) with open(jm, 'r') as mfp: md = json.load(mfp) mfp.close() except: pass for m in measures: collect_data(stanza, m[len(m) - 1], spec=md) except Exception as ex: logger.critical(ex) finally: mi.fini_stream(sys.stdout) logger.info("---- end of opc ua ----") client.disconnect()
#!/usr/bin/env python3 import time import datetime from opcua import Client remoteIO1url = "opc.tcp://*****:*****@192.168.0.51:4840" remoteIO2url = "opc.tcp://*****:*****@192.168.0.52:4840" remoteIO1 = Client(remoteIO1url) remoteIO2 = Client(remoteIO2url) remoteIO1.connect() remoteIO2.connect() print("Client Connected") orders = 2 # Define the process values IO1input1value = False # Punching machine IO1input2value = False IO1output1value = False IO1output2value = False IO2input1value = False # Conveyor belt IO2input2value = False IO2output1value = False IO2output2value = False # Define the OPC-UA nodes IO1input1 = remoteIO1.get_node("ns=1;s=Read Input 1.") IO1input2 = remoteIO1.get_node("ns=1;s=Read Input 2.") IO1output1 = remoteIO1.get_node("ns=1;s=Control Output 1.")
class OpcUaClient(object): CONNECT_TIMEOUT = 15 # [sec] RETRY_DELAY = 10 # [sec] MAX_RETRIES = 3 # [-] class Decorators(object): @staticmethod def autoConnectingClient(wrappedMethod): def wrapper(obj, *args, **kwargs): for retry in range(OpcUaClient.MAX_RETRIES): try: return wrappedMethod(obj, *args, **kwargs) except ua.uaerrors.BadNoMatch: raise except Exception: pass try: obj._logger.warn('(Re)connecting to OPC-UA service.') obj.reconnect() except ConnectionRefusedError: obj._logger.warn( 'Connection refused. Retry in 10s.'.format( OpcUaClient.RETRY_DELAY)) time.sleep(OpcUaClient.RETRY_DELAY) else: # So the exception is exposed. obj.reconnect() return wrappedMethod(obj, *args, **kwargs) return wrapper def __init__(self, serverUrl): self._logger = logging.getLogger(self.__class__.__name__) self._client = Client(serverUrl.geturl(), timeout=self.CONNECT_TIMEOUT) def __enter__(self): self.connect() return self def __exit__(self, exc_type, exc_value, traceback): self.disconnect() self._client = None @property @Decorators.autoConnectingClient def sensorList(self): return self.objectsNode.get_children() @property @Decorators.autoConnectingClient def objectsNode(self): path = [ua.QualifiedName(name='Objects', namespaceidx=0)] return self._client.get_root_node().get_child(path) def connect(self): self._client.connect() self._client.load_type_definitions() def disconnect(self): try: self._client.disconnect() except Exception: pass def reconnect(self): self.disconnect() self.connect() @Decorators.autoConnectingClient def get_browse_name(self, uaNode): return uaNode.get_browse_name() @Decorators.autoConnectingClient def get_node_class(self, uaNode): return uaNode.get_node_class() @Decorators.autoConnectingClient def get_child(self, uaNode, path): return uaNode.get_child(path) @Decorators.autoConnectingClient def read_raw_history(self, uaNode, starttime=None, endtime=None, numvalues=0, cont=None): details = ua.ReadRawModifiedDetails() details.IsReadModified = False details.StartTime = starttime or ua.get_win_epoch() details.EndTime = endtime or ua.get_win_epoch() details.NumValuesPerNode = numvalues details.ReturnBounds = True result = OpcUaClient._history_read(uaNode, details, cont) assert (result.StatusCode.is_good()) return result.HistoryData.DataValues, result.ContinuationPoint @staticmethod def _history_read(uaNode, details, cont): valueid = ua.HistoryReadValueId() valueid.NodeId = uaNode.nodeid valueid.IndexRange = '' valueid.ContinuationPoint = cont params = ua.HistoryReadParameters() params.HistoryReadDetails = details params.TimestampsToReturn = ua.TimestampsToReturn.Both params.ReleaseContinuationPoints = False params.NodesToRead.append(valueid) result = uaNode.server.history_read(params)[0] return result
elevator_opc_info = { 'ep_url': "opc.tcp://IntersectWinPC:4840/elevator/pid/", 'uri': "http://thaintersect.com", } nx_server_info = { "ep_url": "opc.tcp://localhost:4940/nx/pid/", "name": "Elevator_OPC_to_NX", "uri": "localhost" } if __name__ == "__main__": Elevator_client = Client(elevator_opc_info['ep_url']) try: Elevator_client.connect() except Exception as identifier: print("Failed to connect to the OPC Server") print(identifier) else: print("Conected to: ", elevator_opc_info['ep_url']) # Elevator_client.load_type_definitions() disp_c = Elevator_client.get_node("ns=2;i=3") aspd_c = Elevator_client.get_node("ns=2;i=4") lspd_c = Elevator_client.get_node("ns=2;i=5") up_c = Elevator_client.get_node("ns=2;i=7") nx_server = Server() nx_server.set_endpoint(nx_server_info['ep_url']) nx_server.set_server_name(nx_server_info['name'])
""" def data_change(self, handle, node, val, attr): print("Python: New data change event", handle, node, val, attr) def event(self, handle, event): print("Python: New event", handle, event) if __name__ == "__main__": #from IPython import embed logging.basicConfig(level=logging.WARN) client = Client("opc.tcp://*****:*****@localhost:53530/OPCUA/SimulationServer/") try: client.connect() root = client.get_root_node() print("Root is", root) print("childs of root are: ", root.get_children()) print("name of root is", root.get_browse_name()) objects = client.get_objects_node() print("childs og objects are: ", objects.get_children()) 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)
'--path', type=str, help='path for storing tool data. Default is in ./tools', default="./tools") args = parser.parse_args() if args.verbose: logger.setLevel(level=logging.DEBUG) try: url = re.sub(r"\/\/", "//" + args.opcua_user + ":" + args.opcua_password + "@", args.opcua_connection) opcua_client = Client(url) #connect using a user opcua_client.connect() logger.info('Successfully connceted to OPC UA server: %s', [args.opcua_connection]) except Exception as e: logger.error('Failed connecting to OPC UA server: %s', [args.opcua_connection]) logger.debug(traceback.format_exc()) sys.exit(str(e)) try: #get max number of tools TnumWZV = opcua_client.get_node(ua.NodeId("/Tool/Catalogue/TnumWZV", 2)).get_value() logger.info('Number of available tools: {}'.format(TnumWZV)) numCuttEdgeParams = args.numCuttEdgeParams