Beyond a certain level of complexity, specialization is the fastest way to accomplish a task. The creation of the OPC (Open Platform Communications) in 1996 followed precisely this realization. A development team from the five companies Rockwell, Opto 22, Fisher-Rosemount, Intellution, and Intuitive Technologies devised a manufacturer-independent communication scheme under the name OLE for Process Control.

Their goal was to create an interface through which PLCs could provide both live and historical information and trigger alarms. Over time, the close dependence on Microsoft OLE (Object Linking and Embedding) proved to be a limitation that unnecessarily complicated the use of the standard outside the Windows platform.

To solve the problem, a new variant of the protocol was introduced, following the then-relevant design paradigm of service-oriented architecture with a separation between the data and the services that provide the data.

Who Benefits From OPC UA, and What Does It Cost?

Before discussing the technical details, it is worth examining the role of OPC UA (Unified Architecture) within interconnected systems as a whole. In principle, OPC UA is an abstraction layer that enables the connection of automation components from different manufacturers. For developers, the system is relevant in two ways. First, as a programming interface for interaction with finished automation components. Second, OPC UA can be interesting for custom-developed automation components — anyone supporting the technology will certainly enjoy broad market acceptance.

The next question concerns costs. Real OPC UA systems almost always consist of two components — on the one hand, the specifications provided by the OPC Foundation, and on the other, the actual code. In general, specifications are available under various open-source licenses, meaning that no costs arise from their use. However, anyone wishing to use sample code from the Foundation
that implements the specification must become a member of the Foundation. More information can be found here. For small companies, annual membership may cost less than €1,000.

The second major cost factor is the code used as the basis for the implementation. Due to the immense scope, it is unrealistic for a small company to develop an OPC UA stack itself, which means that the stack provider will expect compensation for their work. Pricing depends on negotiation skills, target platform, and order quantity. In addition, there are trial and demo versions of the various stacks, as well as open-source implementations of an OPC-UA server and more (see below).

Cross-Technology System

Because of the experience gained from using OLE in the first version of OPC, OPC UA was designed to be as technology-agnostic as possible. As a result, different standard protocols can be used depending on the task. Here is a brief overview of frequently used technologies:

Opc table


The basic building block of every OPC UA-based architecture is the Uniform OPC UA Object, which — shown schematically and non-scientifically — appears as illustrated in Figure 1.

An OPC UA object can expose properties and process data through its variables, including not only current information but also explicitly historical information. Through methods, callers can trigger actions in the OPC UA object, while events generally behave as one would expect from MQTT and similar technologies.

Figure 1: The Uniform object exposes a wide variety of interfaces.
Figure 1: The Uniform object exposes a wide variety of interfaces.

For communication and interaction with the various parameters and attributes contained in the OPC UA object, the specification defines two fundamental approaches. On the one hand, there is a client/server model based on the SOA (service-oriented architecture) principle. For example, a PLC that stores measurement data can assume the role of the server. Clients such as a tablet app, a PC dashboard, or an analysis tool can then retrieve the data. Such a client/server structure is familiar from other distributed information systems. One important aspect here is that retrieval of measurement data from the server is performed via polling.

With Pub(lish)/Sub(scribe) an alternative communication scheme is available that is oriented toward event-based programming and fundamentally comparable to the event systems implemented in MQTT. It is worth emphasizing that information received in MQTT brokers can also be forwarded to OPC UA.

I recommend a detailed article on OPC UA terminology that thoroughly introduces the concepts of OPC UA.

An OPC UA server network also acts as a unifying system, with the idea being that, particularly in complex industrial automation projects, information is stored across a wide variety of systems.

In the specifications for a “global namespace model,” the OPC Foundation repeatedly emphasizes that different addressing systems — compare fieldbus and TCP/IP — are normalized through the OPC-UA framework. It is also important that the model include not only the actual instances but also the instance types found within the respective automation system.

Commissioning an OPC UA Server

Despite the enormous market presence, there are few easily accessible example implementations of OPC UA servers. In the following steps, we will rely on a container-based system derived from Microsoft Azure.

Despite the independence described above, .NET technologies play a special role in the world of OPC UA. For example, there is the UA.NET repository of the standardization body, available at, which offers reference implementations of the standard in .NET technologies.


In the following steps, we will use the demo server available from, because it provides a set of more or less ready-to-use phenomena for analysis. It should also be noted that the Eclipse Foundation offers a similar product called Milo; the Milo demonstration container can be found here.

In the following steps, the author will use an eight-core workstation running Ubuntu 24.04 as the test system. The installed Docker version appears as follows:

 

tamhan@TAMHAN18:~$ docker --version

Docker version 28.4.0, build d8eb465

 

Ideally, commissioning is performed using the following command, which provides several default settings for the PLC implementation running inside the container:

 

tamhan@TAMHAN18:~$ docker run --rm -it -p 50000:50000 -p 8080:8080 --name opcplc mcr.microsoft.com/iotedge/opc-plc:latest --pn=50000 --autoaccept --sph --sn=5 --sr=10 --st=uint --fn=5 --fr=1 --ft=uint --gn=5 --aa --ut

 

During the first startup process, docker downloads the required components from the repository, after which the message PLC simulation started, press Ctrl+C to exit... appears in the terminal window once startup is successful. Leave the window open to keep the PLC (programmable logic controller) active and monitorable. During operation, the container will continuously output status information there.

The parameters --aa and --ut are important because they disable certificate-based client authentication. OPC UA differs from the previous version, also known as OPC DA, among other things through more stringent security functions, which are inconvenient for our laboratory experiments (see here).

Testing the Connection Using a Generic Client

Developers know the situation well: Anyone wishing to, for example, bring a Bluetooth LE system online, is well advised to first analyze the server with a Bluetooth LE scanner. The formal structure of OPC UA means that more or less generic scanners exist.

We will use UA Expert, available under. It is a “promotional offering” from Unified Automation: the company offers SDKs that enable developers to create programs interacting with OPC UA in a wide variety of programming languages.
UA Expert is but one example in the broad OPC UA market. A regularly updated list of additional components can be found here.

Before downloading the scanner, which is available for both Windows and Linux, registration with Unified Automation is required. Linux users receive a .tar.gz archive, which must be extracted and then prepared for execution and launched as follows:

 

tamhan@TAMHAN18:~/Downloads/UaExpert-2.0.1-x86_64-linux$ chmod +x UaExpert-2.0.1-x86_64.AppImage

tamhan@TAMHAN18:~/Downloads/UaExpert-2.0.1-x86_64-linux$ ./UaExpert-2.0.1-x86_64.AppImage

 

During first launch, the system requests the creation of a cryptographic identity. Figure 2 shows the author’s example settings.

Figure 2: These settings complete the initialization.
Figure 2: These settings complete the initialization.

Next, you must right-click the Servers folder and create a new server configuration. Because our example server does not expose its services on the standard port, 4840, we switch to the Advanced field. Under Server Information  arrow Endpoint Url, the string opc.tcp://localhost:50000 is entered.

After successfully establishing the connection — as mentioned above, parameters --aa and --ut allow for an unsecured connection — the namespace pane shown below is populated with the various objects, as shown in Figure 3.

Figure 3: The attributes offered by the example server appear in the reference client.
Figure 3: The attributes offered by the example server
appear in the reference client.

UA Expert displays all attributes provided by the various servers in this inbox — in this example, we are using only one server.

Figure 4: Numerous methods are available in the OPC PLC.
Figure 4: Numerous methods are available in the OPC PLC.

The OPC PLC object (representing the PLC) is particularly interesting; in Figure 4, we see its method tree. Clicking the functions on the right opens a call dialog. Figure 5 shows how UA Expert acknowledges a successful method call.

Figure 5: The boiler is activated through an OPC UA method call.
Figure 5: The boiler is activated through an OPC UA method call.

Profiles and Facets

One of the most innovative aspects of Bluetooth LE was the profile system; it enabled a flexible yet still generic implementation of systems. The idea is that a “System X” implements at least some attributes that expose the basic functions in a generic way. Manufacturer-specific special features can be realized through additional attributes that appear “transparent” to an unfamiliar counterpart.

OPC UA contains a somewhat similar system. The foundation consists of OPC UA data types: variable types that, similarly to strongly typed programming languages, describe data formats across systems and architectures. In general, familiar types such as Integer, Boolean, and others can be found here — the topic is summarized here.


In the next step, we encounter facets. These are interfaces specifying a particular function. The underlying idea is that a system implementing a particular facet can be processed by a consumer expecting the same facet. Similarities to Bluetooth LE profiles or to interfaces known from object-oriented programming are not coincidental.

One level above are the profiles, which, in the case of OPC UA, summarize a group of both mandatory and optional facets. A list of general profiles can be found at. Industry-specific standards include, for example, OPC for woodworking, described here, which focuses on the needs of the woodworking industry.

When developing OPC UA-certified systems, one also encounters the term Conformance Unit. A good summary of the topic can be found here.

open62541 — Open-Source OPC UA Server

Anyone wishing to use OPC UA in a commercial project will find support from various companies offering more or less ready-to-compile SDKs.

Although trial versions are available for almost all stacks, the completely open-source open62541 (see here) deserves special mention. It is a classical C-based OPC
 UA stack. Here there is an (older) variant illustrating the port to Espressif’s ESP-IDF development environment.

Although a complete discussion of programming the stack is impossible within the scope of this article, we would still like to introduce the core concepts. Technically and conceptually, open62541 feels like a mixture of ESP-IDF and Palm OS. A basic OPC-UA server can be brought to life with the following code:

 

#include <open62541/server.h>

 

int main(void) {

  UA_Server *server = UA_Server_new();

  UA_Server_runUntilInterrupt(server);

  UA_Server_delete(server);

  return 0;

}

 

Particularly important here is the UA_Server object. It represents an OPC UA server in its entirety. In the present code example, we assume that the host platform is capable of multithreading. The runUntilInterrupt() call creates a thread that then provides the OPC UA server until it is terminated via CTRL+C.

If you want to add a variable to the server, the first step is to create an instance of the UA_VariableAttributes class. It then receives the various attributes that are to be exposed to an OPC
 UA client:

 

static void

addVariable(UA_Server *server) {

  UA_VariableAttributes attr =

       UA_VariableAttributes_default;

  UA_Int32 myInteger = 42;

  UA_Variant_setScalar(&attr.value,

      &myInteger, &UA_TYPES[UA_TYPES_INT32]);

  attr.description =

      UA_LOCALIZEDTEXT("en-US","the answer");

  attr.displayName =

      UA_LOCALIZEDTEXT("en-US","the answer");

  attr.dataType =

      UA_TYPES[UA_TYPES_INT32].typeId;

  attr.accessLevel = UA_ACCESSLEVELMASK_READ |

                     UA_ACCESSLEVELMASK_WRITE;

 

In the next step, a container structure is created that maps the variable’s position within the namespace. Finally, the addVariableNode() method is called with a reference to the server object to successfully complete integration of the variable into the server memory:

 

  UA_NodeId myIntegerNodeId =

        UA_NODEID_STRING(1, "the.answer");

  UA_QualifiedName myIntegerName =

        UA_QUALIFIEDNAME(1, "the answer");

  UA_NodeId parentNodeId =

        UA_NS0ID(OBJECTSFOLDER);

  UA_NodeId parentReferenceNodeId =

        UA_NS0ID(ORGANIZES);

  UA_Server_addVariableNode(server,

          myIntegerNodeId, parentNodeId,

          parentReferenceNodeId, myIntegerName,

          UA_NS0ID(BASEDATAVARIABLETYPE),

          attr, NULL, NULL);

}

 

Of course, values stored in variables can later be updated. For this purpose, please refer to the tutorial available at, which explains the various approaches in detail.

To implement the methods demonstrated above, the present stack relies on function pointers. Here as well, the linked documentation provides further information about the programming paradigms.

Conclusion

OPC UA can be regarded as an inspiration for the data management scheme implemented in Bluetooth LE. Anyone imagining the protocol as “Bluetooth LE for automation” may be simplifying things somewhat, but would not be entirely wrong. In general, interaction with OPC UA technology is considerably easier than the immense scope of the standard documents might suggest.

The author and editorial team hope that these considerations encourage readers to explore industrial automation. It is an enormous growth sector in which high hourly rates can be earned.


Questions or Comments?

If you have technical questions or comments about this article, please contact the author (tamhan@tamoggemon.com) or the Elektor editorial team at editor@elektor.com.


Editor's Note: This article (250864-01) appears in Elektor July/August 2026.

Elektor Green Memebrship 4-2026 (1)