convertersystems / opc-ua-client

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

How to change value to a node #258

Closed techvoipit closed 10 months ago

techvoipit commented 1 year ago

Hi, i would like to change values to nodes, i have a look to sample code but i didn't find anything can you please publish a sample code how I can do it ?

ismdiego commented 1 year ago

Hi @techvoipit. If I understand you well, you are asking for a sample code to write values, like the sample code on main page is prepared to read values.

If this is what you need, I have prepared a sample code for you. I have refactored the main sample code into smaller methods to increase readability. And also this code should be considered as learning material only (not production ready as-is).

The sample is prepared to:

You can adapt it to other node types simply modifying the code in Main method. I hope you can find it useful enough.

Don't forget to add your server data here at the beginning:

const string endpointUrl = "<your OPC UA endpoint>";
const string nodeId = "<a bool node id (for this sample)>";

Read-Write sample code:

using Workstation.ServiceModel.Ua;
using Workstation.ServiceModel.Ua.Channels;

namespace WriteNodeTest
{
    internal static class Program
    {
        public static async Task Main(string[] args)
        {
            const string endpointUrl = "<your OPC UA endpoint>";
            const string nodeId = "<a bool node id (for this sample)>";
            var channel = GetAnonymousChannel(endpointUrl);

            bool nodeValue = false;
            bool newNodeValue = false;

            try
            {
                await channel.OpenAsync();

                nodeValue = await ReadNodeValue<bool>(channel, nodeId);
                await WriteNodeValue(channel, nodeId, !nodeValue);
                newNodeValue = await ReadNodeValue<bool>(channel, nodeId);

                await channel.CloseAsync();
            }
            catch (Exception ex)
            {
                await channel.AbortAsync();
                Console.WriteLine(ex.Message);
            }

            Console.WriteLine($"First value was {nodeValue} and now is {newNodeValue}");
        }

        private static async Task WriteNodeValue<T>(ClientSessionChannel channel, string nodeId, T newNodeValue)
        {
            var writeRequest = new WriteRequest
            {
                NodesToWrite = new[]
                {
                    new WriteValue
                    {
                        NodeId = NodeId.Parse(nodeId),
                        AttributeId = AttributeIds.Value,
                        Value = new DataValue(newNodeValue)
                    }
                }
            };

            await channel.WriteAsync(writeRequest);
        }

        private static async Task<T> ReadNodeValue<T>(ClientSessionChannel channel, string nodeId)
        {
            var readRequest = new ReadRequest
            {
                NodesToRead = new[] {
                    new ReadValueId
                    {
                        NodeId = NodeId.Parse(nodeId),
                        AttributeId = AttributeIds.Value
                    }
                }
            };

            var readResult = await channel.ReadAsync(readRequest);

            return readResult.Results[0].GetValueOrDefault<T>();
        }

        private static ClientSessionChannel GetAnonymousChannel(string endpointUrl)
        {
            var clientDescription = GetClientDescription();

            // create a 'ClientSessionChannel', a client-side channel that opens a 'session' with the server.
            return new ClientSessionChannel(
                clientDescription,
                null, // no x509 certificates
                new AnonymousIdentity(), // no user identity
                endpointUrl,
                SecurityPolicyUris.None); // no encryption
        }

        private static ApplicationDescription GetClientDescription()
        {
            // describe this client application.
            return new ApplicationDescription
            {
                ApplicationName = "Workstation.UaClient.FeatureTests",
                ApplicationUri = $"urn:{System.Net.Dns.GetHostName()}:Workstation.UaClient.FeatureTests",
                ApplicationType = ApplicationType.Client
            };
        }
    }
}
techvoipit commented 12 months ago

Hi @ismdiego, thank you for the code I tried (at the moment I can play only with int) the procedure is working (no errors) but value is not updated this is my code:

    public async Task<string> scriviAsync(ClientSessionChannel channel, string nodo, string valorenodo)
    {
        val = null;
        if (channel == null)
        {
            // Canale non inizializzato, gestire l'errore.
            Console.WriteLine("Errore: Canale non inizializzato.");
            return val;
        }
        var writeRequest = new WriteRequest
        {
            NodesToWrite = new[]
           {
                new WriteValue
                {
                    NodeId = NodeId.Parse(nodo),
                    AttributeId = AttributeIds.Value,
                    Value = new DataValue(valorenodo)
                }
            }
        };
        try
        {
            await channel.WriteAsync(writeRequest);
        }
        catch (Exception ex)
        {
            await channel.AbortAsync();
            Console.WriteLine(ex.Message);
        }
        return val;
    }
ismdiego commented 12 months ago

@techvoipit you say "(at the moment I can play only with int)", but I see that here "valorenodo" is defined as string, not int. Maybe this is the problem you are having?

public async Task<string> scriviAsync(
   ClientSessionChannel channel,
   string nodo, 
   string valorenodo)
...
Value = new DataValue(valorenodo)

Try changing valorenodo to int and see what happens.

And other question, can you read the value with the provided channel and/or nodeId?