Exemple #1
0
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()
Exemple #2
0
    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()
Exemple #3
0
    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()
Exemple #4
0
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'])
Exemple #5
0
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()
Exemple #6
0
    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)
Exemple #8
0
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)