topcua
Not logged in

opcua command

Name

opcua - Tcl binding to the OPC/UA implementation of http://www.open62541.org

Synopsis

package require topcua
opcua cmd ?arg?

Description

This command provides several operations to manage and communicate using the OPC/UA implementation of http://www.open62541.org. It is available on common POSIX and Windows platforms. cmd indicates which operation to carry out. Any unique abbreviation for cmd is acceptable. The valid commands are:

opcua acl handle ?user pass ...?

Modifies the user/password based access control list of the server object handle. This command must be called after the server object has been created (see opcua new server) and before it is put into operation (see opcua start).

opcua add handle DataType nodeid parent reftype brname ?attrs?

Adds an new node of node class DataType in the object handle and returns the node identifer. The parameter nodeid is the requested new node identifier of the node to be created. parent is the parent node identifier and reftype the reference type or node identifier of the reference between the parent and the new node. brname is the browse name (see section Qualified Names) of the new node. The optional attrs parameter specifies attributes for the new node in form of a dictionary (see opcua attr default). If it is omitted, default values are used. The DisplayName attribute if left empty is preset to the name part of the browse name parameter.

opcua add handle Method|SimpleMethod nodeid parent reftype outargs brname inargs cmd ?attrs?

Adds an new node of node class Method in the object handle and returns the node identifer. In the SimpleMethod command form the parameter outargs describes the output arguments of the method as a list of zero or more pairs of data type and argument names. To force an argument to be a scalar, the argument name must be prefixed with an exclamation mark. To force an argument to be an array, the argument name must be prefixed with an asterisk. Likewise, inargs describes the input arguments of the method with identical prefix rules. In the Method command form, both outargs and inargs must be provided as lists of dicts with the template obtained from opcua types empty Argument. The parameter cmd is the Tcl callback to handle the method invocation, see section Method Callbacks for more information. For the other parameters, refer to opcua add DataType.

opcua add handle Namespace name

Adds the new namespace name to the server object handle and returns a numeric identifier for this namespace.

opcua add handle Object nodeid parent reftype brname ?typeid attrs?

Adds an new node of node class Object in the object handle and returns the node identifer. The optional parameter typeid must be a known data type name (see opcua types) or a node identifier of a data type. For the other parameters, refer to opcua add DataType.

opcua add handle ObjectType nodeid parent reftype brname ?attrs?

Adds an new node of node class ObjectType in the object handle and returns the node identifer. For the other parameters, refer to opcua add DataType.

opcua add handle Reference srcid reftype target ?forward?

Adds a reference of type reftype (see opcua reftype) between the node identifiers srcid and <target on the object handle. The optional parameter forward must be a boolean indicating the direction of the reference (true, the default, is forward, false is inverse).

opcua add handle ReferenceType nodeid parent reftype brname ?attrs?

Adds an new node of node class ReferenceType in the object handle and returns the node identifer. For the other parameters, refer to opcua add DataType.

opcua add handle Variable nodeid parent reftype brname ?typeid attrs cmd?

Adds an new node of node class Variable in the object handle and returns the node identifer. The optional parameter typeid must be a known data type name (see opcua types) or a node identifier of a data type or an empty string for a default value. Parameter cmd is an optional data source callback which produces (read operation) or consumes (write operation) the variable's value. See section Data Source Callbacks for more information. For the other parameters, refer to opcua add DataType.

opcua add handle VariableType nodeid parent reftype brname ?typeid attrs?

Adds an new node of node class VariableType in the object handle and returns the node identifer. The optional parameter typeid must be a known data type name (see opcua types) or a node identifier of a data type or an empty string for a default value. For the other parameters, refer to opcua add DataType.

opcua add handle View nodeid parent reftype brname ?attrs?

Adds an new node of node class View in the object handle and returns the node identifer. For the other parameters, refer to opcua add DataType.

opcua attrs ?list|default? ?name?

Without further arguments returns a list of attribute names the opcua read and opcua write commands support, e.g. Value, NodeClass, etc. With the list keyword a list of the data types used as attributes for creation of nodes with the opcua add command is returned. With the default keyword combined with the name of the data type a dictionary describing the default attributes of this type is returned, e.g opcua attrs default DataTypeAttributes yields a default dictionary for creation of a DataType node.

opcua browse handle nodeid ?dir refid mask ...?

Performs a browse operation on the client or server object handle starting at the node nodeid. The browse direction can be specified with the dir parameter as Forward, Inverse, or Both. Forward is the default direction. The optional mask and following parameters select specific node classes Object, Variable, Method, ObjectType, VariableType, ReferenceType, DataType, and View. The result of the browse operation is a list where each item is made up of node identifier, browse name (qualified name), display name (locale and text), node class, reference node identifier, and type node identifier.

opcua call handle nodeid methodid ?type value ...? ?-async cmd?

Calls the method with node identifier methodid on the object with node identifier nodeid on the client or server object handle with parameters described by pairs of type (data type, e.g. Int32 or String) and value (the parameter's value). The method's result is returned. The method is carried out on the server, i.e. when directly used with a server handle there's no network traffic since the method is run locally. The type parameters should be prefixed with an asterisk or an exclamation mark in order to achieve the same semantic as in a method definition with opcua add SimpleMethod. Otherwise, array vs. scalar interpretion is automatically performed, i.e. when the corresponding value is a list, it is used as an array. For client objects, asynchronous operation is carried out when the last two arguments are -async and a (possibly empty) callback command cmd. In case of a non-empty callback the command returns an integer request identifier, which can be used to cancel the asynchronous operation. Otherwise the call is performed but the result is ignored. See section Asynchronous Operations for more information.

opcua cancel handle reqid ...

Cancels one or more asynchronous requests on the client object handle. The requests to be cancelled are identified by their integer identifiers reqid. The associated callbacks are evaluated with a timeout status code.

opcua cert handle cert pkey ?trust ...?

Loads the certificate cert and public key pkey into the client or server object handle. Both must be byte arrays. The optional parameters trust are zero or more byte arrays with certicates which are added to the object's trust list. If the underlying open62541 library does not support encryption, this command fails with an appropriate error message. If it succeeds, it forces a server object to only allow encrypted sessions. Similarly, a client object tries to use a sign-and-encrypt endpoint of a server.

opcua children handle nodeid

Returns the child node identifiers of the given node identifier nodeid on the client or server object handle.

opcua connect handle url ?user password?

Connects the client object handle to the URL url using the optional credentials user and password.

opcua connect handle url -async

Connects the client object handle to the URL url. The operation is asynchronous, i.e. the connection establishment takes place in background. It can be observed with the optional onclientstate callback of the client object.

opcua datasources handle

Returns information on data sources (variable nodes with callbacks) for the server object handle. For each data source two list elements with node identifier and callback command are added to the result.

opcua datetime ?seconds|...|utc ?value??

Returns either POSIX or OPC/UA timestamps as Tcl_WideInt values. If called without further parameters the current OPC/UA local DateTime is returned. If called with the single keyword utc the current OPC/UA UtcTime is returned. Otherwise, value is required and converted from POSIX to OPC/UA UtcTime for the keywords seconds, milliseconds, and microseconds, and from OPC/UA UtcTime to POSIX for the keywords unixseconds, unixmillis, and unixmicros, respectively.

opcua deftypes handle nsuri defs

Defines custom datatypes (currently only structures) in the server object handle and namespace URI nsuri. The namespace is created with the opcua add Namespace command and must exist before the opcua deftypes command is called. The parameter defs describes the structures to be created. The command does all necessary steps to create the required nodes in the server object's address space and to store an XML bytestring describing the (de)serialization for the structures as extension objects. That XML is later to be reparsed with the opcua gentypes command. For details refer to section Defining Custom Data Structures below.

opcua delete handle Node nodeid ?withrefs?

Deletes the node with identifier nodeid on the server object handle. If withrefs is true, the references of the node are deleted, too.

opcua delete handle Reference srcid reftypeid targetid ?forward? ?bidir?

Deletes the reference described by srcid, reftypeid, and targetid on the server object handle. The boolean flag forward selects forward or inverse direction of the reference to be deleted. The boolean flag bidir requests a bidirectional reference to be deleted. The default is to delete in forward direction only.

opcua destroy handle

Destroys the client or server object handle and releases its resources, e.g. closes network connections, tears down the handle specific namespace, etc.

opcua disconnect handle ?-async?

Disconnects the client object handle. If the optional parameter -async is specified, the operation is carried out in asynchronous mode.

opcua endpoints ?url?

Queries the local OPC/UA server opc.tcp://localhost:4840 or the server specified by the url parameter for endpoints and returns a list of URLs describing the endpoints found.

opcua genstubs handle ?strip stubsts ...?

Generates stubs for methods in the handle specific address space derived from the client or server object handle. The address space is traversed and browse paths and node class paths are accumulated. The resulting browse paths optionally get the prefix strip stripped off from the beginning and optionally filtered using the glob patterns following the strip parameter. If substs is not empty it specifies pairwise regexps and substitutions which are applied on the browse paths for the final procedure names. For all nodes matching the node class path pattern Object/Method the optional InputArguments and OutputArguments child nodes are retrieved and stub procedures are written using the browse path and argument information.

opcua gentypes handle

Generates custom data type mappings using information obtained from analyzing the address space derived from the client or server object handle. This feature is highly experimental and requires the tDOM package for parsing XML. It can create encoders/decoders for simple structure data types defined in the address space which perform a mapping from/to Tcl dictionaries. For further information, see the server_types.tcl and client_types.tcl scripts in the examples directory. If this command is used, it should be invoked prior to creating method stubs, since methods may require custom data types in their arguments.

opcua info ?handle?

Returns the object type of handle, either client or server. If handle is omitted, a list of all known client and server object handles is returned.

opcua loader handle xml ?evar rvar?

Imports a node set from an XML string xml into the server handle. The amount of imported information highly depends on the build options of the underlying open62541 library. Node descriptions which can't be supported are ignored and internally accumulated. For analysis, that information is made available by the evar and rvar result variables, which receive a list in array set form with each key being the node identifier and each value a dictionary with node information (for evar) including an error description, and reference information (for rvar. A result is returned which is a list in array set form with each key being the method's implementation proc name and each value a list of node identifiers which will invoke the respective implementation.

opcua log ?command?

Retrieves or sets the callback command for open62541 log messages. When a log message is issued, command is invoked with three arguments appended: the log level, e.g. info, warning, the category, e.g. network, client, and the text of the log message.

opcua methods handle ?nodeid outtype cmd

Returns information on methods for the server object handle. Without optional arguments, for each known method three list elements with node identifier, result type information, and callback command are added to the result. With nodeid information for the specified node is returned. With outtype which must be a list of dicts of serialized Argument structs the method's mapping of result values is modified. With cmd, the Tcl callback is changed. If cmd is given as an empty list, that callback is deleted and the method node will report an error upon call from the OPC/UA side.

opcua monitor handle configure subid monid ?cmd mode interval?

Configures the monitor monid in subscription subid on the client object handle with the provided parameters, see opcua monitor new for further information.

opcua monitor handle destroy subid monid

Destroys the monitor monid in subscription subid on the client object handle and releases all its resources.

opcua monitor handle info subid ?monid?

Returns information on monitor monid in subscription subid on the client object handle. The result is a list of monitor type (data or event), the node identifier, the callback command, the attribute, and the interval. If monid is omitted, a list of all monitor identifers registered in the subscription is returned.

opcua monitor handle new subid type cmd nodeid ?attr mode interval?

Creates a monitored item of type (data or event) for the node identifier nodeid in the subscription subid on the client object handle. The optional parameter attr selects the attribute of the node to be monitored (Value is the default). The monitor mode mode must be one of Disabled, Sampling, and Reporting. The monitoring interval interval must be given as number of milliseconds, if omitted its value is derived from the subscription. The callback command parameter cmd is discussed in section Monitor Callbacks below. The command returns a numeric identifier of the newly created monitor.

opcua namespace handle ?uri?

Returns the namespace index for the namespace uri of the client or server object handle (or throws an error e.g. when the namespace doesn't exist). If uri is omitted, a list of all known namespace indices and corresponding URIs is returned.

opcua new ?client? ?name?
opcua new server port name

Creates a new client or server object and returns its handle. The port parameter must be present for server objects and specifies the server's TCP port. The optional name is the object name (the handle). If no arguments are given to opcua new a client object with an automatic name is created. During that process the Tcl namespace ::opcua::name is created which later is used to hold method stub procedures and other information. That namespace is tied to the life time of the client or server object. The initial access control list of a server object is empty.

opcua onclientstate handle ?cmd?

Returns or sets the callback for client connection state changes for the client object handle. The parameter cmd is the Tcl callback to receive connection state information; it is invoked with three added arguments: 1. the connection state as numeric OPC/UA status code, 2. the secure channel state as a string, and 3. the session state as a string. Possible secure channel states are closed, hel_sent, hel_received, ack_sent, ack_received, opn_sent, open, and closing. Possible session states are closed, create_requested, created, activate_requested, activated, and closing.

opcua onfinalize handle ?cmd?

Returns or sets the callback for node finalization events on the server object handle. The parameter cmd is the Tcl callback to handle the finalization event; it is invoked when a node in the server's address space is deleted with one additional argument which is the node identifier of the node being deleted. cmd must have proper list format. If specified as an empty list, no callback on node finalization is carried out.

opcua oninitialize handle ?cmd?

Returns or sets the callback for node initialization events on the server object handle. The parameter cmd is the Tcl callback to handle the initialization event; it is invoked when a new node is added in the server's address space with two additional arguments which are the node identifier of the new node and its node class. Cmd must have proper list format. If specified as an empty list, no callback on node initialization is carried out.

opcua parent handle nodeid

Returns the parent node identifier of the given node identifier nodeid on the client or server object handle.

opcua ptree handle ?nodeid?

Returns information similar to opcua tree using the client or server object handle. The address space is traversed starting at the node identifier nodeid (the root node if omitted). The result list is made up of browse path name, node identifier, node class path, reference node identier, type node identifier, and parent node identifier. The browse path name is a path name like notation made up of the browse names pointing to the final node as seen from the starting node. Browse names are written as qualified names, i.e. including the numeric namespace index if not in root namespace. Similarly, the node class path is a path name like notation made up of the node classes of all nodes along the path. The opcua ptree command is used internally by the opcua genstubs command in order to filter out objects and methods when creating stub Tcl commands to invoke methods on objects.

opcua read handle nodeid ?attr cmd?

Performs a read operation on the client or server object handle and returns the value of attribute attr of the node identifier nodeid. If attr is omitted, it defaults to the Value attribute. The optional parameter cmd can be specified on client objects in order to carry out the read operation in asynchronous mode. See opcua call and section Asynchronous Operations for more information.

opcua reftype ?name?

Returns the node identifier for the reference type name. When name is omitted, a list of all reference type names is returned.

opcua request handle ?reqid?

Returns information on pending asynchronous operations of the client object handle. If a numeric request identifier reqid is given, a two element list for this request is returned made up of the operation type (call, read, or write) and the callback command which receives the response. If reqid is omitted, a list of all known pending request identifiers is returned.

opcua root

Returns the node identifier of the root node.

opcua run handle ?ms?

Runs asynchronous operations (subscriptions, monitored items) on the client object handle for ms milliseconds. If ms is omitted, that duration defaults to zero. Normally, this operation is carried out by the Tcl event loop. Still, this command can be used to test if the client object is in the connected state.

opcua sc2str ?-short? code

Translates the numeric status code code to an error message string. A single word error string such as BadTimeout is produced when the -short option is specified.

opcua servers ?url?

Queries the local OPC/UA server opc.tcp://localhost:4840 or the server specified by the url parameter for server information and returns a list made up of deserialized dictionaries based on the UA_ServerOnNetwork structure. Consult the open62541 documention for more information.

opcua start handle

Starts the server object handle. See section Server Object And Event Loop below for further information.

opcua stop handle

Stops the server object handle.

opcua subscription handle configure id ?interval lifetime keepalive max prio?

Configures the subscription id on the client object handle. See opcua subscription new for the optional arguments.

opcua subscription handle destroy id

Destroys the subscription id on the client object handle.

opcua subscription handle info ?id?

Returns information about subscription id on the client object handle as a list of enable flag, interval, lifetime, keepalive, and maximum counters, and the priority value. If id is omitted, a list of all subscription identifiers of the client object is returned.

opcua subscription handle new ?flag interval lifetime keepalive max prio?

Creates a new subscription (a container for monitored items, see opcua monitor) on the client object handle and returns a numeric identifier of it. The following optional parameters control properties of the subscription: flag is the initial enable state (on by default), interval, lifetime, keepalive, and max the timing and queuing parameters, and prio the subscription's priority.

opcua subscription handle off id

Disables the subscription id on the client object handle.

opcua subscription handle on id

Enables the subscription id on the client object handle.

opcua translate handle nodeid reftype target ...

Performs a translate operation on the client or server object handle. The operation starts at node identifier nodeid and traverses the object tree along the references reftype and browse name target. A list made up of the node identifier, namespace URI, and server index of the final target is returned as the result. References can be preceeded with an exclamation mark in order to reverse their direction. A reference may be abbreviated as slash for HierarchicalReferences or as dot for Aggregates.

opcua tree handle ?nodeid?

Returns information similar to opcua browse using the client or server object handle. The address space is traversed starting at the node identifier nodeid (the root node if omitted). The result list is made up of tree level (0-based), node identifier, browse name (qualified name), display name (locale and text), node class, reference node identifier, type node identifier, and parent node identifier.

opcua type handle nodeid ?attr?

Performs a read operation on the client or server object handle like opcua read but instead of the attribute's value returns the type name of attribute attr of the node identifier nodeid. If attr is omitted, it defaults to the Value attribute.

opcua types basic|empty|list|nodeid ?handle name?

Returns a list of OPC/UA type names for the basic and list subcommands. Basic types are primitives (e.g. integer numbers) for which a mapping to Tcl objects is provided. The empty subcommand requires name to be a known OPC/UA type name and produces and returns an empty value of this type, e.g. 0.0 for a floating point type. The nodeid subcommand returns the node identifier for the type name. For the command forms where a handle can be specified, this allows to deal with additional custom data types (see e.g. opcua deftypes) which where loaded into the client or server object handle.

opcua version

Returns the major and minor version numbers of the integrated open62541 library, e.g. "1.0".

opcua write handle nodeid ?attr? type value ?cmd?

Performs a write operation on the client or server object handle writing value with type type into the attribute attr of the node identifier nodeid. If attr is omitted, it defaults to Value. The optional parameter cmd can be specified on client objects in order to carry out the write operation in asynchronous mode. See opcua call and section Asynchronous Operations for more information.

OPC/UA Ensemble

The current implementation uses an ensemble and namespace opcua, i.e. the command opcua info can be alternatively written as opcua::info. Some more complex subcommands of the opcua namespace are implemented in Tcl, namely the opcua tree and opcua genstubs procedures.

Node Identifiers

Numeric node identifiers can be written as ns=N;i=I where N is the numeric namespace, and I the numeric identifier. Likewise, string node identifiers are written as ns=N;s=S with S being the string identifier. GUID node identifiers are written as ns=N;g=G where the GUID is G with the usual format as sequence of hexadecimal numbers and dashes. The namespace part can be left out when namespace zero is addressed. Currently, byte string node identifiers are not supported. If the format cannot be determined (e.g. since the equal sign is missing) the fallback chosen is string node identifier in namespace zero. String named namespaces are not supported.

Qualified Names

Qualified names are used for example in the opcua browse and opcua translate operations as so called browse names. These are made up of an optional numeric namespace prefix (a number followed by a colon) and a name, e.g. 2:MyObject. The namespace prefix is left out if the name refers to namespace zero.

Localized Text

The data type LocalizedText is represented as a dict with the keys locale and text. When converting a Tcl value to a LocalizedText item, these keys are tried to be associated. If this operation fails, the Tcl value is used as the text part of the LocalizedText item and the locale part is left empty.

Supported Data Types

Currently, most of the data types of namespace zero are supported and can be mapped to/from Tcl, i.e. integral and floating point numbers, strings, GUIDs, and interal extension objects (similar to structures). For the latter, dictionaries are used in both directions, i.e. for encoding, a dictionary is searched for the respective member names, for decoding, a dictionary is created from the internal representation using the member names of the data type, see opcua attrs default for example. Support for custom data types is highly experimental and underdocumented (see opcua gentypes).

Monitor Callbacks

Monitor callbacks are invoked when a monitored item (data or event) is received. The callback parameter given in opcua monitor new must have proper list format and gets a single value (data) or a list of values (event) appended prior to invocation.

Data Source Callbacks

Data source callbacks are invoked when a DataValue is read or written to. The callback parameter given in the node creation (opcua add Variable) must have proper list format and gets the following parameters appended prior to invocation: the node identifier of the DataValue, the operation (either read or write), and the value attribute for write operations. For read operations the callback must return a two element list of the data type (e.g. String or Int32) and the value itself. If the callback returns the TCL_BREAK return code, the value is assumed to be an array and splitted into list elements which then are converted to OPC/UA data in an OPC/UA array.

Method Callbacks

Method callbacks are invoked when a Method node is called. The callback parameter given in the node creation (opcua add Method) must have proper list format and gets the following parameters appended prior to invocation: the object node identifier, the method node identifier, and a list of type names derived from the method's output arguments. This list may be used in the method's implementation to form the result. The callback must return a single value which must be a list with the same number of items of the output argument's type list. Each item gets converted to the respective OPC/UA data value according to the output argument information of the Method node. I.e. for simple types, a list item may be a single integer e.g. for a single UInt16, a list of integers for an array of UInt16's, a single dict for a structure type, or a list of dicts for an array of structured types.

Client Object And Event Loop

A client object obtained with opcua new client requires a running event loop only when subscriptions/monitored items are involved. Most other operations are performed synchronously (and thus blocking).

Asynchronous Operations

Asynchronous mode of operation is supported for client objects and their opcua call, opcua read, and opcua write subcommands. The callback parameter must have proper list format and gets a single value appended prior to invocation which carries the deserialized response message corresponding to the operation. It is made up as a nested dict which contains a ResponseHeader with the status code of the operation and depending on the operation the method call result(s) or the value of the attribute read plus additional diagnostic information. That dict gets an extra key named RequestId appended which is the integer request identifier of the operation which was returned by the command initiating the request. If the callback parameter is specified as empty list, the response is discarded, i.e. no Tcl code is evaluated and the operation appears as a one way request.

Client Example


    package require topcua

    # create client
    opcua new client C

    # connect to server
    opcua connect C opc.tcp://localhost:4840 user pass

    # get MyNamespace
    set ns [opcua namespace C MyNamespace]

    # generate stub procs to methods in server
    # these are created in the client specific ::opcua::C namespace
    opcua genstubs C /Root/Objects/${ns}:MyObject/${ns}:

    # list all procs in client specific namespace
    puts stderr [info procs ::opcua::C::*]

    # call stubs
    puts stderr [::opcua::C::Reverse esreveR]
    puts stderr [::opcua::C::WordSplit "word\n\nsplit"]

    # read a variable
    puts stderr [opcua read C "ns=${ns};ItsTclTime"]

    # monitor callback proc
    proc monitor {data} {
        puts stderr "Monitor: $data"
    }

    # make a subscription
    set sub [opcua subscription C new 1 1000.0]

    # make a monitor
    set mon [opcua monitor C new $sub data monitor "ns=${ns};ItsTclTime"]
    puts stderr "Subscription: $sub"
    puts stderr "Monitor: $mon"

    # handle monitors for a few seconds
    set done 0
    after 10000 {set done 1}
    vwait done

    # delete monitor and subscription
    opcua monitor C destroy $sub $mon
    opcua subscription C destroy $sub

    # shut down the server using a method call
    ::opcua::C::Exit

    # destroy the client
    opcua destroy C

Server Object And Event Loop

A server object obtained with opcua new server requires a running event loop as long as it is in running state (started with opcua start). Depending on the support of the underlying open62541 library, the opcua server's network handler re-dispatches itself using a Tcl timer callback whose interval is controlled by the protocol timers of the OPC/UA stack implementation, or it spins up a dedicated thread which deals with the network traffic. In the latter case, a running event loop is required, too, for processing method and datasource callbacks.

Server Example


    package require topcua

    # create server
    opcua new server 4840 S

    # setup access control
    opcua acl S user pass

    # implementations of methods etc.
    namespace eval ::opcua::S {
        # method callback
        proc _reverse {obj meth string} {
            return [string reverse $string]
        }
        # method callback
        proc _wordsplit {obj meth string} {
            set w [regexp -all -inline {\S+} $string]
            # return code break makes into an array result
            return -code break $w
        }
        # method callback
        proc _exit {obj meth} {
            after 1000 [namespace current]::_real_exit
            return {}
        }
        # helper proc
        proc _real_exit {} {
            catch {
                ::opcua::stop S
                ::opcua::destroy S
            }
            exit 0
        }
        # data source callback
        proc _its_tcl_time {node op {value {}}} {
            if {$op eq "read"} {
                return [list String [clock format [clock seconds]]]
            }
            return {}
        }
    }

    # create our OPC/UA namespace
    set ns [opcua add S Namespace MyNamespace]

    # get Objects folder
    set OF [lindex [opcua translate S [opcua root] / Objects] 0]

    # create an object in our namespace in Objects folder
    set obj [opcua add S Object "ns=$ns;s=MyObject" $OF Organizes \
        "$ns:MyObject"]

    # create methods on object
    set meth [opcua add S Method "ns=$ns;s=Reverse" \
                  $obj HasComponent \
                  {String !out} "$ns:Reverse" {String !in} \
                  ::opcua::S::_reverse]
    set meth [opcua add S Method "ns=$ns;s=WordSplit" \
                  $obj HasComponent \
                  {String !out} "$ns:WordSplit" {String !in} \
                  ::opcua::S::_wordsplit]
    set meth [opcua add S Method "ns=$ns;s=Exit" \
                  $obj HasComponent \
                  {} "$ns:Exit" {} \
                  ::opcua::S::_exit]

    # create a variable in our namespace in Objects folder
    set var [opcua add S Variable "ns=$ns;s=ItsTclTime" \
                 $OF Organizes \
                 "$ns:ItsTclTime" {} {} \
                 ::opcua::S::_its_tcl_time]

    # dump methods
    puts stderr [opcua methods S]

    # generate stubs to methods in server
    # these are created in the server specific ::opcua::S namespace
    opcua genstubs S /Root/Objects/${ns}:MyObject/${ns}:

    # list all procs in server specific namespace
    puts stderr [info procs ::opcua::S::*]

    # call stubs directly on server
    puts stderr [::opcua::S::Reverse esreveR]
    puts stderr [::opcua::S::WordSplit "word\n\nsplit"]

    # read our variable
    puts stderr [opcua read S $var]

    # start server
    opcua start S

    # enter event loop
    vwait forever

Defining Custom Data Structures


    package require topcua

    # create server
    opcua new server 4840 S

    # create our namespace
    set NS http://www.androwish.org/TestNS/
    set nsidx [opcua add S Namespace $NS]

    # create structs, field names prefixed with '*' are arrays
    opcua deftypes S $NS {
        struct KVPair {
            String name
            String value
        }
        struct RGB {
            UInt16 red
            UInt16 green
            UInt16 blue
        }
        struct NamedColor {
            String name
            RGB color
        }
        struct WithArray {
            String name
            String *values
        }
    }

    # import type defs
    opcua gentypes S

    # make some variables using the structs from above
    set OF [lindex [opcua translate S [opcua root] / Objects] 0]
    foreach {name type} {
        X1 KVPair
        X2 RGB
        X3 NamedColor
        X4 WithArray
    } {
        set att [opcua attrs default VariableAttributes]
        dict set att dataType [opcua types nodeid S $type]
        dict set att value [list $type [opcua types empty S $type]]
        opcua add S Variable "ns=${nsidx};s=$name" $OF Organizes \
            "${nsidx}:$name" {} $att
    }

    opcua write S "${nsidx}:X4" Value WithArray {
        name {A B C D E}
        values {A B C D E}
    }

    # start server
    opcua start S

    # enter event loop
    vwait forever