Exemple #1
0
async def load_data_type_definitions(server: Union["Server", "Client"],
                                     base_node: Node = None,
                                     overwrite_existing=False) -> None:
    """
    Read DataTypeDefition attribute on all Structure  and Enumeration  defined
    on server and generate Python objects in ua namespace to be used to talk with server
    """
    new_objects = await load_enums(
        server)  # we need all enums to generate structure code
    if base_node is None:
        base_node = server.nodes.base_structure_type
    dtypes = []
    await _recursive_parse(server,
                           base_node,
                           dtypes,
                           add_existing=overwrite_existing)
    dtypes.sort()
    for dts in dtypes:
        try:
            env = await _generate_object(dts.name,
                                         dts.sdef,
                                         data_type=dts.data_type)
            ua.register_extension_object(dts.name, dts.encoding_id,
                                         env[dts.name], dts.data_type)
            new_objects[dts.name] = env[dts.name]
        except NotImplementedError:
            logger.exception("Structure type %s not implemented", dts.sdef)
    return new_objects
Exemple #2
0
async def load_type_definitions(server, nodes=None):
    """
    Download xml from given variable node defining custom structures.
    If no node is given, attemps to import variables from all nodes under
    "0:OPC Binary"
    the code is generated and imported on the fly. If you know the structures
    are not going to be modified it might be interresting to copy the generated files
    and include them in you code
    """
    if nodes is None:
        nodes = []
        for desc in await server.nodes.opc_binary.get_children_descriptions():
            if desc.BrowseName != ua.QualifiedName("Opc.Ua"):
                nodes.append(server.get_node(desc.NodeId))

    structs_dict = {}
    generators = []
    for node in nodes:
        xml = await node.read_value()
        xml = xml.decode("utf-8")
        generator = StructGenerator()
        generators.append(generator)
        generator.make_model_from_string(xml)
        # generate and execute new code on the fly
        generator.get_python_classes(structs_dict)
        # same but using a file that is imported. This can be usefull for debugging library
        # name = node.get_browse_name().Name
        # Make sure structure names do not contain charaters that cannot be used in Python class file names
        # name = _clean_name(name)
        # name = "structures_" + node.get_browse_name().Name
        # generator.save_and_import(name + ".py", append_to=structs_dict)

        # register classes
        # every children of our node should represent a class
        for ndesc in await node.get_children_descriptions():
            ndesc_node = server.get_node(ndesc.NodeId)
            ref_desc_list = await ndesc_node.get_references(
                refs=ua.ObjectIds.HasDescription,
                direction=ua.BrowseDirection.Inverse)
            if ref_desc_list:  # some server put extra things here
                name = _clean_name(ndesc.BrowseName.Name)
                if not name in structs_dict:
                    _logger.warning(
                        "%s is found as child of binary definition node but is not found in xml",
                        name)
                    continue
                nodeid = ref_desc_list[0].NodeId
                ua.register_extension_object(name, nodeid, structs_dict[name])
                # save the typeid if user want to create static file for type definitnion
                generator.set_typeid(name, nodeid.to_string())

        for key, val in structs_dict.items():
            if isinstance(val, EnumMeta) and key is not "IntEnum":
                setattr(ua, key, val)

    return generators, structs_dict
Exemple #3
0
async def load_custom_struct(node: Node) -> Any:
    sdef = await node.read_data_type_definition()
    name = (await node.read_browse_name()).Name
    for parent in await _get_parent_types(node):
        parent_sdef = await parent.read_data_type_definition()
        for f in reversed(parent_sdef.fields):
            sdef.Fields.insert(0, f)
    env = await _generate_object(name, sdef, data_type=node.nodeid)
    struct = env[name]
    ua.register_extension_object(name, sdef.DefaultEncodingId, struct, node.nodeid)
    return env[name]
Exemple #4
0
async def load_data_type_definitions(server, base_node=None):
    await load_enums(server)  # we need all enums to generate structure code
    if base_node is None:
        base_node = server.nodes.base_structure_type
    dtypes = []
    await _recursive_parse(server, base_node, dtypes)
    dtypes.sort()
    for dts in dtypes:
        try:
            env = await _generate_object(dts.name, dts.sdef, data_type=dts.data_type)
            ua.register_extension_object(dts.name, dts.encoding_id, env[dts.name], dts.desc.NodeId)
        except NotImplementedError:
            logger.exception("Structure type %s not implemented", dts.sdef)
Exemple #5
0
async def register_node_children_as_python_classes(server, node, generator):
    """ Registers in 'ua' all children of a Node
    server: Server
        OPC UA server
    node: Node
        The node to be processed
    generator: StructGenerator
        Struct generator from the xml description of the node
    Return dict of the registered structures
    """
    have_missing_data_types = True
    prev_num_failed_codes = -1
    structs_dict = {}
    while have_missing_data_types:
        # currently the 'get_python_classes' makes a single run on the data types from the information
        # model being loaded; if a certain DataType depends on a DataType that is defined 'later' on
        # the information model(s) it will fail because it makes use of an yet undefined Python class.
        # So for solving this without changing deeply the current implementation of 'get_python_classes'
        # we get get how many DataTypes failed to be converted to Python classes and repeat until the failed
        # conversions is zero or not lower than the previous iteration.
        structs_dict, failed_codes = generator.get_python_classes(structs_dict)

        if len(failed_codes) > 0:
            if prev_num_failed_codes > 0 and len(
                    failed_codes) >= prev_num_failed_codes:
                raise Exception(
                    "The previous number of missing data types is the same after retry."
                )
        else:
            # all parsed
            have_missing_data_types = False

        prev_num_failed_codes = len(failed_codes)
        # same but using a file that is imported. This can be usefull for debugging library
        # name = node.read_browse_name().Name
        # Make sure structure names do not contain charaters that cannot be used in Python class file names
        # name = clean_name(name)
        # name = "structures_" + node.read_browse_name().Name
        # generator.save_and_import(name + ".py", append_to=structs_dict)

        # register classes
        # every children of our node should represent a class
        for ndesc in await node.get_children_descriptions():
            ndesc_node = server.get_node(ndesc.NodeId)
            ref_desc_list = await ndesc_node.get_references(
                refs=ua.ObjectIds.HasDescription,
                direction=ua.BrowseDirection.Inverse)
            if ref_desc_list:  # some server put extra things here
                name = clean_name(ndesc.BrowseName.Name)
                if name not in structs_dict:
                    _logger.warning(
                        "%s is found as child of binary definition node but is not found in xml",
                        name)
                    continue
                nodeid = ref_desc_list[0].NodeId
                ua.register_extension_object(name, nodeid, structs_dict[name])
                # save the typeid if user want to create static file for type definition
                generator.set_typeid(name, nodeid.to_string())

        for key, val in structs_dict.items():
            if isinstance(val, EnumMeta) and key != "IntEnum":
                setattr(ua, key, val)

    return structs_dict