def start(): mServer = Server() mServer.set_endpoint(URL) mServer.set_security_policy([ ua.SecurityPolicyType.NoSecurity, ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt, ua.SecurityPolicyType.Basic256Sha256_Sign ]) address_space = mServer.register_namespace(NAMESPACE_NAME) root_node = mServer.get_objects_node() params = root_node.add_object(address_space, "Parameters") start_time = params.add_variable(address_space, "start_time", start_timestamp) data = root_node.add_object(address_space, "data") pump = data.add_object(address_space, "Pump") temperature = 20 + random.randint(0, 10) pump_temp_var = pump.add_variable(address_space, "temperature", temperature) pump_temp_vup = VarUpdater( pump_temp_var) # just a dummy class update a variable pump_temp_unit = pump.add_variable(address_space, "unit", "°C") pump_status = pump.add_variable(address_space, "status", False) pump_status.set_writable() level = 12 pump_level = pump.add_variable(address_space, "level", level) pump_level.set_writable() sleep_period = 0.5 # Start the server mServer.start() print("Server started at {}".format(URL)) print("root_node: " + root_node.__str__()) print("params: " + params.__str__()) print("pump: " + pump.__str__()) # print(""+pump) # enable following if you want to subscribe to nodes on server side handler = SubHandler() sub = mServer.create_subscription(500, handler) handle = sub.subscribe_data_change(pump_level) # IMPORTANT: This should be started after the mServer.start() pump_temp_vup.start() try: while True: time.sleep(sleep_period) finally: # close connection, remove subscriptions, etc pump_temp_vup.stop() # should be stopped mServer.stop()
sinGen = myobj.add_variable(idx, "SineGenerator", 0.0) print("Led_R: ", ledR) print("Led_G: ", ledG) print("Led_B: ", ledB) print("Switch_1: ", switch1) print("Switch_2: ", switch2) print("Rotary: ", rotaryVal) print("Range: ", rangeVal) print("Flame: ", flameVal) print("SineGenerator: ", sinGen) # starting! server.start() sub = server.create_subscription(50, SubHandler()) sub.subscribe_data_change(ledR) sub.subscribe_data_change(ledG) sub.subscribe_data_change(ledB) try: count = 0 while True: sleep(0.1) count += 0.1 sinGen.set_value(math.sin(count)) rangeVal.set_value(get_range_val()) finally: server.stop()
myobj = objects.add_object(idx, "NewObject") myvar = myobj.add_variable(idx, "MyVariable", 6.7) myarrayvar = myobj.add_variable(idx, "myarrayvar", [6.7, 7.9]) myprop = myobj.add_property(idx, "myproperty", "I am a property") mymethod = myobj.add_method(idx, "mymethod", func, [ua.VariantType.Int64], [ua.VariantType.Boolean]) multiply_node = myobj.add_method( idx, "multiply", multiply, [ua.VariantType.Int64, ua.VariantType.Int64], [ua.VariantType.Int64]) # creating an event object # The event object automatically will have members for all events properties myevent = server.get_event_object(ObjectIds.BaseEventType) myevent.Message.Text = "This is my event" myevent.Severity = 300 # starting! server.start() print("Available loggers are: ", logging.Logger.manager.loggerDict.keys()) try: handler = SubHandler() # enable following if you want to subscribe to nodes on server side sub = server.create_subscription(500, handler) handle = sub.subscribe_data_change(myvar) # trigger event, all subscribed clients wil receive it myevent.trigger() embed() finally: server.stop()
class StationUAServer: def __init__(self, pick_by_light): self._pbl = pick_by_light self._setup_nodes() self._generate_tags() self.ua_server.start() self._generate_subscriptions() Thread(target=self._var_updater, daemon=True).start() def _setup_nodes(self): # Create server instance self.ua_server = Server('./opcua_cache') self.ua_server.set_endpoint('opc.tcp://0.0.0.0:4840/UA/PickByLight') self.ua_server.set_server_name("Pick By Light Server") # idx name will be used later for creating the xml used in data type dictionary # setup our own namespace, not really necessary but should as spec idx_name = 'http://examples.freeopcua.github.io' self.idx = self.ua_server.register_namespace(idx_name) # Set all possible endpoint policies for clients to connect through self.ua_server.set_security_policy([ ua.SecurityPolicyType.NoSecurity, ua.SecurityPolicyType.Basic128Rsa15_SignAndEncrypt, ua.SecurityPolicyType.Basic128Rsa15_Sign, ua.SecurityPolicyType.Basic256_SignAndEncrypt, ua.SecurityPolicyType.Basic256_Sign ]) # get Objects node, this is where we should put our custom stuff objects = self.ua_server.get_objects_node() # Create objects for the pack tags using the above created packMLBasedObjectType self.Status = objects.add_folder('ns=2;s=Status', "Status") self.Command = objects.add_folder('ns=2;s=Command', "Command") self.Command.add_method('ns=2;s=Command.SelectPort', "SelectPort", self._select_method, [ua.VariantType.Int32, ua.VariantType.String], [ua.VariantType.Boolean]) self.Command.add_method('ns=2;s=Command.DeselectPort', "DeselectPort", self._deselect_method, [ua.VariantType.Int32], [ua.VariantType.Boolean]) self.Command.add_method('ns=2;s=Command.DeselectAllPorts', "DeselectAllPorts", self._deselect_all_method, [], [ua.VariantType.Boolean]) root = self.ua_server.get_root_node() DummyFestoObj = root.add_object( "ns=2;s=|var|CECC-LK.Application.Flexstation_globalVariables", "DummyFesto") DummyFestoObj.add_variable( "ns=2;s=|var|CECC-LK.Application.Flexstation_globalVariables.FlexStationStatus", "FlexStationStatus", val=0).set_writable() DummyFestoObj.add_variable( "ns=2;s=|var|CECC-LK.Application.FBs.stpStopper1.stAppControl.uiOpNo", "uiOpNo", val=0).set_writable() DummyFestoObj.add_variable( "ns=2;s=ns=2;s=|var|CECC-LK.Application.AppModul.stRcvData.sOderDes", "sOderDes", val="").set_writable() def _generate_tags(self): # for all ports generate tags for port_number, port in self._pbl.get_ports(): # Make a folder with the port_number as the name b_obj = self.Status.add_object( 'ns=2;s=Status.Port_{}'.format(port_number), "Port_{}".format(port_number)) content = self._pbl.get_content(port_number) b_obj.add_variable( "ns=2;s=Status.Port_{}.Selected".format(port_number), "Selected", bool()) b_obj.add_variable( "ns=2;s=Status.Port_{}.WorkFinished".format(port_number), "WorkFinished", bool()) b_obj.add_variable( "ns=2;s=Status.Port_{}.Instructions".format(port_number), "Instructions", "") b_obj.add_variable( "ns=2;s=Status.Port_{}.Activity".format(port_number), "Activity", bool()) b_obj.add_variable( "ns=2;s=Status.Port_{}.ActivityTimestamp".format(port_number), "ActivityTimestamp", datetime.fromtimestamp(0)) b_obj.add_variable( "ns=2;s=Status.Port_{}.LightState".format(port_number), "LightState", 0) b_obj.add_variable( "ns=2;s=Status.Port_{}.ContentDisplayName".format(port_number), "ContentDisplayName", content['display_name']) b_obj.add_variable( "ns=2;s=Status.Port_{}.ContentName".format(port_number), "ContentName", content['name']) b_obj.add_variable( "ns=2;s=Status.Port_{}.ContentDescription".format(port_number), "ContentDescription", content['description']) b_obj.add_variable( "ns=2;s=Status.Port_{}.ContentImagePath".format(port_number), "ContentImagePath", content['image_path']) ''' create command tags for clients that does not support ua methods. ''' b_obj = self.Command.add_object( 'ns=2;s=Command.Port_{}'.format(port_number), "Port_{}".format(port_number)) b_obj.add_variable( "ns=2;s=Command.Port_{}.Select".format(port_number), "Select", bool()).set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.Deselect".format(port_number), "Deselect", bool()).set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.Instructions".format(port_number), "Instructions", "").set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.ContentDisplayName".format( port_number), "ContentDisplayName", content['display_name']).set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.ContentName".format(port_number), "ContentName", content['name']).set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.ContentDescription".format( port_number), "ContentDescription", content['description']).set_writable() b_obj.add_variable( "ns=2;s=Command.Port_{}.ContentImagePath".format(port_number), "ContentImagePath", content['image_path']).set_writable() ''' Generate some common commands ''' # Make a folder for the commons b_obj = self.Command.add_object('ns=2;s=Command.ByContent', 'ByContent') b_obj.add_variable("ns=2;s=Command.ByContent.Select", "Select", bool()).set_writable() b_obj.add_variable("ns=2;s=Command.ByContent.Deselect", "Deselect", bool()).set_writable() b_obj.add_variable("ns=2;s=Command.ByContent.Name", "Name", "").set_writable() b_obj.add_variable("ns=2;s=Command.ByContent.Instructions", "Instructions", "").set_writable() b_obj.add_variable("ns=2;s=Command.ByContent.Result", "Result", -1).set_writable() def _generate_subscriptions(self): # Create UA subscriber node for the box. Set self as handler. sub = self.ua_server.create_subscription(100, self) # Subscribe to the Select tag and all the content tags for port_number, port in self._pbl.get_ports(): ac = self.ua_server.get_node( "ns=2;s=Command.Port_{}.Select".format(port_number)) sub.subscribe_data_change(ac) ac = self.ua_server.get_node( "ns=2;s=Command.Port_{}.Deselect".format(port_number)) sub.subscribe_data_change(ac) b = self.ua_server.get_node( "ns=2;s=Command.Port_{}.ContentDisplayName".format( port_number)) sub.subscribe_data_change(b) c = self.ua_server.get_node( "ns=2;s=Command.Port_{}.ContentName".format(port_number)) sub.subscribe_data_change(c) d = self.ua_server.get_node( "ns=2;s=Command.Port_{}.ContentDescription".format( port_number)) sub.subscribe_data_change(d) e = self.ua_server.get_node( "ns=2;s=Command.Port_{}.ContentImagePath".format(port_number)) sub.subscribe_data_change(e) a = self.ua_server.get_node("ns=2;s=Command.ByContent.Select") sub.subscribe_data_change(a) a = self.ua_server.get_node("ns=2;s=Command.ByContent.Deselect") sub.subscribe_data_change(a) a = self.ua_server.get_node("ns=2;s=Command.ByContent.Name") sub.subscribe_data_change(a) a = self.ua_server.get_node( "ns=2;s=Command.ByContent.Instructions") sub.subscribe_data_change(a) def _event_notification(self, event): logger.warning( "Python: New event. No function implemented. {}".format(event)) def _select_method(self, parrent, port_number, instructions): r = self._pbl.select_port(port_number.Value, instructions=instructions.Value) return [ua.Variant(value=r, varianttype=ua.VariantType.Boolean)] def _deselect_method(self, parrent, port_number): r = self._pbl.deselect_port(port_number.Value) return [ua.Variant(value=r, varianttype=ua.VariantType.Boolean)] def _deselect_all_method(self, parrent): r = self._pbl.deselect_all() return [ua.Variant(value=r, varianttype=ua.VariantType.Boolean)] def datachange_notification(self, node, val, data): """UA server callback on data change notifications Arguments: node {Node} -- [description] val {[type]} -- [description] data {[type]} -- [description] """ logger.debug("New data change event. node:{}, value:{}".format( node, val)) # Sorry about these lines of code, but I don't see any nicer way of determining the port number than from # the identifier string. Then splitting it up to isolate the port number. # Example "Status.Port_2.Selected" is split into ['Status', 'Port_2', 'Selected'] then 'Port_2' is split into # ['Port', '2'] and then the '2' is turned into an intiger. path_list = str(node.nodeid.Identifier).split(".") # We can safely assume that the last term is the tag that updated. tag = path_list[-1] # Figure out the port number port_number = None if 'Port' in path_list[1]: port_number = int(path_list[1].split("_")[-1]) """ Switch for each possible tag""" # If the command tag "Select" changes go select that port with the instructions saved in the command tag. if tag == 'Select' and port_number: if val == True: node = self.ua_server.get_node( "ns=2;s=Command.Port_{}.Instructions".format(port_number)) instructions = node.get_value() self._pbl.select_port(port_number, instructions=instructions) # Reset the select flag node = self.ua_server.get_node( "ns=2;s=Command.Port_{}.Select".format(port_number)) node.set_value(False) elif tag == 'Deselect' and port_number: if val == True: self._pbl.deselect_port(port_number, work_finished=True) # Reset the select flag node = self.ua_server.get_node( "ns=2;s=Command.Port_{}.Deselect".format(port_number)) node.set_value(False) elif tag == 'ContentDisplayName' and port_number: self._pbl.set_content_key(port_number, 'display_name', str(val)) elif tag == 'ContentName' and port_number: self._pbl.set_content_key(port_number, 'name', str(val)) elif tag == 'ContentDescription' and port_number: self._pbl.set_content_key(port_number, 'description', str(val)) elif tag == 'ContentImagePath' and port_number: self._pbl.set_content_key(port_number, 'image_path', str(val)) elif tag == 'Select' and 'ByContent' in path_list[1]: if val == True: instructions = self.ua_server.get_node( "ns=2;s=Command.ByContent.Instructions").get_value() name = self.ua_server.get_node( "ns=2;s=Command.ByContent.Name").get_value() _, selected_port = self._pbl.select_content( name=name, instructions=instructions) # Reset the select flag node = self.ua_server.get_node( "ns=2;s=Command.ByContent.Select") node.set_value(False) node = self.ua_server.get_node( "ns=2;s=Command.ByContent.Result") node.set_value(selected_port) elif tag == 'Deselect' and 'ByContent' in path_list[1]: if val == True: name = self.ua_server.get_node( "ns=2;s=Command.ByContent.Name").get_value() self._pbl.deselect_content(name=name, work_finished=True) # Reset the select flag node = self.ua_server.get_node( "ns=2;s=Command.ByContent.Deselect") node.set_value(False) def _var_updater(self): while True: sleep(0.1) # for all boxes update tags for port_number, port in self._pbl.get_ports(): # get the object in the packml status object using our unique idx node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.Activity".format(port_number)) node.set_value(port.activity) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.ActivityTimestamp".format( port_number)) node.set_value(port.activity_timestamp) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.LightState".format(port_number)) node.set_value(port.get_light()) state = self._pbl.get_port_state(port_number) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.Selected".format(port_number)) node.set_value(state.selected) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.WorkFinished".format(port_number)) node.set_value(state.work_finished) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.Instructions".format(port_number)) node.set_value(state.select_instructions) content = self._pbl.get_content(port_number) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.ContentDisplayName".format( port_number)) node.set_value(content['display_name']) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.ContentName".format(port_number)) node.set_value(content['name']) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.ContentDescription".format( port_number)) node.set_value(content['description']) node = self.ua_server.get_node( "ns=2;s=Status.Port_{}.ContentImagePath".format( port_number)) node.set_value(content['image_path'])
class TestServer: lang = "cs" def __init__(self, endpoint, name): parser = argparse.ArgumentParser() parser.add_argument("--start_state", "-s", type=int, default=0) args = parser.parse_args() start_state = args.start_state root_dir = os.path.join(os.path.dirname(__file__), os.path.pardir).replace('\\', '/') print(root_dir) variants_file = os.path.join(root_dir, "utils", "next_states.json").replace('\\', '/') variants_file_desc = os.path.join(root_dir, "utils", "state_description.json").replace( '\\', '/') with open(variants_file, encoding="utf-8") as f: self.state_descriptions = json.load(f, encoding="utf-8")[self.lang] with open(variants_file_desc, encoding="utf-8") as f: self.next_state_description = json.load( f, encoding="utf-8")[self.lang] self.server = Server() # self.server.import_xml(model_filepath) # normally, definition would be loaded here self.server.set_endpoint(endpoint) # specify the endpoint (address) self.server.set_server_name(name) # specify server name (whatever) objects = self.server.get_objects_node( ) # get the object containing entity myobj = objects.add_object(4, "DATA") # create new object horse = myobj.add_object(4, "horse") # create new object self.mic_active = horse.add_variable(4, "request", False) self.mic_active.set_writable() response_string = horse.add_variable(4, "response", "") response_string.set_writable() self.actual_state = horse.add_variable(4, "actual_state", True) self.actual_state_num = self.actual_state.add_variable(4, "number", 0) self.actual_state.add_variable(4, "ready", True) next_state_choice = horse.add_variable(4, "next_state_choice", True) self.request_var = next_state_choice.add_variable(4, "request", False) self.request_var.set_writable() dt = ua.DataValue(ua.Variant( 0, ua.VariantType.Int16)) # to ensure correct data type self.state_num = next_state_choice.add_variable(4, "state_num", dt) self.state_num.set_writable() self.next_state_possibilities = horse.add_variable( 4, "next_state_possibilities", [1, 70, 80]) self.change_state(start_state) print( f"Server is in state {self.actual_state_num.get_value()} and the possibilities are {type(self.next_state_possibilities.get_value())}" ) self.start() # start the server self.mic_active.set_value(False) subHandler = SubHandler(self) sub = self.server.create_subscription(500, subHandler) handle = sub.subscribe_data_change(self.request_var) handle_response = sub.subscribe_data_change(response_string) handle_actual = sub.subscribe_data_change(self.actual_state_num) # while True: try: print("Server started.") while True: # print("mic mic", self.mic_active.get_value()) # time.sleep(10) # the variable "mic_active" will be changed periodically every 10 seconds in this loop # change the mic_active (if True -> False, if False -> True) # mic_active.set_value(not mic_active.get_value()) inp = readInput("", timeout=10) if inp == "q": break elif inp == "r": self.mic_active.set_value(True) print( f"Variable 'mic_active' changed to {self.mic_active.get_value()}." ) elif inp == "w": self.mic_active.set_value(False) print( f"Variable 'mic_active' changed to {self.mic_active.get_value()}." ) except KeyboardInterrupt: print("User requested interruption.") except Exception: exc_type, exc_value, exc_traceback = sys.exc_info() traceback.print_exception(exc_type, exc_value, exc_traceback, limit=2, file=sys.stdout) sub.unsubscribe(handle) # cancel subscription sub.unsubscribe(handle_response) # cancel subscription sub.unsubscribe(handle_actual) # cancel subscription sub.delete() def change_state(self, next_state): current_state = str(self.actual_state_num.get_value()) print(f"Changing state from {current_state} to {next_state}.") if current_state in self.state_descriptions: self.next_state_possibilities.set_value( self.state_descriptions[current_state]) self.actual_state_num.set_value(next_state) def check_current_state(self): state = str(self.actual_state_num.get_value()) if state in self.state_descriptions: next_states = self.state_descriptions[state] # self.next_state_possibilities = horse.add_variable(4, "next_state_possibilities", next_states) self.next_state_possibilities.set_value(next_states) # self.next_state_possibilities.set_value = next_states if len(next_states) == 1: next_state = next_states[0] # print(self.next_state_description) if str(next_state) in self.next_state_description: print( f"Current state {state} has single next state: {next_state}" ) print(self.next_state_possibilities) print(self.actual_state) self.mic_active.set_value(True) else: print( f"Current state {state} does not require user input, skipping to next state: {next_state}" ) self.actual_state_num.set_value(next_state) self.mic_active.set_value(False) else: print( f"Current state {state} has multiple choices: {next_states}" ) self.mic_active.set_value(True) else: print("Current state is not in the state description file!") def start(self): self.server.start() return self.server def stop(self): self.server.stop()
myfolder = objects.add_folder(idx, "myfolder") myobj = objects.add_object(idx, "NewObject") myvar = myobj.add_variable(idx, "MyVariable", 6.7) myarrayvar = myobj.add_variable(idx, "myarrayvar", [6.7, 7.9]) myprop = myobj.add_property(idx, "myproperty", "I am a property") mymethod = myobj.add_method(idx, "mymethod", func, [ua.VariantType.Int64], [ua.VariantType.Boolean]) multiply_node = myobj.add_method( idx, "multiply", multiply, [ua.VariantType.Int64, ua.VariantType.Int64], [ua.VariantType.Int64] ) # creating an event object # The event object automatically will have members for all events properties myevent = server.get_event_object(ObjectIds.BaseEventType) myevent.Message.Text = "This is my event" myevent.Severity = 300 # starting! server.start() print("Available loggers are: ", logging.Logger.manager.loggerDict.keys()) try: handler = SubHandler() # enable following if you want to subscribe to nodes on server side sub = server.create_subscription(500, handler) handle = sub.subscribe_data_change(myvar) # trigger event, all subscribed clients wil receive it myevent.trigger() embed() finally: server.stop()
timer.set_writable() # starting! server.start() print("Available loggers are: ", logging.Logger.manager.loggerDict.keys()) try: # create handler objects mode_handler = SubHandler_mode() direction_handler = SubHandler_direction() start_handler = SubHandler_start() timer_handler = SubHandler_timer() # subscribe to nodes on server side sub_dir = server.create_subscription(100, handler=direction_handler) sub_mode = server.create_subscription(50, mode_handler) sub_start = server.create_subscription(50, start_handler) sub_timer = server.create_subscription(30, timer_handler) handle_mode = sub_mode.subscribe_data_change(mode) handle_dir = sub_dir.subscribe_data_change(direction) handle_start = sub_start.subscribe_data_change(start) handle_timer = sub_timer.subscribe_data_change(timer) # embed interactive shell embed() # reset Candy Grabber CG.reset() print(mode)
class UAServer: def __init__(self,rack : rack_controller): self.rack = rack self._setup_nodes() self._generate_tags() self.ua_server.start() self._generate_subscriptions() Thread(target=self._var_updater, daemon=True).start() def _setup_nodes(self): # Create server instance self.ua_server = Server('./opcua_cache') self.ua_server.set_endpoint('opc.tcp://0.0.0.0:4840/UA/PickByLight') self.ua_server.set_server_name("Pick By Light Server") # idx name will be used later for creating the xml used in data type dictionary # setup our own namespace, not really necessary but should as spec idx_name = 'http://examples.freeopcua.github.io' self.idx = self.ua_server.register_namespace(idx_name) # Set all possible endpoint policies for clients to connect through self.ua_server.set_security_policy([ ua.SecurityPolicyType.NoSecurity, ua.SecurityPolicyType.Basic128Rsa15_SignAndEncrypt, ua.SecurityPolicyType.Basic128Rsa15_Sign, ua.SecurityPolicyType.Basic256_SignAndEncrypt, ua.SecurityPolicyType.Basic256_Sign]) # get Objects node, this is where we should put our custom stuff objects = self.ua_server.get_objects_node() # add a PackMLObjects folder pml_folder = objects.add_folder(self.idx, "PackMLObjects") # Get the base type object types = self.ua_server.get_node(ua.ObjectIds.BaseObjectType) # Create a new type for PackMLObjects PackMLBaseObjectType = types.add_object_type(self.idx, "PackMLBaseObjectType") # Create objects for the pack tags using the above created packMLBasedObjectType self.Admin = pml_folder.add_object('ns=2;s=Admin', "Admin", PackMLBaseObjectType.nodeid) self.Status = pml_folder.add_object('ns=2;s=Status', "Status", PackMLBaseObjectType.nodeid) self.Command = pml_folder.add_object('ns=2;s=Command', "Command", PackMLBaseObjectType.nodeid) # Create an object container for the rack self.RackStatus = self.Status.add_object('ns=2;s=Status.Rack', 'Rack') #BoxesCommonStatus = BoxesStatus.add_object('ns=2;s=Status.Boxes.Common', 'Common') root = self.ua_server.get_root_node() DummyFestoObj = root.add_object("ns=2;s=|var|CECC-LK.Application.Flexstation_globalVariables", "DummyFesto") DummyFestoObj.add_variable("ns=2;s=|var|CECC-LK.Application.Flexstation_globalVariables.FlexStationStatus", "FlexStationStatus", val=0).set_writable() DummyFestoObj.add_variable("ns=2;s=|var|CECC-LK.Application.FBs.stpStopper1.stAppControl.uiOpNo","uiOpNo", val=0).set_writable() def _generate_tags(self): # for all ports generate tags for port_number in self.rack.ports: # Make a folder with the port_number as the name b_obj = self.RackStatus.add_object('ns=2;s=Status.Rack.{}'.format(port_number), str(port_number)) b_obj.add_variable("ns=2;s=Status.Rack.{}.Selected".format(port_number) ,"Selected" , bool()) b_obj.add_variable("ns=2;s=Status.Rack.{}.Activity".format(port_number) ,"Activity" , bool()) b_obj.add_variable("ns=2;s=Status.Rack.{}.ActivityTimestamp".format(port_number) ,"ActivityTimestamp", datetime.fromtimestamp(0)) b_obj.add_variable("ns=2;s=Status.Rack.{}.PickTimestamp".format(port_number) ,"PickTimestamp" , datetime.fromtimestamp(0)) b_obj.add_variable("ns=2;s=Status.Rack.{}.LightState".format(port_number) ,"LightState" , bool()) b_obj.add_variable("ns=2;s=Status.Rack.{}.BoxId".format(port_number) ,"BoxId" , str()) b_obj.add_variable("ns=2;s=Status.Rack.{}.ContentId".format(port_number) ,"ContentId" , str()) b_obj.add_variable("ns=2;s=Status.Rack.{}.ContentCount".format(port_number) ,"ContentCount" , int()) ''' create command tags for clients that does not support ua methods. ''' # create an object in the packml Command object called rack for all the commands. b_obj = self.Command.add_object("ns=2;s=Command.Rack", 'Rack') # Create command tag for triggering the selection b_obj.add_variable("ns=2;s=Command.Rack.Select", 'Select', -1, ua.VariantType.Int16).set_writable() b_obj.add_variable("ns=2;s=Command.Rack.DeSelect", 'DeSelect', -1, ua.VariantType.Int16).set_writable() def _generate_subscriptions(self): # Create UA subscriber node for the box. Set self as handler. sub = self.ua_server.create_subscription(100, self) # Subscribe to the Select tag n = self.ua_server.get_node("ns=2;s=Command.Rack.Select") sub.subscribe_data_change(n) # Subscribe to the Deselect tag n = self.ua_server.get_node("ns=2;s=Command.Rack.DeSelect") sub.subscribe_data_change(n) pass def event_notification(self, event): print("Python: New event. No function implemented", event) def datachange_notification(self, node, val, data): """UA server callback on data change notifications This is a workaround for kepware that does not support UA methods, so instead is has "trigger tags" that when set to true it works like calling a method. TODO make this more dynamic instead of hard coding the attributes. Arguments: node {Node} -- [description] val {[type]} -- [description] data {[type]} -- [description] """ # avoid triggereing it all again when resetting the tags to -1 if val != -1 : # Print info print("New data change event", node, val) # get the node browse name. node_id = node.get_browse_name().Name # If the trigger tag changes to true go in and update the status tag and set the trigger back to false. # Also read description above. if node_id == "Select" : self.rack.select_port(val) node.set_value(-1) elif node_id == "Deselect" : self.rack.select_port(val) node.set_value(-1) def _var_updater(self): while True: sleep(0.1) # for all boxes update tags for port_number, port in self.rack.ports.items(): # get the object in the packml status object using our unique idx node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.Activity".format(port_number)) node.set_value(port.activity) node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.ActivityTimestamp".format(port_number)) node.set_value(port.activity_timestamp) node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.LightState".format(port_number)) node.set_value(port.get_light()) for port_number, box in self.rack.boxes.items(): node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.BoxId".format(port_number)) node.set_value(box.box_id) node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.ContentId".format(port_number)) node.set_value(box.content_id) node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.ContentCount".format(port_number)) node.set_value(box.content_count) for port_number, select_state in self.rack.ports_select_state.items(): node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.Selected".format(port_number)) node.set_value(select_state.selected) node = self.ua_server.get_node("ns=2;s=Status.Rack.{}.PickTimestamp".format(port_number)) node.set_value(select_state.pick_timestamp)