OPC Studio User's Guide and Reference
ReadWriteValue(UADataVariable,UANodeId,Int32,Object) Method
Example 



OpcLabs.ServerOpcUA Assembly > OpcLabs.EasyOpc.UA.NodeSpace Namespace > UADataVariableExtension Class > ReadWriteValue Method : ReadWriteValue(UADataVariable,UANodeId,Int32,Object) Method
The data variable that will be modified and returned.

The value of this parameter cannot be null (Nothing in Visual Basic).

Specifies the OPC UA data type of the variable value. For standard data types, see OpcLabs.EasyOpc.UA.AddressSpace.Standard.UADataTypeIds.

Because the OpcLabs.EasyOpc.UA.AddressSpace.UANodeId has an implicit conversion from System.String, in languages that support implicit conversion operators (such as C# or VB.NET), you can simply use a string (representing the expanded text of the nodeId) in place of this parameter, and the corresponding OPC UA node Id will be constructed automatically. When the implicit conversion operators are not supported (such as with Python.NET), you can use the OpcLabs.EasyOpc.UA.AddressSpace.UANodeId.UANodeId Constructor(String) constructor instead.

The value of this parameter cannot be null (Nothing in Visual Basic).

The array rank (number of dimensions) of the array (or 0 for scalars).
The initial value of the data variable.

The value of this parameter can be null (Nothing in Visual Basic).

Makes the data variable into a read-write register, specifying the data type Id, array rank, and initial value.
Syntax
'Declaration
 
<ExtensionAttribute()>
<NotNullAttribute()>
Public Overloads Shared Function ReadWriteValue( _
   ByVal dataVariable As UADataVariable, _
   ByVal dataTypeId As UANodeId, _
   ByVal arrayRank As Integer, _
   ByVal value As Object _
) As UADataVariable
'Usage
 
Dim dataVariable As UADataVariable
Dim dataTypeId As UANodeId
Dim arrayRank As Integer
Dim value As Object
Dim value As UADataVariable
 
value = UADataVariableExtension.ReadWriteValue(dataVariable, dataTypeId, arrayRank, value)
[Extension()]
[NotNull()]
public static UADataVariable ReadWriteValue( 
   UADataVariable dataVariable,
   UANodeId dataTypeId,
   int arrayRank,
   object value
)
[Extension()]
[NotNull()]
public:
static UADataVariable^ ReadWriteValue( 
   UADataVariable^ dataVariable,
   UANodeId^ dataTypeId,
   int arrayRank,
   Object^ value
) 

Parameters

dataVariable
The data variable that will be modified and returned.

The value of this parameter cannot be null (Nothing in Visual Basic).

dataTypeId
Specifies the OPC UA data type of the variable value. For standard data types, see OpcLabs.EasyOpc.UA.AddressSpace.Standard.UADataTypeIds.

Because the OpcLabs.EasyOpc.UA.AddressSpace.UANodeId has an implicit conversion from System.String, in languages that support implicit conversion operators (such as C# or VB.NET), you can simply use a string (representing the expanded text of the nodeId) in place of this parameter, and the corresponding OPC UA node Id will be constructed automatically. When the implicit conversion operators are not supported (such as with Python.NET), you can use the OpcLabs.EasyOpc.UA.AddressSpace.UANodeId.UANodeId Constructor(String) constructor instead.

The value of this parameter cannot be null (Nothing in Visual Basic).

arrayRank
The array rank (number of dimensions) of the array (or 0 for scalars).
value
The initial value of the data variable.

The value of this parameter can be null (Nothing in Visual Basic).

Return Value

Returns the dataVariable, internally modified as defined by the method.

This method never returns null (Nothing in Visual Basic).

Exceptions
ExceptionDescription

A null reference (Nothing in Visual Basic) is passed to a method that does not accept it as a valid argument.

This is a usage error, i.e. it will never occur (the exception will not be thrown) in a correctly written program. Your code should not catch this exception.

The value of an argument is outside the allowable range of values as defined by the invoked method.

This is a usage error, i.e. it will never occur (the exception will not be thrown) in a correctly written program. Your code should not catch this exception.

Remarks

This is an extension method (info: C#, VB.NET). In languages that have support for extensions methods (such as C# and VB.NET), you can use the extension method as if it were a regular method on the object that is its first parameter. In other languages (such as with Python.NET), you will call the extension as a static method, and pass it the object on which it acts as its first parameter.

Example
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client, server and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-OPCStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using OpcLabs.EasyOpc.UA.AddressSpace.Standard;
using OpcLabs.EasyOpc.UA.NodeSpace;

namespace UAServerDemoLibrary
{
    static public class DataNodes
    {
        /// <summary>
        /// Adds static and dynamic nodes that demonstrate various data types and access levels.
        /// </summary>
        /// <param name="parentFolder">The folder to which to add the nodes.</param>
        static public void AddToParent(UAFolder parentFolder)
        {
            // Create Data folder.
            UAFolder dataFolder = UAFolder.CreateIn(parentFolder, "Data");

            // Create read-only data variables of various data types, without adding them to the server first. We store
            // references to them individually, because we later implement write-only variables that write to these
            // read-only variables.
            UADataVariable booleanReadOnlyDataVariable =
                new UADataVariable("BooleanValue").Writable(false).ValueType<bool>();
            UADataVariable byteStringReadOnlyDataVariable =
                new UADataVariable("ByteStringValue").Writable(false).ValueType<byte[]>();
            UADataVariable byteReadOnlyDataVariable = new UADataVariable("ByteValue").Writable(false).ValueType<byte>();
            UADataVariable dateTimeReadOnlyDataVariable =
                new UADataVariable("DateTimeValue").Writable(false).ValueType<DateTime>();
            UADataVariable doubleReadOnlyDataVariable =
                new UADataVariable("DoubleValue").Writable(false).ValueType<double>();
            UADataVariable floatReadOnlyDataVariable =
                new UADataVariable("FloatValue").Writable(false).ValueType<float>();
            UADataVariable guidReadOnlyDataVariable = new UADataVariable("GuidValue").Writable(false).ValueType<Guid>();
            UADataVariable int16ReadOnlyDataVariable =
                new UADataVariable("Int16Value").Writable(false).ValueType<short>();
            UADataVariable int32ReadOnlyDataVariable =
                new UADataVariable("Int32Value").Writable(false).ValueType<int>();
            UADataVariable int64ReadOnlyDataVariable =
                new UADataVariable("Int64Value").Writable(false).ValueType<long>();
            UADataVariable sByteReadOnlyDataVariable =
                new UADataVariable("SByteValue").Writable(false).ValueType<sbyte>();
            UADataVariable stringReadOnlyDataVariable =
                new UADataVariable("StringValue").Writable(false).ValueType<string>();
            UADataVariable uInt16ReadOnlyDataVariable =
                new UADataVariable("UInt16Value").Writable(false).ValueType<ushort>();
            UADataVariable uInt32ReadOnlyDataVariable =
                new UADataVariable("UInt32Value").Writable(false).ValueType<uint>();
            UADataVariable uInt64ReadOnlyDataVariable =
                new UADataVariable("UInt64Value").Writable(false).ValueType<ulong>();
            UADataVariable variantReadOnlyDataVariable =
                new UADataVariable("VariantValue").Writable(false);

            // Create Constant sub-folder under the Data folder. It contains read-only data variables with constant values.
            dataFolder.Add(
                new UAFolder("Constant")
                {
                    new UAFolder("Scalar")
                    {
                        new UADataVariable("BooleanValue").ConstantValue(true),
                        new UADataVariable("ByteStringValue").ConstantValue(new byte[] { 0x57, 0x21, 0x40, 0xfc }),
                        new UADataVariable("ByteValue").ConstantValue((byte)144),
                        new UADataVariable("DateTimeValue").ConstantValue(
                            // We are passing in UTC times, because we want always the same result, and so we must specify
                            // the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                            // server, and the result will depend on the time zone.
                            DateTime.SpecifyKind(new DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                DateTimeKind.Utc)),
                        new UADataVariable("DoubleValue").ConstantValue(7.75630105797e-011),
                        new UADataVariable("FloatValue").ConstantValue(2.77002e+29f),
                        new UADataVariable("GuidValue").ConstantValue(
                            new Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")),
                        new UADataVariable("Int16Value").ConstantValue((short)-30956),
                        new UADataVariable("Int32Value").ConstantValue(276673160),
                        new UADataVariable("Int64Value").ConstantValue(1412096336825367659),
                        new UADataVariable("SByteValue").ConstantValue((sbyte)-113),
                        new UADataVariable("StringValue").ConstantValue("lorem ipsum"),
                        new UADataVariable("UInt16Value").ConstantValue((ushort)64421),
                        new UADataVariable("UInt32Value").ConstantValue(3853116537U),
                        new UADataVariable("UInt64Value").ConstantValue(9431348106520835314UL),
                        new UADataVariable("VariantValue").ConstantValue(529739609)
                    }
                });

            // Create Dynamic sub-folder under the Data folder. It contains data variables with dynamically changing values.
            dataFolder.Add(
                new UAFolder("Dynamic")
                {
                    new UAFolder("Array")
                    {
                        new UADataVariable("BooleanValue").ReadValueFunction(() => NextRandomArray(NextRandomBoolean)),
                        new UADataVariable("ByteStringValue").ReadValueFunction(() =>
                            NextRandomArray(NextRandomByteString)),
                        // This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                        // OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                        // specified explicitly.
                        new UADataVariable("ByteValue").ReadValueFunction(
                            dataTypeId: UADataTypeIds.Byte,
                            arrayRank: 1,
                            () => NextRandomArray(NextRandomByte)),
                        new UADataVariable("DateTimeValue").ReadValueFunction(() =>
                            NextRandomArray(NextRandomDateTime)),
                        new UADataVariable("DoubleValue").ReadValueFunction(() => NextRandomArray(NextRandomDouble)),
                        new UADataVariable("FloatValue").ReadValueFunction(() => NextRandomArray(NextRandomFloat)),
                        new UADataVariable("GuidValue").ReadValueFunction(() => NextRandomArray(NextRandomGuid)),
                        new UADataVariable("Int16Value").ReadValueFunction(() => NextRandomArray(NextRandomInt16)),
                        new UADataVariable("Int32Value").ReadValueFunction(() => NextRandomArray(NextRandomInt32)),
                        new UADataVariable("Int64Value").ReadValueFunction(() => NextRandomArray(NextRandomInt64)),
                        new UADataVariable("SByteValue").ReadValueFunction(() => NextRandomArray(NextRandomSByte)),
                        new UADataVariable("StringValue").ReadValueFunction(() => NextRandomArray(NextRandomString)),
                        new UADataVariable("UInt16Value").ReadValueFunction(() => NextRandomArray(NextRandomUInt16)),
                        new UADataVariable("UInt32Value").ReadValueFunction(() => NextRandomArray(NextRandomUInt32)),
                        new UADataVariable("UInt64Value").ReadValueFunction(() => NextRandomArray(NextRandomUInt64)),
                        new UADataVariable("VariantValue").ReadValueFunction(() => NextRandomArray(NextRandomVariant))
                    },

                    new UAFolder("Scalar")
                    {
                        new UADataVariable("BooleanValue").ReadValueFunction(NextRandomBoolean),
                        new UADataVariable("ByteStringValue").ReadValueFunction(NextRandomByteString),
                        new UADataVariable("ByteValue").ReadValueFunction(NextRandomByte),
                        new UADataVariable("DateTimeValue").ReadValueFunction(NextRandomDateTime),
                        new UADataVariable("DoubleValue").ReadValueFunction(NextRandomDouble),
                        new UADataVariable("FloatValue").ReadValueFunction(NextRandomFloat),
                        new UADataVariable("GuidValue").ReadValueFunction(NextRandomGuid),
                        new UADataVariable("Int16Value").ReadValueFunction(NextRandomInt16),
                        new UADataVariable("Int32Value").ReadValueFunction(NextRandomInt32),
                        new UADataVariable("Int64Value").ReadValueFunction(NextRandomInt64),
                        new UADataVariable("SByteValue").ReadValueFunction(NextRandomSByte),
                        new UADataVariable("StringValue").ReadValueFunction(NextRandomString),
                        new UADataVariable("UInt16Value").ReadValueFunction(NextRandomUInt16),
                        new UADataVariable("UInt32Value").ReadValueFunction(NextRandomUInt32),
                        new UADataVariable("UInt64Value").ReadValueFunction(NextRandomUInt64),
                        new UADataVariable("VariantValue").ReadValueFunction(NextRandomVariant)
                    }
                });

            // The FullyWritable sub-folder contains data variables that have not only writable value, but also writable
            // source timestamp and status code.
            dataFolder.Add(
                new UAFolder("FullyWritable")
                {
                    new UAFolder("Scalar")
                    {
                        new UADataVariable("BooleanValue").ReadWriteValue(true)
                            .Writable(true, true, true),
                        new UADataVariable("ByteStringValue").ReadWriteValue(new byte[] { 0x57, 0x21, 0x40, 0xfc })
                            .Writable(true, true, true),
                        new UADataVariable("ByteValue").ReadWriteValue((byte)144)
                            .Writable(true, true, true),
                        new UADataVariable("DateTimeValue").ReadWriteValue(
                                // We are passing in UTC times, because we want always the same result, and so we must specify
                                // the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                                // server, and the result will depend on the time zone.
                                DateTime.SpecifyKind(new DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                    DateTimeKind.Utc))
                            .Writable(true, true, true),
                        new UADataVariable("DoubleValue").ReadWriteValue(7.75630105797e-011)
                            .Writable(true, true, true),
                        new UADataVariable("FloatValue").ReadWriteValue(2.77002e+29f)
                            .Writable(true, true, true),
                        new UADataVariable("GuidValue")
                            .ReadWriteValue(new Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}"))
                            .Writable(true, true, true),
                        new UADataVariable("Int16Value").ReadWriteValue((short)-30956)
                            .Writable(true, true, true),
                        new UADataVariable("Int32Value").ReadWriteValue(276673160)
                            .Writable(true, true, true),
                        new UADataVariable("Int64Value").ReadWriteValue(1412096336825367659)
                            .Writable(true, true, true),
                        new UADataVariable("SByteValue").ReadWriteValue((sbyte)-113)
                            .Writable(true, true, true),
                        new UADataVariable("StringValue").ReadWriteValue("lorem ipsum")
                            .Writable(true, true, true),
                        new UADataVariable("UInt16Value").ReadWriteValue((ushort)64421)
                            .Writable(true, true, true),
                        new UADataVariable("UInt32Value").ReadWriteValue(3853116537U)
                            .Writable(true, true, true),
                        new UADataVariable("UInt64Value").ReadWriteValue(9431348106520835314UL)
                            .Writable(true, true, true),
                        new UADataVariable("VariantValue").ReadWriteValue(529739609)
                            .Writable(true, true, true)
                    }
                });

            // The ReadOnly sub-folder contains data variables that are read-only, and their values can be changed through
            // corresponding data variables in the WriteOnly sub-folder.
            dataFolder.Add(
                new UAFolder("ReadOnly")
                {
                    new UAFolder("Scalar")
                    {
                        booleanReadOnlyDataVariable,
                        byteStringReadOnlyDataVariable,
                        byteReadOnlyDataVariable,
                        dateTimeReadOnlyDataVariable,
                        doubleReadOnlyDataVariable,
                        floatReadOnlyDataVariable,
                        guidReadOnlyDataVariable,
                        int16ReadOnlyDataVariable,
                        int32ReadOnlyDataVariable,
                        int64ReadOnlyDataVariable,
                        sByteReadOnlyDataVariable,
                        stringReadOnlyDataVariable,
                        uInt16ReadOnlyDataVariable,
                        uInt32ReadOnlyDataVariable,
                        uInt64ReadOnlyDataVariable,
                        variantReadOnlyDataVariable
                    }
                });

            // The Static sub-folder contains data variables with static values which can be changed through writing to
            // them (so-called "registers").
            dataFolder.Add(
                new UAFolder("Static")
                {
                    // For demonstration, we consistently create one-dimensional arrays with initially 3 elements, where the
                    // first element has the same value as the scalar variable with the same name.
                    new UAFolder("Array")
                    {
                        new UADataVariable("BooleanValue").ReadWriteValue(new[]
                        {
                            true,
                            false,
                            true
                        }),
                        new UADataVariable("ByteStringValue").ReadWriteValue(new[]
                        {
                            new byte[] { 0x57, 0x21, 0x40, 0xfc },
                            new byte[] { 248, 131, 217, 210 },
                            new byte[] { 252, 152, 119, 65 }
                        }),
                        // This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                        // OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                        // specified explicitly.
                        new UADataVariable("ByteValue").ReadWriteValue(
                            dataTypeId: UADataTypeIds.Byte,
                            arrayRank: 1,
                            value: new byte[]
                            {
                                144,
                                19,
                                233
                            }),
                        new UADataVariable("DateTimeValue").ReadWriteValue(new[]
                        {
                            // We are passing in UTC times, because we want always the same result, and so we must specify
                            // the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                            // server, and the result will depend on the time zone.
                            DateTime.SpecifyKind(new DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                DateTimeKind.Utc),
                            DateTime.SpecifyKind(new DateTime(2024, 4, 8), DateTimeKind.Utc),
                            DateTime.SpecifyKind(new DateTime(2023, 8, 14, 18, 13, 0), DateTimeKind.Utc)
                        }),
                        new UADataVariable("DoubleValue").ReadWriteValue(new[]
                        {
                            7.75630105797e-011,
                            -0.467227097818268,
                            -3.51653052582609E+300
                        }),
                        new UADataVariable("FloatValue").ReadWriteValue(new[]
                        {
                            2.77002e+29f,
                            -1.103936E+36f,
                            -9.002293E-28f
                        }),
                        new UADataVariable("GuidValue").ReadWriteValue(new[]
                        {
                            new Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}"),
                            new Guid("{E8690EA3-25D0-4F19-9DFC-AA25D2772B2F}"),
                            new Guid("{9E081C84-7953-4A88-B709-447FC187EDD9}"),
                        }),
                        new UADataVariable("Int16Value").ReadWriteValue(new short[]
                        {
                            -30956,
                            31277,
                            21977
                        }),
                        new UADataVariable("Int32Value").ReadWriteValue(new[]
                        {
                            276673160,
                            630080334,
                            -391755284
                        }),
                        new UADataVariable("Int64Value").ReadWriteValue(new[]
                        {
                            1412096336825367659,
                            -808781653700434592,
                            4707848393174903135
                        }),
                        new UADataVariable("SByteValue").ReadWriteValue(new sbyte[]
                        {
                            -113,
                            -92,
                            2
                        }),
                        new UADataVariable("StringValue").ReadWriteValue(new[]
                        {
                            "lorem ipsum",
                            "dolor sit amet",
                            "consectetur adipiscing elit"
                        }),
                        new UADataVariable("UInt16Value").ReadWriteValue(new ushort[]
                        {
                            64421,
                            22663,
                            36755
                        }),
                        new UADataVariable("UInt32Value").ReadWriteValue(new uint[]
                        {
                            3853116537,
                            968679231,
                            995611904
                        }),
                        new UADataVariable("UInt64Value").ReadWriteValue(new ulong[]
                        {
                            9431348106520835314,
                            15635738044048254300,
                            946287779964705249
                        }),
                        new UADataVariable("VariantValue").ReadWriteValue(new object[]
                        {
                            529739609,
                            "lorem ipsum",
                            new Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")
                        })
                    },

                    // We create 2-dimensional arrays with 4x3 size, and default element values.
                    new UAFolder("Array2D")
                    {
                        new UADataVariable("BooleanValue").ReadWriteValue(new bool[4, 3]),
                        new UADataVariable("ByteStringValue").ReadWriteValue(new byte[4, 3][]),
                        new UADataVariable("ByteValue").ReadWriteValue(new byte[4, 3]),
                        new UADataVariable("DateTimeValue").ReadWriteValue(new DateTime[4, 3]),
                        new UADataVariable("DoubleValue").ReadWriteValue(new double[4, 3]),
                        new UADataVariable("FloatValue").ReadWriteValue(new float[4, 3]),
                        new UADataVariable("GuidValue").ReadWriteValue(new Guid[4, 3]),
                        new UADataVariable("Int16Value").ReadWriteValue(new short[4, 3]),
                        new UADataVariable("Int32Value").ReadWriteValue(new int[4, 3]),
                        new UADataVariable("Int64Value").ReadWriteValue(new long[4, 3]),
                        new UADataVariable("SByteValue").ReadWriteValue(new sbyte[4, 3]),
                        new UADataVariable("StringValue").ReadWriteValue(new string[4, 3]),
                        new UADataVariable("UInt16Value").ReadWriteValue(new ushort[4, 3]),
                        new UADataVariable("UInt32Value").ReadWriteValue(new uint[4, 3]),
                        new UADataVariable("UInt64Value").ReadWriteValue(new ulong[4, 3]),
                        new UADataVariable("VariantValue").ReadWriteValue(new object[4, 3])
                    },

                    // Array nodes with specified and enforced maximum array dimensions.
                    new UAFolder("BoundedArray")
                    {
                        new UADataVariable("BooleanValue").ReadWriteValue(new bool[4], arrayDimensions: 5),
                        new UADataVariable("ByteStringValue").ReadWriteValue(new byte[4][], arrayDimensions: 5),
                        // This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                        // OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                        // specified explicitly.
                        new UADataVariable("ByteValue").ReadWriteValue(
                            dataTypeId: UADataTypeIds.Byte,
                            arrayDimensionList: new[] { 5 },
                            new byte[4]),
                        new UADataVariable("DateTimeValue").ReadWriteValue(new DateTime[4], arrayDimensions: 5),
                        new UADataVariable("DoubleValue").ReadWriteValue(new double[4], arrayDimensions: 5),
                        new UADataVariable("FloatValue").ReadWriteValue(new float[4], arrayDimensions: 5),
                        new UADataVariable("GuidValue").ReadWriteValue(new Guid[4], arrayDimensions: 5),
                        new UADataVariable("Int16Value").ReadWriteValue(new short[4], arrayDimensions: 5),
                        new UADataVariable("Int32Value").ReadWriteValue(new int[4], arrayDimensions: 5),
                        new UADataVariable("Int64Value").ReadWriteValue(new long[4], arrayDimensions: 5),
                        new UADataVariable("SByteValue").ReadWriteValue(new sbyte[4], arrayDimensions: 5),
                        new UADataVariable("StringValue").ReadWriteValue(new string[4], arrayDimensions: 5),
                        new UADataVariable("UInt16Value").ReadWriteValue(new ushort[4], arrayDimensions: 5),
                        new UADataVariable("UInt32Value").ReadWriteValue(new uint[4], arrayDimensions: 5),
                        new UADataVariable("UInt64Value").ReadWriteValue(new ulong[4], arrayDimensions: 5),
                        new UADataVariable("VariantValue").ReadWriteValue(new object[4], arrayDimensions: 5)
                    },

                    new UAFolder("Scalar")
                    {
                        new UADataVariable("BooleanValue").ReadWriteValue(true),
                        new UADataVariable("ByteStringValue").ReadWriteValue(new byte[] { 0x57, 0x21, 0x40, 0xfc }),
                        new UADataVariable("ByteValue").ReadWriteValue((byte)144),
                        new UADataVariable("DateTimeValue").ReadWriteValue(
                            // We are passing in UTC times, because we want always the same result, and so we must specify
                            // the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                            // server, and the result will depend on the time zone.
                            DateTime.SpecifyKind(new DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                DateTimeKind.Utc)),
                        new UADataVariable("DoubleValue").ReadWriteValue(7.75630105797e-011),
                        new UADataVariable("FloatValue").ReadWriteValue(2.77002e+29f),
                        new UADataVariable("GuidValue").ReadWriteValue(
                            new Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")),
                        new UADataVariable("Int16Value").ReadWriteValue((short)-30956),
                        new UADataVariable("Int32Value").ReadWriteValue(276673160),
                        new UADataVariable("Int64Value").ReadWriteValue(1412096336825367659),
                        new UADataVariable("SByteValue").ReadWriteValue((sbyte)-113),
                        new UADataVariable("StringValue").ReadWriteValue("lorem ipsum"),
                        new UADataVariable("UInt16Value").ReadWriteValue((ushort)64421),
                        new UADataVariable("UInt32Value").ReadWriteValue(3853116537U),
                        new UADataVariable("UInt64Value").ReadWriteValue(9431348106520835314UL),
                        new UADataVariable("VariantValue").ReadWriteValue(529739609)
                    }
                });

            // Create and add write-only data variables of various data types. Implement write actions that write the value
            // to the corresponding read-only data variable of the same data type.
            dataFolder.Add(
                new UAFolder("WriteOnly")
                {
                    new UAFolder("Scalar")
                    {
                        new UADataVariable("BooleanValue").Readable(false).WriteValueAction((bool value) =>
                            booleanReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("ByteStringValue").Readable(false).WriteValueAction((byte[] value) =>
                            byteStringReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("ByteValue").Readable(false).WriteValueAction((byte value) =>
                            byteReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("DateTimeValue").Readable(false).WriteValueAction((DateTime value) =>
                            dateTimeReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("DoubleValue").Readable(false).WriteValueAction((double value) =>
                            doubleReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("FloatValue").Readable(false).WriteValueAction((float value) =>
                            floatReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("GuidValue").Readable(false).WriteValueAction((Guid value) =>
                            guidReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("Int16Value").Readable(false).WriteValueAction((short value) =>
                            int16ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("Int32Value").Readable(false).WriteValueAction((int value) =>
                            int32ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("Int64Value").Readable(false).WriteValueAction((long value) =>
                            int64ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("SByteValue").Readable(false).WriteValueAction((sbyte value) =>
                            sByteReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("StringValue").Readable(false).WriteValueAction((string value) =>
                            stringReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("UInt16Value").Readable(false).WriteValueAction((ushort value) =>
                            uInt16ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("UInt32Value").Readable(false).WriteValueAction((uint value) =>
                            uInt32ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("UInt64Value").Readable(false).WriteValueAction((ulong value) =>
                            uInt64ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("VariantValue").Readable(false).WriteValueAction((object value) =>
                            variantReadOnlyDataVariable.UpdateReadAttributeData(value))
                    }
                });
        }


        // Random value generators.

        static private readonly Random Random = new Random();

        static private readonly string[] RandomStrings = new[] { "lorem", "ipsum", "dolor", "sit", "amet" };

        static private T[] NextRandomArray<T>(Func<T> nextRandomElement) =>
            new[] { nextRandomElement(), nextRandomElement(), nextRandomElement() };

        static private bool NextRandomBoolean() => Random.Next(2) != 0;

        static private byte NextRandomByte() => (byte)Random.Next(byte.MinValue, byte.MaxValue + 1);

        static private byte[] NextRandomByteString() =>
            new[] { NextRandomByte(), NextRandomByte(), NextRandomByte(), NextRandomByte() };

        static private DateTime NextRandomDateTime() =>
            DateTime.MinValue.AddMilliseconds((DateTime.MaxValue - DateTime.MinValue).TotalMilliseconds *
                                              Random.NextDouble());

        static private float NextRandomFloat() =>
            (float)Math.Pow(10, Math.Log10(float.MaxValue) * Random.NextDouble()) * (2 * Random.Next(2) - 1);

        static private double NextRandomDouble() =>
            Math.Pow(10, Math.Log10(double.MaxValue) * Random.NextDouble()) * (2 * Random.Next(2) - 1);

        static private Guid NextRandomGuid() => Guid.NewGuid();

        static private short NextRandomInt16() => (short)Random.Next(short.MinValue, short.MaxValue + 1);

        static private int NextRandomInt32()
        {
            byte[] buffer = new byte[4];
            Random.NextBytes(buffer);
            return BitConverter.ToInt32(buffer, 0);
        }

        static private long NextRandomInt64()
        {
            byte[] buffer = new byte[8];
            Random.NextBytes(buffer);
            return BitConverter.ToInt64(buffer, 0);
        }

        static private sbyte NextRandomSByte() => (sbyte)Random.Next(sbyte.MinValue, sbyte.MaxValue + 1);

        static private string NextRandomString() => RandomStrings[Random.Next(RandomStrings.Length)];

        static private ushort NextRandomUInt16() => (ushort)Random.Next(ushort.MinValue, ushort.MaxValue + 1);

        static private uint NextRandomUInt32()
        {
            byte[] buffer = new byte[4];
            Random.NextBytes(buffer);
            return BitConverter.ToUInt32(buffer, 0);
        }

        static private ulong NextRandomUInt64()
        {
            byte[] buffer = new byte[8];
            Random.NextBytes(buffer);
            return BitConverter.ToUInt64(buffer, 0);
        }

        static private object NextRandomVariant()
        {
            switch (Random.Next(15))
            {
                case 0:
                    return NextRandomBoolean();
                case 1:
                    return NextRandomByteString();
                case 2:
                    return NextRandomByte();
                case 3:
                    return NextRandomDateTime();
                case 4:
                    return NextRandomDouble();
                case 5:
                    return NextRandomFloat();
                case 6:
                    return NextRandomGuid();
                case 7:
                    return NextRandomInt16();
                case 8:
                    return NextRandomInt32();
                case 9:
                    return NextRandomInt64();
                case 10:
                    return NextRandomSByte();
                case 11:
                    return NextRandomString();
                case 12:
                    return NextRandomUInt16();
                case 13:
                    return NextRandomUInt32();
                case 14:
                    return NextRandomUInt64();
                default:
                    return null;
            }
        }
    }
}
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports System
Imports System.Reactive
Imports Newtonsoft.Json.Linq
Imports OpcLabs.EasyOpc.AlarmsAndEvents.Engine
Imports OpcLabs.EasyOpc.UA.AddressSpace.Standard
Imports OpcLabs.EasyOpc.UA.NodeSpace

'Namespace UAServerDemoLibrary
Public Module DataNodes
        ''' <summary>
        ''' Adds static and dynamic nodes that demonstrate various data types and access levels.
        ''' </summary>
        ''' <param name="parentFolder">The folder to which to add the nodes.</param>
        Sub AddToParent(parentFolder As UAFolder)
            ' Create Data folder.
            Dim dataFolder = UAFolder.CreateIn(parentFolder, "Data")

            ' Create read-only data variables of various data types, without adding them to the server first. We store
            ' references to them individually, because we later implement write-only variables that write to these
            ' read-only variables.
            Dim booleanReadOnlyDataVariable As UADataVariable =
                New UADataVariable("BooleanValue").Writable(False).ValueType(Of Boolean)()
            Dim byteStringReadOnlyDataVariable As UADataVariable =
                New UADataVariable("ByteStringValue").Writable(False).ValueType(Of Byte())()
            Dim byteReadOnlyDataVariable As UADataVariable = New UADataVariable("ByteValue").Writable(False).ValueType(Of Byte)()
            Dim dateTimeReadOnlyDataVariable As UADataVariable =
                New UADataVariable("DateTimeValue").Writable(False).ValueType(Of DateTime)()
            Dim doubleReadOnlyDataVariable As UADataVariable =
                New UADataVariable("DoubleValue").Writable(False).ValueType(Of Double)()
            Dim floatReadOnlyDataVariable As UADataVariable =
                New UADataVariable("FloatValue").Writable(False).ValueType(Of Single)()
            Dim guidReadOnlyDataVariable As UADataVariable = New UADataVariable("GuidValue").Writable(False).ValueType(Of Guid)()
            Dim int16ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("Int16Value").Writable(False).ValueType(Of Short)()
        Dim int32ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("Int32Value").Writable(False).ValueType(Of Integer)()
        Dim int64ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("Int64Value").Writable(False).ValueType(Of Long)()
            Dim sByteReadOnlyDataVariable As UADataVariable =
                New UADataVariable("SByteValue").Writable(False).ValueType(Of SByte)()
            Dim stringReadOnlyDataVariable As UADataVariable =
                New UADataVariable("StringValue").Writable(False).ValueType(Of String)()
            Dim uInt16ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("UInt16Value").Writable(False).ValueType(Of UShort)()
            Dim uInt32ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("UInt32Value").Writable(False).ValueType(Of UInteger)()
            Dim uInt64ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("UInt64Value").Writable(False).ValueType(Of ULong)()
            Dim variantReadOnlyDataVariable As UADataVariable =
                New UADataVariable("VariantValue").Writable(False)

            ' Create Constant sub-folder under the Data folder. It contains read-only data variables with constant values.
            dataFolder.Add(
                New UAFolder("Constant") From
                {
                    New UAFolder("Scalar") From
                    {
                        New UADataVariable("BooleanValue").ConstantValue(True),
                        New UADataVariable("ByteStringValue").ConstantValue(New Byte() {&H57, &H21, &H40, &HFC}),
                        New UADataVariable("ByteValue").ConstantValue(CType(144, Byte)) _
                        , _ ' We are passing In UTC times, because we want always the same result, And so we must specify
                          _ ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                          _ ' server, And the result will depend on the time zone.
                        New UADataVariable("DateTimeValue").ConstantValue(
                            DateTime.SpecifyKind(New DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                            DateTimeKind.Utc)), _
                                                _
                        New UADataVariable("DoubleValue").ConstantValue(0.0000000000775630105797),
                        New UADataVariable("FloatValue").ConstantValue(2.77002E+29F),
                        New UADataVariable("GuidValue").ConstantValue(
                            New Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")),
                        New UADataVariable("Int16Value").ConstantValue(CType(-30956, Short)),
                        New UADataVariable("Int32Value").ConstantValue(276673160),
                        New UADataVariable("Int64Value").ConstantValue(1412096336825367659),
                        New UADataVariable("SByteValue").ConstantValue(CType(-113, SByte)),
                        New UADataVariable("StringValue").ConstantValue("lorem ipsum"),
                        New UADataVariable("UInt16Value").ConstantValue(CType(64421, UShort)),
                        New UADataVariable("UInt32Value").ConstantValue(3853116537UI),
                        New UADataVariable("UInt64Value").ConstantValue(9431348106520835314UL),
                        New UADataVariable("VariantValue").ConstantValue(529739609)
                    }
                })

            ' Create Dynamic sub-folder under the Data folder. It contains data variables with dynamically changing values.

            ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
            ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
            ' specified explicitly.

            dataFolder.Add(
                New UAFolder("Dynamic") From
                {
                    New UAFolder("Array") From
                    {
                        New UADataVariable("BooleanValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomBoolean)),
                        New UADataVariable("ByteStringValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomByteString)) _
                        , _ ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                          _ ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                          _ ' specified explicitly.
                        New UADataVariable("ByteValue").ReadValueFunction(
                            dataTypeId:=UADataTypeIds.Byte,
                            arrayRank:=1,
                            Function() NextRandomArray(AddressOf NextRandomByte)),
                        New UADataVariable("DateTimeValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomDateTime)),
                        New UADataVariable("DoubleValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomDouble)),
                        New UADataVariable("FloatValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomFloat)),
                        New UADataVariable("GuidValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomGuid)),
                        New UADataVariable("Int16Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomInt16)),
                        New UADataVariable("Int32Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomInt32)),
                        New UADataVariable("Int64Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomInt64)),
                        New UADataVariable("SByteValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomSByte)),
                        New UADataVariable("StringValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomString)),
                        New UADataVariable("UInt16Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomUInt16)),
                        New UADataVariable("UInt32Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomUInt32)),
                        New UADataVariable("UInt64Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomUInt64)),
                        New UADataVariable("VariantValue").ReadValueFunction(Function() NextRandomArray(NextRandomVariant))
                    },
                    New UAFolder("Scalar") From
                    {
                        New UADataVariable("BooleanValue").ReadValueFunction(AddressOf NextRandomBoolean),
                        New UADataVariable("ByteStringValue").ReadValueFunction(AddressOf NextRandomByteString),
                        New UADataVariable("ByteValue").ReadValueFunction(AddressOf NextRandomByte),
                        New UADataVariable("DateTimeValue").ReadValueFunction(AddressOf NextRandomDateTime),
                        New UADataVariable("DoubleValue").ReadValueFunction(AddressOf NextRandomDouble),
                        New UADataVariable("FloatValue").ReadValueFunction(AddressOf NextRandomFloat),
                        New UADataVariable("GuidValue").ReadValueFunction(AddressOf NextRandomGuid),
                        New UADataVariable("Int16Value").ReadValueFunction(AddressOf NextRandomInt16),
                        New UADataVariable("Int32Value").ReadValueFunction(AddressOf NextRandomInt32),
                        New UADataVariable("Int64Value").ReadValueFunction(AddressOf NextRandomInt64),
                        New UADataVariable("SByteValue").ReadValueFunction(AddressOf NextRandomSByte),
                        New UADataVariable("StringValue").ReadValueFunction(AddressOf NextRandomString),
                        New UADataVariable("UInt16Value").ReadValueFunction(AddressOf NextRandomUInt16),
                        New UADataVariable("UInt32Value").ReadValueFunction(AddressOf NextRandomUInt32),
                        New UADataVariable("UInt64Value").ReadValueFunction(AddressOf NextRandomUInt64),
                        New UADataVariable("VariantValue").ReadValueFunction(AddressOf NextRandomVariant)
                    }
                })

            ' The FullyWritable sub-folder contains data variables that have not only writable value, but also writable
            ' source timestamp and status code.
            dataFolder.Add(
                New UAFolder("FullyWritable") From
                {
                    New UAFolder("Scalar") From
                    {
                        New UADataVariable("BooleanValue").ReadWriteValue(True) _
                            .Writable(True, True, True),
                        New UADataVariable("ByteStringValue").ReadWriteValue(New Byte() {&H57, &H21, &H40, &HFC}) _
                            .Writable(True, True, True),
                        New UADataVariable("ByteValue").ReadWriteValue(CType(144, Byte)) _
                            .Writable(True, True, True) _
                             , _ ' We are passing in UTC times, because we want always the same result, and so we must specify
                               _ ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                               _ ' server, and the result will depend on the time zone.
                        New UADataVariable("DateTimeValue").ReadWriteValue(
                                DateTime.SpecifyKind(New DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                    DateTimeKind.Utc)) _
                            .Writable(True, True, True),
                        New UADataVariable("DoubleValue").ReadWriteValue(0.0000000000775630105797) _
                            .Writable(True, True, True),
                        New UADataVariable("FloatValue").ReadWriteValue(2.77002E+29F) _
                            .Writable(True, True, True),
                        New UADataVariable("GuidValue") _
                            .ReadWriteValue(New Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")) _
                            .Writable(True, True, True),
                        New UADataVariable("Int16Value").ReadWriteValue(CType(-30956, Short)) _
                            .Writable(True, True, True),
                        New UADataVariable("Int32Value").ReadWriteValue(276673160) _
                            .Writable(True, True, True),
                        New UADataVariable("Int64Value").ReadWriteValue(1412096336825367659) _
                            .Writable(True, True, True),
                        New UADataVariable("SByteValue").ReadWriteValue(CType(-113, SByte)) _
                            .Writable(True, True, True),
                        New UADataVariable("StringValue").ReadWriteValue("lorem ipsum") _
                            .Writable(True, True, True),
                        New UADataVariable("UInt16Value").ReadWriteValue(CType(64421, UShort)) _
                            .Writable(True, True, True),
                        New UADataVariable("UInt32Value").ReadWriteValue(3853116537UI) _
                            .Writable(True, True, True),
                        New UADataVariable("UInt64Value").ReadWriteValue(9431348106520835314UL) _
                            .Writable(True, True, True),
                        New UADataVariable("VariantValue").ReadWriteValue(529739609) _
                            .Writable(True, True, True)
                    }
                })

            ' The ReadOnly sub-folder contains data variables that are read-only, and their values can be changed through
            ' corresponding data variables in the WriteOnly sub-folder.
            dataFolder.Add(
                New UAFolder("ReadOnly") From
                {
                    New UAFolder("Scalar") From
                    {
                        booleanReadOnlyDataVariable,
                        byteStringReadOnlyDataVariable,
                        byteReadOnlyDataVariable,
                        dateTimeReadOnlyDataVariable,
                        doubleReadOnlyDataVariable,
                        floatReadOnlyDataVariable,
                        guidReadOnlyDataVariable,
                        int16ReadOnlyDataVariable,
                        int32ReadOnlyDataVariable,
                        int64ReadOnlyDataVariable,
                        sByteReadOnlyDataVariable,
                        stringReadOnlyDataVariable,
                        uInt16ReadOnlyDataVariable,
                        uInt32ReadOnlyDataVariable,
                        uInt64ReadOnlyDataVariable,
                        variantReadOnlyDataVariable
                    }
                })

            ' The Static sub-folder contains data variables with static values which can be changed through writing to
            ' them (so-called "registers").

            ' "Array":
            ' For demonstration, we consistently create one-dimensional arrays with initially 3 elements, where the
            ' first element has the same value as the scalar variable with the same name.

            ' "Array.ByteValue":
            ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
            ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
            ' specified explicitly.

            ' "Array.DateTimeValue":
            ' We are passing in UTC times, because we want always the same result, and so we must specify
            ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
            ' server, and the result will depend on the time zone.

            ' "Array2D":
            ' We create 2-dimensional arrays with 4x3 size, and default element values.

            ' "BoundedArray":
            ' Array nodes with specified and enforced maximum array dimensions.

            ' "BoundedArray.ByteValue":
            ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
            ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
            ' specified explicitly.

            ' "Scalar.DateTimeValue":
            ' We are passing in UTC times, because we want always the same result, and so we must specify
            ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
            ' server, and the result will depend on the time zone.

            dataFolder.Add(
                New UAFolder("Static") From
                { _
                  _ ' For demonstration, we consistently create one-dimensional arrays with initially 3 elements, where the
                  _ ' first element has the same value as the scalar variable with the same name.
                    New UAFolder("Array") From
                    {
                        New UADataVariable("BooleanValue").ReadWriteValue(
                        {
                            True,
                            False,
                            True
                        }),
                        New UADataVariable("ByteStringValue").ReadWriteValue(
                        {
                            New Byte() {&H57, &H21, &H40, &HFC},
                            New Byte() {248, 131, 217, 210},
                            New Byte() {252, 152, 119, 65}
                        }), _
                            _ ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                            _ ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                            _ ' specified explicitly.
                        New UADataVariable("ByteValue").ReadWriteValue(
                            dataTypeId:=UADataTypeIds.Byte,
                            arrayRank:=1,
                            value:=New Byte() _
                            {
                                144,
                                19,
                                233
                            }),
                        New UADataVariable("DateTimeValue").ReadWriteValue(
                        { _
                          _ ' We are passing in UTC times, because we want always the same result, and so we must specify
                          _ ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                          _ ' server, and the result will depend on the time zone.
                            DateTime.SpecifyKind(New DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                DateTimeKind.Utc),
                            DateTime.SpecifyKind(New DateTime(2024, 4, 8), DateTimeKind.Utc),
                            DateTime.SpecifyKind(New DateTime(2023, 8, 14, 18, 13, 0), DateTimeKind.Utc)
                        }),
                        New UADataVariable("DoubleValue").ReadWriteValue(
                        {
                            0.0000000000775630105797,
                            -0.467227097818268,
                            -3.51653052582609E+300
                        }),
                        New UADataVariable("FloatValue").ReadWriteValue(
                        {
                            2.77002E+29F,
                            -1.103936E+36F,
                            -9.002293E-28F
                        }),
                        New UADataVariable("GuidValue").ReadWriteValue(
                        {
                            New Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}"),
                            New Guid("{E8690EA3-25D0-4F19-9DFC-AA25D2772B2F}"),
                            New Guid("{9E081C84-7953-4A88-B709-447FC187EDD9}")
                        }),
                        New UADataVariable("Int16Value").ReadWriteValue(New Short() _
                        {
                            -30956,
                            31277,
                            21977
                        }),
                        New UADataVariable("Int32Value").ReadWriteValue(
                        {
                            276673160,
                            630080334,
                            -391755284
                        }),
                        New UADataVariable("Int64Value").ReadWriteValue(
                        {
                            1412096336825367659,
                            -808781653700434592,
                            4707848393174903135
                        }),
                        New UADataVariable("SByteValue").ReadWriteValue(New SByte() _
                        {
                            -113,
                            -92,
                            2
                        }),
                        New UADataVariable("StringValue").ReadWriteValue(
                        {
                            "lorem ipsum",
                            "dolor sit amet",
                            "consectetur adipiscing elit"
                        }),
                        New UADataVariable("UInt16Value").ReadWriteValue(New UShort() _
                        {
                            64421US,
                            22663US,
                            36755US
                        }),
                        New UADataVariable("UInt32Value").ReadWriteValue(New UInteger() _
                        {
                            3853116537UI,
                            968679231UI,
                            995611904UI
                        }),
                        New UADataVariable("UInt64Value").ReadWriteValue(New ULong() _
                        {
                            9431348106520835314UL,
                            15635738044048254300UL,
                            946287779964705249UL
                        }),
                        New UADataVariable("VariantValue").ReadWriteValue(New Object() _
                        {
                            529739609,
                            "lorem ipsum",
                            New Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")
                        })
                    }, _
                       _
                       _ ' We create 2-dimensional arrays with 4x3 size, and default element values.
                    New UAFolder("Array2D") From
                    {
                        New UADataVariable("BooleanValue").ReadWriteValue(New Boolean(3, 2) {}),
                        New UADataVariable("ByteStringValue").ReadWriteValue(New Byte(3, 2)() {}),
                        New UADataVariable("ByteValue").ReadWriteValue(New Byte(3, 2) {}),
                        New UADataVariable("DateTimeValue").ReadWriteValue(New DateTime(3, 2) {}),
                        New UADataVariable("DoubleValue").ReadWriteValue(New Double(3, 2) {}),
                        New UADataVariable("FloatValue").ReadWriteValue(New Single(3, 2) {}),
                        New UADataVariable("GuidValue").ReadWriteValue(New Guid(3, 2) {}),
                        New UADataVariable("Int16Value").ReadWriteValue(New Short(3, 2) {}),
                        New UADataVariable("Int32Value").ReadWriteValue(New Integer(3, 2) {}),
                        New UADataVariable("Int64Value").ReadWriteValue(New Long(3, 2) {}),
                        New UADataVariable("SByteValue").ReadWriteValue(New SByte(3, 2) {}),
                        New UADataVariable("StringValue").ReadWriteValue(New String(3, 2) {}),
                        New UADataVariable("UInt16Value").ReadWriteValue(New UShort(3, 2) {}),
                        New UADataVariable("UInt32Value").ReadWriteValue(New UInteger(3, 2) {}),
                        New UADataVariable("UInt64Value").ReadWriteValue(New ULong(3, 2) {}),
                        New UADataVariable("VariantValue").ReadWriteValue(New Object(3, 2) {})
                    }, _
                       _
                       _ ' Array nodes with specified and enforced maximum array dimensions.
                    New UAFolder("BoundedArray") From
                    {
                        New UADataVariable("BooleanValue").ReadWriteValue(New Boolean(3) {}, 5),
                        New UADataVariable("ByteStringValue").ReadWriteValue(New Byte(3)() {}, 5) _
                        , _
                          _ ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                          _ ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                          _ ' specified explicitly.
                        New UADataVariable("ByteValue").ReadWriteValue(
                            dataTypeId:=UADataTypeIds.Byte,
                            arrayDimensionList:={5},
                            New Byte(3) {}),
                        New UADataVariable("DateTimeValue").ReadWriteValue(New DateTime(3) {}, 5),
                        New UADataVariable("DoubleValue").ReadWriteValue(New Double(3) {}, 5),
                        New UADataVariable("FloatValue").ReadWriteValue(New Single(3) {}, 5),
                        New UADataVariable("GuidValue").ReadWriteValue(New Guid(3) {}, 5),
                        New UADataVariable("Int16Value").ReadWriteValue(New Short(3) {}, 5),
                        New UADataVariable("Int32Value").ReadWriteValue(New Integer(3) {}, 5),
                        New UADataVariable("Int64Value").ReadWriteValue(New Long(3) {}, 5),
                        New UADataVariable("SByteValue").ReadWriteValue(New SByte(3) {}, 5),
                        New UADataVariable("StringValue").ReadWriteValue(New String(3) {}, 5),
                        New UADataVariable("UInt16Value").ReadWriteValue(New UShort(3) {}, 5),
                        New UADataVariable("UInt32Value").ReadWriteValue(New UInteger(3) {}, 5),
                        New UADataVariable("UInt64Value").ReadWriteValue(New ULong(3) {}, 5),
                        New UADataVariable("VariantValue").ReadWriteValue(New Object(3) {}, 5)
                    }, _
                       _
                    New UAFolder("Scalar") From
                    {
                        New UADataVariable("BooleanValue").ReadWriteValue(True),
                        New UADataVariable("ByteStringValue").ReadWriteValue(New Byte() {&H57, &H21, &H40, &HFC}),
                        New UADataVariable("ByteValue").ReadWriteValue(CByte(144)) _
                        , _
                          _ ' We are passing in UTC times, because we want always the same result, and so we must specify
                          _ ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                          _ ' server, and the result will depend on the time zone.
                        New UADataVariable("DateTimeValue").ReadWriteValue(
                            DateTime.SpecifyKind(New DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                DateTimeKind.Utc)),
                        New UADataVariable("DoubleValue").ReadWriteValue(0.0000000000775630105797),
                        New UADataVariable("FloatValue").ReadWriteValue(2.77002E+29F),
                        New UADataVariable("GuidValue").ReadWriteValue(
                            New Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")),
                        New UADataVariable("Int16Value").ReadWriteValue(CType(-30956, Short)),
                        New UADataVariable("Int32Value").ReadWriteValue(276673160),
                        New UADataVariable("Int64Value").ReadWriteValue(1412096336825367659),
                        New UADataVariable("SByteValue").ReadWriteValue(CType(-113, SByte)),
                        New UADataVariable("StringValue").ReadWriteValue("lorem ipsum"),
                        New UADataVariable("UInt16Value").ReadWriteValue(CType(64421, UShort)),
                        New UADataVariable("UInt32Value").ReadWriteValue(3853116537UI),
                        New UADataVariable("UInt64Value").ReadWriteValue(9431348106520835314UL),
                        New UADataVariable("VariantValue").ReadWriteValue(529739609)
                    }
                })

            ' Create and add write-only data variables of various data types. Implement write actions that write the value
            ' to the corresponding read-only data variable of the same data type.
            dataFolder.Add(
                New UAFolder("WriteOnly") From
                {
                    New UAFolder("Scalar") From
                    {
                        New UADataVariable("BooleanValue").Readable(False).WriteValueAction(Sub(value As Boolean) _
                            booleanReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("ByteStringValue").Readable(False).WriteValueAction(Sub(value As Byte()) _
                            byteStringReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("ByteValue").Readable(False).WriteValueAction(Sub(value As Byte) _
                            byteReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("DateTimeValue").Readable(False).WriteValueAction(Sub(value As DateTime) _
                            dateTimeReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("DoubleValue").Readable(False).WriteValueAction(Sub(value As Double) _
                            doubleReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("FloatValue").Readable(False).WriteValueAction(Sub(value As Single) _
                            floatReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("GuidValue").Readable(False).WriteValueAction(Sub(value As Guid) _
                            guidReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("Int16Value").Readable(False).WriteValueAction(Sub(value As Short) _
                            int16ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("Int32Value").Readable(False).WriteValueAction(Sub(value As Integer()) _
                            int32ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("Int64Value").Readable(False).WriteValueAction(Sub(value As Long) _
                            int64ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("SByteValue").Readable(False).WriteValueAction(Sub(value As SByte) _
                            sByteReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("StringValue").Readable(False).WriteValueAction(Sub(value As String) _
                            stringReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("UInt16Value").Readable(False).WriteValueAction(Sub(value As UShort) _
                            uInt16ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("UInt32Value").Readable(False).WriteValueAction(Sub(value As UInteger) _
                            uInt32ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("UInt64Value").Readable(False).WriteValueAction(Sub(value As ULong) _
                            uInt64ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("VariantValue").Readable(False).WriteValueAction(Sub(value As Object) _
                            variantReadOnlyDataVariable.UpdateReadAttributeData(value))
                    }
                })

        End Sub

        ' Random value generators.
        Private ReadOnly Random As Random = New Random()

        Private ReadOnly RandomStrings As String() = {"lorem", "ipsum", "dolor", "sit", "amet"}

        Private Function NextRandomArray(Of T)(nextRandomElement As Func(Of T)) As T()
            Return {nextRandomElement(), nextRandomElement(), nextRandomElement()}
        End Function

        Private Function NextRandomBoolean() As Boolean
            Return Random.Next(2) <> 0
        End Function

        Private Function NextRandomByte() As Byte
            Return CType(Random.Next(Byte.MinValue, Byte.MaxValue + 1), Byte)
        End Function

        Private Function NextRandomByteString() As Byte()
            Return {NextRandomByte(), NextRandomByte(), NextRandomByte(), NextRandomByte()}
        End Function

        Private Function NextRandomDateTime() As DateTime
            Return DateTime.MinValue.AddMilliseconds((DateTime.MaxValue - DateTime.MinValue).TotalMilliseconds *
                                              Random.NextDouble())
        End Function

        Private Function NextRandomFloat() As Single
            Return CType(Math.Pow(10, Math.Log10(Single.MaxValue) * Random.NextDouble()) * (2 * Random.Next(2) - 1), Single)
        End Function

        Private Function NextRandomDouble() As Double
            Return Math.Pow(10, Math.Log10(Double.MaxValue) * Random.NextDouble()) * (2 * Random.Next(2) - 1)
        End Function

        Private Function NextRandomGuid() As Guid
            Return Guid.NewGuid()
        End Function

        Private Function NextRandomInt16() As Short
            Return CType(Random.Next(Short.MinValue, Short.MaxValue + 1), Short)
        End Function

        Private Function NextRandomInt32() As Integer
            Dim buffer As Byte() = New Byte(3) {}
            Random.NextBytes(buffer)
            Return BitConverter.ToInt32(buffer, 0)
        End Function

        Private Function NextRandomInt64() As Long
            Dim buffer As Byte() = New Byte(7) {}
            Random.NextBytes(buffer)
            Return BitConverter.ToInt64(buffer, 0)
        End Function

        Private Function NextRandomSByte() As SByte
            Return CType(Random.Next(SByte.MinValue, SByte.MaxValue + 1), SByte)
        End Function

        Private Function NextRandomString() As String
            Return RandomStrings(Random.Next(RandomStrings.Length))
        End Function

        Private Function NextRandomUInt16() As UShort
            Return CType(Random.Next(UShort.MinValue, UShort.MaxValue + 1), UShort)
        End Function

        Private Function NextRandomUInt32() As UInteger
            Dim buffer As Byte() = New Byte(3) {}
            Random.NextBytes(buffer)
            Return BitConverter.ToUInt32(buffer, 0)
        End Function

        Private Function NextRandomUInt64() As ULong
            Dim buffer As Byte() = New Byte(7) {}
            Random.NextBytes(buffer)
            Return BitConverter.ToUInt64(buffer, 0)
        End Function

        Private Function NextRandomVariant() As Object
            Select Case Random.Next(15)
                Case 0
                    Return NextRandomBoolean()
                Case 1
                    Return NextRandomByteString()
                Case 2
                    Return NextRandomByte()
                Case 3
                    Return NextRandomDateTime()
                Case 4
                    Return NextRandomDouble()
                Case 5
                    Return NextRandomFloat()
                Case 6
                    Return NextRandomGuid()
                Case 7
                    Return NextRandomInt16()
                Case 8
                    Return NextRandomInt32()
                Case 9
                    Return NextRandomInt64()
                Case 10
                    Return NextRandomSByte()
                Case 11
                    Return NextRandomString()
                Case 12
                    Return NextRandomUInt16()
                Case 13
                    Return NextRandomUInt32()
                Case 14
                    Return NextRandomUInt64()
                Case Else
                    Return Nothing
            End Select
        End Function
    End Module
'End Namespace
Requirements

Target Platforms: .NET Framework: Windows 10 (selected versions), Windows 11 (selected versions), Windows Server 2016, Windows Server 2022; .NET: Linux, macOS, Microsoft Windows

See Also