예제 #1
0
    server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")
    server.set_server_name("FreeOpcUa Example Server")

    server.load_certificate("robotarm_cert.der")
    server.load_private_key("robotarm_pk.pem")

    # setup our own namespace, not really necessary but should as spec
    uri = "http://examples.freeopcua.github.io"
    idx = server.register_namespace(uri)

    # get Objects node, this is where we should put our custom stuff
    objects = server.get_objects_node()

    # populating our address space
    myfolder = objects.add_folder(idx, "GFISmartFleet")
    myobj = server.get_root_node().get_child(["0:Objects", "2:GFISmartFleet"
                                              ]).add_object(idx, "RobotArm")

    var_Servo_left_angle = myobj.add_variable(idx, "Servo_left_angle", 90)
    var_Servo_left_angle.set_writable()

    var_Servo_right_angle = myobj.add_variable(idx, "Servo_right_angle", 90)
    var_Servo_right_angle.set_writable()

    var_Servo_middle_angle = myobj.add_variable(idx, "Servo_middle_angle", 90)
    var_Servo_middle_angle.set_writable()

    var_Servo_claw_angle = myobj.add_variable(idx, "Servo_claw_angle", 25)
    var_Servo_claw_angle.set_writable()

    #myarrayvar = myobj.add_variable(idx, "myarrayvar", [6.7, 7.9])
    #myarrayvar = myobj.add_variable(idx, "myStronglytTypedVariable", ua.Variant([], ua.VariantType.UInt32))
예제 #2
0
from opcua import ua, Server
import asyncio, random, time
from datetime import datetime

server = Server()
server.set_endpoint("opc.tcp://127.0.0.1:4840")
server.set_server_name("OPCUA-Test")
address_space = server.register_namespace("http://andreas-heine.net/UA")

root_node = server.get_root_node()
object_node = server.get_objects_node()
server_node = server.get_server_node()

parameter_obj = object_node.add_object(address_space, "Parameter")
random_node = parameter_obj.add_variable(address_space, "random",
                                         ua.Variant(0, ua.VariantType.UInt64))

etype = server.create_custom_event_type(
    address_space, 'MyFirstEvent', ua.ObjectIds.BaseEventType,
    [('MyNumericProperty', ua.VariantType.Float),
     ('MyStringProperty', ua.VariantType.String)])
myevgen = server.get_event_generator(etype, parameter_obj)

vars_obj = object_node.add_object(address_space, "Vars")
var_list = []
for i in range(100):
    var = vars_obj.add_variable(
        ua.NodeId.from_string(f'ns={address_space};s=DB_DATA.Test.var{i}'),
        f'Test.var{i}', 0)
    var.set_writable(True)
    var_list.append(var)
예제 #3
0
def main():
    # logging.basicConfig(level=logging.ERROR)
    # logger=logging.getLogger("opcua.server.internal_subscription")
    # logger.setLevel(logging.ERROR)
    read = open('config.txt', 'r')
    configs = read.readlines()
    read.close()

    server = Server()
    endpoint = configs[0].split('@')[1].rstrip('\n')
    servername = configs[1].split('@')[1].rstrip('\n')
    kafkaservers = configs[2].split('@')[1].replace("'", "").replace(
        "\"", "").rstrip('\n')
    kafkaserver = kafkaservers[1:-1].split(',')
    kafkatopic = configs[3].split('@')[1].rstrip('\n')
    eventname = configs[4].split('@')[1].rstrip('\n')
    # auto_offset_reset='earlist'
    consumer = KafkaConsumer(kafkatopic, bootstrap_servers=kafkaserver)

    server.set_endpoint(endpoint)
    server.set_server_name(servername)

    print("Program running......")
    print("Please do not close this page")

    # 证书
    # server.load_certificate("certificate-example.der")
    # server.load_private_key("private-key-example.pem")
    # 安全策略
    server.set_security_policy([
        ua.SecurityPolicyType.NoSecurity,
        # ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
        # ua.SecurityPolicyType.Basic256Sha256_Sign
    ])

    uri = "http://taiji.com.cn"
    idx = server.register_namespace(uri)

    objs = server.get_objects_node()
    myobj = objs.add_object(idx, "MyObject")
    # 节点
    taglists = readFile("node.csv")
    for taglist in taglists:
        # myobj.add_variable(idx, taglist, 6.7).set_writable()
        myobj.add_variable(idx, taglist, random.random()).set_writable()
        # myobj.add_variable(idx, taglist, 6.7)

    attrs = readFile("ae_attr.csv")
    custom_etype = server.nodes.base_event_type.add_object_type(idx, eventname)
    for attr in attrs:
        custom_etype.add_property(2, attr, ua.Variant("",
                                                      ua.VariantType.String))
    myevent = server.get_event_generator(custom_etype, myobj)

    server.start()

    try:
        rootnode = server.get_root_node().get_child(
            ["0:Objects", "{}:MyObject".format(idx)])
        rootnodes = rootnode.get_variables()

        nodeAll = {}
        for i in range(len(rootnodes)):
            nodeId = rootnodes[i]
            nodeName = rootnodes[i].get_browse_name().Name
            nodeAll.update({nodeName: nodeId})

        for message in consumer:
            recv = message.value.decode("utf8")
            # print("recvevent=",recv)

            if recv[0] == '{' and recv[-1] == '}':
                nodeKafka = json.loads(recv)
                # print("nodeKafka=", nodeKafka)
                comName = nodeKafka.keys() & nodeAll.keys()
                for row in comName:
                    rootnode.get_child(["2:{}".format(row)
                                        ]).set_value(nodeKafka[row])
            else:
                recv = recv.replace('\n', '').replace('\r', '')
                datas = recv.split("|")[1:]
                # print("datas=", datas)
                if len(datas) == 9:
                    for i in range(len(attrs)):
                        # exec("myevent.event.{}='{}'".format(attrs[i], datas[i].replace('\n', '').replace('\r', '')))
                        exec("myevent.event.{}='{}'".format(
                            attrs[i], datas[i]))
                    myevent.trigger()
                else:
                    # continue
                    f = open('ErrorAE.bak', 'a', encoding='utf8')
                    f.write(recv)
                    f.write('\n')
                    f.close
                # print("mysecondevgen=",mysecondevgen)
                # print("mysecondevgen=", myevent.event)

    except Exception as e:
        print(e)

    finally:
        server.stop()
예제 #4
0
    return items


if __name__ == "__main__":
    # setup our server
    server = Server()
    server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")

    # setup our own namespace, not really necessary but should as spec
    uri = "http://examples.freeopcua.github.io"
    nsidx = server.register_namespace(uri)

    # --------------------------------------------------------
    # create custom enum data type
    # --------------------------------------------------------
    enums = server.get_root_node().get_child(
        ["0:Types", "0:DataTypes", "0:BaseDataType", "0:Enumeration"])

    # 1.
    # Create Enum Type
    myenum_type = enums.add_subtype(nsidx, 'MyEnum', ua.NodeClass.DataType)

    # 2.
    # Add enumerations as EnumStrings (Not yet tested with EnumValues)
    # Essential to use namespace 0 for EnumStrings !

    # By hand
    #     es = myenum_type.add_variable(0, "EnumStrings" , [ua.LocalizedText("ok"),
    #                                                       ua.LocalizedText("idle")])

    # Or convert the existing IntEnum MyEnum
    es = myenum_type.add_variable(0, "EnumStrings", enum_to_stringlist(MyEnum))
예제 #5
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'])
    uri = "http://examples.freeopcua.github.io"
    idx = server.register_namespace(uri)

    # Import customobject type
    server.import_xml('customobject.xml')

    # get Objects node, this is where we should put our custom stuff
    objects = server.get_objects_node()

    # get nodeid of custom object type by :
    # 1) Use node ID
    # 2) Or Full path
    # 3) Or As child from parent
    nodeid_a = ua.NodeId.from_string('ns=1;i=1002')
    nodeid_b = server.get_root_node().get_child(
        ["0:Types", "0:ObjectTypes", "0:BaseObjectType",
         "1:MyObjectType"]).nodeid
    nodeid_c = server.get_node(ua.ObjectIds.BaseObjectType).get_child(
        ["1:MyObjectType"]).nodeid

    myobject_type_nodeid = nodeid_a

    # populating our address space
    myobj = objects.add_object(
        idx,
        "MyObject",
    )
    myobj = objects.add_object(idx, "MyCustomObject", myobject_type_nodeid)

    # starting!
    server.start()
    uri = "http://examples.freeopcua.github.io"
    idx = server.register_namespace(uri)

    # get Objects node, this is where we should put our custom stuff
    objects = server.get_objects_node()

    # Example 1 - create a basic object
    #-------------------------------------------------------------------------------
    myobj = objects.add_object(idx, "MyObject")
    #-------------------------------------------------------------------------------

    # Example 2 - create a new object type and a instance of the new object type
    #-------------------------------------------------------------------------------
    types = server.get_node(ua.ObjectIds.BaseObjectType)

    object_type_to_derive_from = server.get_root_node().get_child(
        ["0:Types", "0:ObjectTypes", "0:BaseObjectType"])
    mycustomobj_type = types.add_object_type(idx, "MyCustomObject")
    mycustomobj_type.add_variable(0, "var_should_be_there_after_instantiate",
                                  1.0)  # demonstrates instantiate

    myobj = objects.add_object(idx, "MyCustomObjectA", mycustomobj_type.nodeid)
    #-------------------------------------------------------------------------------

    # Example 3 - import a new object from xml address space and create a instance of the new object type
    #-------------------------------------------------------------------------------
    # Import customobject type
    server.import_xml('customobject.xml')

    # get nodeid of custom object type by one of the following 3 ways:
    # 1) Use node ID
    # 2) Or Full path
예제 #8
0
        items.append(ua.LocalizedText(value.name))
    return items

if __name__ == "__main__":
    # setup our server
    server = Server()
    server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")

    # setup our own namespace, not really necessary but should as spec
    uri = "http://examples.freeopcua.github.io"
    nsidx = server.register_namespace(uri)

    # --------------------------------------------------------
    # create custom enum data type
    # --------------------------------------------------------
    enums = server.get_root_node().get_child(["0:Types", "0:DataTypes", "0:BaseDataType", "0:Enumeration"])

    # 1.
    # Create Enum Type
    myenum_type = enums.add_subtype(nsidx, 'MyEnum', ua.NodeClass.DataType)

    # 2.
    # Add enumerations as EnumStrings (Not yet tested with EnumValues)
    # Essential to use namespace 0 for EnumStrings !

    # By hand
    #     es = myenum_type.add_variable(0, "EnumStrings" , [ua.LocalizedText("ok"),
    #                                                       ua.LocalizedText("idle")])

    # Or convert the existing IntEnum MyEnum
    es = myenum_type.add_variable(0, "EnumStrings" , enum_to_stringlist(MyEnum))
class CustomServer(object):
    def __init__(self):
        self.SERVER_ENDPOINT = os.environ.get("SERVER_ENDPOINT")
        self.NAMESPACE = os.environ.get("NAMESPACE")
        self.SERVER_NAME = os.environ.get("SERVER_NAME")
        self.ENABLE_CERTIFICATE = bool(
            strtobool(os.environ.get("ENABLE_CERTIFICATE")))

        # setup our server
        self.server = Server()
        self.server.set_endpoint(self.SERVER_ENDPOINT)
        self.server.set_server_name(self.SERVER_NAME)

        # set the security endpoints for identification of clients
        if self.ENABLE_CERTIFICATE:
            # load server certificate and private key. This enables endpoints with signing and encryption.
            self.CERTIFICATE_PATH_SERVER_CERT = os.path.dirname(
                os.getcwd()) + os.environ.get("CERTIFICATE_PATH_SERVER_CERT")
            self.CERTIFICATE_PATH_SERVER_PRIVATE_KEY = os.path.dirname(
                os.getcwd()) + os.environ.get(
                    "CERTIFICATE_PATH_SERVER_PRIVATE_KEY")
            self.server.load_certificate(self.CERTIFICATE_PATH_SERVER_CERT)
            self.server.load_private_key(
                self.CERTIFICATE_PATH_SERVER_PRIVATE_KEY)

            # set all possible endpoint policies for clients to connect through
            self.server.set_security_policy([
                # ua.SecurityPolicyType.NoSecurity,
                ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
                # ua.SecurityPolicyType.Basic256Sha256_Sign,
            ])

            self.server.set_security_IDs(["Username", "Basic256Sha256"])
        else:
            self.server.set_security_policy([ua.SecurityPolicyType.NoSecurity])
            self.server.set_security_IDs(["Anonymous", "Username"])

        # set the user_manager function
        self.server.user_manager.set_user_manager(user_manager)

        # setup our own namespace, not really necessary but should as spec
        uri = self.NAMESPACE
        self.idx = self.server.register_namespace(uri)

        # get important nodes
        self.root = self.server.get_root_node()
        self.obj = self.server.get_objects_node()

        self.init_methods()

    def init_methods(self):
        # method: ADD_OBJECTS_DIR
        inarg1 = ua.Argument()
        inarg1.Name = "objects folder"
        inarg1.DataType = ua.NodeId(ua.ObjectIds.String)  # String
        inarg1.ValueRank = -1
        inarg1.ArrayDimensions = []
        inarg1.Description = ua.LocalizedText("Name the new objects folder")

        method_node = self.obj.add_method(self.idx, "ADD_NEW_OBJECTS_FOLDER",
                                          self.add_objects_subfolder, [inarg1])

        # method: ADD_OPC_TAG
        inarg1 = ua.Argument()
        inarg1.Name = "opctag"
        inarg1.DataType = ua.NodeId(ua.ObjectIds.String)  # String
        inarg1.ValueRank = -1
        inarg1.ArrayDimensions = []
        inarg1.Description = ua.LocalizedText("Name new OPC variable")

        inarg2 = ua.Argument()
        inarg2.Name = "variant_type"
        inarg2.DataType = ua.NodeId(ua.ObjectIds.String)  # String
        inarg2.ValueRank = -1
        inarg2.ArrayDimensions = []
        inarg2.Description = ua.LocalizedText("Type of variable")

        inarg3 = ua.Argument()
        inarg3.Name = "parent_node"
        inarg3.DataType = ua.NodeId(ua.ObjectIds.String)  # String
        inarg3.ValueRank = -1
        inarg3.ArrayDimensions = []
        inarg3.Description = ua.LocalizedText(
            "Type in the name of the parent node the new variable should assigned to"
        )

        method_node = self.obj.add_method(self.idx, "ADD_OPC_TAG",
                                          self.register_opc_tag,
                                          [inarg1, inarg2, inarg3])

        # method: SET_PV_LIMIT
        inarg1 = ua.Argument()
        inarg1.Name = "active_power_setpoint"
        inarg1.DataType = ua.NodeId(ua.ObjectIds.Int32)  # Integer
        inarg1.ValueRank = -1
        inarg1.ArrayDimensions = []
        inarg1.Description = ua.LocalizedText(
            "Type in active power setpoint in percent [0 ... 100]")

        inarg2 = ua.Argument()
        inarg2.Name = "parent_node"
        inarg2.DataType = ua.NodeId(ua.ObjectIds.String)  # String
        inarg2.ValueRank = -1
        inarg2.ArrayDimensions = []
        inarg2.Description = ua.LocalizedText(
            "Type in the name of the parent node")

        method_node = self.obj.add_method(self.idx, "SET_PV_LIMIT",
                                          self.set_pv_active_power_setpoint,
                                          [inarg1, inarg2])

        # method: RUN_ONLINE_GRID_PROTECTION
        inarg1 = ua.Argument()
        inarg1.Name = "On/Off"
        inarg1.DataType = ua.NodeId(ua.ObjectIds.Int32)  # Integer
        inarg1.ValueRank = -1
        inarg1.ArrayDimensions = []
        inarg1.Description = ua.LocalizedText(
            "Type in 1 to RUN or 0 to STOP ONLINE_GRID_PROTECTION")

        inarg2 = ua.Argument()
        inarg2.Name = "parent_node"
        inarg2.DataType = ua.NodeId(ua.ObjectIds.String)  # String
        inarg2.ValueRank = -1
        inarg2.ArrayDimensions = []
        inarg2.Description = ua.LocalizedText(
            "Type in the name of the parent node")

        method_node = self.obj.add_method(self.idx,
                                          "RUN_ONLINE_GRID_PROTECTION",
                                          self.run_online_grid_protection,
                                          [inarg1, inarg2])

    @uamethod
    def add_objects_subfolder(self, parent, dir_name):
        # check if old dir with dir_name exists. if so then delete this dir first
        try:
            obj = self.root.get_child(
                ["0:Objects", ("{}:" + dir_name).format(self.idx)])
            self.server.delete_nodes([obj], True)
        except BadNoMatch:
            print(DateHelper.get_local_datetime(),
                  "There is no old folder with the name: " + dir_name)

        folder = self.obj.add_folder(self.idx, dir_name)
        print(DateHelper.get_local_datetime(), "Add subfolder: " + dir_name)

    @uamethod
    def register_opc_tag(self,
                         parent,
                         opctag,
                         variant_type="Float",
                         parent_node=""):
        # Object "parent_node":
        try:
            obj = self.root.get_child(
                ["0:Objects", ("{}:" + parent_node).format(self.idx)])
        except BadNoMatch:
            print(
                DateHelper.get_local_datetime(),
                "register_opc_tag(): OPCUA_server_dir the variables should be assigned to, doesn't exists."
            )
            raise

        var = ua.Variant(0, strings_to_vartyps(variant_type))
        mvar = obj.add_variable(self.idx, opctag.strip(), var)
        mvar.set_writable()
        print(
            DateHelper.get_local_datetime(), "Add variable: " + opctag +
            " of type " + variant_type + " @node " + parent_node)

    @uamethod
    def set_pv_active_power_setpoint(self, parent, setpoint, parent_node=""):
        try:
            obj = self.root.get_child(
                ["0:Objects", ("{}:" + parent_node).format(self.idx)])
        except BadNoMatch:
            print(
                DateHelper.get_local_datetime(),
                "set_pv_active_power_setpoint(): assign new value to node failed."
            )
            raise

        for mvar in obj.get_variables():
            if "PV" and "CTRL" in mvar.get_browse_name().Name:
                variant_type = mvar.get_data_value().Value.VariantType
                mvar.set_value(clamp(setpoint, 0, 100), variant_type)
                print(
                    DateHelper.get_local_datetime(),
                    "Set Value of node " + mvar.get_browse_name().Name +
                    " to " + str(clamp(setpoint, 0, 100)))

    @uamethod
    def run_online_grid_protection(self, parent, setpoint, parent_node=""):
        try:
            obj = self.root.get_child(
                ["0:Objects", ("{}:" + parent_node).format(self.idx)])
        except BadNoMatch:
            print(DateHelper.get_local_datetime(),
                  "run_online_grid_protection(): Change in On/Off failed.")
            raise

        for mvar in obj.get_variables():
            if "RUN_ONLINE_GRID_PROTECTION" in mvar.get_browse_name().Name:
                variant_type = mvar.get_data_value().Value.VariantType
                mvar.set_value(clamp(setpoint, 0, 1), variant_type)
                print(
                    DateHelper.get_local_datetime(),
                    "Change status of online grid protection to " +
                    str(clamp(setpoint, 0, 1)))

    def start(self):
        self.server.start()
        print(DateHelper.get_local_datetime(), self.__class__.__name__,
              " successful started")

    def stop(self):
        self.server.stop()
        print(DateHelper.get_local_datetime(), self.__class__.__name__,
              " successful stopped")
예제 #10
0
    uri = "http://examples.freeopcua.github.io"
    idx = server.register_namespace(uri)

    # Import customobject type
    server.import_xml('customobject.xml')

    # get Objects node, this is where we should put our custom stuff
    objects = server.get_objects_node()


    # get nodeid of custom object type by :
    # 1) Use node ID
    # 2) Or Full path
    # 3) Or As child from parent
    nodeid_a = ua.NodeId.from_string('ns=1;i=1002')
    nodeid_b = server.get_root_node().get_child(["0:Types", "0:ObjectTypes", "0:BaseObjectType", "1:MyObjectType"]).nodeid
    nodeid_c = server.get_node(ua.ObjectIds.BaseObjectType).get_child(["1:MyObjectType"]).nodeid


    myobject_type_nodeid = nodeid_a

    # populating our address space
    myobj = objects.add_object(idx, "MyObject",)
    myobj = objects.add_object(idx, "MyCustomObject", myobject_type_nodeid)

    # starting!
    server.start()

    try:
        while True:
            time.sleep(1)
예제 #11
0
class UaModeler(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.ui = Ui_UaModeler()
        self.ui.setupUi(self)
        self.setWindowIcon(QIcon(":/network.svg"))

        # we only show statusbar in case of errors
        self.ui.statusBar.hide()

        # load settings, seconds arg is default
        self.settings = QSettings("FreeOpcUa", "OpcUaModeler")

        self.server = Server()
        self.server.set_endpoint(
            "opc.tcp://0.0.0.0:48400/freeopcua/uamodeler/")
        self.server.set_server_name("OpcUa Modeler Server")

        self._new_nodes = []  # the added nodes we will save

        self.tree_ui = TreeWidget(self.ui.treeView)
        self.tree_ui.error.connect(self.show_error)
        self.refs_ui = RefsWidget(self.ui.refView)
        self.refs_ui.error.connect(self.show_error)
        self.attrs_ui = AttrsWidget(self.ui.attrView)
        self.attrs_ui.error.connect(self.show_error)
        self.idx_ui = NamespaceWidget(self.ui.namespaceView)

        self.ui.treeView.activated.connect(self.show_refs)
        self.ui.treeView.clicked.connect(self.show_refs)
        self.ui.treeView.activated.connect(self.show_attrs)
        self.ui.treeView.clicked.connect(self.show_attrs)

        self.resize(int(self.settings.value("main_window_width", 800)),
                    int(self.settings.value("main_window_height", 600)))
        #self.restoreState(self.settings.value("main_window_state", b"", type="QByteArray"))
        self.restoreState(self.settings.value("main_window_state", b""))

        self.ui.splitterLeft.restoreState(
            self.settings.value("splitter_left", b""))
        self.ui.splitterRight.restoreState(
            self.settings.value("splitter_right", b""))
        self.ui.splitterCenter.restoreState(
            self.settings.value("splitter_center", b""))

        self.server.start()
        self.tree_ui.set_root_node(self.server.get_root_node())
        self.idx_ui.set_node(
            self.server.get_node(ua.ObjectIds.Server_NamespaceArray))

        # fix icon stuff
        self.ui.actionAddFolder.setIcon(QIcon(":/folder.svg"))
        self.ui.actionAddObject.setIcon(QIcon(":/object.svg"))
        self.ui.actionAddObjectType.setIcon(QIcon(":/object_type.svg"))
        self.ui.actionAddProperty.setIcon(QIcon(":/property.svg"))
        self.ui.actionAddVariable.setIcon(QIcon(":/variable.svg"))
        self.ui.actionAddVariableType.setIcon(QIcon(":/variable_type.svg"))

        # menu
        self.ui.treeView.addAction(self.ui.actionAddFolder)
        self.ui.treeView.addAction(self.ui.actionAddObject)
        self.ui.treeView.addAction(self.ui.actionAddVariable)
        self.ui.treeView.addAction(self.ui.actionAddProperty)
        self.ui.treeView.addAction(self.ui.actionAddObjectType)
        self.ui.treeView.addAction(self.ui.actionAddVariableType)
        self.ui.treeView.addAction(self.ui.actionAddDataType)

        # actions
        self.ui.actionOpen.triggered.connect(self._open)
        self.ui.actionSave.triggered.connect(self._save)
        self.ui.actionAddObjectType.triggered.connect(self._add_object_type)
        self.ui.actionAddObject.triggered.connect(self._add_object)
        self.ui.actionAddDataType.triggered.connect(self._add_data_type)
        self.ui.actionAddVariable.triggered.connect(self._add_variable)
        self.ui.actionAddProperty.triggered.connect(self._add_property)

    def _open(self):
        path = QFileDialog.getOpenFileName(self)
        f = open(path[0], 'r')
        xml = f.read()
        print("should read", xml)

    def _save(self):
        raise NotImplementedError

    def _add_node(self, func_name, node_type=None, default_value=None):
        node = self.tree_ui.get_current_node()
        if not node:
            self.show_error("No node selected")
            raise RuntimeError("No node selected")
        args, ok = NewNodeDialog.getArgs(self,
                                         func_name,
                                         self.server,
                                         node_type=node_type,
                                         default_value=default_value)
        print("ARGS are", args)
        if ok:
            new_node = getattr(node, func_name)(*args)
            self._new_nodes.append(new_node)
            self.tree_ui.reload_current()
            self.show_refs()

    def _add_object_type(self):
        return self._add_node("add_object_type")

    def _add_object(self):
        return self._add_node("add_object",
                              node_type=self.server.get_node(
                                  ua.ObjectIds.BaseObjectType))

    def _add_data_type(self):
        return self._add_node("add_data_type")

    def _add_variable(self):
        return self._add_node("add_variable", default_value=9.99)

    def _add_property(self):
        return self._add_node("add_property", default_value=1.11)

    def show_refs(self, idx=None):
        node = self.get_current_node(idx)
        if node:
            self.refs_ui.show_refs(node)

    def show_attrs(self, idx=None):
        if not isinstance(idx, QModelIndex):
            idx = None
        node = self.get_current_node(idx)
        if node:
            self.attrs_ui.show_attrs(node)

    def show_error(self, msg, level=1):
        print("showing error: ", msg, level)
        self.ui.statusBar.show()
        self.ui.statusBar.setStyleSheet(
            "QStatusBar { background-color : red; color : black; }")
        self.ui.statusBar.showMessage(str(msg))
        QTimer.singleShot(1500, self.ui.statusBar.hide)

    def get_current_node(self, idx=None):
        return self.tree_ui.get_current_node(idx)

    def closeEvent(self, event):
        self.settings.setValue("main_window_width", self.size().width())
        self.settings.setValue("main_window_height", self.size().height())
        self.settings.setValue("main_window_state", self.saveState())
        self.settings.setValue("splitter_left",
                               self.ui.splitterLeft.saveState())
        self.settings.setValue("splitter_right",
                               self.ui.splitterRight.saveState())
        self.settings.setValue("splitter_center",
                               self.ui.splitterCenter.saveState())
        self.server.stop()
        event.accept()
예제 #12
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)                   
예제 #13
0
    # get Objects node, this is where we should put our custom stuff
    objects = server.get_objects_node()

    # Example 1 - create a basic object
    #-------------------------------------------------------------------------------
    myobj = objects.add_object(idx, "MyObject")    
    #-------------------------------------------------------------------------------


    # Example 2 - create a new object type and a instance of the new object type
    #-------------------------------------------------------------------------------
    types = server.get_node(ua.ObjectIds.BaseObjectType)
    
    object_type_to_derive_from = server.get_root_node().get_child(["0:Types", 
                                                                   "0:ObjectTypes", 
                                                                   "0:BaseObjectType"])
    mycustomobj_type = types.add_object_type(idx, "MyCustomObjectType")
    mycustomobj_type.add_variable(0, "var_should_be_there_after_instantiate", 1.0) # demonstrates instantiate
    
    myobj = objects.add_object(idx, "MyCustomObjectA", mycustomobj_type.nodeid)
    #-------------------------------------------------------------------------------


    # Example 3 - import a new object from xml address space and create a instance of the new object type
    #-------------------------------------------------------------------------------
    # Import customobject type
    server.import_xml('customobject.xml')
        

    # get nodeid of custom object type by one of the following 3 ways: