locka99 / opcua

A client and server implementation of the OPC UA specification written in Rust
Mozilla Public License 2.0
504 stars 135 forks source link

Can't generate address space for EUROMAP schemas #46

Closed evanjs closed 4 years ago

evanjs commented 4 years ago

I noticed that the EUROMAP OPC specifications are not among the schemas provided in this repository, so I figured I'd try to add them to the list of files to be generated locally, and see what happens.


Unfortunately, I am encountering plenty of errors, and the generators seem to be struggling to properly parse the XML files.

example:

error: expected expression, found `=`
   --> server/src/address_space/generated/nodeset_82_13.rs:321:34
    |
321 |     let node_id = NodeId::new(0, =1;i=7051);
    |                                  ^ expected expression

Enabling trace, I see ReferenceError: ns is not defined

No clue if supporting these schemas is within the scope of the current tools provided in this repo, but currently it's sort of impractical to interop with EUROMAP via OPC with this crate as the EUROMAP-specific properties must be explicitly defined.

Hopefully I'm just doing something dumb/wrong. Currently I'm just running node gen_address_space.js, followed by cargo build.


It might be helpful to either include some examples in the tools/schema directory, have something in the docs, or at some point, maybe even a build.rs-type solution, so we don't have to manually do anything aside from dropping the files into a schema folder or etc.


Anyway! Right now my goal is simply to consume the EUROMAP OPC-UA schemas utilizing this crate. Any help would be much appreciated!


Also happy to provide any additional information that might help.

locka99 commented 4 years ago

I haven't tested with other nodeset definitions yet although I had refactored the script into a command line tool for that eventual purpose.

The issue is mostly with the function node_id_ctor() in gen_nodeset.js#149. The code is very simple and assumes that the node id is of the form "i=1234" which is the notation in the default nodeset. It takes off the first two chars and injects the remainder:

function node_id_ctor(snippet) {
    // This turns a snippet like "i=2015" into a node id
    return `NodeId::new(0, ${snippet.substr(2)})`;
}

So if this code were given "ns=1;i=7051" it would take off the first 2 chars and inject "=1;i=7051" which is what you see.

Changing the function to use a regex would solve the issue and make it more general purpose, e.g.

(?:ns=([0-9]+);)?(i|b|s|g)=([a-zA-Z0-9\-]+)

Capture groups can be used to test if the namespace is supplied and also if its

There are also a few other places in that code that test for strings starting with "i=" which would also have to change. I'm sure these won't be the only problem consuming other nodesets.

I'll keep the bug open until I address the basic issues and see where it goes from there.

locka99 commented 4 years ago

I've made the change for this and tested that it doesn't break the default nodeset generation but I can't do any more for the time being to test it. It is possible that there could be issues with derived DataTypes or references in random schemes.

evanjs commented 4 years ago

Thank you!

Looks like I can generate a great deal more than I was able to previously!

Errors from generating EUROMAP 82 ``` Checking opcua-server v0.8.0 (/home/evanjs/src/opcua/server) error[E0599]: no variant or associated item named `PIDParametersDataType` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_1.rs:1946:94 | 1946 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::PIDParametersDataType, value); | ^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_2.rs:798:94 | 798 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_2.rs:957:94 | 957 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_2.rs:1116:94 | 1116 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_2.rs:1275:94 | 1275 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `PIDParametersDataType` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_3.rs:1471:94 | 1471 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::PIDParametersDataType, value); | ^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `PIDParametersDataType` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_8.rs:211:94 | 211 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::PIDParametersDataType, value); | ^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_8.rs:427:94 | 427 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_8.rs:586:94 | 586 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_8.rs:745:94 | 745 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_8.rs:904:94 | 904 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `ActiveErrorDataType` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_8.rs:1134:94 | 1134 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::ActiveErrorDataType, value); | ^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `OperatingModeEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_8.rs:1222:94 | 1222 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::OperatingModeEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `PIDParametersDataType` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_9.rs:123:94 | 123 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::PIDParametersDataType, value); | ^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_9.rs:913:94 | 913 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_9.rs:1072:94 | 1072 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_9.rs:1231:94 | 1231 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `MaintenanceStatusEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_9.rs:1390:94 | 1390 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::MaintenanceStatusEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `PIDParametersDataType` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_11.rs:153:94 | 153 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::PIDParametersDataType, value); | ^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `PageEntryDataType` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_11.rs:1438:94 | 1438 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::PageEntryDataType, value); | ^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `ActiveErrorDataType` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_11.rs:1496:94 | 1496 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::ActiveErrorDataType, value); | ^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` error[E0599]: no variant or associated item named `OperatingModeEnumeration` found for type `opcua_types::node_ids::DataTypeId` in the current scope --> server/src/address_space/generated/nodeset_82_12.rs:149:94 | 149 | let mut node = Variable::new_data_value(&node_id, browse_name, display_name, DataTypeId::OperatingModeEnumeration, value); | ^^^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `opcua_types::node_ids::DataTypeId` ```
evanjs commented 4 years ago

Ah, I'm assuming this might be related to EUROMAP providing XSD, not BSD types.

https://github.com/open62541/open62541/issues/2784 https://github.com/open62541/open62541/issues/2868 https://github.com/open62541/open62541/issues/2587

locka99 commented 4 years ago

I updated the gen_nodeset.js so you can do something like this and it compiles:

node gen_nodeset.js --nodeset Opc_Ua.EUROMAP83.NodeSet2.xml --module euromap83 --ns 3

Where --ns 3 sets the namespace index used when it generates all the node ids. Note that you should ensure the --ns arg value is the same as as returned by AddressSpace::register_namespace();

For this example you must do something like this in your own code:

mod euromap83;

//...

   let address_space = server.address_space();

    // The address space is guarded so obtain a lock to change it
    {
        let mut address_space = address_space.write().unwrap();
        let ns_idx = address_space.register_namespace("http://www.euromap.org/euromap83/");
        assert_eq!(ns_idx, 3); // Should match the code you generated!
        euromap83::populate_address_space(&mut address_space);
    }

I can't say if I perfectly generate everything in the schema but it does populate values.

evanjs commented 4 years ago

2020-02-26_14:41:27 Woo!

    ObjectBuilder::new(&machine_id, "conair", "conair")
      .organized_by(thermolator_folder_id.clone())
      .has_component(machine_type_id())
      .has_type_definition(machine_type_id())
      .insert(&mut address_space);

has_component(type_id) is what I needed that was throwing me off. Looks great, now. Thank you!

evanjs commented 4 years ago

Closed by 82e9f8e7e591a95b9b3725c6483da80854fd0467

amit009999 commented 7 months ago

hello, I want to browse only object node from opc server address space window in which object, type, view node is available inside root folder. I want to browse this object in node js. if anyone has done similar type of task, please share the code snippet. i am using node-opcua library from npm.