convertersystems / opc-ua-client

Visualize and control your enterprise using OPC Unified Architecture (OPC UA) and Visual Studio.
MIT License
403 stars 119 forks source link

Write Array to node #183

Closed djonasdev closed 3 years ago

djonasdev commented 3 years ago

Actually I'm able to successfully read a complex structure (To do so I have to use the following hack: https://github.com/convertersystems/opc-ua-client/issues/179).

If I now try to write the list/array of Structure back to the Node, I get a Type not supported exception.

Would it be possible to show me an example of how to write an array on a node or an a specific index?

djonasdev commented 3 years ago

My workaround to write the array on by one fails due to the following OPC error:

OPC_BAD_INTERNAL_ERROR - An internal error occurred as a result of a programming or configuration error.

My approach was to instantiate each Structure from the array in a new DataValue and then write this individually to the respective Node. In the debug, both sides (read value and value to be written) look the same to me. Unfortunately, I am not getting anywhere here.

Read operation:

grafik

Write operation:

Convert to new DataValue. TypeId is the same as in the read operation grafik

Write to Node[0]

grafik grafik

preview from dataFEED Browser

grafik

awcullen commented 3 years ago

Hi, This test passes using the UnifiedAutomation Cpp test server. Could there be an issue with the RecipeInfoStruct Encode() function?

[Fact]
public async Task StructureTest()
{
    var channel = new UaTcpSessionChannel(
        localDescription,
        certificateStore,
        new AnonymousIdentity(),
        EndpointUrl,
        loggerFactory: loggerFactory);

    await channel.OpenAsync();

    var readRequest = new ReadRequest
    {
        NodesToRead = new[]
        {
        new ReadValueId { AttributeId = AttributeIds.Value, NodeId = NodeId.Parse("ns=2;s=Demo.Static.Arrays.Structure") },
        },
    };

    var readResponse = await channel.ReadAsync(readRequest);
    foreach (var result in readResponse.Results)
    {
        StatusCode.IsGood(result.StatusCode)
            .Should().BeTrue();
    }

    // reading this node returns an array of ExtensionObjects 
    var obj = readResponse.Results[0].Value;

    // create new DataValue for writing.  Most servers reject writing values with timestamps.
    var newValue = new DataValue(obj);

    var writeRequest = new WriteRequest
    {
        NodesToWrite = new[]
        {
        new WriteValue { AttributeId = AttributeIds.Value, NodeId = NodeId.Parse("ns=2;s=Demo.Static.Arrays.Structure"), Value =  newValue},
        },
    };
    var writeResponse = await channel.WriteAsync(writeRequest);
    foreach (var result in writeResponse.Results)
    {
        StatusCode.IsGood(result)
            .Should().BeTrue();
    }

    logger.LogInformation($"Closing session '{channel.SessionId}'.");
    await channel.CloseAsync();
}
djonasdev commented 3 years ago

Thanks for your test! You are right and I had a twist in the encode function. Had two variables swapped in the order .. very annoying. I will probably consider to fork @quinmars https://github.com/quinmars/UaTypeGenerator and adapt it to my needs.